Skip to content

Commit 7192c22

Browse files
authored
[GlobalISel][RISCV] Use constant pool for large integer constants. (#81101)
We apply custom lowering to 64 bit constants where we use the same logic as in non-global isel: if materializing in registers is too expensive, we emit a load from constant pool. Later, during instruction selection, constant pool address is generated using `selectAddr`.
1 parent e165bea commit 7192c22

File tree

4 files changed

+138
-24
lines changed

4 files changed

+138
-24
lines changed

llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "RISCVLegalizerInfo.h"
14+
#include "MCTargetDesc/RISCVMatInt.h"
1415
#include "RISCVMachineFunctionInfo.h"
1516
#include "RISCVSubtarget.h"
17+
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h"
1618
#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
1719
#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
1820
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
21+
#include "llvm/CodeGen/MachineConstantPool.h"
1922
#include "llvm/CodeGen/MachineRegisterInfo.h"
2023
#include "llvm/CodeGen/TargetOpcodes.h"
2124
#include "llvm/CodeGen/ValueTypes.h"
@@ -182,7 +185,13 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
182185
CTPOPActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower();
183186
}
184187

185-
getActionDefinitionsBuilder({G_CONSTANT, G_IMPLICIT_DEF})
188+
auto &ConstantActions = getActionDefinitionsBuilder(G_CONSTANT);
189+
ConstantActions.legalFor({s32, p0});
190+
if (ST.is64Bit())
191+
ConstantActions.customFor({s64});
192+
ConstantActions.widenScalarToNextPow2(0).clampScalar(0, s32, sXLen);
193+
194+
getActionDefinitionsBuilder(G_IMPLICIT_DEF)
186195
.legalFor({s32, sXLen, p0})
187196
.widenScalarToNextPow2(0)
188197
.clampScalar(0, s32, sXLen);
@@ -451,17 +460,95 @@ bool RISCVLegalizerInfo::legalizeVAStart(MachineInstr &MI,
451460
return true;
452461
}
453462

463+
bool RISCVLegalizerInfo::shouldBeInConstantPool(APInt APImm,
464+
bool ShouldOptForSize) const {
465+
unsigned BitWidth = APImm.getBitWidth();
466+
assert(BitWidth == 32 || BitWidth == 64);
467+
int64_t Imm = APImm.getSExtValue();
468+
// All simm32 constants should be handled by isel.
469+
// NOTE: The getMaxBuildIntsCost call below should return a value >= 2 making
470+
// this check redundant, but small immediates are common so this check
471+
// should have better compile time.
472+
if (isInt<32>(Imm))
473+
return false;
474+
475+
// We only need to cost the immediate, if constant pool lowering is enabled.
476+
if (!STI.useConstantPoolForLargeInts())
477+
return false;
478+
479+
RISCVMatInt::InstSeq Seq = RISCVMatInt::generateInstSeq(Imm, STI);
480+
if (Seq.size() <= STI.getMaxBuildIntsCost())
481+
return false;
482+
483+
// Optimizations below are disabled for opt size. If we're optimizing for
484+
// size, use a constant pool.
485+
if (ShouldOptForSize)
486+
return true;
487+
//
488+
// Special case. See if we can build the constant as (ADD (SLLI X, C), X) do
489+
// that if it will avoid a constant pool.
490+
// It will require an extra temporary register though.
491+
// If we have Zba we can use (ADD_UW X, (SLLI X, 32)) to handle cases where
492+
// low and high 32 bits are the same and bit 31 and 63 are set.
493+
unsigned ShiftAmt, AddOpc;
494+
RISCVMatInt::InstSeq SeqLo =
495+
RISCVMatInt::generateTwoRegInstSeq(Imm, STI, ShiftAmt, AddOpc);
496+
return !(!SeqLo.empty() && (SeqLo.size() + 2) <= STI.getMaxBuildIntsCost());
497+
}
498+
499+
// TODO: This is almost the same as LegalizerHelper::lowerFConstant and is
500+
// target-independent. Should we move this to LegalizeHelper?
501+
bool RISCVLegalizerInfo::emitLoadFromConstantPool(
502+
Register DstReg, const Constant *ConstVal,
503+
MachineIRBuilder &MIRBuilder) const {
504+
MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
505+
MachineFunction &MF = MIRBuilder.getMF();
506+
const DataLayout &DL = MIRBuilder.getDataLayout();
507+
LLVMContext &Ctx = MF.getFunction().getContext();
508+
unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
509+
LLT AddrPtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
510+
LLT DstLLT = MRI.getType(DstReg);
511+
512+
Align Alignment(DL.getABITypeAlign(getTypeForLLT(DstLLT, Ctx)));
513+
514+
auto Addr = MIRBuilder.buildConstantPool(
515+
AddrPtrTy,
516+
MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
517+
518+
MachineMemOperand *MMO =
519+
MF.getMachineMemOperand(MachinePointerInfo::getConstantPool(MF),
520+
MachineMemOperand::MOLoad, DstLLT, Alignment);
521+
522+
MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, DstReg, Addr, *MMO);
523+
return true;
524+
}
525+
454526
bool RISCVLegalizerInfo::legalizeCustom(
455527
LegalizerHelper &Helper, MachineInstr &MI,
456528
LostDebugLocObserver &LocObserver) const {
457529
MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
458530
GISelChangeObserver &Observer = Helper.Observer;
531+
MachineFunction &MF = *MI.getParent()->getParent();
459532
switch (MI.getOpcode()) {
460533
default:
461534
// No idea what to do.
462535
return false;
463536
case TargetOpcode::G_ABS:
464537
return Helper.lowerAbsToMaxNeg(MI);
538+
// TODO: G_FCONSTANT
539+
case TargetOpcode::G_CONSTANT: {
540+
const Function &F = MF.getFunction();
541+
// TODO: if PSI and BFI are present, add " ||
542+
// llvm::shouldOptForSize(*CurMBB, PSI, BFI)".
543+
bool ShouldOptForSize = F.hasOptSize() || F.hasMinSize();
544+
const ConstantInt *ConstVal = MI.getOperand(1).getCImm();
545+
if (!shouldBeInConstantPool(ConstVal->getValue(), ShouldOptForSize))
546+
return true;
547+
emitLoadFromConstantPool(MI.getOperand(0).getReg(),
548+
MI.getOperand(1).getCImm(), MIRBuilder);
549+
MI.eraseFromParent();
550+
return true;
551+
}
465552
case TargetOpcode::G_SHL:
466553
case TargetOpcode::G_ASHR:
467554
case TargetOpcode::G_LSHR:

llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define LLVM_LIB_TARGET_RISCV_RISCVMACHINELEGALIZER_H
1515

1616
#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
17+
#include "llvm/CodeGen/Register.h"
1718

1819
namespace llvm {
1920

@@ -36,6 +37,9 @@ class RISCVLegalizerInfo : public LegalizerInfo {
3637
MachineInstr &MI) const override;
3738

3839
private:
40+
bool shouldBeInConstantPool(APInt APImm, bool ShouldOptForSize) const;
41+
bool emitLoadFromConstantPool(Register DstReg, const Constant *CPVal,
42+
MachineIRBuilder &MIRBuilder) const;
3943
bool legalizeShlAshrLshr(MachineInstr &MI, MachineIRBuilder &MIRBuilder,
4044
GISelChangeObserver &Observer) const;
4145

llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-bitreverse-rv64.mir

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -220,25 +220,28 @@ body: |
220220
; CHECK-NEXT: [[AND5:%[0-9]+]]:_(s64) = G_AND [[LSHR3]], [[C5]]
221221
; CHECK-NEXT: [[OR6:%[0-9]+]]:_(s64) = G_OR [[OR5]], [[AND5]]
222222
; CHECK-NEXT: [[C7:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
223-
; CHECK-NEXT: [[C8:%[0-9]+]]:_(s64) = G_CONSTANT i64 -1085102592571150096
224-
; CHECK-NEXT: [[AND6:%[0-9]+]]:_(s64) = G_AND [[OR6]], [[C8]]
223+
; CHECK-NEXT: [[CONSTANT_POOL:%[0-9]+]]:_(p0) = G_CONSTANT_POOL %const.2
224+
; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[CONSTANT_POOL]](p0) :: (load (s64) from constant-pool)
225+
; CHECK-NEXT: [[AND6:%[0-9]+]]:_(s64) = G_AND [[OR6]], [[LOAD]]
225226
; CHECK-NEXT: [[LSHR4:%[0-9]+]]:_(s64) = G_LSHR [[AND6]], [[C7]](s64)
226227
; CHECK-NEXT: [[SHL4:%[0-9]+]]:_(s64) = G_SHL [[OR6]], [[C7]](s64)
227-
; CHECK-NEXT: [[AND7:%[0-9]+]]:_(s64) = G_AND [[SHL4]], [[C8]]
228+
; CHECK-NEXT: [[AND7:%[0-9]+]]:_(s64) = G_AND [[SHL4]], [[LOAD]]
228229
; CHECK-NEXT: [[OR7:%[0-9]+]]:_(s64) = G_OR [[LSHR4]], [[AND7]]
229-
; CHECK-NEXT: [[C9:%[0-9]+]]:_(s64) = G_CONSTANT i64 2
230-
; CHECK-NEXT: [[C10:%[0-9]+]]:_(s64) = G_CONSTANT i64 -3689348814741910324
231-
; CHECK-NEXT: [[AND8:%[0-9]+]]:_(s64) = G_AND [[OR7]], [[C10]]
232-
; CHECK-NEXT: [[LSHR5:%[0-9]+]]:_(s64) = G_LSHR [[AND8]], [[C9]](s64)
233-
; CHECK-NEXT: [[SHL5:%[0-9]+]]:_(s64) = G_SHL [[OR7]], [[C9]](s64)
234-
; CHECK-NEXT: [[AND9:%[0-9]+]]:_(s64) = G_AND [[SHL5]], [[C10]]
230+
; CHECK-NEXT: [[C8:%[0-9]+]]:_(s64) = G_CONSTANT i64 2
231+
; CHECK-NEXT: [[CONSTANT_POOL1:%[0-9]+]]:_(p0) = G_CONSTANT_POOL %const.1
232+
; CHECK-NEXT: [[LOAD1:%[0-9]+]]:_(s64) = G_LOAD [[CONSTANT_POOL1]](p0) :: (load (s64) from constant-pool)
233+
; CHECK-NEXT: [[AND8:%[0-9]+]]:_(s64) = G_AND [[OR7]], [[LOAD1]]
234+
; CHECK-NEXT: [[LSHR5:%[0-9]+]]:_(s64) = G_LSHR [[AND8]], [[C8]](s64)
235+
; CHECK-NEXT: [[SHL5:%[0-9]+]]:_(s64) = G_SHL [[OR7]], [[C8]](s64)
236+
; CHECK-NEXT: [[AND9:%[0-9]+]]:_(s64) = G_AND [[SHL5]], [[LOAD1]]
235237
; CHECK-NEXT: [[OR8:%[0-9]+]]:_(s64) = G_OR [[LSHR5]], [[AND9]]
236-
; CHECK-NEXT: [[C11:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
237-
; CHECK-NEXT: [[C12:%[0-9]+]]:_(s64) = G_CONSTANT i64 -6148914691236517206
238-
; CHECK-NEXT: [[AND10:%[0-9]+]]:_(s64) = G_AND [[OR8]], [[C12]]
239-
; CHECK-NEXT: [[LSHR6:%[0-9]+]]:_(s64) = G_LSHR [[AND10]], [[C11]](s64)
240-
; CHECK-NEXT: [[SHL6:%[0-9]+]]:_(s64) = G_SHL [[OR8]], [[C11]](s64)
241-
; CHECK-NEXT: [[AND11:%[0-9]+]]:_(s64) = G_AND [[SHL6]], [[C12]]
238+
; CHECK-NEXT: [[C9:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
239+
; CHECK-NEXT: [[CONSTANT_POOL2:%[0-9]+]]:_(p0) = G_CONSTANT_POOL %const.0
240+
; CHECK-NEXT: [[LOAD2:%[0-9]+]]:_(s64) = G_LOAD [[CONSTANT_POOL2]](p0) :: (load (s64) from constant-pool)
241+
; CHECK-NEXT: [[AND10:%[0-9]+]]:_(s64) = G_AND [[OR8]], [[LOAD2]]
242+
; CHECK-NEXT: [[LSHR6:%[0-9]+]]:_(s64) = G_LSHR [[AND10]], [[C9]](s64)
243+
; CHECK-NEXT: [[SHL6:%[0-9]+]]:_(s64) = G_SHL [[OR8]], [[C9]](s64)
244+
; CHECK-NEXT: [[AND11:%[0-9]+]]:_(s64) = G_AND [[SHL6]], [[LOAD2]]
242245
; CHECK-NEXT: [[OR9:%[0-9]+]]:_(s64) = G_OR [[LSHR6]], [[AND11]]
243246
; CHECK-NEXT: $x10 = COPY [[OR9]](s64)
244247
; CHECK-NEXT: PseudoRET implicit $x10

llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-const-rv64.mir

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ name: const_i8
66
body: |
77
bb.0.entry:
88
; CHECK-LABEL: name: const_i8
9-
; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 -127
10-
; CHECK-NEXT: $x10 = COPY [[C]](s64)
9+
; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 -127
10+
; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(s64) = G_ANYEXT [[C]](s32)
11+
; CHECK-NEXT: $x10 = COPY [[ANYEXT]](s64)
1112
; CHECK-NEXT: PseudoRET implicit $x10
1213
%0:_(s8) = G_CONSTANT i8 129
1314
%1:_(s64) = G_ANYEXT %0(s8)
@@ -20,8 +21,9 @@ name: const_i15
2021
body: |
2122
bb.0.entry:
2223
; CHECK-LABEL: name: const_i15
23-
; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 15
24-
; CHECK-NEXT: $x10 = COPY [[C]](s64)
24+
; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 15
25+
; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(s64) = G_ANYEXT [[C]](s32)
26+
; CHECK-NEXT: $x10 = COPY [[ANYEXT]](s64)
2527
; CHECK-NEXT: PseudoRET implicit $x10
2628
%0:_(s15) = G_CONSTANT i15 15
2729
%1:_(s64) = G_ANYEXT %0(s15)
@@ -34,8 +36,9 @@ name: const_i16
3436
body: |
3537
bb.0.entry:
3638
; CHECK-LABEL: name: const_i16
37-
; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 767
38-
; CHECK-NEXT: $x10 = COPY [[C]](s64)
39+
; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 767
40+
; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(s64) = G_ANYEXT [[C]](s32)
41+
; CHECK-NEXT: $x10 = COPY [[ANYEXT]](s64)
3942
; CHECK-NEXT: PseudoRET implicit $x10
4043
%0:_(s16) = G_CONSTANT i16 -64769
4144
%1:_(s64) = G_ANYEXT %0(s16)
@@ -48,8 +51,9 @@ name: const_i32
4851
body: |
4952
bb.0.entry:
5053
; CHECK-LABEL: name: const_i32
51-
; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 -64769
52-
; CHECK-NEXT: $x10 = COPY [[C]](s64)
54+
; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 -64769
55+
; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(s64) = G_ANYEXT [[C]](s32)
56+
; CHECK-NEXT: $x10 = COPY [[ANYEXT]](s64)
5357
; CHECK-NEXT: PseudoRET implicit $x10
5458
%0:_(s32) = G_CONSTANT i32 -64769
5559
%1:_(s64) = G_ANYEXT %0(s32)
@@ -180,3 +184,19 @@ body: |
180184
PseudoRET implicit $x10
181185
182186
...
187+
188+
...
189+
---
190+
name: constant_pool_i64
191+
body: |
192+
bb.0.entry:
193+
; CHECK-LABEL: name: constant_pool_i64
194+
; CHECK: [[CONSTANT_POOL:%[0-9]+]]:_(p0) = G_CONSTANT_POOL %const.0
195+
; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[CONSTANT_POOL]](p0) :: (load (s64) from constant-pool)
196+
; CHECK-NEXT: $x10 = COPY [[LOAD]](s64)
197+
; CHECK-NEXT: PseudoRET implicit $x10
198+
%0:_(s64) = G_CONSTANT i64 -1085102592571150096
199+
$x10 = COPY %0(s64)
200+
PseudoRET implicit $x10
201+
202+
...

0 commit comments

Comments
 (0)