aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMatInt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/RISCV/MCTargetDesc/RISCVMatInt.cpp')
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVMatInt.cpp149
1 files changed, 139 insertions, 10 deletions
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMatInt.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMatInt.cpp
index 2ca5eeb8392e..0ee6d8de78c9 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMatInt.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMatInt.cpp
@@ -20,7 +20,8 @@ static int getInstSeqCost(RISCVMatInt::InstSeq &Res, bool HasRVC) {
for (auto Instr : Res) {
bool Compressed;
switch (Instr.Opc) {
- default: llvm_unreachable("Unexpected opcode");
+ default:
+ llvm_unreachable("Unexpected opcode");
case RISCV::SLLI:
case RISCV::SRLI:
Compressed = true;
@@ -77,7 +78,7 @@ static void generateInstSeqImpl(int64_t Val,
assert(IsRV64 && "Can't emit >32-bit imm for non-RV64 target");
// In the worst case, for a full 64-bit constant, a sequence of 8 instructions
- // (i.e., LUI+ADDIW+SLLI+ADDI+SLLI+ADDI+SLLI+ADDI) has to be emmitted. Note
+ // (i.e., LUI+ADDIW+SLLI+ADDI+SLLI+ADDI+SLLI+ADDI) has to be emitted. Note
// that the first two instructions (LUI+ADDIW) can contribute up to 32 bits
// while the following ADDI instructions contribute up to 12 bits each.
//
@@ -106,15 +107,36 @@ static void generateInstSeqImpl(int64_t Val,
// If the remaining bits don't fit in 12 bits, we might be able to reduce the
// shift amount in order to use LUI which will zero the lower 12 bits.
- if (ShiftAmount > 12 && !isInt<12>(Hi52) && isInt<32>((uint64_t)Hi52 << 12)) {
- // Reduce the shift amount and add zeros to the LSBs so it will match LUI.
- ShiftAmount -= 12;
- Hi52 = (uint64_t)Hi52 << 12;
+ bool Unsigned = false;
+ if (ShiftAmount > 12 && !isInt<12>(Hi52)) {
+ if (isInt<32>((uint64_t)Hi52 << 12)) {
+ // Reduce the shift amount and add zeros to the LSBs so it will match LUI.
+ ShiftAmount -= 12;
+ Hi52 = (uint64_t)Hi52 << 12;
+ } else if (isUInt<32>((uint64_t)Hi52 << 12) &&
+ ActiveFeatures[RISCV::FeatureStdExtZba]) {
+ // Reduce the shift amount and add zeros to the LSBs so it will match
+ // LUI, then shift left with SLLI.UW to clear the upper 32 set bits.
+ ShiftAmount -= 12;
+ Hi52 = ((uint64_t)Hi52 << 12) | (0xffffffffull << 32);
+ Unsigned = true;
+ }
+ }
+
+ // Try to use SLLIUW for Hi52 when it is uint32 but not int32.
+ if (isUInt<32>((uint64_t)Hi52) && !isInt<32>((uint64_t)Hi52) &&
+ ActiveFeatures[RISCV::FeatureStdExtZba]) {
+ // Use LUI+ADDI or LUI to compose, then clear the upper 32 bits with SLLIUW.
+ Hi52 = ((uint64_t)Hi52) | (0xffffffffull << 32);
+ Unsigned = true;
}
generateInstSeqImpl(Hi52, ActiveFeatures, Res);
- Res.push_back(RISCVMatInt::Inst(RISCV::SLLI, ShiftAmount));
+ if (Unsigned)
+ Res.push_back(RISCVMatInt::Inst(RISCV::SLLIUW, ShiftAmount));
+ else
+ Res.push_back(RISCVMatInt::Inst(RISCV::SLLI, ShiftAmount));
if (Lo12)
Res.push_back(RISCVMatInt::Inst(RISCV::ADDI, Lo12));
}
@@ -165,7 +187,7 @@ InstSeq generateInstSeq(int64_t Val, const FeatureBitset &ActiveFeatures) {
// If we have exactly 32 leading zeros and Zba, we can try using zext.w at
// the end of the sequence.
- if (LeadingZeros == 32 && ActiveFeatures[RISCV::FeatureExtZba]) {
+ if (LeadingZeros == 32 && ActiveFeatures[RISCV::FeatureStdExtZba]) {
// Try replacing upper bits with 1.
uint64_t LeadingOnesVal = Val | maskLeadingOnes<uint64_t>(LeadingZeros);
TmpSeq.clear();
@@ -182,12 +204,119 @@ InstSeq generateInstSeq(int64_t Val, const FeatureBitset &ActiveFeatures) {
}
}
+ // Perform optimization with BCLRI/BSETI in the Zbs extension.
+ if (Res.size() > 2 && ActiveFeatures[RISCV::FeatureStdExtZbs]) {
+ assert(ActiveFeatures[RISCV::Feature64Bit] &&
+ "Expected RV32 to only need 2 instructions");
+
+ // 1. For values in range 0xffffffff 7fffffff ~ 0xffffffff 00000000,
+ // call generateInstSeqImpl with Val|0x80000000 (which is expected be
+ // an int32), then emit (BCLRI r, 31).
+ // 2. For values in range 0x80000000 ~ 0xffffffff, call generateInstSeqImpl
+ // with Val&~0x80000000 (which is expected to be an int32), then
+ // emit (BSETI r, 31).
+ int64_t NewVal;
+ unsigned Opc;
+ if (Val < 0) {
+ Opc = RISCV::BCLRI;
+ NewVal = Val | 0x80000000ll;
+ } else {
+ Opc = RISCV::BSETI;
+ NewVal = Val & ~0x80000000ll;
+ }
+ if (isInt<32>(NewVal)) {
+ RISCVMatInt::InstSeq TmpSeq;
+ generateInstSeqImpl(NewVal, ActiveFeatures, TmpSeq);
+ TmpSeq.push_back(RISCVMatInt::Inst(Opc, 31));
+ if (TmpSeq.size() < Res.size())
+ Res = TmpSeq;
+ }
+
+ // Try to use BCLRI for upper 32 bits if the original lower 32 bits are
+ // negative int32, or use BSETI for upper 32 bits if the original lower
+ // 32 bits are positive int32.
+ int32_t Lo = Val;
+ uint32_t Hi = Val >> 32;
+ Opc = 0;
+ RISCVMatInt::InstSeq TmpSeq;
+ generateInstSeqImpl(Lo, ActiveFeatures, TmpSeq);
+ // Check if it is profitable to use BCLRI/BSETI.
+ if (Lo > 0 && TmpSeq.size() + countPopulation(Hi) < Res.size()) {
+ Opc = RISCV::BSETI;
+ } else if (Lo < 0 && TmpSeq.size() + countPopulation(~Hi) < Res.size()) {
+ Opc = RISCV::BCLRI;
+ Hi = ~Hi;
+ }
+ // Search for each bit and build corresponding BCLRI/BSETI.
+ if (Opc > 0) {
+ while (Hi != 0) {
+ unsigned Bit = countTrailingZeros(Hi);
+ TmpSeq.push_back(RISCVMatInt::Inst(Opc, Bit + 32));
+ Hi &= ~(1 << Bit);
+ }
+ if (TmpSeq.size() < Res.size())
+ Res = TmpSeq;
+ }
+ }
+
+ // Perform optimization with SH*ADD in the Zba extension.
+ if (Res.size() > 2 && ActiveFeatures[RISCV::FeatureStdExtZba]) {
+ assert(ActiveFeatures[RISCV::Feature64Bit] &&
+ "Expected RV32 to only need 2 instructions");
+ int64_t Div = 0;
+ unsigned Opc = 0;
+ RISCVMatInt::InstSeq TmpSeq;
+ // Select the opcode and divisor.
+ if ((Val % 3) == 0 && isInt<32>(Val / 3)) {
+ Div = 3;
+ Opc = RISCV::SH1ADD;
+ } else if ((Val % 5) == 0 && isInt<32>(Val / 5)) {
+ Div = 5;
+ Opc = RISCV::SH2ADD;
+ } else if ((Val % 9) == 0 && isInt<32>(Val / 9)) {
+ Div = 9;
+ Opc = RISCV::SH3ADD;
+ }
+ // Build the new instruction sequence.
+ if (Div > 0) {
+ generateInstSeqImpl(Val / Div, ActiveFeatures, TmpSeq);
+ TmpSeq.push_back(RISCVMatInt::Inst(Opc, 0));
+ if (TmpSeq.size() < Res.size())
+ Res = TmpSeq;
+ }
+ // Try to use LUI+SH*ADD+ADDI.
+ int64_t Hi52 = ((uint64_t)Val + 0x800ull) & ~0xfffull;
+ int64_t Lo12 = SignExtend64<12>(Val);
+ Div = 0;
+ if (isInt<32>(Hi52 / 3) && (Hi52 % 3) == 0) {
+ Div = 3;
+ Opc = RISCV::SH1ADD;
+ } else if (isInt<32>(Hi52 / 5) && (Hi52 % 5) == 0) {
+ Div = 5;
+ Opc = RISCV::SH2ADD;
+ } else if (isInt<32>(Hi52 / 9) && (Hi52 % 9) == 0) {
+ Div = 9;
+ Opc = RISCV::SH3ADD;
+ }
+ // Build the new instruction sequence.
+ if (Div > 0) {
+ // For Val that has zero Lo12 (implies Val equals to Hi52) should has
+ // already been processed to LUI+SH*ADD by previous optimization.
+ assert(Lo12 != 0 &&
+ "unexpected instruction sequence for immediate materialisation");
+ generateInstSeqImpl(Hi52 / Div, ActiveFeatures, TmpSeq);
+ TmpSeq.push_back(RISCVMatInt::Inst(Opc, 0));
+ TmpSeq.push_back(RISCVMatInt::Inst(RISCV::ADDI, Lo12));
+ if (TmpSeq.size() < Res.size())
+ Res = TmpSeq;
+ }
+ }
+
return Res;
}
int getIntMatCost(const APInt &Val, unsigned Size,
- const FeatureBitset &ActiveFeatures,
- bool CompressionCost) {
+ const FeatureBitset &ActiveFeatures, bool CompressionCost) {
bool IsRV64 = ActiveFeatures[RISCV::Feature64Bit];
bool HasRVC = CompressionCost && ActiveFeatures[RISCV::FeatureStdExtC];
int PlatRegSize = IsRV64 ? 64 : 32;