Skip to content

Commit

Permalink
[GlobalISel][ARM] Legalization of G_CONSTANT using constant pool (#98308
Browse files Browse the repository at this point in the history
)

ARM uses complex encoding of immediate values using small number of
bits. As a result, some values cannot be represented as immediate
operands, they need to be synthesized in a register. This change
implements legalization of such constants with loading values from
constant pool.

---------

Co-authored-by: Matt Arsenault <[email protected]>
  • Loading branch information
spavloff and arsenm authored Oct 14, 2024
1 parent fe1e1e3 commit 52e5683
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 9 deletions.
23 changes: 22 additions & 1 deletion llvm/lib/Target/ARM/ARMInstructionSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "ARMSubtarget.h"
#include "ARMTargetMachine.h"
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
Expand Down Expand Up @@ -1088,7 +1089,7 @@ bool ARMInstructionSelector::select(MachineInstr &I) {
return selectGlobal(MIB, MRI);
case G_STORE:
case G_LOAD: {
const auto &MemOp = **I.memoperands_begin();
auto &MemOp = **I.memoperands_begin();
if (MemOp.isAtomic()) {
LLVM_DEBUG(dbgs() << "Atomic load/store not supported yet\n");
return false;
Expand All @@ -1103,6 +1104,26 @@ bool ARMInstructionSelector::select(MachineInstr &I) {
assert((ValSize != 64 || STI.hasVFP2Base()) &&
"Don't know how to load/store 64-bit value without VFP");

if (auto *LoadMI = dyn_cast<GLoad>(&I)) {
Register PtrReg = LoadMI->getPointerReg();
MachineInstr *Ptr = MRI.getVRegDef(PtrReg);
if (Ptr->getOpcode() == TargetOpcode::G_CONSTANT_POOL) {
const MachineOperand &Index = Ptr->getOperand(1);
unsigned Opcode = Subtarget->isThumb() ? ARM::tLDRpci : ARM::LDRcp;

auto Instr = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Opcode))
.addDef(Reg)
.add(Index)
.addImm(0)
.add(predOps(ARMCC::AL))
.addMemOperand(&MemOp);
if (!constrainSelectedInstRegOperands(*Instr, TII, TRI, RBI))
return false;
I.eraseFromParent();
return true;
}
}

const auto NewOpc = selectLoadStoreOpCode(I.getOpcode(), RegBank, ValSize);
if (NewOpc == G_LOAD || NewOpc == G_STORE)
return false;
Expand Down
13 changes: 11 additions & 2 deletions llvm/lib/Target/ARM/ARMLegalizerInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ static bool AEABI(const ARMSubtarget &ST) {
return ST.isTargetAEABI() || ST.isTargetGNUAEABI() || ST.isTargetMuslAEABI();
}

ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) : ST(ST) {
using namespace TargetOpcode;

const LLT p0 = LLT::pointer(0, 32);
Expand Down Expand Up @@ -99,9 +99,11 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
.minScalar(0, s32);

getActionDefinitionsBuilder(G_CONSTANT)
.legalFor({s32, p0})
.customFor({s32, p0})
.clampScalar(0, s32, s32);

getActionDefinitionsBuilder(G_CONSTANT_POOL).legalFor({p0});

getActionDefinitionsBuilder(G_ICMP)
.legalForCartesianProduct({s1}, {s32, p0})
.minScalar(1, s32);
Expand Down Expand Up @@ -435,6 +437,13 @@ bool ARMLegalizerInfo::legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI,
}
break;
}
case G_CONSTANT: {
const ConstantInt *ConstVal = MI.getOperand(1).getCImm();
uint64_t ImmVal = ConstVal->getZExtValue();
if (ConstantMaterializationCost(ImmVal, &ST) > 2 && !ST.genExecuteOnly())
return Helper.lowerConstant(MI) == LegalizerHelper::Legalized;
return true;
}
case G_FCONSTANT: {
// Convert to integer constants, while preserving the binary representation.
auto AsInteger =
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/ARM/ARMLegalizerInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ class ARMLegalizerInfo : public LegalizerInfo {
// Get the libcall(s) corresponding to \p Predicate for operands of \p Size
// bits.
FCmpLibcallsList getFCmpLibcalls(CmpInst::Predicate, unsigned Size) const;

const ARMSubtarget &ST;
};
} // End llvm namespace.
#endif
1 change: 1 addition & 0 deletions llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ ARMRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case G_CONSTANT:
case G_FRAME_INDEX:
case G_GLOBAL_VALUE:
case G_CONSTANT_POOL:
OperandsMapping =
getOperandsMapping({&ARM::ValueMappings[ARM::GPR3OpsIdx], nullptr});
break;
Expand Down
20 changes: 20 additions & 0 deletions llvm/test/CodeGen/ARM/GlobalISel/arm-legalize-const.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
# RUN: llc -mtriple arm-- -run-pass=legalizer %s -o - | FileCheck %s

