diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -250,7 +250,8 @@ setOperationAction(ISD::SRL_PARTS, XLenVT, Custom); setOperationAction(ISD::SRA_PARTS, XLenVT, Custom); - if (Subtarget.hasStdExtZbb() || Subtarget.hasStdExtZbp()) { + if (Subtarget.hasStdExtZbb() || Subtarget.hasStdExtZbp() + || Subtarget.hasStdExtZbkb()) { if (Subtarget.is64Bit()) { setOperationAction(ISD::ROTL, MVT::i32, Custom); setOperationAction(ISD::ROTR, MVT::i32, Custom); diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td @@ -519,7 +519,7 @@ Sched<[WriteRotateReg32, ReadRotateReg32, ReadRotateReg32]>; def RORW : ALUW_rr<0b0110000, 0b101, "rorw">, Sched<[WriteRotateReg32, ReadRotateReg32, ReadRotateReg32]>; -} // Predicates = [HasStdExtZbbOrZbp, IsRV64] +} // Predicates = [HasStdExtZbbOrZbpOrZbkb, IsRV64] let Predicates = [HasStdExtZbp, IsRV64] in { def GORCW : ALUW_rr<0b0010100, 0b101, "gorcw">, Sched<[]>; @@ -740,15 +740,15 @@ def : InstAlias<"orc $rd, $rs", (GORCI GPR:$rd, GPR:$rs, 0b111111)>; } // Predicates = [HasStdExtZbp, IsRV64] -let Predicates = [HasStdExtZbbOrZbp] in { +let Predicates = [HasStdExtZbbOrZbpOrZbkb] in { def : InstAlias<"ror $rd, $rs1, $shamt", (RORI GPR:$rd, GPR:$rs1, uimmlog2xlen:$shamt), 0>; -} // Predicates = [HasStdExtZbbOrZbp] +} // Predicates = [HasStdExtZbbOrZbpOrZbkb] -let Predicates = [HasStdExtZbbOrZbp, IsRV64] in { +let Predicates = [HasStdExtZbbOrZbpOrZbkb, IsRV64] in { def : InstAlias<"rorw $rd, $rs1, $shamt", (RORIW GPR:$rd, GPR:$rs1, uimm5:$shamt), 0>; -} // Predicates = [HasStdExtZbbOrZbp, IsRV64] +} // Predicates = [HasStdExtZbbOrZbpOrZbkb, IsRV64] let Predicates = [HasStdExtZbp] in { def : InstAlias<"grev $rd, $rs1, $shamt", @@ -783,16 +783,16 @@ // Codegen patterns //===----------------------------------------------------------------------===// -let Predicates = [HasStdExtZbbOrZbp] in { +let Predicates = [HasStdExtZbbOrZbpOrZbkb] in { def : Pat<(and GPR:$rs1, (not GPR:$rs2)), (ANDN GPR:$rs1, GPR:$rs2)>; def : Pat<(or GPR:$rs1, (not GPR:$rs2)), (ORN GPR:$rs1, GPR:$rs2)>; def : Pat<(xor GPR:$rs1, (not GPR:$rs2)), (XNOR GPR:$rs1, GPR:$rs2)>; -} // Predicates = [HasStdExtZbbOrZbp] +} // Predicates = [HasStdExtZbbOrZbpOrZbkb] -let Predicates = [HasStdExtZbbOrZbp] in { +let Predicates = [HasStdExtZbbOrZbpOrZbkb] in { def : PatGprGpr; def : PatGprGpr; -} // Predicates = [HasStdExtZbbOrZbp] +} // Predicates = [HasStdExtZbbOrZbpOrZbkb] let Predicates = [HasStdExtZbs] in { def : Pat<(and (not (shiftop 1, GPR:$rs2)), GPR:$rs1), @@ -843,15 +843,17 @@ // There's no encoding for roli in the the 'B' extension as it can be // implemented with rori by negating the immediate. -let Predicates = [HasStdExtZbbOrZbp] in { +let Predicates = [HasStdExtZbbOrZbpOrZbkb] in { def : PatGprImm; def : Pat<(rotl GPR:$rs1, uimmlog2xlen:$shamt), (RORI GPR:$rs1, (ImmSubFromXLen uimmlog2xlen:$shamt))>; +} // Predicates = [HasStdExtZbbOrZbpOrZbkb] +let Predicates = [HasStdExtZbbOrZbp] in { // We treat orc.b as a separate instruction, so match it directly. We also // lower the Zbb orc.b intrinsic to this. def : Pat<(riscv_gorc GPR:$rs1, 7), (ORCB GPR:$rs1)>; -} +} // Predicates = [HasStdExtZbbOrZbp] let Predicates = [HasStdExtZbp] in { def : PatGprGpr; @@ -1080,13 +1082,13 @@ (SH3ADDUW GPR:$rs1, GPR:$rs2)>; } // Predicates = [HasStdExtZba, IsRV64] -let Predicates = [HasStdExtZbbOrZbp, IsRV64] in { +let Predicates = [HasStdExtZbbOrZbpOrZbkb, IsRV64] in { def : PatGprGpr; def : PatGprGpr; def : PatGprImm; def : Pat<(riscv_rolw GPR:$rs1, uimm5:$rs2), (RORIW GPR:$rs1, (ImmSubFrom32 uimm5:$rs2))>; -} // Predicates = [HasStdExtZbbOrZbp, IsRV64] +} // Predicates = [HasStdExtZbbOrZbpOrZbkb, IsRV64] let Predicates = [HasStdExtZbp, IsRV64] in { def : Pat<(riscv_rorw (riscv_grevw GPR:$rs1, 24), 16), (GREVIW GPR:$rs1, 8)>; diff --git a/llvm/test/CodeGen/RISCV/rv32zbb-zbp-zbkb.ll b/llvm/test/CodeGen/RISCV/rv32zbb-zbp-zbkb.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rv32zbb-zbp-zbkb.ll @@ -0,0 +1,596 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I +; RUN: llc -mtriple=riscv32 -mattr=+zbb -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32ZBB +; RUN: llc -mtriple=riscv32 -mattr=+experimental-zbp -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32ZBP +; RUN: llc -mtriple=riscv32 -mattr=+zbkb -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32ZBKB + +define i32 @andn_i32(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: andn_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: not a1, a1 +; RV32I-NEXT: and a0, a1, a0 +; RV32I-NEXT: ret +; +; RV32ZBB-LABEL: andn_i32: +; RV32ZBB: # %bb.0: +; RV32ZBB-NEXT: andn a0, a0, a1 +; RV32ZBB-NEXT: ret +; +; RV32ZBP-LABEL: andn_i32: +; RV32ZBP: # %bb.0: +; RV32ZBP-NEXT: andn a0, a0, a1 +; RV32ZBP-NEXT: ret +; +; RV32ZBKB-LABEL: andn_i32: +; RV32ZBKB: # %bb.0: +; RV32ZBKB-NEXT: andn a0, a0, a1 +; RV32ZBKB-NEXT: ret + %neg = xor i32 %b, -1 + %and = and i32 %neg, %a + ret i32 %and +} + +define i64 @andn_i64(i64 %a, i64 %b) nounwind { +; RV32I-LABEL: andn_i64: +; RV32I: # %bb.0: +; RV32I-NEXT: not a3, a3 +; RV32I-NEXT: not a2, a2 +; RV32I-NEXT: and a0, a2, a0 +; RV32I-NEXT: and a1, a3, a1 +; RV32I-NEXT: ret +; +; RV32ZBB-LABEL: andn_i64: +; RV32ZBB: # %bb.0: +; RV32ZBB-NEXT: andn a0, a0, a2 +; RV32ZBB-NEXT: andn a1, a1, a3 +; RV32ZBB-NEXT: ret +; +; RV32ZBP-LABEL: andn_i64: +; RV32ZBP: # %bb.0: +; RV32ZBP-NEXT: andn a0, a0, a2 +; RV32ZBP-NEXT: andn a1, a1, a3 +; RV32ZBP-NEXT: ret +; +; RV32ZBKB-LABEL: andn_i64: +; RV32ZBKB: # %bb.0: +; RV32ZBKB-NEXT: andn a0, a0, a2 +; RV32ZBKB-NEXT: andn a1, a1, a3 +; RV32ZBKB-NEXT: ret + %neg = xor i64 %b, -1 + %and = and i64 %neg, %a + ret i64 %and +} + +define i32 @orn_i32(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: orn_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: not a1, a1 +; RV32I-NEXT: or a0, a1, a0 +; RV32I-NEXT: ret +; +; RV32ZBB-LABEL: orn_i32: +; RV32ZBB: # %bb.0: +; RV32ZBB-NEXT: orn a0, a0, a1 +; RV32ZBB-NEXT: ret +; +; RV32ZBP-LABEL: orn_i32: +; RV32ZBP: # %bb.0: +; RV32ZBP-NEXT: orn a0, a0, a1 +; RV32ZBP-NEXT: ret +; +; RV32ZBKB-LABEL: orn_i32: +; RV32ZBKB: # %bb.0: +; RV32ZBKB-NEXT: orn a0, a0, a1 +; RV32ZBKB-NEXT: ret + %neg = xor i32 %b, -1 + %or = or i32 %neg, %a + ret i32 %or +} + +define i64 @orn_i64(i64 %a, i64 %b) nounwind { +; RV32I-LABEL: orn_i64: +; RV32I: # %bb.0: +; RV32I-NEXT: not a3, a3 +; RV32I-NEXT: not a2, a2 +; RV32I-NEXT: or a0, a2, a0 +; RV32I-NEXT: or a1, a3, a1 +; RV32I-NEXT: ret +; +; RV32ZBB-LABEL: orn_i64: +; RV32ZBB: # %bb.0: +; RV32ZBB-NEXT: orn a0, a0, a2 +; RV32ZBB-NEXT: orn a1, a1, a3 +; RV32ZBB-NEXT: ret +; +; RV32ZBP-LABEL: orn_i64: +; RV32ZBP: # %bb.0: +; RV32ZBP-NEXT: orn a0, a0, a2 +; RV32ZBP-NEXT: orn a1, a1, a3 +; RV32ZBP-NEXT: ret +; +; RV32ZBKB-LABEL: orn_i64: +; RV32ZBKB: # %bb.0: +; RV32ZBKB-NEXT: orn a0, a0, a2 +; RV32ZBKB-NEXT: orn a1, a1, a3 +; RV32ZBKB-NEXT: ret + %neg = xor i64 %b, -1 + %or = or i64 %neg, %a + ret i64 %or +} + +define i32 @xnor_i32(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: xnor_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: xor a0, a0, a1 +; RV32I-NEXT: not a0, a0 +; RV32I-NEXT: ret +; +; RV32ZBB-LABEL: xnor_i32: +; RV32ZBB: # %bb.0: +; RV32ZBB-NEXT: xnor a0, a0, a1 +; RV32ZBB-NEXT: ret +; +; RV32ZBP-LABEL: xnor_i32: +; RV32ZBP: # %bb.0: +; RV32ZBP-NEXT: xnor a0, a0, a1 +; RV32ZBP-NEXT: ret +; +; RV32ZBKB-LABEL: xnor_i32: +; RV32ZBKB: # %bb.0: +; RV32ZBKB-NEXT: xnor a0, a0, a1 +; RV32ZBKB-NEXT: ret + %neg = xor i32 %a, -1 + %xor = xor i32 %neg, %b + ret i32 %xor +} + +define i64 @xnor_i64(i64 %a, i64 %b) nounwind { +; RV32I-LABEL: xnor_i64: +; RV32I: # %bb.0: +; RV32I-NEXT: xor a1, a1, a3 +; RV32I-NEXT: xor a0, a0, a2 +; RV32I-NEXT: not a0, a0 +; RV32I-NEXT: not a1, a1 +; RV32I-NEXT: ret +; +; RV32ZBB-LABEL: xnor_i64: +; RV32ZBB: # %bb.0: +; RV32ZBB-NEXT: xnor a0, a0, a2 +; RV32ZBB-NEXT: xnor a1, a1, a3 +; RV32ZBB-NEXT: ret +; +; RV32ZBP-LABEL: xnor_i64: +; RV32ZBP: # %bb.0: +; RV32ZBP-NEXT: xnor a0, a0, a2 +; RV32ZBP-NEXT: xnor a1, a1, a3 +; RV32ZBP-NEXT: ret +; +; RV32ZBKB-LABEL: xnor_i64: +; RV32ZBKB: # %bb.0: +; RV32ZBKB-NEXT: xnor a0, a0, a2 +; RV32ZBKB-NEXT: xnor a1, a1, a3 +; RV32ZBKB-NEXT: ret + %neg = xor i64 %a, -1 + %xor = xor i64 %neg, %b + ret i64 %xor +} + +declare i32 @llvm.fshl.i32(i32, i32, i32) + +define i32 @rol_i32(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: rol_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: sll a2, a0, a1 +; RV32I-NEXT: neg a1, a1 +; RV32I-NEXT: srl a0, a0, a1 +; RV32I-NEXT: or a0, a2, a0 +; RV32I-NEXT: ret +; +; RV32ZBB-LABEL: rol_i32: +; RV32ZBB: # %bb.0: +; RV32ZBB-NEXT: rol a0, a0, a1 +; RV32ZBB-NEXT: ret +; +; RV32ZBP-LABEL: rol_i32: +; RV32ZBP: # %bb.0: +; RV32ZBP-NEXT: rol a0, a0, a1 +; RV32ZBP-NEXT: ret +; +; RV32ZBKB-LABEL: rol_i32: +; RV32ZBKB: # %bb.0: +; RV32ZBKB-NEXT: rol a0, a0, a1 +; RV32ZBKB-NEXT: ret + %or = tail call i32 @llvm.fshl.i32(i32 %a, i32 %a, i32 %b) + ret i32 %or +} + +; This test is presented here in case future expansions of the Bitmanip +; extensions introduce instructions suitable for this pattern. + +declare i64 @llvm.fshl.i64(i64, i64, i64) + +define i64 @rol_i64(i64 %a, i64 %b) nounwind { +; RV32I-LABEL: rol_i64: +; RV32I: # %bb.0: +; RV32I-NEXT: srli a3, a2, 5 +; RV32I-NEXT: andi a3, a3, 1 +; RV32I-NEXT: mv a4, a1 +; RV32I-NEXT: bnez a3, .LBB7_2 +; RV32I-NEXT: # %bb.1: +; RV32I-NEXT: mv a4, a0 +; RV32I-NEXT: .LBB7_2: +; RV32I-NEXT: sll a5, a4, a2 +; RV32I-NEXT: bnez a3, .LBB7_4 +; RV32I-NEXT: # %bb.3: +; RV32I-NEXT: mv a0, a1 +; RV32I-NEXT: .LBB7_4: +; RV32I-NEXT: srli a1, a0, 1 +; RV32I-NEXT: not a6, a2 +; RV32I-NEXT: srl a1, a1, a6 +; RV32I-NEXT: or a3, a5, a1 +; RV32I-NEXT: sll a0, a0, a2 +; RV32I-NEXT: srli a1, a4, 1 +; RV32I-NEXT: srl a1, a1, a6 +; RV32I-NEXT: or a1, a0, a1 +; RV32I-NEXT: mv a0, a3 +; RV32I-NEXT: ret +; +; RV32ZBB-LABEL: rol_i64: +; RV32ZBB: # %bb.0: +; RV32ZBB-NEXT: srli a3, a2, 5 +; RV32ZBB-NEXT: andi a3, a3, 1 +; RV32ZBB-NEXT: mv a4, a1 +; RV32ZBB-NEXT: bnez a3, .LBB7_2 +; RV32ZBB-NEXT: # %bb.1: +; RV32ZBB-NEXT: mv a4, a0 +; RV32ZBB-NEXT: .LBB7_2: +; RV32ZBB-NEXT: sll a5, a4, a2 +; RV32ZBB-NEXT: bnez a3, .LBB7_4 +; RV32ZBB-NEXT: # %bb.3: +; RV32ZBB-NEXT: mv a0, a1 +; RV32ZBB-NEXT: .LBB7_4: +; RV32ZBB-NEXT: srli a1, a0, 1 +; RV32ZBB-NEXT: not a6, a2 +; RV32ZBB-NEXT: srl a1, a1, a6 +; RV32ZBB-NEXT: or a3, a5, a1 +; RV32ZBB-NEXT: sll a0, a0, a2 +; RV32ZBB-NEXT: srli a1, a4, 1 +; RV32ZBB-NEXT: srl a1, a1, a6 +; RV32ZBB-NEXT: or a1, a0, a1 +; RV32ZBB-NEXT: mv a0, a3 +; RV32ZBB-NEXT: ret +; +; RV32ZBP-LABEL: rol_i64: +; RV32ZBP: # %bb.0: +; RV32ZBP-NEXT: srli a3, a2, 5 +; RV32ZBP-NEXT: andi a3, a3, 1 +; RV32ZBP-NEXT: mv a4, a1 +; RV32ZBP-NEXT: bnez a3, .LBB7_2 +; RV32ZBP-NEXT: # %bb.1: +; RV32ZBP-NEXT: mv a4, a0 +; RV32ZBP-NEXT: .LBB7_2: +; RV32ZBP-NEXT: sll a5, a4, a2 +; RV32ZBP-NEXT: bnez a3, .LBB7_4 +; RV32ZBP-NEXT: # %bb.3: +; RV32ZBP-NEXT: mv a0, a1 +; RV32ZBP-NEXT: .LBB7_4: +; RV32ZBP-NEXT: srli a1, a0, 1 +; RV32ZBP-NEXT: not a6, a2 +; RV32ZBP-NEXT: srl a1, a1, a6 +; RV32ZBP-NEXT: or a3, a5, a1 +; RV32ZBP-NEXT: sll a0, a0, a2 +; RV32ZBP-NEXT: srli a1, a4, 1 +; RV32ZBP-NEXT: srl a1, a1, a6 +; RV32ZBP-NEXT: or a1, a0, a1 +; RV32ZBP-NEXT: mv a0, a3 +; RV32ZBP-NEXT: ret +; +; RV32ZBKB-LABEL: rol_i64: +; RV32ZBKB: # %bb.0: +; RV32ZBKB-NEXT: srli a3, a2, 5 +; RV32ZBKB-NEXT: andi a3, a3, 1 +; RV32ZBKB-NEXT: mv a4, a1 +; RV32ZBKB-NEXT: bnez a3, .LBB7_2 +; RV32ZBKB-NEXT: # %bb.1: +; RV32ZBKB-NEXT: mv a4, a0 +; RV32ZBKB-NEXT: .LBB7_2: +; RV32ZBKB-NEXT: sll a5, a4, a2 +; RV32ZBKB-NEXT: bnez a3, .LBB7_4 +; RV32ZBKB-NEXT: # %bb.3: +; RV32ZBKB-NEXT: mv a0, a1 +; RV32ZBKB-NEXT: .LBB7_4: +; RV32ZBKB-NEXT: srli a1, a0, 1 +; RV32ZBKB-NEXT: not a6, a2 +; RV32ZBKB-NEXT: srl a1, a1, a6 +; RV32ZBKB-NEXT: or a3, a5, a1 +; RV32ZBKB-NEXT: sll a0, a0, a2 +; RV32ZBKB-NEXT: srli a1, a4, 1 +; RV32ZBKB-NEXT: srl a1, a1, a6 +; RV32ZBKB-NEXT: or a1, a0, a1 +; RV32ZBKB-NEXT: mv a0, a3 +; RV32ZBKB-NEXT: ret + %or = tail call i64 @llvm.fshl.i64(i64 %a, i64 %a, i64 %b) + ret i64 %or +} + +declare i32 @llvm.fshr.i32(i32, i32, i32) + +define i32 @ror_i32(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: ror_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: srl a2, a0, a1 +; RV32I-NEXT: neg a1, a1 +; RV32I-NEXT: sll a0, a0, a1 +; RV32I-NEXT: or a0, a2, a0 +; RV32I-NEXT: ret +; +; RV32ZBB-LABEL: ror_i32: +; RV32ZBB: # %bb.0: +; RV32ZBB-NEXT: ror a0, a0, a1 +; RV32ZBB-NEXT: ret +; +; RV32ZBP-LABEL: ror_i32: +; RV32ZBP: # %bb.0: +; RV32ZBP-NEXT: ror a0, a0, a1 +; RV32ZBP-NEXT: ret +; +; RV32ZBKB-LABEL: ror_i32: +; RV32ZBKB: # %bb.0: +; RV32ZBKB-NEXT: ror a0, a0, a1 +; RV32ZBKB-NEXT: ret + %or = tail call i32 @llvm.fshr.i32(i32 %a, i32 %a, i32 %b) + ret i32 %or +} + +; This test is presented here in case future expansions of the Bitmanip +; extensions introduce instructions suitable for this pattern. + +declare i64 @llvm.fshr.i64(i64, i64, i64) + +define i64 @ror_i64(i64 %a, i64 %b) nounwind { +; RV32I-LABEL: ror_i64: +; RV32I: # %bb.0: +; RV32I-NEXT: andi a4, a2, 32 +; RV32I-NEXT: mv a3, a0 +; RV32I-NEXT: beqz a4, .LBB9_2 +; RV32I-NEXT: # %bb.1: +; RV32I-NEXT: mv a3, a1 +; RV32I-NEXT: .LBB9_2: +; RV32I-NEXT: srl a5, a3, a2 +; RV32I-NEXT: beqz a4, .LBB9_4 +; RV32I-NEXT: # %bb.3: +; RV32I-NEXT: mv a1, a0 +; RV32I-NEXT: .LBB9_4: +; RV32I-NEXT: slli a0, a1, 1 +; RV32I-NEXT: not a4, a2 +; RV32I-NEXT: sll a0, a0, a4 +; RV32I-NEXT: or a0, a0, a5 +; RV32I-NEXT: srl a1, a1, a2 +; RV32I-NEXT: slli a2, a3, 1 +; RV32I-NEXT: sll a2, a2, a4 +; RV32I-NEXT: or a1, a2, a1 +; RV32I-NEXT: ret +; +; RV32ZBB-LABEL: ror_i64: +; RV32ZBB: # %bb.0: +; RV32ZBB-NEXT: andi a4, a2, 32 +; RV32ZBB-NEXT: mv a3, a0 +; RV32ZBB-NEXT: beqz a4, .LBB9_2 +; RV32ZBB-NEXT: # %bb.1: +; RV32ZBB-NEXT: mv a3, a1 +; RV32ZBB-NEXT: .LBB9_2: +; RV32ZBB-NEXT: srl a5, a3, a2 +; RV32ZBB-NEXT: beqz a4, .LBB9_4 +; RV32ZBB-NEXT: # %bb.3: +; RV32ZBB-NEXT: mv a1, a0 +; RV32ZBB-NEXT: .LBB9_4: +; RV32ZBB-NEXT: slli a0, a1, 1 +; RV32ZBB-NEXT: not a4, a2 +; RV32ZBB-NEXT: sll a0, a0, a4 +; RV32ZBB-NEXT: or a0, a0, a5 +; RV32ZBB-NEXT: srl a1, a1, a2 +; RV32ZBB-NEXT: slli a2, a3, 1 +; RV32ZBB-NEXT: sll a2, a2, a4 +; RV32ZBB-NEXT: or a1, a2, a1 +; RV32ZBB-NEXT: ret +; +; RV32ZBP-LABEL: ror_i64: +; RV32ZBP: # %bb.0: +; RV32ZBP-NEXT: andi a4, a2, 32 +; RV32ZBP-NEXT: mv a3, a0 +; RV32ZBP-NEXT: beqz a4, .LBB9_2 +; RV32ZBP-NEXT: # %bb.1: +; RV32ZBP-NEXT: mv a3, a1 +; RV32ZBP-NEXT: .LBB9_2: +; RV32ZBP-NEXT: srl a5, a3, a2 +; RV32ZBP-NEXT: beqz a4, .LBB9_4 +; RV32ZBP-NEXT: # %bb.3: +; RV32ZBP-NEXT: mv a1, a0 +; RV32ZBP-NEXT: .LBB9_4: +; RV32ZBP-NEXT: slli a0, a1, 1 +; RV32ZBP-NEXT: not a4, a2 +; RV32ZBP-NEXT: sll a0, a0, a4 +; RV32ZBP-NEXT: or a0, a0, a5 +; RV32ZBP-NEXT: srl a1, a1, a2 +; RV32ZBP-NEXT: slli a2, a3, 1 +; RV32ZBP-NEXT: sll a2, a2, a4 +; RV32ZBP-NEXT: or a1, a2, a1 +; RV32ZBP-NEXT: ret +; +; RV32ZBKB-LABEL: ror_i64: +; RV32ZBKB: # %bb.0: +; RV32ZBKB-NEXT: andi a4, a2, 32 +; RV32ZBKB-NEXT: mv a3, a0 +; RV32ZBKB-NEXT: beqz a4, .LBB9_2 +; RV32ZBKB-NEXT: # %bb.1: +; RV32ZBKB-NEXT: mv a3, a1 +; RV32ZBKB-NEXT: .LBB9_2: +; RV32ZBKB-NEXT: srl a5, a3, a2 +; RV32ZBKB-NEXT: beqz a4, .LBB9_4 +; RV32ZBKB-NEXT: # %bb.3: +; RV32ZBKB-NEXT: mv a1, a0 +; RV32ZBKB-NEXT: .LBB9_4: +; RV32ZBKB-NEXT: slli a0, a1, 1 +; RV32ZBKB-NEXT: not a4, a2 +; RV32ZBKB-NEXT: sll a0, a0, a4 +; RV32ZBKB-NEXT: or a0, a0, a5 +; RV32ZBKB-NEXT: srl a1, a1, a2 +; RV32ZBKB-NEXT: slli a2, a3, 1 +; RV32ZBKB-NEXT: sll a2, a2, a4 +; RV32ZBKB-NEXT: or a1, a2, a1 +; RV32ZBKB-NEXT: ret + %or = tail call i64 @llvm.fshr.i64(i64 %a, i64 %a, i64 %b) + ret i64 %or +} + +define i32 @rori_i32_fshl(i32 %a) nounwind { +; RV32I-LABEL: rori_i32_fshl: +; RV32I: # %bb.0: +; RV32I-NEXT: srli a1, a0, 1 +; RV32I-NEXT: slli a0, a0, 31 +; RV32I-NEXT: or a0, a0, a1 +; RV32I-NEXT: ret +; +; RV32ZBB-LABEL: rori_i32_fshl: +; RV32ZBB: # %bb.0: +; RV32ZBB-NEXT: rori a0, a0, 1 +; RV32ZBB-NEXT: ret +; +; RV32ZBP-LABEL: rori_i32_fshl: +; RV32ZBP: # %bb.0: +; RV32ZBP-NEXT: rori a0, a0, 1 +; RV32ZBP-NEXT: ret +; +; RV32ZBKB-LABEL: rori_i32_fshl: +; RV32ZBKB: # %bb.0: +; RV32ZBKB-NEXT: rori a0, a0, 1 +; RV32ZBKB-NEXT: ret + %1 = tail call i32 @llvm.fshl.i32(i32 %a, i32 %a, i32 31) + ret i32 %1 +} + +define i32 @rori_i32_fshr(i32 %a) nounwind { +; RV32I-LABEL: rori_i32_fshr: +; RV32I: # %bb.0: +; RV32I-NEXT: slli a1, a0, 1 +; RV32I-NEXT: srli a0, a0, 31 +; RV32I-NEXT: or a0, a0, a1 +; RV32I-NEXT: ret +; +; RV32ZBB-LABEL: rori_i32_fshr: +; RV32ZBB: # %bb.0: +; RV32ZBB-NEXT: rori a0, a0, 31 +; RV32ZBB-NEXT: ret +; +; RV32ZBP-LABEL: rori_i32_fshr: +; RV32ZBP: # %bb.0: +; RV32ZBP-NEXT: rori a0, a0, 31 +; RV32ZBP-NEXT: ret +; +; RV32ZBKB-LABEL: rori_i32_fshr: +; RV32ZBKB: # %bb.0: +; RV32ZBKB-NEXT: rori a0, a0, 31 +; RV32ZBKB-NEXT: ret + %1 = tail call i32 @llvm.fshr.i32(i32 %a, i32 %a, i32 31) + ret i32 %1 +} + +define i64 @rori_i64(i64 %a) nounwind { +; RV32I-LABEL: rori_i64: +; RV32I: # %bb.0: +; RV32I-NEXT: srli a2, a0, 1 +; RV32I-NEXT: slli a3, a1, 31 +; RV32I-NEXT: or a2, a3, a2 +; RV32I-NEXT: srli a1, a1, 1 +; RV32I-NEXT: slli a0, a0, 31 +; RV32I-NEXT: or a1, a0, a1 +; RV32I-NEXT: mv a0, a2 +; RV32I-NEXT: ret +; +; RV32ZBB-LABEL: rori_i64: +; RV32ZBB: # %bb.0: +; RV32ZBB-NEXT: srli a2, a0, 1 +; RV32ZBB-NEXT: slli a3, a1, 31 +; RV32ZBB-NEXT: or a2, a3, a2 +; RV32ZBB-NEXT: srli a1, a1, 1 +; RV32ZBB-NEXT: slli a0, a0, 31 +; RV32ZBB-NEXT: or a1, a0, a1 +; RV32ZBB-NEXT: mv a0, a2 +; RV32ZBB-NEXT: ret +; +; RV32ZBP-LABEL: rori_i64: +; RV32ZBP: # %bb.0: +; RV32ZBP-NEXT: srli a2, a0, 1 +; RV32ZBP-NEXT: slli a3, a1, 31 +; RV32ZBP-NEXT: or a2, a3, a2 +; RV32ZBP-NEXT: srli a1, a1, 1 +; RV32ZBP-NEXT: slli a0, a0, 31 +; RV32ZBP-NEXT: or a1, a0, a1 +; RV32ZBP-NEXT: mv a0, a2 +; RV32ZBP-NEXT: ret +; +; RV32ZBKB-LABEL: rori_i64: +; RV32ZBKB: # %bb.0: +; RV32ZBKB-NEXT: srli a2, a0, 1 +; RV32ZBKB-NEXT: slli a3, a1, 31 +; RV32ZBKB-NEXT: or a2, a3, a2 +; RV32ZBKB-NEXT: srli a1, a1, 1 +; RV32ZBKB-NEXT: slli a0, a0, 31 +; RV32ZBKB-NEXT: or a1, a0, a1 +; RV32ZBKB-NEXT: mv a0, a2 +; RV32ZBKB-NEXT: ret + %1 = tail call i64 @llvm.fshl.i64(i64 %a, i64 %a, i64 63) + ret i64 %1 +} + +define i64 @rori_i64_fshr(i64 %a) nounwind { +; RV32I-LABEL: rori_i64_fshr: +; RV32I: # %bb.0: +; RV32I-NEXT: srli a2, a1, 31 +; RV32I-NEXT: slli a3, a0, 1 +; RV32I-NEXT: or a2, a3, a2 +; RV32I-NEXT: srli a0, a0, 31 +; RV32I-NEXT: slli a1, a1, 1 +; RV32I-NEXT: or a1, a1, a0 +; RV32I-NEXT: mv a0, a2 +; RV32I-NEXT: ret +; +; RV32ZBB-LABEL: rori_i64_fshr: +; RV32ZBB: # %bb.0: +; RV32ZBB-NEXT: srli a2, a1, 31 +; RV32ZBB-NEXT: slli a3, a0, 1 +; RV32ZBB-NEXT: or a2, a3, a2 +; RV32ZBB-NEXT: srli a0, a0, 31 +; RV32ZBB-NEXT: slli a1, a1, 1 +; RV32ZBB-NEXT: or a1, a1, a0 +; RV32ZBB-NEXT: mv a0, a2 +; RV32ZBB-NEXT: ret +; +; RV32ZBP-LABEL: rori_i64_fshr: +; RV32ZBP: # %bb.0: +; RV32ZBP-NEXT: srli a2, a1, 31 +; RV32ZBP-NEXT: slli a3, a0, 1 +; RV32ZBP-NEXT: or a2, a3, a2 +; RV32ZBP-NEXT: srli a0, a0, 31 +; RV32ZBP-NEXT: slli a1, a1, 1 +; RV32ZBP-NEXT: or a1, a1, a0 +; RV32ZBP-NEXT: mv a0, a2 +; RV32ZBP-NEXT: ret +; +; RV32ZBKB-LABEL: rori_i64_fshr: +; RV32ZBKB: # %bb.0: +; RV32ZBKB-NEXT: srli a2, a1, 31 +; RV32ZBKB-NEXT: slli a3, a0, 1 +; RV32ZBKB-NEXT: or a2, a3, a2 +; RV32ZBKB-NEXT: srli a0, a0, 31 +; RV32ZBKB-NEXT: slli a1, a1, 1 +; RV32ZBKB-NEXT: or a1, a1, a0 +; RV32ZBKB-NEXT: mv a0, a2 +; RV32ZBKB-NEXT: ret + %1 = tail call i64 @llvm.fshr.i64(i64 %a, i64 %a, i64 63) + ret i64 %1 +} diff --git a/llvm/test/CodeGen/RISCV/rv32zbb-zbp.ll b/llvm/test/CodeGen/RISCV/rv32zbb-zbp.ll --- a/llvm/test/CodeGen/RISCV/rv32zbb-zbp.ll +++ b/llvm/test/CodeGen/RISCV/rv32zbb-zbp.ll @@ -6,470 +6,6 @@ ; RUN: llc -mtriple=riscv32 -mattr=+experimental-zbp -verify-machineinstrs < %s \ ; RUN: | FileCheck %s -check-prefix=RV32ZBP -define i32 @andn_i32(i32 %a, i32 %b) nounwind { -; RV32I-LABEL: andn_i32: -; RV32I: # %bb.0: -; RV32I-NEXT: not a1, a1 -; RV32I-NEXT: and a0, a1, a0 -; RV32I-NEXT: ret -; -; RV32ZBB-LABEL: andn_i32: -; RV32ZBB: # %bb.0: -; RV32ZBB-NEXT: andn a0, a0, a1 -; RV32ZBB-NEXT: ret -; -; RV32ZBP-LABEL: andn_i32: -; RV32ZBP: # %bb.0: -; RV32ZBP-NEXT: andn a0, a0, a1 -; RV32ZBP-NEXT: ret - %neg = xor i32 %b, -1 - %and = and i32 %neg, %a - ret i32 %and -} - -define i64 @andn_i64(i64 %a, i64 %b) nounwind { -; RV32I-LABEL: andn_i64: -; RV32I: # %bb.0: -; RV32I-NEXT: not a3, a3 -; RV32I-NEXT: not a2, a2 -; RV32I-NEXT: and a0, a2, a0 -; RV32I-NEXT: and a1, a3, a1 -; RV32I-NEXT: ret -; -; RV32ZBB-LABEL: andn_i64: -; RV32ZBB: # %bb.0: -; RV32ZBB-NEXT: andn a0, a0, a2 -; RV32ZBB-NEXT: andn a1, a1, a3 -; RV32ZBB-NEXT: ret -; -; RV32ZBP-LABEL: andn_i64: -; RV32ZBP: # %bb.0: -; RV32ZBP-NEXT: andn a0, a0, a2 -; RV32ZBP-NEXT: andn a1, a1, a3 -; RV32ZBP-NEXT: ret - %neg = xor i64 %b, -1 - %and = and i64 %neg, %a - ret i64 %and -} - -define i32 @orn_i32(i32 %a, i32 %b) nounwind { -; RV32I-LABEL: orn_i32: -; RV32I: # %bb.0: -; RV32I-NEXT: not a1, a1 -; RV32I-NEXT: or a0, a1, a0 -; RV32I-NEXT: ret -; -; RV32ZBB-LABEL: orn_i32: -; RV32ZBB: # %bb.0: -; RV32ZBB-NEXT: orn a0, a0, a1 -; RV32ZBB-NEXT: ret -; -; RV32ZBP-LABEL: orn_i32: -; RV32ZBP: # %bb.0: -; RV32ZBP-NEXT: orn a0, a0, a1 -; RV32ZBP-NEXT: ret - %neg = xor i32 %b, -1 - %or = or i32 %neg, %a - ret i32 %or -} - -define i64 @orn_i64(i64 %a, i64 %b) nounwind { -; RV32I-LABEL: orn_i64: -; RV32I: # %bb.0: -; RV32I-NEXT: not a3, a3 -; RV32I-NEXT: not a2, a2 -; RV32I-NEXT: or a0, a2, a0 -; RV32I-NEXT: or a1, a3, a1 -; RV32I-NEXT: ret -; -; RV32ZBB-LABEL: orn_i64: -; RV32ZBB: # %bb.0: -; RV32ZBB-NEXT: orn a0, a0, a2 -; RV32ZBB-NEXT: orn a1, a1, a3 -; RV32ZBB-NEXT: ret -; -; RV32ZBP-LABEL: orn_i64: -; RV32ZBP: # %bb.0: -; RV32ZBP-NEXT: orn a0, a0, a2 -; RV32ZBP-NEXT: orn a1, a1, a3 -; RV32ZBP-NEXT: ret - %neg = xor i64 %b, -1 - %or = or i64 %neg, %a - ret i64 %or -} - -define i32 @xnor_i32(i32 %a, i32 %b) nounwind { -; RV32I-LABEL: xnor_i32: -; RV32I: # %bb.0: -; RV32I-NEXT: xor a0, a0, a1 -; RV32I-NEXT: not a0, a0 -; RV32I-NEXT: ret -; -; RV32ZBB-LABEL: xnor_i32: -; RV32ZBB: # %bb.0: -; RV32ZBB-NEXT: xnor a0, a0, a1 -; RV32ZBB-NEXT: ret -; -; RV32ZBP-LABEL: xnor_i32: -; RV32ZBP: # %bb.0: -; RV32ZBP-NEXT: xnor a0, a0, a1 -; RV32ZBP-NEXT: ret - %neg = xor i32 %a, -1 - %xor = xor i32 %neg, %b - ret i32 %xor -} - -define i64 @xnor_i64(i64 %a, i64 %b) nounwind { -; RV32I-LABEL: xnor_i64: -; RV32I: # %bb.0: -; RV32I-NEXT: xor a1, a1, a3 -; RV32I-NEXT: xor a0, a0, a2 -; RV32I-NEXT: not a0, a0 -; RV32I-NEXT: not a1, a1 -; RV32I-NEXT: ret -; -; RV32ZBB-LABEL: xnor_i64: -; RV32ZBB: # %bb.0: -; RV32ZBB-NEXT: xnor a0, a0, a2 -; RV32ZBB-NEXT: xnor a1, a1, a3 -; RV32ZBB-NEXT: ret -; -; RV32ZBP-LABEL: xnor_i64: -; RV32ZBP: # %bb.0: -; RV32ZBP-NEXT: xnor a0, a0, a2 -; RV32ZBP-NEXT: xnor a1, a1, a3 -; RV32ZBP-NEXT: ret - %neg = xor i64 %a, -1 - %xor = xor i64 %neg, %b - ret i64 %xor -} - -declare i32 @llvm.fshl.i32(i32, i32, i32) - -define i32 @rol_i32(i32 %a, i32 %b) nounwind { -; RV32I-LABEL: rol_i32: -; RV32I: # %bb.0: -; RV32I-NEXT: sll a2, a0, a1 -; RV32I-NEXT: neg a1, a1 -; RV32I-NEXT: srl a0, a0, a1 -; RV32I-NEXT: or a0, a2, a0 -; RV32I-NEXT: ret -; -; RV32ZBB-LABEL: rol_i32: -; RV32ZBB: # %bb.0: -; RV32ZBB-NEXT: rol a0, a0, a1 -; RV32ZBB-NEXT: ret -; -; RV32ZBP-LABEL: rol_i32: -; RV32ZBP: # %bb.0: -; RV32ZBP-NEXT: rol a0, a0, a1 -; RV32ZBP-NEXT: ret - %or = tail call i32 @llvm.fshl.i32(i32 %a, i32 %a, i32 %b) - ret i32 %or -} - -; This test is presented here in case future expansions of the Bitmanip -; extensions introduce instructions suitable for this pattern. - -declare i64 @llvm.fshl.i64(i64, i64, i64) - -define i64 @rol_i64(i64 %a, i64 %b) nounwind { -; RV32I-LABEL: rol_i64: -; RV32I: # %bb.0: -; RV32I-NEXT: srli a3, a2, 5 -; RV32I-NEXT: andi a3, a3, 1 -; RV32I-NEXT: mv a4, a1 -; RV32I-NEXT: bnez a3, .LBB7_2 -; RV32I-NEXT: # %bb.1: -; RV32I-NEXT: mv a4, a0 -; RV32I-NEXT: .LBB7_2: -; RV32I-NEXT: sll a5, a4, a2 -; RV32I-NEXT: bnez a3, .LBB7_4 -; RV32I-NEXT: # %bb.3: -; RV32I-NEXT: mv a0, a1 -; RV32I-NEXT: .LBB7_4: -; RV32I-NEXT: srli a1, a0, 1 -; RV32I-NEXT: not a6, a2 -; RV32I-NEXT: srl a1, a1, a6 -; RV32I-NEXT: or a3, a5, a1 -; RV32I-NEXT: sll a0, a0, a2 -; RV32I-NEXT: srli a1, a4, 1 -; RV32I-NEXT: srl a1, a1, a6 -; RV32I-NEXT: or a1, a0, a1 -; RV32I-NEXT: mv a0, a3 -; RV32I-NEXT: ret -; -; RV32ZBB-LABEL: rol_i64: -; RV32ZBB: # %bb.0: -; RV32ZBB-NEXT: srli a3, a2, 5 -; RV32ZBB-NEXT: andi a3, a3, 1 -; RV32ZBB-NEXT: mv a4, a1 -; RV32ZBB-NEXT: bnez a3, .LBB7_2 -; RV32ZBB-NEXT: # %bb.1: -; RV32ZBB-NEXT: mv a4, a0 -; RV32ZBB-NEXT: .LBB7_2: -; RV32ZBB-NEXT: sll a5, a4, a2 -; RV32ZBB-NEXT: bnez a3, .LBB7_4 -; RV32ZBB-NEXT: # %bb.3: -; RV32ZBB-NEXT: mv a0, a1 -; RV32ZBB-NEXT: .LBB7_4: -; RV32ZBB-NEXT: srli a1, a0, 1 -; RV32ZBB-NEXT: not a6, a2 -; RV32ZBB-NEXT: srl a1, a1, a6 -; RV32ZBB-NEXT: or a3, a5, a1 -; RV32ZBB-NEXT: sll a0, a0, a2 -; RV32ZBB-NEXT: srli a1, a4, 1 -; RV32ZBB-NEXT: srl a1, a1, a6 -; RV32ZBB-NEXT: or a1, a0, a1 -; RV32ZBB-NEXT: mv a0, a3 -; RV32ZBB-NEXT: ret -; -; RV32ZBP-LABEL: rol_i64: -; RV32ZBP: # %bb.0: -; RV32ZBP-NEXT: srli a3, a2, 5 -; RV32ZBP-NEXT: andi a3, a3, 1 -; RV32ZBP-NEXT: mv a4, a1 -; RV32ZBP-NEXT: bnez a3, .LBB7_2 -; RV32ZBP-NEXT: # %bb.1: -; RV32ZBP-NEXT: mv a4, a0 -; RV32ZBP-NEXT: .LBB7_2: -; RV32ZBP-NEXT: sll a5, a4, a2 -; RV32ZBP-NEXT: bnez a3, .LBB7_4 -; RV32ZBP-NEXT: # %bb.3: -; RV32ZBP-NEXT: mv a0, a1 -; RV32ZBP-NEXT: .LBB7_4: -; RV32ZBP-NEXT: srli a1, a0, 1 -; RV32ZBP-NEXT: not a6, a2 -; RV32ZBP-NEXT: srl a1, a1, a6 -; RV32ZBP-NEXT: or a3, a5, a1 -; RV32ZBP-NEXT: sll a0, a0, a2 -; RV32ZBP-NEXT: srli a1, a4, 1 -; RV32ZBP-NEXT: srl a1, a1, a6 -; RV32ZBP-NEXT: or a1, a0, a1 -; RV32ZBP-NEXT: mv a0, a3 -; RV32ZBP-NEXT: ret - %or = tail call i64 @llvm.fshl.i64(i64 %a, i64 %a, i64 %b) - ret i64 %or -} - -declare i32 @llvm.fshr.i32(i32, i32, i32) - -define i32 @ror_i32(i32 %a, i32 %b) nounwind { -; RV32I-LABEL: ror_i32: -; RV32I: # %bb.0: -; RV32I-NEXT: srl a2, a0, a1 -; RV32I-NEXT: neg a1, a1 -; RV32I-NEXT: sll a0, a0, a1 -; RV32I-NEXT: or a0, a2, a0 -; RV32I-NEXT: ret -; -; RV32ZBB-LABEL: ror_i32: -; RV32ZBB: # %bb.0: -; RV32ZBB-NEXT: ror a0, a0, a1 -; RV32ZBB-NEXT: ret -; -; RV32ZBP-LABEL: ror_i32: -; RV32ZBP: # %bb.0: -; RV32ZBP-NEXT: ror a0, a0, a1 -; RV32ZBP-NEXT: ret - %or = tail call i32 @llvm.fshr.i32(i32 %a, i32 %a, i32 %b) - ret i32 %or -} - -; This test is presented here in case future expansions of the Bitmanip -; extensions introduce instructions suitable for this pattern. - -declare i64 @llvm.fshr.i64(i64, i64, i64) - -define i64 @ror_i64(i64 %a, i64 %b) nounwind { -; RV32I-LABEL: ror_i64: -; RV32I: # %bb.0: -; RV32I-NEXT: andi a4, a2, 32 -; RV32I-NEXT: mv a3, a0 -; RV32I-NEXT: beqz a4, .LBB9_2 -; RV32I-NEXT: # %bb.1: -; RV32I-NEXT: mv a3, a1 -; RV32I-NEXT: .LBB9_2: -; RV32I-NEXT: srl a5, a3, a2 -; RV32I-NEXT: beqz a4, .LBB9_4 -; RV32I-NEXT: # %bb.3: -; RV32I-NEXT: mv a1, a0 -; RV32I-NEXT: .LBB9_4: -; RV32I-NEXT: slli a0, a1, 1 -; RV32I-NEXT: not a4, a2 -; RV32I-NEXT: sll a0, a0, a4 -; RV32I-NEXT: or a0, a0, a5 -; RV32I-NEXT: srl a1, a1, a2 -; RV32I-NEXT: slli a2, a3, 1 -; RV32I-NEXT: sll a2, a2, a4 -; RV32I-NEXT: or a1, a2, a1 -; RV32I-NEXT: ret -; -; RV32ZBB-LABEL: ror_i64: -; RV32ZBB: # %bb.0: -; RV32ZBB-NEXT: andi a4, a2, 32 -; RV32ZBB-NEXT: mv a3, a0 -; RV32ZBB-NEXT: beqz a4, .LBB9_2 -; RV32ZBB-NEXT: # %bb.1: -; RV32ZBB-NEXT: mv a3, a1 -; RV32ZBB-NEXT: .LBB9_2: -; RV32ZBB-NEXT: srl a5, a3, a2 -; RV32ZBB-NEXT: beqz a4, .LBB9_4 -; RV32ZBB-NEXT: # %bb.3: -; RV32ZBB-NEXT: mv a1, a0 -; RV32ZBB-NEXT: .LBB9_4: -; RV32ZBB-NEXT: slli a0, a1, 1 -; RV32ZBB-NEXT: not a4, a2 -; RV32ZBB-NEXT: sll a0, a0, a4 -; RV32ZBB-NEXT: or a0, a0, a5 -; RV32ZBB-NEXT: srl a1, a1, a2 -; RV32ZBB-NEXT: slli a2, a3, 1 -; RV32ZBB-NEXT: sll a2, a2, a4 -; RV32ZBB-NEXT: or a1, a2, a1 -; RV32ZBB-NEXT: ret -; -; RV32ZBP-LABEL: ror_i64: -; RV32ZBP: # %bb.0: -; RV32ZBP-NEXT: andi a4, a2, 32 -; RV32ZBP-NEXT: mv a3, a0 -; RV32ZBP-NEXT: beqz a4, .LBB9_2 -; RV32ZBP-NEXT: # %bb.1: -; RV32ZBP-NEXT: mv a3, a1 -; RV32ZBP-NEXT: .LBB9_2: -; RV32ZBP-NEXT: srl a5, a3, a2 -; RV32ZBP-NEXT: beqz a4, .LBB9_4 -; RV32ZBP-NEXT: # %bb.3: -; RV32ZBP-NEXT: mv a1, a0 -; RV32ZBP-NEXT: .LBB9_4: -; RV32ZBP-NEXT: slli a0, a1, 1 -; RV32ZBP-NEXT: not a4, a2 -; RV32ZBP-NEXT: sll a0, a0, a4 -; RV32ZBP-NEXT: or a0, a0, a5 -; RV32ZBP-NEXT: srl a1, a1, a2 -; RV32ZBP-NEXT: slli a2, a3, 1 -; RV32ZBP-NEXT: sll a2, a2, a4 -; RV32ZBP-NEXT: or a1, a2, a1 -; RV32ZBP-NEXT: ret - %or = tail call i64 @llvm.fshr.i64(i64 %a, i64 %a, i64 %b) - ret i64 %or -} - -define i32 @rori_i32_fshl(i32 %a) nounwind { -; RV32I-LABEL: rori_i32_fshl: -; RV32I: # %bb.0: -; RV32I-NEXT: srli a1, a0, 1 -; RV32I-NEXT: slli a0, a0, 31 -; RV32I-NEXT: or a0, a0, a1 -; RV32I-NEXT: ret -; -; RV32ZBB-LABEL: rori_i32_fshl: -; RV32ZBB: # %bb.0: -; RV32ZBB-NEXT: rori a0, a0, 1 -; RV32ZBB-NEXT: ret -; -; RV32ZBP-LABEL: rori_i32_fshl: -; RV32ZBP: # %bb.0: -; RV32ZBP-NEXT: rori a0, a0, 1 -; RV32ZBP-NEXT: ret - %1 = tail call i32 @llvm.fshl.i32(i32 %a, i32 %a, i32 31) - ret i32 %1 -} - -define i32 @rori_i32_fshr(i32 %a) nounwind { -; RV32I-LABEL: rori_i32_fshr: -; RV32I: # %bb.0: -; RV32I-NEXT: slli a1, a0, 1 -; RV32I-NEXT: srli a0, a0, 31 -; RV32I-NEXT: or a0, a0, a1 -; RV32I-NEXT: ret -; -; RV32ZBB-LABEL: rori_i32_fshr: -; RV32ZBB: # %bb.0: -; RV32ZBB-NEXT: rori a0, a0, 31 -; RV32ZBB-NEXT: ret -; -; RV32ZBP-LABEL: rori_i32_fshr: -; RV32ZBP: # %bb.0: -; RV32ZBP-NEXT: rori a0, a0, 31 -; RV32ZBP-NEXT: ret - %1 = tail call i32 @llvm.fshr.i32(i32 %a, i32 %a, i32 31) - ret i32 %1 -} - -define i64 @rori_i64(i64 %a) nounwind { -; RV32I-LABEL: rori_i64: -; RV32I: # %bb.0: -; RV32I-NEXT: srli a2, a0, 1 -; RV32I-NEXT: slli a3, a1, 31 -; RV32I-NEXT: or a2, a3, a2 -; RV32I-NEXT: srli a1, a1, 1 -; RV32I-NEXT: slli a0, a0, 31 -; RV32I-NEXT: or a1, a0, a1 -; RV32I-NEXT: mv a0, a2 -; RV32I-NEXT: ret -; -; RV32ZBB-LABEL: rori_i64: -; RV32ZBB: # %bb.0: -; RV32ZBB-NEXT: srli a2, a0, 1 -; RV32ZBB-NEXT: slli a3, a1, 31 -; RV32ZBB-NEXT: or a2, a3, a2 -; RV32ZBB-NEXT: srli a1, a1, 1 -; RV32ZBB-NEXT: slli a0, a0, 31 -; RV32ZBB-NEXT: or a1, a0, a1 -; RV32ZBB-NEXT: mv a0, a2 -; RV32ZBB-NEXT: ret -; -; RV32ZBP-LABEL: rori_i64: -; RV32ZBP: # %bb.0: -; RV32ZBP-NEXT: srli a2, a0, 1 -; RV32ZBP-NEXT: slli a3, a1, 31 -; RV32ZBP-NEXT: or a2, a3, a2 -; RV32ZBP-NEXT: srli a1, a1, 1 -; RV32ZBP-NEXT: slli a0, a0, 31 -; RV32ZBP-NEXT: or a1, a0, a1 -; RV32ZBP-NEXT: mv a0, a2 -; RV32ZBP-NEXT: ret - %1 = tail call i64 @llvm.fshl.i64(i64 %a, i64 %a, i64 63) - ret i64 %1 -} - -define i64 @rori_i64_fshr(i64 %a) nounwind { -; RV32I-LABEL: rori_i64_fshr: -; RV32I: # %bb.0: -; RV32I-NEXT: srli a2, a1, 31 -; RV32I-NEXT: slli a3, a0, 1 -; RV32I-NEXT: or a2, a3, a2 -; RV32I-NEXT: srli a0, a0, 31 -; RV32I-NEXT: slli a1, a1, 1 -; RV32I-NEXT: or a1, a1, a0 -; RV32I-NEXT: mv a0, a2 -; RV32I-NEXT: ret -; -; RV32ZBB-LABEL: rori_i64_fshr: -; RV32ZBB: # %bb.0: -; RV32ZBB-NEXT: srli a2, a1, 31 -; RV32ZBB-NEXT: slli a3, a0, 1 -; RV32ZBB-NEXT: or a2, a3, a2 -; RV32ZBB-NEXT: srli a0, a0, 31 -; RV32ZBB-NEXT: slli a1, a1, 1 -; RV32ZBB-NEXT: or a1, a1, a0 -; RV32ZBB-NEXT: mv a0, a2 -; RV32ZBB-NEXT: ret -; -; RV32ZBP-LABEL: rori_i64_fshr: -; RV32ZBP: # %bb.0: -; RV32ZBP-NEXT: srli a2, a1, 31 -; RV32ZBP-NEXT: slli a3, a0, 1 -; RV32ZBP-NEXT: or a2, a3, a2 -; RV32ZBP-NEXT: srli a0, a0, 31 -; RV32ZBP-NEXT: slli a1, a1, 1 -; RV32ZBP-NEXT: or a1, a1, a0 -; RV32ZBP-NEXT: mv a0, a2 -; RV32ZBP-NEXT: ret - %1 = tail call i64 @llvm.fshr.i64(i64 %a, i64 %a, i64 63) - ret i64 %1 -} - define i8 @srli_i8(i8 %a) nounwind { ; RV32I-LABEL: srli_i8: ; RV32I: # %bb.0: diff --git a/llvm/test/CodeGen/RISCV/rv64zbb-zbp-zbkb.ll b/llvm/test/CodeGen/RISCV/rv64zbb-zbp-zbkb.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rv64zbb-zbp-zbkb.ll @@ -0,0 +1,667 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV64I +; RUN: llc -mtriple=riscv64 -mattr=+zbb -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV64ZBB +; RUN: llc -mtriple=riscv64 -mattr=+experimental-zbp -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV64ZBP +; RUN: llc -mtriple=riscv64 -mattr=+zbkb -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV64ZBKB + +define signext i32 @andn_i32(i32 signext %a, i32 signext %b) nounwind { +; RV64I-LABEL: andn_i32: +; RV64I: # %bb.0: +; RV64I-NEXT: not a1, a1 +; RV64I-NEXT: and a0, a1, a0 +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: andn_i32: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: andn a0, a0, a1 +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: andn_i32: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: andn a0, a0, a1 +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: andn_i32: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: andn a0, a0, a1 +; RV64ZBKB-NEXT: ret + %neg = xor i32 %b, -1 + %and = and i32 %neg, %a + ret i32 %and +} + +define i64 @andn_i64(i64 %a, i64 %b) nounwind { +; RV64I-LABEL: andn_i64: +; RV64I: # %bb.0: +; RV64I-NEXT: not a1, a1 +; RV64I-NEXT: and a0, a1, a0 +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: andn_i64: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: andn a0, a0, a1 +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: andn_i64: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: andn a0, a0, a1 +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: andn_i64: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: andn a0, a0, a1 +; RV64ZBKB-NEXT: ret + %neg = xor i64 %b, -1 + %and = and i64 %neg, %a + ret i64 %and +} + +define signext i32 @orn_i32(i32 signext %a, i32 signext %b) nounwind { +; RV64I-LABEL: orn_i32: +; RV64I: # %bb.0: +; RV64I-NEXT: not a1, a1 +; RV64I-NEXT: or a0, a1, a0 +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: orn_i32: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: orn a0, a0, a1 +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: orn_i32: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: orn a0, a0, a1 +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: orn_i32: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: orn a0, a0, a1 +; RV64ZBKB-NEXT: ret + %neg = xor i32 %b, -1 + %or = or i32 %neg, %a + ret i32 %or +} + +define i64 @orn_i64(i64 %a, i64 %b) nounwind { +; RV64I-LABEL: orn_i64: +; RV64I: # %bb.0: +; RV64I-NEXT: not a1, a1 +; RV64I-NEXT: or a0, a1, a0 +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: orn_i64: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: orn a0, a0, a1 +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: orn_i64: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: orn a0, a0, a1 +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: orn_i64: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: orn a0, a0, a1 +; RV64ZBKB-NEXT: ret + %neg = xor i64 %b, -1 + %or = or i64 %neg, %a + ret i64 %or +} + +define signext i32 @xnor_i32(i32 signext %a, i32 signext %b) nounwind { +; RV64I-LABEL: xnor_i32: +; RV64I: # %bb.0: +; RV64I-NEXT: xor a0, a0, a1 +; RV64I-NEXT: not a0, a0 +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: xnor_i32: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: xnor a0, a0, a1 +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: xnor_i32: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: xnor a0, a0, a1 +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: xnor_i32: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: xnor a0, a0, a1 +; RV64ZBKB-NEXT: ret + %neg = xor i32 %a, -1 + %xor = xor i32 %neg, %b + ret i32 %xor +} + +define i64 @xnor_i64(i64 %a, i64 %b) nounwind { +; RV64I-LABEL: xnor_i64: +; RV64I: # %bb.0: +; RV64I-NEXT: xor a0, a0, a1 +; RV64I-NEXT: not a0, a0 +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: xnor_i64: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: xnor a0, a0, a1 +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: xnor_i64: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: xnor a0, a0, a1 +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: xnor_i64: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: xnor a0, a0, a1 +; RV64ZBKB-NEXT: ret + %neg = xor i64 %a, -1 + %xor = xor i64 %neg, %b + ret i64 %xor +} + +declare i32 @llvm.fshl.i32(i32, i32, i32) + +define signext i32 @rol_i32(i32 signext %a, i32 signext %b) nounwind { +; RV64I-LABEL: rol_i32: +; RV64I: # %bb.0: +; RV64I-NEXT: sllw a2, a0, a1 +; RV64I-NEXT: negw a1, a1 +; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: or a0, a2, a0 +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: rol_i32: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: rolw a0, a0, a1 +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: rol_i32: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: rolw a0, a0, a1 +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: rol_i32: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: rolw a0, a0, a1 +; RV64ZBKB-NEXT: ret + %1 = tail call i32 @llvm.fshl.i32(i32 %a, i32 %a, i32 %b) + ret i32 %1 +} + +; Similar to rol_i32, but doesn't sign extend the result. +define void @rol_i32_nosext(i32 signext %a, i32 signext %b, i32* %x) nounwind { +; RV64I-LABEL: rol_i32_nosext: +; RV64I: # %bb.0: +; RV64I-NEXT: sllw a3, a0, a1 +; RV64I-NEXT: negw a1, a1 +; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: or a0, a3, a0 +; RV64I-NEXT: sw a0, 0(a2) +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: rol_i32_nosext: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: rolw a0, a0, a1 +; RV64ZBB-NEXT: sw a0, 0(a2) +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: rol_i32_nosext: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: rolw a0, a0, a1 +; RV64ZBP-NEXT: sw a0, 0(a2) +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: rol_i32_nosext: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: rolw a0, a0, a1 +; RV64ZBKB-NEXT: sw a0, 0(a2) +; RV64ZBKB-NEXT: ret + %1 = tail call i32 @llvm.fshl.i32(i32 %a, i32 %a, i32 %b) + store i32 %1, i32* %x + ret void +} + +define signext i32 @rol_i32_neg_constant_rhs(i32 signext %a) nounwind { +; RV64I-LABEL: rol_i32_neg_constant_rhs: +; RV64I: # %bb.0: +; RV64I-NEXT: li a1, -2 +; RV64I-NEXT: sllw a2, a1, a0 +; RV64I-NEXT: negw a0, a0 +; RV64I-NEXT: srlw a0, a1, a0 +; RV64I-NEXT: or a0, a2, a0 +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: rol_i32_neg_constant_rhs: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: li a1, -2 +; RV64ZBB-NEXT: rolw a0, a1, a0 +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: rol_i32_neg_constant_rhs: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: li a1, -2 +; RV64ZBP-NEXT: rolw a0, a1, a0 +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: rol_i32_neg_constant_rhs: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: li a1, -2 +; RV64ZBKB-NEXT: rolw a0, a1, a0 +; RV64ZBKB-NEXT: ret + %1 = tail call i32 @llvm.fshl.i32(i32 -2, i32 -2, i32 %a) + ret i32 %1 +} + +declare i64 @llvm.fshl.i64(i64, i64, i64) + +define i64 @rol_i64(i64 %a, i64 %b) nounwind { +; RV64I-LABEL: rol_i64: +; RV64I: # %bb.0: +; RV64I-NEXT: sll a2, a0, a1 +; RV64I-NEXT: neg a1, a1 +; RV64I-NEXT: srl a0, a0, a1 +; RV64I-NEXT: or a0, a2, a0 +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: rol_i64: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: rol a0, a0, a1 +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: rol_i64: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: rol a0, a0, a1 +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: rol_i64: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: rol a0, a0, a1 +; RV64ZBKB-NEXT: ret + %or = tail call i64 @llvm.fshl.i64(i64 %a, i64 %a, i64 %b) + ret i64 %or +} + +declare i32 @llvm.fshr.i32(i32, i32, i32) + +define signext i32 @ror_i32(i32 signext %a, i32 signext %b) nounwind { +; RV64I-LABEL: ror_i32: +; RV64I: # %bb.0: +; RV64I-NEXT: srlw a2, a0, a1 +; RV64I-NEXT: negw a1, a1 +; RV64I-NEXT: sllw a0, a0, a1 +; RV64I-NEXT: or a0, a2, a0 +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: ror_i32: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: rorw a0, a0, a1 +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: ror_i32: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: rorw a0, a0, a1 +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: ror_i32: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: rorw a0, a0, a1 +; RV64ZBKB-NEXT: ret + %1 = tail call i32 @llvm.fshr.i32(i32 %a, i32 %a, i32 %b) + ret i32 %1 +} + +; Similar to ror_i32, but doesn't sign extend the result. +define void @ror_i32_nosext(i32 signext %a, i32 signext %b, i32* %x) nounwind { +; RV64I-LABEL: ror_i32_nosext: +; RV64I: # %bb.0: +; RV64I-NEXT: srlw a3, a0, a1 +; RV64I-NEXT: negw a1, a1 +; RV64I-NEXT: sllw a0, a0, a1 +; RV64I-NEXT: or a0, a3, a0 +; RV64I-NEXT: sw a0, 0(a2) +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: ror_i32_nosext: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: rorw a0, a0, a1 +; RV64ZBB-NEXT: sw a0, 0(a2) +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: ror_i32_nosext: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: rorw a0, a0, a1 +; RV64ZBP-NEXT: sw a0, 0(a2) +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: ror_i32_nosext: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: rorw a0, a0, a1 +; RV64ZBKB-NEXT: sw a0, 0(a2) +; RV64ZBKB-NEXT: ret + %1 = tail call i32 @llvm.fshr.i32(i32 %a, i32 %a, i32 %b) + store i32 %1, i32* %x + ret void +} + +define signext i32 @ror_i32_neg_constant_rhs(i32 signext %a) nounwind { +; RV64I-LABEL: ror_i32_neg_constant_rhs: +; RV64I: # %bb.0: +; RV64I-NEXT: li a1, -2 +; RV64I-NEXT: srlw a2, a1, a0 +; RV64I-NEXT: negw a0, a0 +; RV64I-NEXT: sllw a0, a1, a0 +; RV64I-NEXT: or a0, a2, a0 +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: ror_i32_neg_constant_rhs: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: li a1, -2 +; RV64ZBB-NEXT: rorw a0, a1, a0 +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: ror_i32_neg_constant_rhs: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: li a1, -2 +; RV64ZBP-NEXT: rorw a0, a1, a0 +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: ror_i32_neg_constant_rhs: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: li a1, -2 +; RV64ZBKB-NEXT: rorw a0, a1, a0 +; RV64ZBKB-NEXT: ret + %1 = tail call i32 @llvm.fshr.i32(i32 -2, i32 -2, i32 %a) + ret i32 %1 +} + +declare i64 @llvm.fshr.i64(i64, i64, i64) + +define i64 @ror_i64(i64 %a, i64 %b) nounwind { +; RV64I-LABEL: ror_i64: +; RV64I: # %bb.0: +; RV64I-NEXT: srl a2, a0, a1 +; RV64I-NEXT: neg a1, a1 +; RV64I-NEXT: sll a0, a0, a1 +; RV64I-NEXT: or a0, a2, a0 +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: ror_i64: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: ror a0, a0, a1 +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: ror_i64: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: ror a0, a0, a1 +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: ror_i64: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: ror a0, a0, a1 +; RV64ZBKB-NEXT: ret + %or = tail call i64 @llvm.fshr.i64(i64 %a, i64 %a, i64 %b) + ret i64 %or +} + +define signext i32 @rori_i32_fshl(i32 signext %a) nounwind { +; RV64I-LABEL: rori_i32_fshl: +; RV64I: # %bb.0: +; RV64I-NEXT: srliw a1, a0, 1 +; RV64I-NEXT: slliw a0, a0, 31 +; RV64I-NEXT: or a0, a0, a1 +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: rori_i32_fshl: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: roriw a0, a0, 1 +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: rori_i32_fshl: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: roriw a0, a0, 1 +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: rori_i32_fshl: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: roriw a0, a0, 1 +; RV64ZBKB-NEXT: ret + %1 = tail call i32 @llvm.fshl.i32(i32 %a, i32 %a, i32 31) + ret i32 %1 +} + +; Similar to rori_i32_fshl, but doesn't sign extend the result. +define void @rori_i32_fshl_nosext(i32 signext %a, i32* %x) nounwind { +; RV64I-LABEL: rori_i32_fshl_nosext: +; RV64I: # %bb.0: +; RV64I-NEXT: srliw a2, a0, 1 +; RV64I-NEXT: slli a0, a0, 31 +; RV64I-NEXT: or a0, a0, a2 +; RV64I-NEXT: sw a0, 0(a1) +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: rori_i32_fshl_nosext: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: roriw a0, a0, 1 +; RV64ZBB-NEXT: sw a0, 0(a1) +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: rori_i32_fshl_nosext: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: roriw a0, a0, 1 +; RV64ZBP-NEXT: sw a0, 0(a1) +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: rori_i32_fshl_nosext: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: roriw a0, a0, 1 +; RV64ZBKB-NEXT: sw a0, 0(a1) +; RV64ZBKB-NEXT: ret + %1 = tail call i32 @llvm.fshl.i32(i32 %a, i32 %a, i32 31) + store i32 %1, i32* %x + ret void +} + +define signext i32 @rori_i32_fshr(i32 signext %a) nounwind { +; RV64I-LABEL: rori_i32_fshr: +; RV64I: # %bb.0: +; RV64I-NEXT: slliw a1, a0, 1 +; RV64I-NEXT: srliw a0, a0, 31 +; RV64I-NEXT: or a0, a0, a1 +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: rori_i32_fshr: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: roriw a0, a0, 31 +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: rori_i32_fshr: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: roriw a0, a0, 31 +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: rori_i32_fshr: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: roriw a0, a0, 31 +; RV64ZBKB-NEXT: ret + %1 = tail call i32 @llvm.fshr.i32(i32 %a, i32 %a, i32 31) + ret i32 %1 +} + +; Similar to rori_i32_fshr, but doesn't sign extend the result. +define void @rori_i32_fshr_nosext(i32 signext %a, i32* %x) nounwind { +; RV64I-LABEL: rori_i32_fshr_nosext: +; RV64I: # %bb.0: +; RV64I-NEXT: slli a2, a0, 1 +; RV64I-NEXT: srliw a0, a0, 31 +; RV64I-NEXT: or a0, a0, a2 +; RV64I-NEXT: sw a0, 0(a1) +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: rori_i32_fshr_nosext: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: roriw a0, a0, 31 +; RV64ZBB-NEXT: sw a0, 0(a1) +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: rori_i32_fshr_nosext: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: roriw a0, a0, 31 +; RV64ZBP-NEXT: sw a0, 0(a1) +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: rori_i32_fshr_nosext: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: roriw a0, a0, 31 +; RV64ZBKB-NEXT: sw a0, 0(a1) +; RV64ZBKB-NEXT: ret + %1 = tail call i32 @llvm.fshr.i32(i32 %a, i32 %a, i32 31) + store i32 %1, i32* %x + ret void +} + +; This test is similar to the type legalized version of the fshl/fshr tests, but +; instead of having the same input to both shifts it has different inputs. Make +; sure we don't match it as a roriw. +define signext i32 @not_rori_i32(i32 signext %x, i32 signext %y) nounwind { +; RV64I-LABEL: not_rori_i32: +; RV64I: # %bb.0: +; RV64I-NEXT: slliw a0, a0, 31 +; RV64I-NEXT: srliw a1, a1, 1 +; RV64I-NEXT: or a0, a0, a1 +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: not_rori_i32: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: slliw a0, a0, 31 +; RV64ZBB-NEXT: srliw a1, a1, 1 +; RV64ZBB-NEXT: or a0, a0, a1 +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: not_rori_i32: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: slliw a0, a0, 31 +; RV64ZBP-NEXT: srliw a1, a1, 1 +; RV64ZBP-NEXT: or a0, a0, a1 +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: not_rori_i32: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: slliw a0, a0, 31 +; RV64ZBKB-NEXT: srliw a1, a1, 1 +; RV64ZBKB-NEXT: or a0, a0, a1 +; RV64ZBKB-NEXT: ret + %a = shl i32 %x, 31 + %b = lshr i32 %y, 1 + %c = or i32 %a, %b + ret i32 %c +} + +; This is similar to the type legalized roriw pattern, but the and mask is more +; than 32 bits so the lshr doesn't shift zeroes into the lower 32 bits. Make +; sure we don't match it to roriw. +define i64 @roriw_bug(i64 %x) nounwind { +; RV64I-LABEL: roriw_bug: +; RV64I: # %bb.0: +; RV64I-NEXT: slli a1, a0, 31 +; RV64I-NEXT: andi a0, a0, -2 +; RV64I-NEXT: srli a2, a0, 1 +; RV64I-NEXT: or a1, a1, a2 +; RV64I-NEXT: sext.w a1, a1 +; RV64I-NEXT: xor a0, a0, a1 +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: roriw_bug: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: slli a1, a0, 31 +; RV64ZBB-NEXT: andi a0, a0, -2 +; RV64ZBB-NEXT: srli a2, a0, 1 +; RV64ZBB-NEXT: or a1, a1, a2 +; RV64ZBB-NEXT: sext.w a1, a1 +; RV64ZBB-NEXT: xor a0, a0, a1 +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: roriw_bug: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: slli a1, a0, 31 +; RV64ZBP-NEXT: andi a0, a0, -2 +; RV64ZBP-NEXT: srli a2, a0, 1 +; RV64ZBP-NEXT: or a1, a1, a2 +; RV64ZBP-NEXT: sext.w a1, a1 +; RV64ZBP-NEXT: xor a0, a0, a1 +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: roriw_bug: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: slli a1, a0, 31 +; RV64ZBKB-NEXT: andi a0, a0, -2 +; RV64ZBKB-NEXT: srli a2, a0, 1 +; RV64ZBKB-NEXT: or a1, a1, a2 +; RV64ZBKB-NEXT: sext.w a1, a1 +; RV64ZBKB-NEXT: xor a0, a0, a1 +; RV64ZBKB-NEXT: ret + %a = shl i64 %x, 31 + %b = and i64 %x, 18446744073709551614 + %c = lshr i64 %b, 1 + %d = or i64 %a, %c + %e = shl i64 %d, 32 + %f = ashr i64 %e, 32 + %g = xor i64 %b, %f ; to increase the use count on %b to disable SimplifyDemandedBits. + ret i64 %g +} + +define i64 @rori_i64_fshl(i64 %a) nounwind { +; RV64I-LABEL: rori_i64_fshl: +; RV64I: # %bb.0: +; RV64I-NEXT: srli a1, a0, 1 +; RV64I-NEXT: slli a0, a0, 63 +; RV64I-NEXT: or a0, a0, a1 +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: rori_i64_fshl: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: rori a0, a0, 1 +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: rori_i64_fshl: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: rori a0, a0, 1 +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: rori_i64_fshl: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: rori a0, a0, 1 +; RV64ZBKB-NEXT: ret + %1 = tail call i64 @llvm.fshl.i64(i64 %a, i64 %a, i64 63) + ret i64 %1 +} + +define i64 @rori_i64_fshr(i64 %a) nounwind { +; RV64I-LABEL: rori_i64_fshr: +; RV64I: # %bb.0: +; RV64I-NEXT: slli a1, a0, 1 +; RV64I-NEXT: srli a0, a0, 63 +; RV64I-NEXT: or a0, a0, a1 +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: rori_i64_fshr: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: rori a0, a0, 63 +; RV64ZBB-NEXT: ret +; +; RV64ZBP-LABEL: rori_i64_fshr: +; RV64ZBP: # %bb.0: +; RV64ZBP-NEXT: rori a0, a0, 63 +; RV64ZBP-NEXT: ret +; +; RV64ZBKB-LABEL: rori_i64_fshr: +; RV64ZBKB: # %bb.0: +; RV64ZBKB-NEXT: rori a0, a0, 63 +; RV64ZBKB-NEXT: ret + %1 = tail call i64 @llvm.fshr.i64(i64 %a, i64 %a, i64 63) + ret i64 %1 +} diff --git a/llvm/test/CodeGen/RISCV/rv64zbb-zbp.ll b/llvm/test/CodeGen/RISCV/rv64zbb-zbp.ll --- a/llvm/test/CodeGen/RISCV/rv64zbb-zbp.ll +++ b/llvm/test/CodeGen/RISCV/rv64zbb-zbp.ll @@ -6,541 +6,6 @@ ; RUN: llc -mtriple=riscv64 -mattr=+experimental-zbp -verify-machineinstrs < %s \ ; RUN: | FileCheck %s -check-prefix=RV64ZBP -define signext i32 @andn_i32(i32 signext %a, i32 signext %b) nounwind { -; RV64I-LABEL: andn_i32: -; RV64I: # %bb.0: -; RV64I-NEXT: not a1, a1 -; RV64I-NEXT: and a0, a1, a0 -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: andn_i32: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: andn a0, a0, a1 -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: andn_i32: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: andn a0, a0, a1 -; RV64ZBP-NEXT: ret - %neg = xor i32 %b, -1 - %and = and i32 %neg, %a - ret i32 %and -} - -define i64 @andn_i64(i64 %a, i64 %b) nounwind { -; RV64I-LABEL: andn_i64: -; RV64I: # %bb.0: -; RV64I-NEXT: not a1, a1 -; RV64I-NEXT: and a0, a1, a0 -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: andn_i64: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: andn a0, a0, a1 -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: andn_i64: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: andn a0, a0, a1 -; RV64ZBP-NEXT: ret - %neg = xor i64 %b, -1 - %and = and i64 %neg, %a - ret i64 %and -} - -define signext i32 @orn_i32(i32 signext %a, i32 signext %b) nounwind { -; RV64I-LABEL: orn_i32: -; RV64I: # %bb.0: -; RV64I-NEXT: not a1, a1 -; RV64I-NEXT: or a0, a1, a0 -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: orn_i32: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: orn a0, a0, a1 -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: orn_i32: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: orn a0, a0, a1 -; RV64ZBP-NEXT: ret - %neg = xor i32 %b, -1 - %or = or i32 %neg, %a - ret i32 %or -} - -define i64 @orn_i64(i64 %a, i64 %b) nounwind { -; RV64I-LABEL: orn_i64: -; RV64I: # %bb.0: -; RV64I-NEXT: not a1, a1 -; RV64I-NEXT: or a0, a1, a0 -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: orn_i64: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: orn a0, a0, a1 -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: orn_i64: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: orn a0, a0, a1 -; RV64ZBP-NEXT: ret - %neg = xor i64 %b, -1 - %or = or i64 %neg, %a - ret i64 %or -} - -define signext i32 @xnor_i32(i32 signext %a, i32 signext %b) nounwind { -; RV64I-LABEL: xnor_i32: -; RV64I: # %bb.0: -; RV64I-NEXT: xor a0, a0, a1 -; RV64I-NEXT: not a0, a0 -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: xnor_i32: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: xnor a0, a0, a1 -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: xnor_i32: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: xnor a0, a0, a1 -; RV64ZBP-NEXT: ret - %neg = xor i32 %a, -1 - %xor = xor i32 %neg, %b - ret i32 %xor -} - -define i64 @xnor_i64(i64 %a, i64 %b) nounwind { -; RV64I-LABEL: xnor_i64: -; RV64I: # %bb.0: -; RV64I-NEXT: xor a0, a0, a1 -; RV64I-NEXT: not a0, a0 -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: xnor_i64: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: xnor a0, a0, a1 -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: xnor_i64: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: xnor a0, a0, a1 -; RV64ZBP-NEXT: ret - %neg = xor i64 %a, -1 - %xor = xor i64 %neg, %b - ret i64 %xor -} - -declare i32 @llvm.fshl.i32(i32, i32, i32) - -define signext i32 @rol_i32(i32 signext %a, i32 signext %b) nounwind { -; RV64I-LABEL: rol_i32: -; RV64I: # %bb.0: -; RV64I-NEXT: sllw a2, a0, a1 -; RV64I-NEXT: negw a1, a1 -; RV64I-NEXT: srlw a0, a0, a1 -; RV64I-NEXT: or a0, a2, a0 -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: rol_i32: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: rolw a0, a0, a1 -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: rol_i32: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: rolw a0, a0, a1 -; RV64ZBP-NEXT: ret - %1 = tail call i32 @llvm.fshl.i32(i32 %a, i32 %a, i32 %b) - ret i32 %1 -} - -; Similar to rol_i32, but doesn't sign extend the result. -define void @rol_i32_nosext(i32 signext %a, i32 signext %b, i32* %x) nounwind { -; RV64I-LABEL: rol_i32_nosext: -; RV64I: # %bb.0: -; RV64I-NEXT: sllw a3, a0, a1 -; RV64I-NEXT: negw a1, a1 -; RV64I-NEXT: srlw a0, a0, a1 -; RV64I-NEXT: or a0, a3, a0 -; RV64I-NEXT: sw a0, 0(a2) -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: rol_i32_nosext: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: rolw a0, a0, a1 -; RV64ZBB-NEXT: sw a0, 0(a2) -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: rol_i32_nosext: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: rolw a0, a0, a1 -; RV64ZBP-NEXT: sw a0, 0(a2) -; RV64ZBP-NEXT: ret - %1 = tail call i32 @llvm.fshl.i32(i32 %a, i32 %a, i32 %b) - store i32 %1, i32* %x - ret void -} - -define signext i32 @rol_i32_neg_constant_rhs(i32 signext %a) nounwind { -; RV64I-LABEL: rol_i32_neg_constant_rhs: -; RV64I: # %bb.0: -; RV64I-NEXT: li a1, -2 -; RV64I-NEXT: sllw a2, a1, a0 -; RV64I-NEXT: negw a0, a0 -; RV64I-NEXT: srlw a0, a1, a0 -; RV64I-NEXT: or a0, a2, a0 -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: rol_i32_neg_constant_rhs: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: li a1, -2 -; RV64ZBB-NEXT: rolw a0, a1, a0 -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: rol_i32_neg_constant_rhs: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: li a1, -2 -; RV64ZBP-NEXT: rolw a0, a1, a0 -; RV64ZBP-NEXT: ret - %1 = tail call i32 @llvm.fshl.i32(i32 -2, i32 -2, i32 %a) - ret i32 %1 -} - -declare i64 @llvm.fshl.i64(i64, i64, i64) - -define i64 @rol_i64(i64 %a, i64 %b) nounwind { -; RV64I-LABEL: rol_i64: -; RV64I: # %bb.0: -; RV64I-NEXT: sll a2, a0, a1 -; RV64I-NEXT: neg a1, a1 -; RV64I-NEXT: srl a0, a0, a1 -; RV64I-NEXT: or a0, a2, a0 -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: rol_i64: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: rol a0, a0, a1 -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: rol_i64: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: rol a0, a0, a1 -; RV64ZBP-NEXT: ret - %or = tail call i64 @llvm.fshl.i64(i64 %a, i64 %a, i64 %b) - ret i64 %or -} - -declare i32 @llvm.fshr.i32(i32, i32, i32) - -define signext i32 @ror_i32(i32 signext %a, i32 signext %b) nounwind { -; RV64I-LABEL: ror_i32: -; RV64I: # %bb.0: -; RV64I-NEXT: srlw a2, a0, a1 -; RV64I-NEXT: negw a1, a1 -; RV64I-NEXT: sllw a0, a0, a1 -; RV64I-NEXT: or a0, a2, a0 -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: ror_i32: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: rorw a0, a0, a1 -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: ror_i32: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: rorw a0, a0, a1 -; RV64ZBP-NEXT: ret - %1 = tail call i32 @llvm.fshr.i32(i32 %a, i32 %a, i32 %b) - ret i32 %1 -} - -; Similar to ror_i32, but doesn't sign extend the result. -define void @ror_i32_nosext(i32 signext %a, i32 signext %b, i32* %x) nounwind { -; RV64I-LABEL: ror_i32_nosext: -; RV64I: # %bb.0: -; RV64I-NEXT: srlw a3, a0, a1 -; RV64I-NEXT: negw a1, a1 -; RV64I-NEXT: sllw a0, a0, a1 -; RV64I-NEXT: or a0, a3, a0 -; RV64I-NEXT: sw a0, 0(a2) -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: ror_i32_nosext: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: rorw a0, a0, a1 -; RV64ZBB-NEXT: sw a0, 0(a2) -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: ror_i32_nosext: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: rorw a0, a0, a1 -; RV64ZBP-NEXT: sw a0, 0(a2) -; RV64ZBP-NEXT: ret - %1 = tail call i32 @llvm.fshr.i32(i32 %a, i32 %a, i32 %b) - store i32 %1, i32* %x - ret void -} - -define signext i32 @ror_i32_neg_constant_rhs(i32 signext %a) nounwind { -; RV64I-LABEL: ror_i32_neg_constant_rhs: -; RV64I: # %bb.0: -; RV64I-NEXT: li a1, -2 -; RV64I-NEXT: srlw a2, a1, a0 -; RV64I-NEXT: negw a0, a0 -; RV64I-NEXT: sllw a0, a1, a0 -; RV64I-NEXT: or a0, a2, a0 -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: ror_i32_neg_constant_rhs: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: li a1, -2 -; RV64ZBB-NEXT: rorw a0, a1, a0 -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: ror_i32_neg_constant_rhs: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: li a1, -2 -; RV64ZBP-NEXT: rorw a0, a1, a0 -; RV64ZBP-NEXT: ret - %1 = tail call i32 @llvm.fshr.i32(i32 -2, i32 -2, i32 %a) - ret i32 %1 -} - -declare i64 @llvm.fshr.i64(i64, i64, i64) - -define i64 @ror_i64(i64 %a, i64 %b) nounwind { -; RV64I-LABEL: ror_i64: -; RV64I: # %bb.0: -; RV64I-NEXT: srl a2, a0, a1 -; RV64I-NEXT: neg a1, a1 -; RV64I-NEXT: sll a0, a0, a1 -; RV64I-NEXT: or a0, a2, a0 -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: ror_i64: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: ror a0, a0, a1 -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: ror_i64: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: ror a0, a0, a1 -; RV64ZBP-NEXT: ret - %or = tail call i64 @llvm.fshr.i64(i64 %a, i64 %a, i64 %b) - ret i64 %or -} - -define signext i32 @rori_i32_fshl(i32 signext %a) nounwind { -; RV64I-LABEL: rori_i32_fshl: -; RV64I: # %bb.0: -; RV64I-NEXT: srliw a1, a0, 1 -; RV64I-NEXT: slliw a0, a0, 31 -; RV64I-NEXT: or a0, a0, a1 -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: rori_i32_fshl: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: roriw a0, a0, 1 -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: rori_i32_fshl: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: roriw a0, a0, 1 -; RV64ZBP-NEXT: ret - %1 = tail call i32 @llvm.fshl.i32(i32 %a, i32 %a, i32 31) - ret i32 %1 -} - -; Similar to rori_i32_fshl, but doesn't sign extend the result. -define void @rori_i32_fshl_nosext(i32 signext %a, i32* %x) nounwind { -; RV64I-LABEL: rori_i32_fshl_nosext: -; RV64I: # %bb.0: -; RV64I-NEXT: srliw a2, a0, 1 -; RV64I-NEXT: slli a0, a0, 31 -; RV64I-NEXT: or a0, a0, a2 -; RV64I-NEXT: sw a0, 0(a1) -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: rori_i32_fshl_nosext: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: roriw a0, a0, 1 -; RV64ZBB-NEXT: sw a0, 0(a1) -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: rori_i32_fshl_nosext: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: roriw a0, a0, 1 -; RV64ZBP-NEXT: sw a0, 0(a1) -; RV64ZBP-NEXT: ret - %1 = tail call i32 @llvm.fshl.i32(i32 %a, i32 %a, i32 31) - store i32 %1, i32* %x - ret void -} - -define signext i32 @rori_i32_fshr(i32 signext %a) nounwind { -; RV64I-LABEL: rori_i32_fshr: -; RV64I: # %bb.0: -; RV64I-NEXT: slliw a1, a0, 1 -; RV64I-NEXT: srliw a0, a0, 31 -; RV64I-NEXT: or a0, a0, a1 -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: rori_i32_fshr: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: roriw a0, a0, 31 -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: rori_i32_fshr: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: roriw a0, a0, 31 -; RV64ZBP-NEXT: ret - %1 = tail call i32 @llvm.fshr.i32(i32 %a, i32 %a, i32 31) - ret i32 %1 -} - -; Similar to rori_i32_fshr, but doesn't sign extend the result. -define void @rori_i32_fshr_nosext(i32 signext %a, i32* %x) nounwind { -; RV64I-LABEL: rori_i32_fshr_nosext: -; RV64I: # %bb.0: -; RV64I-NEXT: slli a2, a0, 1 -; RV64I-NEXT: srliw a0, a0, 31 -; RV64I-NEXT: or a0, a0, a2 -; RV64I-NEXT: sw a0, 0(a1) -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: rori_i32_fshr_nosext: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: roriw a0, a0, 31 -; RV64ZBB-NEXT: sw a0, 0(a1) -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: rori_i32_fshr_nosext: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: roriw a0, a0, 31 -; RV64ZBP-NEXT: sw a0, 0(a1) -; RV64ZBP-NEXT: ret - %1 = tail call i32 @llvm.fshr.i32(i32 %a, i32 %a, i32 31) - store i32 %1, i32* %x - ret void -} - -; This test is similar to the type legalized version of the fshl/fshr tests, but -; instead of having the same input to both shifts it has different inputs. Make -; sure we don't match it as a roriw. -define signext i32 @not_rori_i32(i32 signext %x, i32 signext %y) nounwind { -; RV64I-LABEL: not_rori_i32: -; RV64I: # %bb.0: -; RV64I-NEXT: slliw a0, a0, 31 -; RV64I-NEXT: srliw a1, a1, 1 -; RV64I-NEXT: or a0, a0, a1 -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: not_rori_i32: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: slliw a0, a0, 31 -; RV64ZBB-NEXT: srliw a1, a1, 1 -; RV64ZBB-NEXT: or a0, a0, a1 -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: not_rori_i32: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: slliw a0, a0, 31 -; RV64ZBP-NEXT: srliw a1, a1, 1 -; RV64ZBP-NEXT: or a0, a0, a1 -; RV64ZBP-NEXT: ret - %a = shl i32 %x, 31 - %b = lshr i32 %y, 1 - %c = or i32 %a, %b - ret i32 %c -} - -; This is similar to the type legalized roriw pattern, but the and mask is more -; than 32 bits so the lshr doesn't shift zeroes into the lower 32 bits. Make -; sure we don't match it to roriw. -define i64 @roriw_bug(i64 %x) nounwind { -; RV64I-LABEL: roriw_bug: -; RV64I: # %bb.0: -; RV64I-NEXT: slli a1, a0, 31 -; RV64I-NEXT: andi a0, a0, -2 -; RV64I-NEXT: srli a2, a0, 1 -; RV64I-NEXT: or a1, a1, a2 -; RV64I-NEXT: sext.w a1, a1 -; RV64I-NEXT: xor a0, a0, a1 -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: roriw_bug: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: slli a1, a0, 31 -; RV64ZBB-NEXT: andi a0, a0, -2 -; RV64ZBB-NEXT: srli a2, a0, 1 -; RV64ZBB-NEXT: or a1, a1, a2 -; RV64ZBB-NEXT: sext.w a1, a1 -; RV64ZBB-NEXT: xor a0, a0, a1 -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: roriw_bug: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: slli a1, a0, 31 -; RV64ZBP-NEXT: andi a0, a0, -2 -; RV64ZBP-NEXT: srli a2, a0, 1 -; RV64ZBP-NEXT: or a1, a1, a2 -; RV64ZBP-NEXT: sext.w a1, a1 -; RV64ZBP-NEXT: xor a0, a0, a1 -; RV64ZBP-NEXT: ret - %a = shl i64 %x, 31 - %b = and i64 %x, 18446744073709551614 - %c = lshr i64 %b, 1 - %d = or i64 %a, %c - %e = shl i64 %d, 32 - %f = ashr i64 %e, 32 - %g = xor i64 %b, %f ; to increase the use count on %b to disable SimplifyDemandedBits. - ret i64 %g -} - -define i64 @rori_i64_fshl(i64 %a) nounwind { -; RV64I-LABEL: rori_i64_fshl: -; RV64I: # %bb.0: -; RV64I-NEXT: srli a1, a0, 1 -; RV64I-NEXT: slli a0, a0, 63 -; RV64I-NEXT: or a0, a0, a1 -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: rori_i64_fshl: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: rori a0, a0, 1 -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: rori_i64_fshl: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: rori a0, a0, 1 -; RV64ZBP-NEXT: ret - %1 = tail call i64 @llvm.fshl.i64(i64 %a, i64 %a, i64 63) - ret i64 %1 -} - -define i64 @rori_i64_fshr(i64 %a) nounwind { -; RV64I-LABEL: rori_i64_fshr: -; RV64I: # %bb.0: -; RV64I-NEXT: slli a1, a0, 1 -; RV64I-NEXT: srli a0, a0, 63 -; RV64I-NEXT: or a0, a0, a1 -; RV64I-NEXT: ret -; -; RV64ZBB-LABEL: rori_i64_fshr: -; RV64ZBB: # %bb.0: -; RV64ZBB-NEXT: rori a0, a0, 63 -; RV64ZBB-NEXT: ret -; -; RV64ZBP-LABEL: rori_i64_fshr: -; RV64ZBP: # %bb.0: -; RV64ZBP-NEXT: rori a0, a0, 63 -; RV64ZBP-NEXT: ret - %1 = tail call i64 @llvm.fshr.i64(i64 %a, i64 %a, i64 63) - ret i64 %1 -} - define i8 @srli_i8(i8 %a) nounwind { ; RV64I-LABEL: srli_i8: ; RV64I: # %bb.0: