diff --git a/llvm/include/llvm/IR/IntrinsicsRISCV.td b/llvm/include/llvm/IR/IntrinsicsRISCV.td --- a/llvm/include/llvm/IR/IntrinsicsRISCV.td +++ b/llvm/include/llvm/IR/IntrinsicsRISCV.td @@ -79,6 +79,21 @@ } 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>, + ImmArg>]>; + def int_riscv_vsetvlimax : Intrinsic<[llvm_anyint_ty], + /* VSEW */ [LLVMMatchType<0>, + /* VLMUL */ LLVMMatchType<0>], + [IntrNoMem, IntrHasSideEffects, + ImmArg>, + ImmArg>]>; + // For unit stride load // Input: (pointer, vl) class RISCVUSLoad diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -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 @@ } break; } + case ISD::INTRINSIC_W_CHAIN: { + unsigned IntNo = cast(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(Node->getConstantOperandVal(3) & 0x7); + RISCVVLMUL VLMul = + static_cast(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(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(Node->getConstantOperandVal(2) & 0x7); + RISCVVLMUL VLMul = + static_cast(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. diff --git a/llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.h --- a/llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.h +++ b/llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.h @@ -346,7 +346,8 @@ LMUL_2, LMUL_4, LMUL_8, - LMUL_F8 = 5, + LMUL_RESERVED, + LMUL_F8, LMUL_F4, LMUL_F2 }; diff --git a/llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.cpp b/llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.cpp --- a/llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.cpp +++ b/llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.cpp @@ -109,6 +109,8 @@ 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: diff --git a/llvm/test/CodeGen/RISCV/rvv/rv32-vsetvli-intrinsics.ll b/llvm/test/CodeGen/RISCV/rvv/rv32-vsetvli-intrinsics.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rvv/rv32-vsetvli-intrinsics.ll @@ -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 +} diff --git a/llvm/test/CodeGen/RISCV/rvv/rv64-vsetvli-intrinsics.ll b/llvm/test/CodeGen/RISCV/rvv/rv64-vsetvli-intrinsics.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rvv/rv64-vsetvli-intrinsics.ll @@ -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 +}