[RISCV] Add intrinsics for vsetvli instruction
This patch adds two IR intrinsics for vsetvli instruction. One to set the vector length to a user specified value and one to set it to vlmax. The vlmax uses the X0 source register encoding. Clang builtins will follow in a separate patch Differential Revision: https://reviews.llvm.org/D92973
This commit is contained in:
		
							parent
							
								
									9c978dd6e1
								
							
						
					
					
						commit
						69c8d121f7
					
				| 
						 | 
				
			
			@ -79,6 +79,21 @@ class RISCVVIntrinsic {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
let TargetPrefix = "riscv" in {
 | 
			
		||||
  // We use anyint here but we only support XLen.
 | 
			
		||||
  def int_riscv_vsetvli   : Intrinsic<[llvm_anyint_ty],
 | 
			
		||||
                           /* AVL */  [LLVMMatchType<0>,
 | 
			
		||||
                           /* VSEW */  LLVMMatchType<0>,
 | 
			
		||||
                           /* VLMUL */ LLVMMatchType<0>],
 | 
			
		||||
                                      [IntrNoMem, IntrHasSideEffects,
 | 
			
		||||
                                       ImmArg<ArgIndex<1>>,
 | 
			
		||||
                                       ImmArg<ArgIndex<2>>]>;
 | 
			
		||||
  def int_riscv_vsetvlimax : Intrinsic<[llvm_anyint_ty],
 | 
			
		||||
                            /* VSEW */ [LLVMMatchType<0>,
 | 
			
		||||
                            /* VLMUL */ LLVMMatchType<0>],
 | 
			
		||||
                                      [IntrNoMem, IntrHasSideEffects,
 | 
			
		||||
                                       ImmArg<ArgIndex<0>>,
 | 
			
		||||
                                       ImmArg<ArgIndex<1>>]>;
 | 
			
		||||
 | 
			
		||||
  // For unit stride load
 | 
			
		||||
  // Input: (pointer, vl)
 | 
			
		||||
  class RISCVUSLoad
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,7 @@
 | 
			
		|||
#include "MCTargetDesc/RISCVMCTargetDesc.h"
 | 
			
		||||
#include "Utils/RISCVMatInt.h"
 | 
			
		||||
#include "llvm/CodeGen/MachineFrameInfo.h"
 | 
			
		||||
#include "llvm/IR/IntrinsicsRISCV.h"
 | 
			
		||||
#include "llvm/Support/Alignment.h"
 | 
			
		||||
#include "llvm/Support/Debug.h"
 | 
			
		||||
#include "llvm/Support/MathExtras.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -141,6 +142,70 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
 | 
			
		|||
    }
 | 
			
		||||
    break;
 | 
			
		||||
  }
 | 
			
		||||
  case ISD::INTRINSIC_W_CHAIN: {
 | 
			
		||||
    unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue();
 | 
			
		||||
    switch (IntNo) {
 | 
			
		||||
      // By default we do not custom select any intrinsic.
 | 
			
		||||
    default:
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case Intrinsic::riscv_vsetvli: {
 | 
			
		||||
      if (!Subtarget->hasStdExtV())
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      assert(Node->getNumOperands() == 5);
 | 
			
		||||
 | 
			
		||||
      RISCVVSEW VSEW =
 | 
			
		||||
          static_cast<RISCVVSEW>(Node->getConstantOperandVal(3) & 0x7);
 | 
			
		||||
      RISCVVLMUL VLMul =
 | 
			
		||||
          static_cast<RISCVVLMUL>(Node->getConstantOperandVal(4) & 0x7);
 | 
			
		||||
 | 
			
		||||
      unsigned VTypeI = RISCVVType::encodeVTYPE(
 | 
			
		||||
          VLMul, VSEW, /*TailAgnostic*/ true, /*MaskAgnostic*/ false);
 | 
			
		||||
      SDValue VTypeIOp = CurDAG->getTargetConstant(VTypeI, DL, XLenVT);
 | 
			
		||||
 | 
			
		||||
      SDValue VLOperand = Node->getOperand(2);
 | 
			
		||||
      if (auto *C = dyn_cast<ConstantSDNode>(VLOperand)) {
 | 
			
		||||
        if (C->isNullValue()) {
 | 
			
		||||
          VLOperand = SDValue(
 | 
			
		||||
              CurDAG->getMachineNode(RISCV::ADDI, DL, XLenVT,
 | 
			
		||||
                                     CurDAG->getRegister(RISCV::X0, XLenVT),
 | 
			
		||||
                                     CurDAG->getTargetConstant(0, DL, XLenVT)),
 | 
			
		||||
              0);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      ReplaceNode(Node,
 | 
			
		||||
                  CurDAG->getMachineNode(RISCV::PseudoVSETVLI, DL, XLenVT,
 | 
			
		||||
                                         MVT::Other, VLOperand, VTypeIOp,
 | 
			
		||||
                                         /* Chain */ Node->getOperand(0)));
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    case Intrinsic::riscv_vsetvlimax: {
 | 
			
		||||
      if (!Subtarget->hasStdExtV())
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      assert(Node->getNumOperands() == 4);
 | 
			
		||||
 | 
			
		||||
      RISCVVSEW VSEW =
 | 
			
		||||
          static_cast<RISCVVSEW>(Node->getConstantOperandVal(2) & 0x7);
 | 
			
		||||
      RISCVVLMUL VLMul =
 | 
			
		||||
          static_cast<RISCVVLMUL>(Node->getConstantOperandVal(3) & 0x7);
 | 
			
		||||
 | 
			
		||||
      unsigned VTypeI = RISCVVType::encodeVTYPE(
 | 
			
		||||
          VLMul, VSEW, /*TailAgnostic*/ true, /*MaskAgnostic*/ false);
 | 
			
		||||
      SDValue VTypeIOp = CurDAG->getTargetConstant(VTypeI, DL, XLenVT);
 | 
			
		||||
 | 
			
		||||
      SDValue VLOperand = CurDAG->getRegister(RISCV::X0, XLenVT);
 | 
			
		||||
      ReplaceNode(Node,
 | 
			
		||||
                  CurDAG->getMachineNode(RISCV::PseudoVSETVLI, DL, XLenVT,
 | 
			
		||||
                                         MVT::Other, VLOperand, VTypeIOp,
 | 
			
		||||
                                         /* Chain */ Node->getOperand(0)));
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
    break;
 | 
			
		||||
  }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Select the default instruction.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -109,6 +109,8 @@ void RISCVVType::printVType(unsigned VType, raw_ostream &OS) {
 | 
			
		|||
  OS << "e" << Sew;
 | 
			
		||||
 | 
			
		||||
  switch (VLMUL) {
 | 
			
		||||
  case RISCVVLMUL::LMUL_RESERVED:
 | 
			
		||||
    llvm_unreachable("Unexpected LMUL value!");
 | 
			
		||||
  case RISCVVLMUL::LMUL_1:
 | 
			
		||||
  case RISCVVLMUL::LMUL_2:
 | 
			
		||||
  case RISCVVLMUL::LMUL_4:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -346,7 +346,8 @@ enum class RISCVVLMUL {
 | 
			
		|||
  LMUL_2,
 | 
			
		||||
  LMUL_4,
 | 
			
		||||
  LMUL_8,
 | 
			
		||||
  LMUL_F8 = 5,
 | 
			
		||||
  LMUL_RESERVED,
 | 
			
		||||
  LMUL_F8,
 | 
			
		||||
  LMUL_F4,
 | 
			
		||||
  LMUL_F2
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,33 @@
 | 
			
		|||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
 | 
			
		||||
; RUN: llc -mtriple=riscv32 -mattr=+experimental-v -verify-machineinstrs < %s | FileCheck %s
 | 
			
		||||
 | 
			
		||||
declare i32 @llvm.riscv.vsetvli.i32(i32, i32, i32)
 | 
			
		||||
declare i32 @llvm.riscv.vsetvlimax.i32(i32, i32)
 | 
			
		||||
 | 
			
		||||
define void @test_vsetvli_e64mf8(i32 %avl) nounwind {
 | 
			
		||||
; CHECK-LABEL: test_vsetvli_e64mf8:
 | 
			
		||||
; CHECK:       # %bb.0:
 | 
			
		||||
; CHECK-NEXT:    vsetvli a0, a0, e64,mf8,ta,mu
 | 
			
		||||
; CHECK-NEXT:    ret
 | 
			
		||||
  call i32 @llvm.riscv.vsetvli.i32(i32 %avl, i32 3, i32 5)
 | 
			
		||||
  ret void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
define void @test_vsetvli_e8mf2_zero_avl() nounwind {
 | 
			
		||||
; CHECK-LABEL: test_vsetvli_e8mf2_zero_avl:
 | 
			
		||||
; CHECK:       # %bb.0:
 | 
			
		||||
; CHECK-NEXT:    mv a0, zero
 | 
			
		||||
; CHECK-NEXT:    vsetvli a0, a0, e8,mf2,ta,mu
 | 
			
		||||
; CHECK-NEXT:    ret
 | 
			
		||||
  call i32 @llvm.riscv.vsetvli.i32(i32 0, i32 0, i32 7)
 | 
			
		||||
  ret void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
define void @test_vsetvlimax_e64m8() nounwind {
 | 
			
		||||
; CHECK-LABEL: test_vsetvlimax_e64m8:
 | 
			
		||||
; CHECK:       # %bb.0:
 | 
			
		||||
; CHECK-NEXT:    vsetvli a0, zero, e64,m8,ta,mu
 | 
			
		||||
; CHECK-NEXT:    ret
 | 
			
		||||
  call i32 @llvm.riscv.vsetvlimax.i32(i32 3, i32 3)
 | 
			
		||||
  ret void
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,51 @@
 | 
			
		|||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
 | 
			
		||||
; RUN: llc -mtriple=riscv64 -mattr=+experimental-v -verify-machineinstrs < %s | FileCheck %s
 | 
			
		||||
 | 
			
		||||
declare i64 @llvm.riscv.vsetvli.i64(i64, i64, i64)
 | 
			
		||||
declare i64 @llvm.riscv.vsetvlimax.i64(i64, i64)
 | 
			
		||||
 | 
			
		||||
define void @test_vsetvli_e8m1(i64 %avl) nounwind {
 | 
			
		||||
; CHECK-LABEL: test_vsetvli_e8m1:
 | 
			
		||||
; CHECK:       # %bb.0:
 | 
			
		||||
; CHECK-NEXT:    vsetvli a0, a0, e8,m1,ta,mu
 | 
			
		||||
; CHECK-NEXT:    ret
 | 
			
		||||
  call i64 @llvm.riscv.vsetvli.i64(i64 %avl, i64 0, i64 0)
 | 
			
		||||
  ret void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
define void @test_vsetvli_e16mf4(i64 %avl) nounwind {
 | 
			
		||||
; CHECK-LABEL: test_vsetvli_e16mf4:
 | 
			
		||||
; CHECK:       # %bb.0:
 | 
			
		||||
; CHECK-NEXT:    vsetvli a0, a0, e16,mf4,ta,mu
 | 
			
		||||
; CHECK-NEXT:    ret
 | 
			
		||||
  call i64 @llvm.riscv.vsetvli.i64(i64 %avl, i64 1, i64 6)
 | 
			
		||||
  ret void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
define void @test_vsetvli_e32mf8_zero_avl() nounwind {
 | 
			
		||||
; CHECK-LABEL: test_vsetvli_e32mf8_zero_avl:
 | 
			
		||||
; CHECK:       # %bb.0:
 | 
			
		||||
; CHECK-NEXT:    mv a0, zero
 | 
			
		||||
; CHECK-NEXT:    vsetvli a0, a0, e16,mf4,ta,mu
 | 
			
		||||
; CHECK-NEXT:    ret
 | 
			
		||||
  call i64 @llvm.riscv.vsetvli.i64(i64 0, i64 1, i64 6)
 | 
			
		||||
  ret void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
define void @test_vsetvlimax_e32m2() nounwind {
 | 
			
		||||
; CHECK-LABEL: test_vsetvlimax_e32m2:
 | 
			
		||||
; CHECK:       # %bb.0:
 | 
			
		||||
; CHECK-NEXT:    vsetvli a0, zero, e32,m2,ta,mu
 | 
			
		||||
; CHECK-NEXT:    ret
 | 
			
		||||
  call i64 @llvm.riscv.vsetvlimax.i64(i64 2, i64 1)
 | 
			
		||||
  ret void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
define void @test_vsetvlimax_e64m4() nounwind {
 | 
			
		||||
; CHECK-LABEL: test_vsetvlimax_e64m4:
 | 
			
		||||
; CHECK:       # %bb.0:
 | 
			
		||||
; CHECK-NEXT:    vsetvli a0, zero, e64,m4,ta,mu
 | 
			
		||||
; CHECK-NEXT:    ret
 | 
			
		||||
  call i64 @llvm.riscv.vsetvlimax.i64(i64 3, i64 2)
 | 
			
		||||
  ret void
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue