Skip to content

Commit 766c7cd

Browse files
committed
[X86][GlobalISel] Support addr matching in SDAG pattern
addr matching was the only gatekeeper for starting selecting G_LOAD and G_STORE using SDAG patterns. * Replace getLoadStoreOp with getPtrLoadStoreOp in Load/Store selector as GlobalISel matcher or emitter can't map the pointer type into i32/i64 types used in SDAG patterns for pointers. So the load and store selection of pointers is still manual. * X86SelectAddress now is used for both: pattern matching and manual selection. As a result it accumulates all the code that previously was distrubuted among different selection functions. * Introduce a complex rederer `gi_addr` for `addr`. In this patch only existing functionality has been implemented. The renderer's name is the same as in SDAG: `selectAddr`. * Since truncating stores are not supported, we custom legalize them by matching types of store and MMO. * Introduce a ConstantPool flag to X86AddressMode because otherwise we need to introduce a GlobalISel copy for X86ISelAddressMode.
1 parent 4d59552 commit 766c7cd

37 files changed

+503
-363
lines changed

llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ class GMemOperation : public GenericMachineInstr {
6666
/// memory operations can't be reordered.
6767
bool isUnordered() const { return getMMO().isUnordered(); }
6868

69+
/// Return the minimum known alignment in bytes of the actual memory
70+
/// reference.
71+
Align getAlign() const { return getMMO().getAlign(); }
6972
/// Returns the size in bytes of the memory access.
7073
LocationSize getMemSize() const { return getMMO().getSize(); }
7174
/// Returns the size in bits of the memory access.

llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp

Lines changed: 121 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ class X86InstructionSelector : public InstructionSelector {
7373
// TODO: remove after supported by Tablegen-erated instruction selection.
7474
unsigned getLoadStoreOp(const LLT &Ty, const RegisterBank &RB, unsigned Opc,
7575
Align Alignment) const;
76+
// TODO: remove once p0<->i32/i64 matching is available
77+
unsigned getPtrLoadStoreOp(const LLT &Ty, const RegisterBank &RB,
78+
unsigned Opc) const;
7679

7780
bool selectLoadStoreOp(MachineInstr &I, MachineRegisterInfo &MRI,
7881
MachineFunction &MF) const;
@@ -119,6 +122,8 @@ class X86InstructionSelector : public InstructionSelector {
119122
bool selectSelect(MachineInstr &I, MachineRegisterInfo &MRI,
120123
MachineFunction &MF) const;
121124

125+
ComplexRendererFns selectAddr(MachineOperand &Root) const;
126+
122127
// emit insert subreg instruction and insert it before MachineInstr &I
123128
bool emitInsertSubreg(unsigned DstReg, unsigned SrcReg, MachineInstr &I,
124129
MachineRegisterInfo &MRI, MachineFunction &MF) const;
@@ -445,6 +450,17 @@ bool X86InstructionSelector::select(MachineInstr &I) {
445450
return false;
446451
}
447452

453+
unsigned X86InstructionSelector::getPtrLoadStoreOp(const LLT &Ty,
454+
const RegisterBank &RB,
455+
unsigned Opc) const {
456+
bool Isload = (Opc == TargetOpcode::G_LOAD);
457+
if (Ty == LLT::pointer(0, 32) && X86::GPRRegBankID == RB.getID())
458+
return Isload ? X86::MOV32rm : X86::MOV32mr;
459+
if (Ty == LLT::pointer(0, 64) && X86::GPRRegBankID == RB.getID())
460+
return Isload ? X86::MOV64rm : X86::MOV64mr;
461+
return Opc;
462+
}
463+
448464
unsigned X86InstructionSelector::getLoadStoreOp(const LLT &Ty,
449465
const RegisterBank &RB,
450466
unsigned Opc,
@@ -460,7 +476,7 @@ unsigned X86InstructionSelector::getLoadStoreOp(const LLT &Ty,
460476
} else if (Ty == LLT::scalar(16)) {
461477
if (X86::GPRRegBankID == RB.getID())
462478
return Isload ? X86::MOV16rm : X86::MOV16mr;
463-
} else if (Ty == LLT::scalar(32) || Ty == LLT::pointer(0, 32)) {
479+
} else if (Ty == LLT::scalar(32)) {
464480
if (X86::GPRRegBankID == RB.getID())
465481
return Isload ? X86::MOV32rm : X86::MOV32mr;
466482
if (X86::VECRRegBankID == RB.getID())
@@ -472,7 +488,7 @@ unsigned X86InstructionSelector::getLoadStoreOp(const LLT &Ty,
472488
X86::MOVSSmr);
473489
if (X86::PSRRegBankID == RB.getID())
474490
return Isload ? X86::LD_Fp32m : X86::ST_Fp32m;
475-
} else if (Ty == LLT::scalar(64) || Ty == LLT::pointer(0, 64)) {
491+
} else if (Ty == LLT::scalar(64)) {
476492
if (X86::GPRRegBankID == RB.getID())
477493
return Isload ? X86::MOV64rm : X86::MOV64mr;
478494
if (X86::VECRRegBankID == RB.getID())
@@ -530,30 +546,75 @@ unsigned X86InstructionSelector::getLoadStoreOp(const LLT &Ty,
530546
}
531547

532548
// Fill in an address from the given instruction.
533-
static void X86SelectAddress(const MachineInstr &I,
549+
static bool X86SelectAddress(MachineInstr &I, const X86TargetMachine &TM,
534550
const MachineRegisterInfo &MRI,
535-
X86AddressMode &AM) {
536-
assert(I.getOperand(0).isReg() && "unsupported opperand.");
551+
const X86Subtarget &STI, X86AddressMode &AM) {
552+
assert(I.getOperand(0).isReg() && "unsupported operand.");
537553
assert(MRI.getType(I.getOperand(0).getReg()).isPointer() &&
538554
"unsupported type.");
539555

540-
if (I.getOpcode() == TargetOpcode::G_PTR_ADD) {
556+
switch (I.getOpcode()) {
557+
default:
558+
break;
559+
case TargetOpcode::G_FRAME_INDEX:
560+
AM.Base.FrameIndex = I.getOperand(1).getIndex();
561+
AM.BaseType = X86AddressMode::FrameIndexBase;
562+
return true;
563+
case TargetOpcode::G_PTR_ADD: {
541564
if (auto COff = getIConstantVRegSExtVal(I.getOperand(2).getReg(), MRI)) {
542565
int64_t Imm = *COff;
543566
if (isInt<32>(Imm)) { // Check for displacement overflow.
544567
AM.Disp = static_cast<int32_t>(Imm);
545568
AM.Base.Reg = I.getOperand(1).getReg();
546-
return;
569+
return true;
547570
}
548571
}
549-
} else if (I.getOpcode() == TargetOpcode::G_FRAME_INDEX) {
550-
AM.Base.FrameIndex = I.getOperand(1).getIndex();
551-
AM.BaseType = X86AddressMode::FrameIndexBase;
552-
return;
572+
break;
553573
}
574+
case TargetOpcode::G_GLOBAL_VALUE: {
575+
auto GV = I.getOperand(1).getGlobal();
576+
if (GV->isThreadLocal()) {
577+
return false; // TODO: we don't support TLS yet.
578+
}
579+
// Can't handle alternate code models yet.
580+
if (TM.getCodeModel() != CodeModel::Small)
581+
return false;
582+
AM.GV = GV;
583+
AM.GVOpFlags = STI.classifyGlobalReference(GV);
584+
585+
// TODO: The ABI requires an extra load. not supported yet.
586+
if (isGlobalStubReference(AM.GVOpFlags))
587+
return false;
554588

589+
// TODO: This reference is relative to the pic base. not supported yet.
590+
if (isGlobalRelativeToPICBase(AM.GVOpFlags))
591+
return false;
592+
593+
if (STI.isPICStyleRIPRel()) {
594+
// Use rip-relative addressing.
595+
assert(AM.Base.Reg == 0 && AM.IndexReg == 0);
596+
AM.Base.Reg = X86::RIP;
597+
}
598+
return true;
599+
}
600+
case TargetOpcode::G_CONSTANT_POOL: {
601+
// TODO: Need a separate move for Large model
602+
if (TM.getCodeModel() == CodeModel::Large)
603+
return false;
604+
605+
AM.GVOpFlags = STI.classifyLocalReference(nullptr);
606+
if (AM.GVOpFlags == X86II::MO_GOTOFF)
607+
AM.Base.Reg = STI.getInstrInfo()->getGlobalBaseReg(I.getMF());
608+
else if (STI.is64Bit())
609+
AM.Base.Reg = X86::RIP;
610+
AM.CP = true;
611+
AM.Disp = I.getOperand(1).getIndex();
612+
return true;
613+
}
614+
}
555615
// Default behavior.
556616
AM.Base.Reg = I.getOperand(0).getReg();
617+
return true;
557618
}
558619

559620
bool X86InstructionSelector::selectLoadStoreOp(MachineInstr &I,
@@ -586,36 +647,18 @@ bool X86InstructionSelector::selectLoadStoreOp(MachineInstr &I,
586647
}
587648
}
588649

589-
unsigned NewOpc = getLoadStoreOp(Ty, RB, Opc, MemOp.getAlign());
650+
unsigned NewOpc = getPtrLoadStoreOp(Ty, RB, Opc);
590651
if (NewOpc == Opc)
591652
return false;
592653

593654
I.setDesc(TII.get(NewOpc));
594655
MachineInstrBuilder MIB(MF, I);
595-
const MachineInstr *Ptr = MRI.getVRegDef(I.getOperand(1).getReg());
596-
597-
if (Ptr->getOpcode() == TargetOpcode::G_CONSTANT_POOL) {
598-
assert(Opc == TargetOpcode::G_LOAD &&
599-
"Only G_LOAD from constant pool is expected");
600-
// TODO: Need a separate move for Large model
601-
if (TM.getCodeModel() == CodeModel::Large)
602-
return false;
603-
604-
unsigned char OpFlag = STI.classifyLocalReference(nullptr);
605-
unsigned PICBase = 0;
606-
if (OpFlag == X86II::MO_GOTOFF)
607-
PICBase = TII.getGlobalBaseReg(&MF);
608-
else if (STI.is64Bit())
609-
PICBase = X86::RIP;
610-
611-
I.removeOperand(1);
612-
addConstantPoolReference(MIB, Ptr->getOperand(1).getIndex(), PICBase,
613-
OpFlag);
614-
return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
615-
}
656+
MachineInstr *Ptr = MRI.getVRegDef(I.getOperand(1).getReg());
616657

617658
X86AddressMode AM;
618-
X86SelectAddress(*Ptr, MRI, AM);
659+
if (!X86SelectAddress(*Ptr, TM, MRI, STI, AM))
660+
return false;
661+
619662
if (Opc == TargetOpcode::G_LOAD) {
620663
I.removeOperand(1);
621664
addFullAddress(MIB, AM);
@@ -673,33 +716,10 @@ bool X86InstructionSelector::selectGlobalValue(MachineInstr &I,
673716
assert((I.getOpcode() == TargetOpcode::G_GLOBAL_VALUE) &&
674717
"unexpected instruction");
675718

676-
auto GV = I.getOperand(1).getGlobal();
677-
if (GV->isThreadLocal()) {
678-
return false; // TODO: we don't support TLS yet.
679-
}
680-
681-
// Can't handle alternate code models yet.
682-
if (TM.getCodeModel() != CodeModel::Small)
683-
return false;
684-
685719
X86AddressMode AM;
686-
AM.GV = GV;
687-
AM.GVOpFlags = STI.classifyGlobalReference(GV);
688-
689-
// TODO: The ABI requires an extra load. not supported yet.
690-
if (isGlobalStubReference(AM.GVOpFlags))
720+
if (!X86SelectAddress(I, TM, MRI, STI, AM))
691721
return false;
692722

693-
// TODO: This reference is relative to the pic base. not supported yet.
694-
if (isGlobalRelativeToPICBase(AM.GVOpFlags))
695-
return false;
696-
697-
if (STI.isPICStyleRIPRel()) {
698-
// Use rip-relative addressing.
699-
assert(AM.Base.Reg == 0 && AM.IndexReg == 0);
700-
AM.Base.Reg = X86::RIP;
701-
}
702-
703723
const Register DefReg = I.getOperand(0).getReg();
704724
LLT Ty = MRI.getType(DefReg);
705725
unsigned NewOpc = getLeaOP(Ty, STI);
@@ -1880,6 +1900,49 @@ bool X86InstructionSelector::selectSelect(MachineInstr &I,
18801900
return true;
18811901
}
18821902

1903+
InstructionSelector::ComplexRendererFns
1904+
X86InstructionSelector::selectAddr(MachineOperand &Root) const {
1905+
MachineInstr *MI = Root.getParent();
1906+
MachineIRBuilder MIRBuilder(*MI);
1907+
1908+
MachineRegisterInfo &MRI = MI->getMF()->getRegInfo();
1909+
MachineInstr *Ptr = MRI.getVRegDef(Root.getReg());
1910+
X86AddressMode AM;
1911+
X86SelectAddress(*Ptr, TM, MRI, STI, AM);
1912+
1913+
if (AM.Scale != 1)
1914+
return std::nullopt;
1915+
1916+
if (AM.IndexReg)
1917+
return std::nullopt;
1918+
1919+
return {// Base
1920+
{[=](MachineInstrBuilder &MIB) {
1921+
if (AM.BaseType == X86AddressMode::RegBase)
1922+
MIB.addUse(AM.Base.Reg);
1923+
else {
1924+
assert(AM.BaseType == X86AddressMode::FrameIndexBase &&
1925+
"Unknown type of address base");
1926+
MIB.addFrameIndex(AM.Base.FrameIndex);
1927+
}
1928+
},
1929+
// Scale
1930+
[=](MachineInstrBuilder &MIB) { MIB.addImm(AM.Scale); },
1931+
// Index
1932+
[=](MachineInstrBuilder &MIB) { MIB.addUse(0); },
1933+
// Disp
1934+
[=](MachineInstrBuilder &MIB) {
1935+
if (AM.GV)
1936+
MIB.addGlobalAddress(AM.GV, AM.Disp, AM.GVOpFlags);
1937+
else if (AM.CP)
1938+
MIB.addConstantPoolIndex(AM.Disp, 0, AM.GVOpFlags);
1939+
else
1940+
MIB.addImm(AM.Disp);
1941+
},
1942+
// Segment
1943+
[=](MachineInstrBuilder &MIB) { MIB.addUse(0); }}};
1944+
}
1945+
18831946
InstructionSelector *
18841947
llvm::createX86InstructionSelector(const X86TargetMachine &TM,
18851948
const X86Subtarget &Subtarget,

llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -368,22 +368,16 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
368368
// load/store: add more corner cases
369369
for (unsigned Op : {G_LOAD, G_STORE}) {
370370
auto &Action = getActionDefinitionsBuilder(Op);
371-
Action.legalForTypesWithMemDesc({{s8, p0, s1, 1},
372-
{s8, p0, s8, 1},
373-
{s16, p0, s8, 1},
371+
Action.legalForTypesWithMemDesc({{s8, p0, s8, 1},
374372
{s16, p0, s16, 1},
375-
{s32, p0, s8, 1},
376-
{s32, p0, s16, 1},
377373
{s32, p0, s32, 1},
378374
{s80, p0, s80, 1},
379375
{p0, p0, p0, 1},
380376
{v4s8, p0, v4s8, 1}});
381377
if (Is64Bit)
382-
Action.legalForTypesWithMemDesc({{s64, p0, s8, 1},
383-
{s64, p0, s16, 1},
384-
{s64, p0, s32, 1},
385-
{s64, p0, s64, 1},
378+
Action.legalForTypesWithMemDesc({{s64, p0, s64, 1},
386379
{v2s32, p0, v2s32, 1}});
380+
387381
if (HasSSE1)
388382
Action.legalForTypesWithMemDesc({{v4s32, p0, v4s32, 1}});
389383
if (HasSSE2)
@@ -402,6 +396,22 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
402396
{v32s16, p0, v32s16, 1},
403397
{v16s32, p0, v16s32, 1},
404398
{v8s64, p0, v8s64, 1}});
399+
400+
// X86 supports extending loads but not stores for GPRs
401+
if (Op == G_LOAD) {
402+
Action.legalForTypesWithMemDesc({{s8, p0, s1, 1},
403+
{s16, p0, s8, 1},
404+
{s32, p0, s8, 1},
405+
{s32, p0, s16, 1}});
406+
if (Is64Bit)
407+
Action.legalForTypesWithMemDesc({{s64, p0, s8, 1},
408+
{s64, p0, s16, 1},
409+
{s64, p0, s32, 1}});
410+
} else {
411+
Action.customIf([=](const LegalityQuery &Query) {
412+
return Query.Types[0] != Query.MMODescrs[0].MemoryTy;
413+
});
414+
}
405415
Action.widenScalarToNextPow2(0, /*Min=*/8)
406416
.clampScalar(0, s8, sMaxScalar)
407417
.scalarize(0);
@@ -655,6 +665,8 @@ bool X86LegalizerInfo::legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI,
655665
return legalizeFPTOUI(MI, MRI, Helper);
656666
case TargetOpcode::G_UITOFP:
657667
return legalizeUITOFP(MI, MRI, Helper);
668+
case TargetOpcode::G_STORE:
669+
return legalizeNarrowingStore(MI, MRI, Helper);
658670
}
659671
llvm_unreachable("expected switch to return");
660672
}
@@ -749,6 +761,22 @@ bool X86LegalizerInfo::legalizeUITOFP(MachineInstr &MI,
749761
return false;
750762
}
751763

764+
bool X86LegalizerInfo::legalizeNarrowingStore(MachineInstr &MI,
765+
MachineRegisterInfo &MRI,
766+
LegalizerHelper &Helper) const {
767+
auto &Store = cast<GStore>(MI);
768+
MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
769+
MachineMemOperand &MMO = **Store.memoperands_begin();
770+
MachineFunction &MF = MIRBuilder.getMF();
771+
LLT ValTy = MRI.getType(Store.getValueReg());
772+
auto *NewMMO = MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), ValTy);
773+
774+
Helper.Observer.changingInstr(Store);
775+
Store.setMemRefs(MF, {NewMMO});
776+
Helper.Observer.changedInstr(Store);
777+
return true;
778+
}
779+
752780
bool X86LegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
753781
MachineInstr &MI) const {
754782
return true;

llvm/lib/Target/X86/GISel/X86LegalizerInfo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ class X86LegalizerInfo : public LegalizerInfo {
4545

4646
bool legalizeUITOFP(MachineInstr &MI, MachineRegisterInfo &MRI,
4747
LegalizerHelper &Helper) const;
48+
49+
bool legalizeNarrowingStore(MachineInstr &MI, MachineRegisterInfo &MRI,
50+
LegalizerHelper &Helper) const;
4851
};
4952
} // namespace llvm
5053
#endif

llvm/lib/Target/X86/X86InstrBuilder.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,11 @@ struct X86AddressMode {
5555
int Disp;
5656
const GlobalValue *GV;
5757
unsigned GVOpFlags;
58+
bool CP;
5859

5960
X86AddressMode()
60-
: BaseType(RegBase), Scale(1), IndexReg(0), Disp(0), GV(nullptr),
61-
GVOpFlags(0) {
61+
: BaseType(RegBase), Scale(1), IndexReg(0), Disp(0), GV(nullptr),
62+
GVOpFlags(0), CP(false) {
6263
Base.Reg = 0;
6364
}
6465

0 commit comments

Comments
 (0)