Skip to content

Commit

Permalink
[PowerPC][Future] Initial support for PCRel addressing for constant p…
Browse files Browse the repository at this point in the history
…ool loads

Add initial support for PC Relative addressing for constant pool loads.
This includes adding a new relocation for @pcrel and adding a new PowerPC flag
to identify PC relative addressing.

Differential Revision: https://reviews.llvm.org/D74486
  • Loading branch information
stefanp-ibm authored and kamaub committed Apr 9, 2020
1 parent 015dee1 commit 75828ef
Show file tree
Hide file tree
Showing 18 changed files with 279 additions and 19 deletions.
2 changes: 2 additions & 0 deletions llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def
Expand Up @@ -97,6 +97,7 @@
#undef R_PPC64_DTPREL16_HIGH
#undef R_PPC64_DTPREL16_HIGHA
#undef R_PPC64_REL24_NOTOC
#undef R_PPC64_PCREL34
#undef R_PPC64_IRELATIVE
#undef R_PPC64_REL16
#undef R_PPC64_REL16_LO
Expand Down Expand Up @@ -192,6 +193,7 @@ ELF_RELOC(R_PPC64_TPREL16_HIGHA, 113)
ELF_RELOC(R_PPC64_DTPREL16_HIGH, 114)
ELF_RELOC(R_PPC64_DTPREL16_HIGHA, 115)
ELF_RELOC(R_PPC64_REL24_NOTOC, 116)
ELF_RELOC(R_PPC64_PCREL34, 132)
ELF_RELOC(R_PPC64_IRELATIVE, 248)
ELF_RELOC(R_PPC64_REL16, 249)
ELF_RELOC(R_PPC64_REL16_LO, 250)
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
Expand Up @@ -45,6 +45,8 @@ static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) {
return Value & 0xffff;
case PPC::fixup_ppc_half16ds:
return Value & 0xfffc;
case PPC::fixup_ppc_pcrel34:
return Value & 0x3ffffffff;
}
}

Expand All @@ -65,6 +67,7 @@ static unsigned getFixupKindNumBytes(unsigned Kind) {
case PPC::fixup_ppc_br24abs:
case PPC::fixup_ppc_br24_notoc:
return 4;
case PPC::fixup_ppc_pcrel34:
case FK_Data_8:
return 8;
case PPC::fixup_ppc_nofixup:
Expand Down Expand Up @@ -96,6 +99,7 @@ class PPCAsmBackend : public MCAsmBackend {
{ "fixup_ppc_brcond14abs", 16, 14, 0 },
{ "fixup_ppc_half16", 0, 16, 0 },
{ "fixup_ppc_half16ds", 0, 14, 0 },
{ "fixup_ppc_pcrel34", 0, 34, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_ppc_nofixup", 0, 0, 0 }
};
const static MCFixupKindInfo InfosLE[PPC::NumTargetFixupKinds] = {
Expand All @@ -107,6 +111,7 @@ class PPCAsmBackend : public MCAsmBackend {
{ "fixup_ppc_brcond14abs", 2, 14, 0 },
{ "fixup_ppc_half16", 0, 16, 0 },
{ "fixup_ppc_half16ds", 2, 14, 0 },
{ "fixup_ppc_pcrel34", 0, 34, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_ppc_nofixup", 0, 0, 0 }
};

Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp
Expand Up @@ -128,6 +128,9 @@ unsigned PPCELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
Target.print(errs());
errs() << '\n';
report_fatal_error("Invalid PC-relative half16ds relocation");
case PPC::fixup_ppc_pcrel34:
Type = ELF::R_PPC64_PCREL34;
break;
case FK_Data_4:
case FK_PCRel_4:
Type = ELF::R_PPC_REL32;
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h
Expand Up @@ -40,6 +40,9 @@ enum Fixups {
/// instrs like 'std'.
fixup_ppc_half16ds,

// A 34-bit fixup corresponding to PC-relative paddi.
fixup_ppc_pcrel34,

/// Not a true fixup, but ties a symbol to a call to __tls_get_addr for the
/// TLS general and local dynamic models, or inserts the thread-pointer
/// register number.
Expand Down
10 changes: 7 additions & 3 deletions llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
Expand Up @@ -400,9 +400,13 @@ void PPCInstPrinter::printS16ImmOperand(const MCInst *MI, unsigned OpNo,

void PPCInstPrinter::printS34ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
long long Value = MI->getOperand(OpNo).getImm();
assert(isInt<34>(Value) && "Invalid s34imm argument!");
O << (long long)Value;
if (MI->getOperand(OpNo).isImm()) {
long long Value = MI->getOperand(OpNo).getImm();
assert(isInt<34>(Value) && "Invalid s34imm argument!");
O << (long long)Value;
}
else
printOperand(MI, OpNo, O);
}

void PPCInstPrinter::printU16ImmOperand(const MCInst *MI, unsigned OpNo,
Expand Down
24 changes: 24 additions & 0 deletions llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp
Expand Up @@ -104,6 +104,20 @@ unsigned PPCMCCodeEmitter::getImm16Encoding(const MCInst &MI, unsigned OpNo,
return 0;
}

unsigned long
PPCMCCodeEmitter::getImm34Encoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MO = MI.getOperand(OpNo);
if (MO.isReg() || MO.isImm())
return getMachineOpValue(MI, MO, Fixups, STI);

// Add a fixup for the immediate field.
Fixups.push_back(MCFixup::create(IsLittleEndian? 0 : 1, MO.getExpr(),
(MCFixupKind)PPC::fixup_ppc_pcrel34));
return 0;
}

unsigned PPCMCCodeEmitter::getMemRIEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
Expand Down Expand Up @@ -175,6 +189,16 @@ PPCMCCodeEmitter::getMemRI34PCRelEncoding(const MCInst &MI, unsigned OpNo,
report_fatal_error("Operand must be 0");

const MCOperand &MO = MI.getOperand(OpNo);
if (MO.isExpr()) {
const MCExpr *Expr = MO.getExpr();
const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(Expr);
assert(SRE->getKind() == MCSymbolRefExpr::VK_PCREL &&
"VariantKind must be VK_PCREL");
Fixups.push_back(
MCFixup::create(IsLittleEndian ? 0 : 1, Expr,
static_cast<MCFixupKind>(PPC::fixup_ppc_pcrel34)));
return 0;
}
return ((getMachineOpValue(MI, MO, Fixups, STI)) & 0x3FFFFFFFFUL) | RegBits;
}

Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h
Expand Up @@ -50,6 +50,9 @@ class PPCMCCodeEmitter : public MCCodeEmitter {
unsigned getImm16Encoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
unsigned long getImm34Encoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
unsigned getMemRIEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
Expand Down
22 changes: 13 additions & 9 deletions llvm/lib/Target/PowerPC/PPC.h
Expand Up @@ -98,24 +98,28 @@ namespace llvm {
/// the function's picbase, e.g. lo16(symbol-picbase).
MO_PIC_FLAG = 2,

/// MO_PCREL_FLAG - If this bit is set, the symbol reference is relative to
/// the current instruction address(pc), e.g., var@pcrel. Fixup is VK_PCREL.
MO_PCREL_FLAG = 4,

/// The next are not flags but distinct values.
MO_ACCESS_MASK = 0xf0,
MO_ACCESS_MASK = 0xf00,

/// MO_LO, MO_HA - lo16(symbol) and ha16(symbol)
MO_LO = 1 << 4,
MO_HA = 2 << 4,
MO_LO = 1 << 8,
MO_HA = 2 << 8,

MO_TPREL_LO = 4 << 4,
MO_TPREL_HA = 3 << 4,
MO_TPREL_LO = 4 << 8,
MO_TPREL_HA = 3 << 8,

/// These values identify relocations on immediates folded
/// into memory operations.
MO_DTPREL_LO = 5 << 4,
MO_TLSLD_LO = 6 << 4,
MO_TOC_LO = 7 << 4,
MO_DTPREL_LO = 5 << 8,
MO_TLSLD_LO = 6 << 8,
MO_TOC_LO = 7 << 8,

// Symbol for VK_PPC_TLS fixup attached to an ADD instruction
MO_TLS = 8 << 4
MO_TLS = 8 << 8
};
} // end namespace PPCII

Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
Expand Up @@ -296,6 +296,10 @@ namespace {
return true;
}

bool SelectAddrPCRel(SDValue N, SDValue &Base) {
return PPCLowering->SelectAddressPCRel(N, Base);
}

/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
/// inline asm expressions. It is always correct to compute the value into
/// a register. The case of adding a (possibly relocatable) constant to a
Expand Down
36 changes: 36 additions & 0 deletions llvm/lib/Target/PowerPC/PPCISelLowering.cpp
Expand Up @@ -1480,6 +1480,7 @@ const char *PPCTargetLowering::getTargetNodeName(unsigned Opcode) const {
case PPCISD::EXTSWSLI: return "PPCISD::EXTSWSLI";
case PPCISD::LD_VSX_LH: return "PPCISD::LD_VSX_LH";
case PPCISD::FP_EXTEND_HALF: return "PPCISD::FP_EXTEND_HALF";
case PPCISD::MAT_PCREL_ADDR: return "PPCISD::MAT_PCREL_ADDR";
case PPCISD::LD_SPLAT: return "PPCISD::LD_SPLAT";
}
return nullptr;
Expand Down Expand Up @@ -2346,6 +2347,11 @@ bool PPCTargetLowering::SelectAddressEVXRegReg(SDValue N, SDValue &Base,
bool PPCTargetLowering::SelectAddressRegReg(SDValue N, SDValue &Base,
SDValue &Index, SelectionDAG &DAG,
unsigned EncodingAlignment) const {
// If we have a PC Relative target flag don't select as [reg+reg]. It will be
// a [pc+imm].
if (SelectAddressPCRel(N, Base))
return false;

int16_t imm = 0;
if (N.getOpcode() == ISD::ADD) {
// Is there any SPE load/store (f64), which can't handle 16bit offset?
Expand Down Expand Up @@ -2435,6 +2441,12 @@ bool PPCTargetLowering::SelectAddressRegImm(SDValue N, SDValue &Disp,
unsigned EncodingAlignment) const {
// FIXME dl should come from parent load or store, not from address
SDLoc dl(N);

// If we have a PC Relative target flag don't select as [reg+imm]. It will be
// a [pc+imm].
if (SelectAddressPCRel(N, Base))
return false;

// If this can be more profitably realized as r+r, fail.
if (SelectAddressRegReg(N, Disp, Base, DAG, EncodingAlignment))
return false;
Expand Down Expand Up @@ -2558,6 +2570,21 @@ bool PPCTargetLowering::SelectAddressRegRegOnly(SDValue N, SDValue &Base,
return true;
}

/// Returns true if this address is a PC Relative address.
/// PC Relative addresses are marked with the flag PPCII::MO_PCREL_FLAG.
bool PPCTargetLowering::SelectAddressPCRel(SDValue N, SDValue &Base) const {
ConstantPoolSDNode *ConstPoolNode =
dyn_cast<ConstantPoolSDNode>(N.getNode());
bool HasFlag = ConstPoolNode &&
ConstPoolNode->getTargetFlags() == PPCII::MO_PCREL_FLAG;
bool HasNode = N.getOpcode() == PPCISD::MAT_PCREL_ADDR;
if (HasFlag || HasNode) {
Base = N;
return true;
}
return false;
}

/// Returns true if we should use a direct load into vector instruction
/// (such as lxsd or lfd), instead of a load into gpr + direct move sequence.
static bool usePartialVectorLoads(SDNode *N, const PPCSubtarget& ST) {
Expand Down Expand Up @@ -2763,6 +2790,15 @@ SDValue PPCTargetLowering::LowerConstantPool(SDValue Op,
// 64-bit SVR4 ABI and AIX ABI code are always position-independent.
// The actual address of the GlobalValue is stored in the TOC.
if (Subtarget.is64BitELFABI() || Subtarget.isAIXABI()) {
if (Subtarget.hasPCRelativeMemops()) {
SDLoc DL(CP);
EVT Ty = getPointerTy(DAG.getDataLayout());
SDValue ConstPool = DAG.getTargetConstantPool(C, Ty,
CP->getAlignment(),
CP->getOffset(),
PPCII::MO_PCREL_FLAG);
return DAG.getNode(PPCISD::MAT_PCREL_ADDR, DL, Ty, ConstPool);
}
setUsesTOCBasePtr(DAG);
SDValue GA = DAG.getTargetConstantPool(C, PtrVT, CP->getAlignment(), 0);
return getTOCEntry(DAG, SDLoc(CP), GA);
Expand Down
9 changes: 9 additions & 0 deletions llvm/lib/Target/PowerPC/PPCISelLowering.h
Expand Up @@ -428,6 +428,11 @@ namespace llvm {
/// lower (IDX=1) half of v4f32 to v2f64.
FP_EXTEND_HALF,

/// MAT_PCREL_ADDR = Materialize a PC Relative address. This can be done
/// either through an add like PADDI or through a PC Relative load like
/// PLD.
MAT_PCREL_ADDR,

/// CHAIN = STBRX CHAIN, GPRC, Ptr, Type - This is a
/// byte-swapping store instruction. It byte-swaps the low "Type" bits of
/// the GPRC input, then stores it through Ptr. Type can be either i16 or
Expand Down Expand Up @@ -730,6 +735,10 @@ namespace llvm {
bool SelectAddressRegRegOnly(SDValue N, SDValue &Base, SDValue &Index,
SelectionDAG &DAG) const;

/// SelectAddressPCRel - Represent the specified address as pc relative to
/// be represented as [pc+imm]
bool SelectAddressPCRel(SDValue N, SDValue &Base) const;

Sched::Preference getSchedulingPreference(SDNode *N) const override;

/// LowerOperation - Provide custom lowering hooks for some operations.
Expand Down
4 changes: 3 additions & 1 deletion llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
Expand Up @@ -2046,7 +2046,9 @@ ArrayRef<std::pair<unsigned, const char *>>
PPCInstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {
using namespace PPCII;
static const std::pair<unsigned, const char *> TargetFlags[] = {
{MO_PLT, "ppc-plt"}, {MO_PIC_FLAG, "ppc-pic"}};
{MO_PLT, "ppc-plt"},
{MO_PIC_FLAG, "ppc-pic"},
{MO_PCREL_FLAG, "ppc-pcrel"}};
return makeArrayRef(TargetFlags);
}

Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Target/PowerPC/PPCInstrInfo.td
Expand Up @@ -319,6 +319,9 @@ def SDTDynAreaOp : SDTypeProfile<1, 1, []>;
def PPCdynalloc : SDNode<"PPCISD::DYNALLOC", SDTDynOp, [SDNPHasChain]>;
def PPCdynareaoffset : SDNode<"PPCISD::DYNAREAOFFSET", SDTDynAreaOp, [SDNPHasChain]>;

// PC Relative Specific Nodes
def PPCmatpcreladdr : SDNode<"PPCISD::MAT_PCREL_ADDR", SDTIntUnaryOp, []>;

//===----------------------------------------------------------------------===//
// PowerPC specific transformation functions and pattern fragments.
//
Expand Down Expand Up @@ -730,6 +733,7 @@ def PPCS34ImmAsmOperand : AsmOperandClass {
}
def s34imm : Operand<i64> {
let PrintMethod = "printS34ImmOperand";
let EncoderMethod = "getImm34Encoding";
let ParserMatchClass = PPCS34ImmAsmOperand;
let DecoderMethod = "decodeSImmOperand<34>";
}
Expand Down Expand Up @@ -977,6 +981,9 @@ def addr : ComplexPattern<iPTR, 1, "SelectAddr",[], []>;
/// This is just the offset part of iaddr, used for preinc.
def iaddroff : ComplexPattern<iPTR, 1, "SelectAddrImmOffs", [], []>;

// PC Relative Address
def pcreladdr : ComplexPattern<iPTR, 1, "SelectAddrPCRel", [], []>;

//===----------------------------------------------------------------------===//
// PowerPC Instruction Predicate Definitions.
def In32BitMode : Predicate<"!PPCSubTarget->isPPC64()">;
Expand Down
40 changes: 40 additions & 0 deletions llvm/lib/Target/PowerPC/PPCInstrPrefix.td
Expand Up @@ -337,3 +337,43 @@ let Predicates = [PrefixInstrs] in {
}
}

// TODO: We have an added complexity of 500 here. This is only a temporary
// solution to have tablegen consider these patterns first. The way we do
// addressing for PowerPC is complex depending on available D form, X form, or
// aligned D form loads/stores like DS and DQ forms. The prefixed
// instructions in this file also add additional PC Relative loads/stores
// and D form loads/stores with 34 bit immediates. It is very difficult to force
// instruction selection to consistently pick these first without the current
// added complexity. Once pc-relative implementation is complete, a set of
// follow-up patches will address this refactoring and the AddedComplexity will
// be removed.
let Predicates = [PCRelativeMemops], AddedComplexity = 500 in {
// Load f32
def : Pat<(f32 (load (PPCmatpcreladdr pcreladdr:$addr))), (PLFSpc $addr, 0)>;

// Load f64
def : Pat<(f64 (extloadf32 (PPCmatpcreladdr pcreladdr:$addr))),
(COPY_TO_REGCLASS (PLFSpc $addr, 0), VSFRC)>;
def : Pat<(f64 (load (PPCmatpcreladdr pcreladdr:$addr))), (PLFDpc $addr, 0)>;

// Load f128
def : Pat<(f128 (load (PPCmatpcreladdr pcreladdr:$addr))),
(COPY_TO_REGCLASS (PLXVpc $addr, 0), VRRC)>;

// Load v4i32
def : Pat<(v4i32 (load (PPCmatpcreladdr pcreladdr:$addr))), (PLXVpc $addr, 0)>;

// Load v2i64
def : Pat<(v2i64 (load (PPCmatpcreladdr pcreladdr:$addr))), (PLXVpc $addr, 0)>;

// Load v4f32
def : Pat<(v4f32 (load (PPCmatpcreladdr pcreladdr:$addr))), (PLXVpc $addr, 0)>;

// Load v2f64
def : Pat<(v2f64 (load (PPCmatpcreladdr pcreladdr:$addr))), (PLXVpc $addr, 0)>;

// If the PPCmatpcreladdr node is not caught by any other pattern it should be
// caught here and turned into a paddi instruction to materialize the address.
def : Pat<(PPCmatpcreladdr pcreladdr:$addr), (PADDI8pc 0, $addr)>;
}

4 changes: 3 additions & 1 deletion llvm/lib/Target/PowerPC/PPCMCInstLower.cpp
Expand Up @@ -78,8 +78,10 @@ static MCOperand GetSymbolRef(const MachineOperand &MO, const MCSymbol *Symbol,
break;
}

if (MO.getTargetFlags() == PPCII::MO_PLT)
if (MO.getTargetFlags() == PPCII::MO_PLT)
RefKind = MCSymbolRefExpr::VK_PLT;
else if (MO.getTargetFlags() == PPCII::MO_PCREL_FLAG)
RefKind = MCSymbolRefExpr::VK_PCREL;

const MachineInstr *MI = MO.getParent();

Expand Down

0 comments on commit 75828ef

Please sign in to comment.