---
name: get_const
legalized: false
regBankSelected: false
selected: false
tracksRegLiveness: true
body: |
bb.1.entry:
; CHECK-LABEL: name: get_const
; CHECK: [[CONSTANT_POOL:%[0-9]+]]:_(p0) = G_CONSTANT_POOL %const.0
; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[CONSTANT_POOL]](p0) :: (load (s32) from constant-pool)
; CHECK-NEXT: $r0 = COPY [[LOAD]](s32)
; CHECK-NEXT: MOVPCLR 14 /* CC::al */, $noreg, implicit $r0
%0:_(s32) = G_CONSTANT i32 287454020
$r0 = COPY %0(s32)
MOVPCLR 14 /* CC::al */, $noreg, implicit $r0
...
22 changes: 16 additions & 6 deletions llvm/test/CodeGen/ARM/GlobalISel/arm-legalize-fp.mir
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# RUN: llc -O0 -mtriple arm-linux-gnueabihf -mattr=+vfp2 -float-abi=hard -run-pass=legalizer %s -o - | FileCheck %s -check-prefix CHECK -check-prefix HARD
# RUN: llc -O0 -mtriple arm-linux-gnueabi -mattr=+vfp2,+soft-float -float-abi=soft -run-pass=legalizer %s -o - | FileCheck %s -check-prefix CHECK -check-prefix SOFT -check-prefix SOFT-AEABI
# RUN: llc -O0 -mtriple arm-linux-gnu -mattr=+soft-float -float-abi=soft -run-pass=legalizer %s -o - | FileCheck %s -check-prefix CHECK -check-prefix SOFT -check-prefix SOFT-DEFAULT
# RUN: llc -O0 -mtriple arm-linux-gnueabi -mattr=+vfp2,+soft-float -float-abi=soft -run-pass=legalizer %s -o - | FileCheck %s -check-prefix CHECK -check-prefix SOFT -check-prefix SOFT-AEABI -check-prefix SOFT_POOL
# RUN: llc -O0 -mtriple arm-linux-gnu -mattr=+soft-float -float-abi=soft -run-pass=legalizer %s -o - | FileCheck %s -check-prefix CHECK -check-prefix SOFT -check-prefix SOFT-DEFAULT -check-prefix SOFT_POOL
# RUN: llc -O0 -mtriple thumb-linux-gnueabihf -mattr=+v6t2,+vfp2 -float-abi=hard -run-pass=legalizer %s -o - | FileCheck %s -check-prefix CHECK -check-prefix HARD
# RUN: llc -O0 -mtriple thumb-linux-gnueabi -mattr=+v6t2,+vfp2,+soft-float -float-abi=soft -run-pass=legalizer %s -o - | FileCheck %s -check-prefix CHECK -check-prefix SOFT -check-prefix SOFT-AEABI
# RUN: llc -O0 -mtriple thumb-linux-gnu -mattr=+v6t2,+soft-float -float-abi=soft -run-pass=legalizer %s -o - | FileCheck %s -check-prefix CHECK -check-prefix SOFT -check-prefix SOFT-DEFAULT
# RUN: llc -O0 -mtriple thumb-linux-gnueabi -mattr=+v6t2,+vfp2,+soft-float -float-abi=soft -run-pass=legalizer %s -o - | FileCheck %s -check-prefix CHECK -check-prefix SOFT -check-prefix=SOFT-AEABI -check-prefix SOFT_CONST
# RUN: llc -O0 -mtriple thumb-linux-gnu -mattr=+v6t2,+soft-float -float-abi=soft -run-pass=legalizer %s -o - | FileCheck %s -check-prefix CHECK -check-prefix SOFT -check-prefix SOFT-DEFAULT -check-prefix SOFT_CONST
--- |
define void @test_frem_float() { ret void }
define void @test_frem_double() { ret void }
Expand Down Expand Up @@ -657,10 +657,20 @@ body: |
bb.0:
liveins:
; SOFT_POOL: constants:
; SOFT_POOL: id: 0
; SOFT_POOL: value: i32 -1073532109
; SOFT_POOL: id: 1
; SOFT_POOL: value: i32 858993459
; HARD: [[R:%[0-9]+]]:_(s64) = G_FCONSTANT double -2.4
; SOFT-NOT: G_FCONSTANT
; SOFT-DAG: [[HI:%[0-9]+]]:_(s32) = G_CONSTANT i32 -1073532109
; SOFT-DAG: [[LO:%[0-9]+]]:_(s32) = G_CONSTANT i32 858993459
; SOFT_CONST-DAG: [[HI:%[0-9]+]]:_(s32) = G_CONSTANT i32 -1073532109
; SOFT_CONST-DAG: [[LO:%[0-9]+]]:_(s32) = G_CONSTANT i32 858993459
; SOFT_POOL-DAG: [[HIPTR:%[0-9]+]]:_(p0) = G_CONSTANT_POOL %const.0
; SOFT_POOL-DAG: [[HI:%[0-9]+]]:_(s32) = G_LOAD [[HIPTR]]
; SOFT_POOL-DAG: [[LOPTR:%[0-9]+]]:_(p0) = G_CONSTANT_POOL %const.1
; SOFT_POOL-DAG: [[LO:%[0-9]+]]:_(s32) = G_LOAD [[LOPTR]]
; SOFT-NOT: G_FCONSTANT
%0(s64) = G_FCONSTANT double -2.4
; HARD-DAG: G_UNMERGE_VALUES [[R]](s64)
Expand Down
25 changes: 25 additions & 0 deletions llvm/test/CodeGen/ARM/GlobalISel/select-constpool.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
# RUN: llc -mtriple arm-- -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s

---
name: get_const
legalized: true
regBankSelected: true
selected: false
tracksRegLiveness: true
constants:
- id: 0
value: i32 287454020
alignment: 4
isTargetSpecific: false
body: |
bb.1.entry:
; CHECK-LABEL: name: get_const
; CHECK: [[LDRcp:%[0-9]+]]:gpr = LDRcp %const.0, 0, 14 /* CC::al */, $noreg :: (load (s32) from constant-pool)
; CHECK-NEXT: $r0 = COPY [[LDRcp]]
; CHECK-NEXT: MOVPCLR 14 /* CC::al */, $noreg, implicit $r0
%1:gprb(p0) = G_CONSTANT_POOL %const.0
%0:gprb(s32) = G_LOAD %1(p0) :: (load (s32) from constant-pool)
$r0 = COPY %0(s32)
MOVPCLR 14 /* CC::al */, $noreg, implicit $r0
...

0 comments on commit 52e5683

Please sign in to comment.