diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMatInt.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMatInt.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMatInt.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMatInt.cpp @@ -141,6 +141,28 @@ Res.push_back(RISCVMatInt::Inst(RISCV::ADDI, Lo12)); } +static bool extractRotateInfo(int64_t Val, int &NegImm12, int &Rotate) { + // for case: 0b111..1..xxxxxx1..1.. + unsigned LeadingOnes = countLeadingOnes((uint64_t)Val); + unsigned TrailingOnes = countTrailingOnes((uint64_t)Val); + if (TrailingOnes > 0 && (LeadingOnes + TrailingOnes) > (64 - 12)) { + NegImm12 = ((uint64_t)Val >> TrailingOnes) | + ((uint64_t)Val << (64 - TrailingOnes)); + Rotate = 64 - TrailingOnes; + return true; + } + // for case: 0bxxx1..1..1...xxx + unsigned UpperTrailingOnes = countTrailingOnes(Hi_32(Val)); + unsigned LowerLeadingOnes = countLeadingOnes(Lo_32(Val)); + if ((UpperTrailingOnes + LowerLeadingOnes) > (64 - 12)) { + NegImm12 = ((uint64_t)Val << (32 - UpperTrailingOnes)) | + (((uint64_t)Val >> (32 + UpperTrailingOnes))); + Rotate = 32 - UpperTrailingOnes; + return true; + } + return false; +} + namespace llvm { namespace RISCVMatInt { InstSeq generateInstSeq(int64_t Val, const FeatureBitset &ActiveFeatures) { @@ -312,6 +334,17 @@ } } + // Perform optimization with rori in the Zbb extension. + if (Res.size() > 2 && ActiveFeatures[RISCV::FeatureStdExtZbb]) { + int NegImm12; + int Rotate; + if (extractRotateInfo(Val, NegImm12, Rotate)) { + RISCVMatInt::InstSeq TmpSeq; + TmpSeq.push_back(RISCVMatInt::Inst(RISCV::ADDI, NegImm12)); + TmpSeq.push_back(RISCVMatInt::Inst(RISCV::RORI, Rotate)); + Res = TmpSeq; + } + } return Res; } diff --git a/llvm/test/CodeGen/RISCV/imm_zbb.ll b/llvm/test/CodeGen/RISCV/imm_zbb.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/imm_zbb.ll @@ -0,0 +1,30 @@ +; RUN: llc -mtriple=riscv64 -mattr=+experimental-zbb \ +; RUN: -verify-machineinstrs < %s | FileCheck %s -check-prefix=RV64IZBB + + +; Materializing constants with zbb + +define i64 @li_rori_1() { +; RV64IZBB-LABEL: li_rori_1: +; RV64IZBB: # %bb.0: +; RV64IZBB-NEXT: li a0, -18 +; RV64IZBB-NEXT: rori a0, a0, 21 +; RV64IZBB-NEXT: ret + ret i64 -149533581377537 +} +define i64 @li_rori_2() { +; RV64IZBB-LABEL: li_rori_2: +; RV64IZBB: # %bb.0: +; RV64IZBB-NEXT: li a0, -86 +; RV64IZBB-NEXT: rori a0, a0, 4 +; RV64IZBB-NEXT: ret + ret i64 -5764607523034234886 +} +define i64 @li_rori_3() { +; RV64IZBB-LABEL: li_rori_3: +; RV64IZBB: # %bb.0: +; RV64IZBB-NEXT: li a0, -18 +; RV64IZBB-NEXT: rori a0, a0, 37 +; RV64IZBB-NEXT: ret + ret i64 -2281701377 +} diff --git a/llvm/test/MC/RISCV/rv64zbb-valid.s b/llvm/test/MC/RISCV/rv64zbb-valid.s --- a/llvm/test/MC/RISCV/rv64zbb-valid.s +++ b/llvm/test/MC/RISCV/rv64zbb-valid.s @@ -14,3 +14,13 @@ # CHECK-ASM-AND-OBJ: cpopw t0, t1 # CHECK-ASM: encoding: [0x9b,0x12,0x23,0x60] cpopw t0, t1 + +# CHECK-ASM-AND-OBJ: addi t0, zero, -18 +# CHECK-ASM-AND-OBJ: rori t0, t0, 21 +li t0, -149533581377537 +# CHECK-ASM-AND-OBJ: addi t0, zero, -86 +# CHECK-ASM-AND-OBJ: rori t0, t0, 4 +li t0, -5764607523034234886 +# CHECK-ASM-AND-OBJ: addi t0, zero, -18 +# CHECK-ASM-AND-OBJ: rori t0, t0, 37 +li t0, -2281701377