From 1442f85383a519ca2f9976b8f6790f3a97db5963 Mon Sep 17 00:00:00 2001 From: QIHAN CAI Date: Thu, 25 May 2023 11:15:47 +1000 Subject: [PATCH] [RISCV] Implement Alu Intrinsics Implement XcvAlu LLVM intrinsics. Spec: https://github.com/openhwgroup/cv32e40p/blob/62bec66b36182215e18c9cf10f723567e23878e9/docs/source/instruction_set_extensions.rst --- llvm/include/llvm/IR/IntrinsicsRISCV.td | 32 ++ llvm/lib/Support/RISCVISAInfo.cpp | 3 +- .../Target/RISCV/RISCVExpandPseudoInsts.cpp | 95 +++++ llvm/lib/Target/RISCV/RISCVInstrInfoCOREV.td | 48 +++ llvm/test/CodeGen/RISCV/corev/alu.ll | 344 ++++++++++++++++++ 5 files changed, 521 insertions(+), 1 deletion(-) diff --git a/llvm/include/llvm/IR/IntrinsicsRISCV.td b/llvm/include/llvm/IR/IntrinsicsRISCV.td index 2eaecd94bff5..caf5f1b67855 100644 --- a/llvm/include/llvm/IR/IntrinsicsRISCV.td +++ b/llvm/include/llvm/IR/IntrinsicsRISCV.td @@ -1771,4 +1771,36 @@ def int_riscv_cv_mac_machhsrn : ScalarCoreVMacGprGprGprImmIntrinsic; def int_riscv_cv_elw_elw : Intrinsic<[llvm_i32_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; + +class ScalarCoreVAluGprIntrinsic + : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], + [IntrNoMem, IntrWillReturn, IntrSpeculatable]>; +class ScalarCoreVAluGprGprIntrinsic + : Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrWillReturn, IntrSpeculatable]>; +class ScalarCoreVAluGprGprGprIntrinsic + : Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrWillReturn, IntrSpeculatable]>; +def int_riscv_cv_alu_abs : ScalarCoreVAluGprIntrinsic; +def int_riscv_cv_alu_slet : ScalarCoreVAluGprGprIntrinsic; +def int_riscv_cv_alu_sletu : ScalarCoreVAluGprGprIntrinsic; +def int_riscv_cv_alu_min : ScalarCoreVAluGprGprIntrinsic; +def int_riscv_cv_alu_minu : ScalarCoreVAluGprGprIntrinsic; +def int_riscv_cv_alu_max : ScalarCoreVAluGprGprIntrinsic; +def int_riscv_cv_alu_maxu : ScalarCoreVAluGprGprIntrinsic; +def int_riscv_cv_alu_exths : ScalarCoreVAluGprIntrinsic; +def int_riscv_cv_alu_exthz : ScalarCoreVAluGprIntrinsic; +def int_riscv_cv_alu_extbs : ScalarCoreVAluGprIntrinsic; +def int_riscv_cv_alu_extbz : ScalarCoreVAluGprIntrinsic; + +def int_riscv_cv_alu_clip : ScalarCoreVAluGprGprIntrinsic; +def int_riscv_cv_alu_clipu : ScalarCoreVAluGprGprIntrinsic; +def int_riscv_cv_alu_addn : ScalarCoreVAluGprGprGprIntrinsic; +def int_riscv_cv_alu_addun : ScalarCoreVAluGprGprGprIntrinsic; +def int_riscv_cv_alu_addrn : ScalarCoreVAluGprGprGprIntrinsic; +def int_riscv_cv_alu_addurn : ScalarCoreVAluGprGprGprIntrinsic; +def int_riscv_cv_alu_subn : ScalarCoreVAluGprGprGprIntrinsic; +def int_riscv_cv_alu_subun : ScalarCoreVAluGprGprGprIntrinsic; +def int_riscv_cv_alu_subrn : ScalarCoreVAluGprGprGprIntrinsic; +def int_riscv_cv_alu_suburn : ScalarCoreVAluGprGprGprIntrinsic; } // TargetPrefix = "riscv" diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp index 7e75bbc205dd..acd7312e9b2d 100644 --- a/llvm/lib/Support/RISCVISAInfo.cpp +++ b/llvm/lib/Support/RISCVISAInfo.cpp @@ -108,7 +108,8 @@ static const RISCVSupportedExtension SupportedExtensions[] = { {"xcvbitmanip", RISCVExtensionVersion{1, 0}}, {"xcvbi", RISCVExtensionVersion{1, 0}}, {"xcvmac", RISCVExtensionVersion{1, 0}}, - {"xcvelw", RISCVExtensionVersion{1, 0}} + {"xcvelw", RISCVExtensionVersion{1, 0}}, + {"xcvalu", RISCVExtensionVersion{1, 0}} }; static const RISCVSupportedExtension SupportedExperimentalExtensions[] = { diff --git a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp index 553f19193835..647f88888369 100644 --- a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp +++ b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp @@ -54,6 +54,8 @@ class RISCVExpandPseudo : public MachineFunctionPass { bool expandVRELOAD(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI); bool expandCoreVShuffle(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI); bool expandCoreVBitManip(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI); + bool expandCoreVClip(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI); + bool expandCoreVAddSub(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI); }; char RISCVExpandPseudo::ID = 0; @@ -142,6 +144,18 @@ bool RISCVExpandPseudo::expandMI(MachineBasicBlock &MBB, case RISCV::CV_BCLR_PSEUDO: case RISCV::CV_INSERT_PSEUDO: return expandCoreVBitManip(MBB, MBBI); + case RISCV::CV_CLIP_PSEUDO: + case RISCV::CV_CLIPU_PSEUDO: + return expandCoreVClip(MBB, MBBI); + case RISCV::CV_ADDN_PSEUDO: + case RISCV::CV_ADDUN_PSEUDO: + case RISCV::CV_ADDRN_PSEUDO: + case RISCV::CV_ADDURN_PSEUDO: + case RISCV::CV_SUBN_PSEUDO: + case RISCV::CV_SUBUN_PSEUDO: + case RISCV::CV_SUBRN_PSEUDO: + case RISCV::CV_SUBURN_PSEUDO: + return expandCoreVAddSub(MBB, MBBI); } return false; @@ -395,6 +409,87 @@ bool RISCVExpandPseudo::expandCoreVBitManip(MachineBasicBlock &MBB, return true; } +bool RISCVExpandPseudo::expandCoreVClip(llvm::MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI) { + DebugLoc DL = MBBI->getDebugLoc(); + Register DstReg = MBBI->getOperand(0).getReg(); + Register I = MBBI->getOperand(1).getReg(); + uint64_t J = MBBI->getOperand(2).getImm(); + + unsigned Opcode; + switch (MBBI->getOpcode()) { + case RISCV::CV_CLIPU_PSEUDO: + Opcode = RISCV::CV_CLIPU; + break; + case RISCV::CV_CLIP_PSEUDO: + Opcode = RISCV::CV_CLIP; + break; + default: + llvm_unreachable("unknown instruction"); + } + const MCInstrDesc &Desc = TII->get(Opcode); + BuildMI(MBB, MBBI, DL, Desc, DstReg). + addReg(I). + addImm(Log2_32_Ceil(J + 1) + 1); + MBBI->eraseFromParent(); + return true; +} + +bool RISCVExpandPseudo::expandCoreVAddSub(llvm::MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI) { + auto *MRI = &MBB.getParent()->getRegInfo(); + DebugLoc DL = MBBI->getDebugLoc(); + Register DstReg = MBBI->getOperand(0).getReg(); + Register X = MBBI->getOperand(1).getReg(); + Register Y = MBBI->getOperand(2).getReg(); + uint8_t Shift = MBBI->getOperand(3).getImm(); + + bool IsImm = 0 <= Shift && Shift <= 31; + unsigned Opcode; + switch (MBBI->getOpcode()) { + case RISCV::CV_ADDN_PSEUDO: + Opcode = IsImm ? RISCV::CV_ADDN : RISCV::CV_ADDNR; + break; + case RISCV::CV_ADDUN_PSEUDO: + Opcode = IsImm ? RISCV::CV_ADDUN : RISCV::CV_ADDUNR; + break; + case RISCV::CV_ADDRN_PSEUDO: + Opcode = IsImm ? RISCV::CV_ADDRN : RISCV::CV_ADDRNR; + break; + case RISCV::CV_ADDURN_PSEUDO: + Opcode = IsImm ? RISCV::CV_ADDURN : RISCV::CV_ADDURNR; + break; + case RISCV::CV_SUBN_PSEUDO: + Opcode = IsImm ? RISCV::CV_SUBN : RISCV::CV_SUBNR; + break; + case RISCV::CV_SUBUN_PSEUDO: + Opcode = IsImm ? RISCV::CV_SUBUN : RISCV::CV_SUBUNR; + break; + case RISCV::CV_SUBRN_PSEUDO: + Opcode = IsImm ? RISCV::CV_SUBRN : RISCV::CV_SUBRNR; + break; + case RISCV::CV_SUBURN_PSEUDO: + Opcode = IsImm ? RISCV::CV_SUBURN : RISCV::CV_SUBURNR; + break; + default: + llvm_unreachable("unknown instruction"); + } + const MCInstrDesc &Desc = TII->get(Opcode); + if (IsImm) { + BuildMI(MBB, MBBI, DL, Desc, DstReg). + addReg(X). + addReg(Y). + addImm(Shift); + } else { + MRI->replaceRegWith(DstReg, X); + BuildMI(MBB, MBBI, DL, Desc, DstReg). + addReg(Y). + addReg(DstReg); + } + MBBI->eraseFromParent(); + return true; +} + class RISCVPreRAExpandPseudo : public MachineFunctionPass { public: const RISCVInstrInfo *TII; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoCOREV.td b/llvm/lib/Target/RISCV/RISCVInstrInfoCOREV.td index 25a29bc1509b..15f98eeb3e11 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoCOREV.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoCOREV.td @@ -100,6 +100,10 @@ def cv_tuimm5: Operand, TImmLeaf(Imm);}]>; def cv_uimm10: Operand, ImmLeaf(Imm);}]>; def cv_tuimm10: Operand, TImmLeaf(Imm);}]>; +def cv_uimm32: Operand, + ImmLeaf; + + //===----------------------------------------------------------------------===// // CORE-V specific instructions //===----------------------------------------------------------------------===// @@ -797,6 +801,27 @@ let Predicates = [HasExtXcvmac] in { // Patterns for general ALU operations //===----------------------------------------------------------------------===// +class PatCoreVAluGpr : + PatGpr("int_riscv_cv_alu_" # intr), + !cast("CV_" # asm)>; +class PatCoreVAluGprGpr : + PatGprGpr("int_riscv_cv_alu_" # intr), + !cast("CV_" # asm)>; +multiclass PatCoreVAluGprImm { + def "CV_" # NAME # "_PSEUDO" : + Pseudo<(outs GPR:$rd), (ins GPR:$rs, cv_uimm32:$imm), []>; + def : PatGprGpr("CV_" # NAME # "R")>; + def : PatGprImm("CV_" # NAME # "_PSEUDO"), cv_uimm32>; +} +multiclass PatCoreVAluGprGprImm { + def "CV_" # NAME # "_PSEUDO" : + Pseudo<(outs GPR:$rd), (ins GPR:$rs1, GPR:$rs2, uimm5:$imm), []>; + def : Pat<(intr GPR:$rs1, GPR:$rs2, GPR:$rs3), + (!cast("CV_" # NAME # "R") GPR:$rs1, GPR:$rs2, GPR:$rs3)>; + def : Pat<(intr GPR:$rs1, GPR:$rs2, uimm5:$imm), + (!cast("CV_" # NAME # "_PSEUDO") GPR:$rs1, GPR:$rs2, uimm5:$imm)>; +} + let Predicates = [HasExtXcvalu] in { def : Pat<(abs GPR:$rs1), (CV_ABS GPR:$rs1)>; @@ -856,6 +881,29 @@ let Predicates = [HasExtXcvalu] in { (CV_SUBRNR GPR:$rd, GPR:$rs1, GPR:$rs2)>; def : Pat<(srl (add (sub GPR:$rd, GPR:$rs1), (roundBit GPR:$rs2)), GPR:$rs2), (CV_SUBURNR GPR:$rd, GPR:$rs1, GPR:$rs2)>; + + def : PatCoreVAluGpr<"abs", "ABS">; + def : PatCoreVAluGprGpr<"slet", "SLET">; + def : PatCoreVAluGprGpr<"sletu", "SLETU">; + def : PatCoreVAluGprGpr<"min", "MIN">; + def : PatCoreVAluGprGpr<"minu", "MINU">; + def : PatCoreVAluGprGpr<"max", "MAX">; + def : PatCoreVAluGprGpr<"maxu", "MAXU">; + def : PatCoreVAluGpr<"exths", "EXTHS">; + def : PatCoreVAluGpr<"exthz", "EXTHZ">; + def : PatCoreVAluGpr<"extbs", "EXTBS">; + def : PatCoreVAluGpr<"extbz", "EXTBZ">; + + defm CLIP : PatCoreVAluGprImm; + defm CLIPU : PatCoreVAluGprImm; + defm ADDN : PatCoreVAluGprGprImm; + defm ADDUN : PatCoreVAluGprGprImm; + defm ADDRN : PatCoreVAluGprGprImm; + defm ADDURN : PatCoreVAluGprGprImm; + defm SUBN : PatCoreVAluGprGprImm; + defm SUBUN : PatCoreVAluGprGprImm; + defm SUBRN : PatCoreVAluGprGprImm; + defm SUBURN : PatCoreVAluGprGprImm; } //===----------------------------------------------------------------------===// diff --git a/llvm/test/CodeGen/RISCV/corev/alu.ll b/llvm/test/CodeGen/RISCV/corev/alu.ll index ca9c0f536be7..01aec1732f85 100644 --- a/llvm/test/CodeGen/RISCV/corev/alu.ll +++ b/llvm/test/CodeGen/RISCV/corev/alu.ll @@ -327,3 +327,347 @@ define i32 @subuRNr(i32 %a, i32 %b, i32 %c) { %5 = lshr i32 %4, %c ret i32 %5 } + +declare i32 @llvm.riscv.cv.alu.abs(i32) + +define i32 @test.cv.alu.abs(i32 %a) { +; CHECK-LABEL: test.cv.alu.abs: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.abs a0, a0 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.abs(i32 %a) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.slet(i32, i32) + +define i32 @test.cv.alu.slet(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.slet: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.slet a0, a0, a1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.slet(i32 %a, i32 %b) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.sletu(i32, i32) + +define i32 @test.cv.alu.sletu(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.sletu: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.sletu a0, a0, a1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.sletu(i32 %a, i32 %b) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.min(i32, i32) + +define i32 @test.cv.alu.min(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.min: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.min a0, a0, a1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.min(i32 %a, i32 %b) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.minu(i32, i32) + +define i32 @test.cv.alu.minu(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.minu: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.minu a0, a0, a1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.minu(i32 %a, i32 %b) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.max(i32, i32) + +define i32 @test.cv.alu.max(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.max: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.max a0, a0, a1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.max(i32 %a, i32 %b) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.maxu(i32, i32) + +define i32 @test.cv.alu.maxu(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.maxu: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.maxu a0, a0, a1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.maxu(i32 %a, i32 %b) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.exths(i32) + +define i32 @test.cv.alu.exths(i32 %a) { +; CHECK-LABEL: test.cv.alu.exths: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.exths a0, a0 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.exths(i32 %a) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.exthz(i32) + +define i32 @test.cv.alu.exthz(i32 %a) { +; CHECK-LABEL: test.cv.alu.exthz: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.exthz a0, a0 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.exthz(i32 %a) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.extbs(i32) + +define i32 @test.cv.alu.extbs(i32 %a) { +; CHECK-LABEL: test.cv.alu.extbs: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.extbs a0, a0 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.extbs(i32 %a) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.extbz(i32) + +define i32 @test.cv.alu.extbz(i32 %a) { +; CHECK-LABEL: test.cv.alu.extbz: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.extbz a0, a0 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.extbz(i32 %a) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.clip(i32, i32) + +define i32 @test.cv.alu.clip.case.a(i32 %a) { +; CHECK-LABEL: test.cv.alu.clip.case.a: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.clip a0, a0, 5 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.clip(i32 %a, i32 15) + ret i32 %1 +} + +define i32 @test.cv.alu.clip.case.b(i32 %a) { +; CHECK-LABEL: test.cv.alu.clip.case.b: +; CHECK: # %bb.0: +; CHECK-NEXT: li a1, 10 +; CHECK-NEXT: cv.clipr a0, a0, a1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.clip(i32 %a, i32 10) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.clipu(i32, i32) + +define i32 @test.cv.alu.clipu.case.a(i32 %a) { +; CHECK-LABEL: test.cv.alu.clipu.case.a: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.clipu a0, a0, 9 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.clipu(i32 %a, i32 255) + ret i32 %1 +} + +define i32 @test.cv.alu.clipu.case.b(i32 %a) { +; CHECK-LABEL: test.cv.alu.clipu.case.b: +; CHECK: # %bb.0: +; CHECK-NEXT: li a1, 200 +; CHECK-NEXT: cv.clipur a0, a0, a1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.clipu(i32 %a, i32 200) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.addn(i32, i32, i32) + +define i32 @test.cv.alu.addn.case.a(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.addn.case.a: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.addn a0, a0, a1, 15 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.addn(i32 %a, i32 %b, i32 15) + ret i32 %1 +} + +define i32 @test.cv.alu.addn.case.b(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.addn.case.b: +; CHECK: # %bb.0: +; CHECK-NEXT: li a2, 32 +; CHECK-NEXT: cv.addnr a0, a1, a2 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.addn(i32 %a, i32 %b, i32 32) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.addun(i32, i32, i32) + +define i32 @test.cv.alu.addun.case.a(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.addun.case.a: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.addun a0, a0, a1, 15 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.addun(i32 %a, i32 %b, i32 15) + ret i32 %1 +} + +define i32 @test.cv.alu.addun.case.b(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.addun.case.b: +; CHECK: # %bb.0: +; CHECK-NEXT: li a2, 32 +; CHECK-NEXT: cv.addunr a0, a1, a2 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.addun(i32 %a, i32 %b, i32 32) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.addrn(i32, i32, i32) + +define i32 @test.cv.alu.addrn.case.a(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.addrn.case.a: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.addrn a0, a0, a1, 15 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.addrn(i32 %a, i32 %b, i32 15) + ret i32 %1 +} + +define i32 @test.cv.alu.addrn.case.b(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.addrn.case.b: +; CHECK: # %bb.0: +; CHECK-NEXT: li a2, 32 +; CHECK-NEXT: cv.addrnr a0, a1, a2 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.addrn(i32 %a, i32 %b, i32 32) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.adurn(i32, i32, i32) + +define i32 @test.cv.alu.adurn.case.a(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.adurn.case.a: +; CHECK: # %bb.0: +; CHECK-NEXT: addi sp, sp, -16 +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; CHECK-NEXT: .cfi_offset ra, -4 +; CHECK-NEXT: li a2, 15 +; CHECK-NEXT: call llvm.riscv.cv.alu.adurn@plt +; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; CHECK-NEXT: addi sp, sp, 16 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.adurn(i32 %a, i32 %b, i32 15) + ret i32 %1 +} + +define i32 @test.cv.alu.adurn.case.b(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.adurn.case.b: +; CHECK: # %bb.0: +; CHECK-NEXT: addi sp, sp, -16 +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; CHECK-NEXT: .cfi_offset ra, -4 +; CHECK-NEXT: li a2, 32 +; CHECK-NEXT: call llvm.riscv.cv.alu.adurn@plt +; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; CHECK-NEXT: addi sp, sp, 16 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.adurn(i32 %a, i32 %b, i32 32) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.subn(i32, i32, i32) + +define i32 @test.cv.alu.subn.case.a(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.subn.case.a: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.subn a0, a0, a1, 15 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.subn(i32 %a, i32 %b, i32 15) + ret i32 %1 +} + +define i32 @test.cv.alu.subn.case.b(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.subn.case.b: +; CHECK: # %bb.0: +; CHECK-NEXT: li a2, 32 +; CHECK-NEXT: cv.subnr a0, a1, a2 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.subn(i32 %a, i32 %b, i32 32) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.subun(i32, i32, i32) + +define i32 @test.cv.alu.subun.case.a(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.subun.case.a: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.subun a0, a0, a1, 15 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.subun(i32 %a, i32 %b, i32 15) + ret i32 %1 +} + +define i32 @test.cv.alu.subun.case.b(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.subun.case.b: +; CHECK: # %bb.0: +; CHECK-NEXT: li a2, 32 +; CHECK-NEXT: cv.subunr a0, a1, a2 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.subun(i32 %a, i32 %b, i32 32) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.subrn(i32, i32, i32) + +define i32 @test.cv.alu.subrn.case.a(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.subrn.case.a: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.subrn a0, a0, a1, 15 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.subrn(i32 %a, i32 %b, i32 15) + ret i32 %1 +} + +define i32 @test.cv.alu.subrn.case.b(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.subrn.case.b: +; CHECK: # %bb.0: +; CHECK-NEXT: li a2, 32 +; CHECK-NEXT: cv.subrnr a0, a1, a2 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.subrn(i32 %a, i32 %b, i32 32) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.alu.suburn(i32, i32, i32) + +define i32 @test.cv.alu.suburn.case.a(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.suburn.case.a: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.suburn a0, a0, a1, 15 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.suburn(i32 %a, i32 %b, i32 15) + ret i32 %1 +} + +define i32 @test.cv.alu.suburn.case.b(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.alu.suburn.case.b: +; CHECK: # %bb.0: +; CHECK-NEXT: li a2, 32 +; CHECK-NEXT: cv.suburnr a0, a1, a2 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.alu.suburn(i32 %a, i32 %b, i32 32) + ret i32 %1 +}