mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-16 16:16:45 +00:00
[SystemZ] Improve handling of PC-relative addresses
The backend previously folded offsets into PC-relative addresses whereever possible. That's the right thing to do when the address can be used directly in a PC-relative memory reference (using things like LRL). But if we have a register-based memory reference and need to load the PC-relative address separately, it's better to use an anchor point that could be shared with other accesses to the same area of the variable. Fixes a FIXME. llvm-svn: 191524
This commit is contained in:
parent
0987676281
commit
cae9d29151
@ -128,7 +128,7 @@ class SystemZDAGToDAGISel : public SelectionDAGISel {
|
||||
const SystemZSubtarget &Subtarget;
|
||||
|
||||
// Used by SystemZOperands.td to create integer constants.
|
||||
inline SDValue getImm(const SDNode *Node, uint64_t Imm) {
|
||||
inline SDValue getImm(const SDNode *Node, uint64_t Imm) const {
|
||||
return CurDAG->getTargetConstant(Imm, Node->getValueType(0));
|
||||
}
|
||||
|
||||
@ -142,39 +142,39 @@ class SystemZDAGToDAGISel : public SelectionDAGISel {
|
||||
|
||||
// Try to fold more of the base or index of AM into AM, where IsBase
|
||||
// selects between the base and index.
|
||||
bool expandAddress(SystemZAddressingMode &AM, bool IsBase);
|
||||
bool expandAddress(SystemZAddressingMode &AM, bool IsBase) const;
|
||||
|
||||
// Try to describe N in AM, returning true on success.
|
||||
bool selectAddress(SDValue N, SystemZAddressingMode &AM);
|
||||
bool selectAddress(SDValue N, SystemZAddressingMode &AM) const;
|
||||
|
||||
// Extract individual target operands from matched address AM.
|
||||
void getAddressOperands(const SystemZAddressingMode &AM, EVT VT,
|
||||
SDValue &Base, SDValue &Disp);
|
||||
SDValue &Base, SDValue &Disp) const;
|
||||
void getAddressOperands(const SystemZAddressingMode &AM, EVT VT,
|
||||
SDValue &Base, SDValue &Disp, SDValue &Index);
|
||||
SDValue &Base, SDValue &Disp, SDValue &Index) const;
|
||||
|
||||
// Try to match Addr as a FormBD address with displacement type DR.
|
||||
// Return true on success, storing the base and displacement in
|
||||
// Base and Disp respectively.
|
||||
bool selectBDAddr(SystemZAddressingMode::DispRange DR, SDValue Addr,
|
||||
SDValue &Base, SDValue &Disp);
|
||||
SDValue &Base, SDValue &Disp) const;
|
||||
|
||||
// Try to match Addr as a FormBDX address with displacement type DR.
|
||||
// Return true on success and if the result had no index. Store the
|
||||
// base and displacement in Base and Disp respectively.
|
||||
bool selectMVIAddr(SystemZAddressingMode::DispRange DR, SDValue Addr,
|
||||
SDValue &Base, SDValue &Disp);
|
||||
SDValue &Base, SDValue &Disp) const;
|
||||
|
||||
// Try to match Addr as a FormBDX* address of form Form with
|
||||
// displacement type DR. Return true on success, storing the base,
|
||||
// displacement and index in Base, Disp and Index respectively.
|
||||
bool selectBDXAddr(SystemZAddressingMode::AddrForm Form,
|
||||
SystemZAddressingMode::DispRange DR, SDValue Addr,
|
||||
SDValue &Base, SDValue &Disp, SDValue &Index);
|
||||
SDValue &Base, SDValue &Disp, SDValue &Index) const;
|
||||
|
||||
// PC-relative address matching routines used by SystemZOperands.td.
|
||||
bool selectPCRelAddress(SDValue Addr, SDValue &Target) {
|
||||
if (Addr.getOpcode() == SystemZISD::PCREL_WRAPPER) {
|
||||
bool selectPCRelAddress(SDValue Addr, SDValue &Target) const {
|
||||
if (SystemZISD::isPCREL(Addr.getOpcode())) {
|
||||
Target = Addr.getOperand(0);
|
||||
return true;
|
||||
}
|
||||
@ -182,72 +182,72 @@ class SystemZDAGToDAGISel : public SelectionDAGISel {
|
||||
}
|
||||
|
||||
// BD matching routines used by SystemZOperands.td.
|
||||
bool selectBDAddr12Only(SDValue Addr, SDValue &Base, SDValue &Disp) {
|
||||
bool selectBDAddr12Only(SDValue Addr, SDValue &Base, SDValue &Disp) const {
|
||||
return selectBDAddr(SystemZAddressingMode::Disp12Only, Addr, Base, Disp);
|
||||
}
|
||||
bool selectBDAddr12Pair(SDValue Addr, SDValue &Base, SDValue &Disp) {
|
||||
bool selectBDAddr12Pair(SDValue Addr, SDValue &Base, SDValue &Disp) const {
|
||||
return selectBDAddr(SystemZAddressingMode::Disp12Pair, Addr, Base, Disp);
|
||||
}
|
||||
bool selectBDAddr20Only(SDValue Addr, SDValue &Base, SDValue &Disp) {
|
||||
bool selectBDAddr20Only(SDValue Addr, SDValue &Base, SDValue &Disp) const {
|
||||
return selectBDAddr(SystemZAddressingMode::Disp20Only, Addr, Base, Disp);
|
||||
}
|
||||
bool selectBDAddr20Pair(SDValue Addr, SDValue &Base, SDValue &Disp) {
|
||||
bool selectBDAddr20Pair(SDValue Addr, SDValue &Base, SDValue &Disp) const {
|
||||
return selectBDAddr(SystemZAddressingMode::Disp20Pair, Addr, Base, Disp);
|
||||
}
|
||||
|
||||
// MVI matching routines used by SystemZOperands.td.
|
||||
bool selectMVIAddr12Pair(SDValue Addr, SDValue &Base, SDValue &Disp) {
|
||||
bool selectMVIAddr12Pair(SDValue Addr, SDValue &Base, SDValue &Disp) const {
|
||||
return selectMVIAddr(SystemZAddressingMode::Disp12Pair, Addr, Base, Disp);
|
||||
}
|
||||
bool selectMVIAddr20Pair(SDValue Addr, SDValue &Base, SDValue &Disp) {
|
||||
bool selectMVIAddr20Pair(SDValue Addr, SDValue &Base, SDValue &Disp) const {
|
||||
return selectMVIAddr(SystemZAddressingMode::Disp20Pair, Addr, Base, Disp);
|
||||
}
|
||||
|
||||
// BDX matching routines used by SystemZOperands.td.
|
||||
bool selectBDXAddr12Only(SDValue Addr, SDValue &Base, SDValue &Disp,
|
||||
SDValue &Index) {
|
||||
SDValue &Index) const {
|
||||
return selectBDXAddr(SystemZAddressingMode::FormBDXNormal,
|
||||
SystemZAddressingMode::Disp12Only,
|
||||
Addr, Base, Disp, Index);
|
||||
}
|
||||
bool selectBDXAddr12Pair(SDValue Addr, SDValue &Base, SDValue &Disp,
|
||||
SDValue &Index) {
|
||||
SDValue &Index) const {
|
||||
return selectBDXAddr(SystemZAddressingMode::FormBDXNormal,
|
||||
SystemZAddressingMode::Disp12Pair,
|
||||
Addr, Base, Disp, Index);
|
||||
}
|
||||
bool selectDynAlloc12Only(SDValue Addr, SDValue &Base, SDValue &Disp,
|
||||
SDValue &Index) {
|
||||
SDValue &Index) const {
|
||||
return selectBDXAddr(SystemZAddressingMode::FormBDXDynAlloc,
|
||||
SystemZAddressingMode::Disp12Only,
|
||||
Addr, Base, Disp, Index);
|
||||
}
|
||||
bool selectBDXAddr20Only(SDValue Addr, SDValue &Base, SDValue &Disp,
|
||||
SDValue &Index) {
|
||||
SDValue &Index) const {
|
||||
return selectBDXAddr(SystemZAddressingMode::FormBDXNormal,
|
||||
SystemZAddressingMode::Disp20Only,
|
||||
Addr, Base, Disp, Index);
|
||||
}
|
||||
bool selectBDXAddr20Only128(SDValue Addr, SDValue &Base, SDValue &Disp,
|
||||
SDValue &Index) {
|
||||
SDValue &Index) const {
|
||||
return selectBDXAddr(SystemZAddressingMode::FormBDXNormal,
|
||||
SystemZAddressingMode::Disp20Only128,
|
||||
Addr, Base, Disp, Index);
|
||||
}
|
||||
bool selectBDXAddr20Pair(SDValue Addr, SDValue &Base, SDValue &Disp,
|
||||
SDValue &Index) {
|
||||
SDValue &Index) const {
|
||||
return selectBDXAddr(SystemZAddressingMode::FormBDXNormal,
|
||||
SystemZAddressingMode::Disp20Pair,
|
||||
Addr, Base, Disp, Index);
|
||||
}
|
||||
bool selectLAAddr12Pair(SDValue Addr, SDValue &Base, SDValue &Disp,
|
||||
SDValue &Index) {
|
||||
SDValue &Index) const {
|
||||
return selectBDXAddr(SystemZAddressingMode::FormBDXLA,
|
||||
SystemZAddressingMode::Disp12Pair,
|
||||
Addr, Base, Disp, Index);
|
||||
}
|
||||
bool selectLAAddr20Pair(SDValue Addr, SDValue &Base, SDValue &Disp,
|
||||
SDValue &Index) {
|
||||
SDValue &Index) const {
|
||||
return selectBDXAddr(SystemZAddressingMode::FormBDXLA,
|
||||
SystemZAddressingMode::Disp20Pair,
|
||||
Addr, Base, Disp, Index);
|
||||
@ -256,21 +256,21 @@ class SystemZDAGToDAGISel : public SelectionDAGISel {
|
||||
// Check whether (or Op (and X InsertMask)) is effectively an insertion
|
||||
// of X into bits InsertMask of some Y != Op. Return true if so and
|
||||
// set Op to that Y.
|
||||
bool detectOrAndInsertion(SDValue &Op, uint64_t InsertMask);
|
||||
bool detectOrAndInsertion(SDValue &Op, uint64_t InsertMask) const;
|
||||
|
||||
// Try to update RxSBG so that only the bits of RxSBG.Input in Mask are used.
|
||||
// Return true on success.
|
||||
bool refineRxSBGMask(RxSBGOperands &RxSBG, uint64_t Mask);
|
||||
bool refineRxSBGMask(RxSBGOperands &RxSBG, uint64_t Mask) const;
|
||||
|
||||
// Try to fold some of RxSBG.Input into other fields of RxSBG.
|
||||
// Return true on success.
|
||||
bool expandRxSBG(RxSBGOperands &RxSBG);
|
||||
bool expandRxSBG(RxSBGOperands &RxSBG) const;
|
||||
|
||||
// Return an undefined i64 value.
|
||||
SDValue getUNDEF64(SDLoc DL);
|
||||
SDValue getUNDEF64(SDLoc DL) const;
|
||||
|
||||
// Convert N to VT, if it isn't already.
|
||||
SDValue convertTo(SDLoc DL, EVT VT, SDValue N);
|
||||
SDValue convertTo(SDLoc DL, EVT VT, SDValue N) const;
|
||||
|
||||
// Try to implement AND or shift node N using RISBG with the zero flag set.
|
||||
// Return the selected node on success, otherwise return null.
|
||||
@ -384,9 +384,9 @@ static bool expandIndex(SystemZAddressingMode &AM, SDValue Base,
|
||||
// The base or index of AM is equivalent to Op0 + Op1, where IsBase selects
|
||||
// between the base and index. Try to fold Op1 into AM's displacement.
|
||||
static bool expandDisp(SystemZAddressingMode &AM, bool IsBase,
|
||||
SDValue Op0, ConstantSDNode *Op1) {
|
||||
SDValue Op0, uint64_t Op1) {
|
||||
// First try adjusting the displacement.
|
||||
int64_t TestDisp = AM.Disp + Op1->getSExtValue();
|
||||
int64_t TestDisp = AM.Disp + Op1;
|
||||
if (selectDisp(AM.DR, TestDisp)) {
|
||||
changeComponent(AM, IsBase, Op0);
|
||||
AM.Disp = TestDisp;
|
||||
@ -399,7 +399,7 @@ static bool expandDisp(SystemZAddressingMode &AM, bool IsBase,
|
||||
}
|
||||
|
||||
bool SystemZDAGToDAGISel::expandAddress(SystemZAddressingMode &AM,
|
||||
bool IsBase) {
|
||||
bool IsBase) const {
|
||||
SDValue N = IsBase ? AM.Base : AM.Index;
|
||||
unsigned Opcode = N.getOpcode();
|
||||
if (Opcode == ISD::TRUNCATE) {
|
||||
@ -419,13 +419,23 @@ bool SystemZDAGToDAGISel::expandAddress(SystemZAddressingMode &AM,
|
||||
return expandAdjDynAlloc(AM, IsBase, Op0);
|
||||
|
||||
if (Op0Code == ISD::Constant)
|
||||
return expandDisp(AM, IsBase, Op1, cast<ConstantSDNode>(Op0));
|
||||
return expandDisp(AM, IsBase, Op1,
|
||||
cast<ConstantSDNode>(Op0)->getSExtValue());
|
||||
if (Op1Code == ISD::Constant)
|
||||
return expandDisp(AM, IsBase, Op0, cast<ConstantSDNode>(Op1));
|
||||
return expandDisp(AM, IsBase, Op0,
|
||||
cast<ConstantSDNode>(Op1)->getSExtValue());
|
||||
|
||||
if (IsBase && expandIndex(AM, Op0, Op1))
|
||||
return true;
|
||||
}
|
||||
if (Opcode == SystemZISD::PCREL_OFFSET) {
|
||||
SDValue Full = N.getOperand(0);
|
||||
SDValue Base = N.getOperand(1);
|
||||
SDValue Anchor = Base.getOperand(0);
|
||||
uint64_t Offset = (cast<GlobalAddressSDNode>(Full)->getOffset() -
|
||||
cast<GlobalAddressSDNode>(Anchor)->getOffset());
|
||||
return expandDisp(AM, IsBase, Base, Offset);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -504,14 +514,15 @@ static bool shouldUseLA(SDNode *Base, int64_t Disp, SDNode *Index) {
|
||||
|
||||
// Return true if Addr is suitable for AM, updating AM if so.
|
||||
bool SystemZDAGToDAGISel::selectAddress(SDValue Addr,
|
||||
SystemZAddressingMode &AM) {
|
||||
SystemZAddressingMode &AM) const {
|
||||
// Start out assuming that the address will need to be loaded separately,
|
||||
// then try to extend it as much as we can.
|
||||
AM.Base = Addr;
|
||||
|
||||
// First try treating the address as a constant.
|
||||
if (Addr.getOpcode() == ISD::Constant &&
|
||||
expandDisp(AM, true, SDValue(), cast<ConstantSDNode>(Addr)))
|
||||
expandDisp(AM, true, SDValue(),
|
||||
cast<ConstantSDNode>(Addr)->getSExtValue()))
|
||||
;
|
||||
else
|
||||
// Otherwise try expanding each component.
|
||||
@ -551,7 +562,7 @@ static void insertDAGNode(SelectionDAG *DAG, SDNode *Pos, SDValue N) {
|
||||
|
||||
void SystemZDAGToDAGISel::getAddressOperands(const SystemZAddressingMode &AM,
|
||||
EVT VT, SDValue &Base,
|
||||
SDValue &Disp) {
|
||||
SDValue &Disp) const {
|
||||
Base = AM.Base;
|
||||
if (!Base.getNode())
|
||||
// Register 0 means "no base". This is mostly useful for shifts.
|
||||
@ -576,7 +587,8 @@ void SystemZDAGToDAGISel::getAddressOperands(const SystemZAddressingMode &AM,
|
||||
|
||||
void SystemZDAGToDAGISel::getAddressOperands(const SystemZAddressingMode &AM,
|
||||
EVT VT, SDValue &Base,
|
||||
SDValue &Disp, SDValue &Index) {
|
||||
SDValue &Disp,
|
||||
SDValue &Index) const {
|
||||
getAddressOperands(AM, VT, Base, Disp);
|
||||
|
||||
Index = AM.Index;
|
||||
@ -587,7 +599,7 @@ void SystemZDAGToDAGISel::getAddressOperands(const SystemZAddressingMode &AM,
|
||||
|
||||
bool SystemZDAGToDAGISel::selectBDAddr(SystemZAddressingMode::DispRange DR,
|
||||
SDValue Addr, SDValue &Base,
|
||||
SDValue &Disp) {
|
||||
SDValue &Disp) const {
|
||||
SystemZAddressingMode AM(SystemZAddressingMode::FormBD, DR);
|
||||
if (!selectAddress(Addr, AM))
|
||||
return false;
|
||||
@ -598,7 +610,7 @@ bool SystemZDAGToDAGISel::selectBDAddr(SystemZAddressingMode::DispRange DR,
|
||||
|
||||
bool SystemZDAGToDAGISel::selectMVIAddr(SystemZAddressingMode::DispRange DR,
|
||||
SDValue Addr, SDValue &Base,
|
||||
SDValue &Disp) {
|
||||
SDValue &Disp) const {
|
||||
SystemZAddressingMode AM(SystemZAddressingMode::FormBDXNormal, DR);
|
||||
if (!selectAddress(Addr, AM) || AM.Index.getNode())
|
||||
return false;
|
||||
@ -610,7 +622,7 @@ bool SystemZDAGToDAGISel::selectMVIAddr(SystemZAddressingMode::DispRange DR,
|
||||
bool SystemZDAGToDAGISel::selectBDXAddr(SystemZAddressingMode::AddrForm Form,
|
||||
SystemZAddressingMode::DispRange DR,
|
||||
SDValue Addr, SDValue &Base,
|
||||
SDValue &Disp, SDValue &Index) {
|
||||
SDValue &Disp, SDValue &Index) const {
|
||||
SystemZAddressingMode AM(Form, DR);
|
||||
if (!selectAddress(Addr, AM))
|
||||
return false;
|
||||
@ -620,7 +632,7 @@ bool SystemZDAGToDAGISel::selectBDXAddr(SystemZAddressingMode::AddrForm Form,
|
||||
}
|
||||
|
||||
bool SystemZDAGToDAGISel::detectOrAndInsertion(SDValue &Op,
|
||||
uint64_t InsertMask) {
|
||||
uint64_t InsertMask) const {
|
||||
// We're only interested in cases where the insertion is into some operand
|
||||
// of Op, rather than into Op itself. The only useful case is an AND.
|
||||
if (Op.getOpcode() != ISD::AND)
|
||||
@ -651,7 +663,8 @@ bool SystemZDAGToDAGISel::detectOrAndInsertion(SDValue &Op,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SystemZDAGToDAGISel::refineRxSBGMask(RxSBGOperands &RxSBG, uint64_t Mask) {
|
||||
bool SystemZDAGToDAGISel::refineRxSBGMask(RxSBGOperands &RxSBG,
|
||||
uint64_t Mask) const {
|
||||
const SystemZInstrInfo *TII = getInstrInfo();
|
||||
if (RxSBG.Rotate != 0)
|
||||
Mask = (Mask << RxSBG.Rotate) | (Mask >> (64 - RxSBG.Rotate));
|
||||
@ -682,7 +695,7 @@ static bool shiftedInBitsMatter(RxSBGOperands &RxSBG, uint64_t Count,
|
||||
return (ShiftedIn & RxSBG.Mask) != 0;
|
||||
}
|
||||
|
||||
bool SystemZDAGToDAGISel::expandRxSBG(RxSBGOperands &RxSBG) {
|
||||
bool SystemZDAGToDAGISel::expandRxSBG(RxSBGOperands &RxSBG) const {
|
||||
SDValue N = RxSBG.Input;
|
||||
unsigned Opcode = N.getOpcode();
|
||||
switch (Opcode) {
|
||||
@ -808,12 +821,12 @@ bool SystemZDAGToDAGISel::expandRxSBG(RxSBGOperands &RxSBG) {
|
||||
}
|
||||
}
|
||||
|
||||
SDValue SystemZDAGToDAGISel::getUNDEF64(SDLoc DL) {
|
||||
SDValue SystemZDAGToDAGISel::getUNDEF64(SDLoc DL) const {
|
||||
SDNode *N = CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, MVT::i64);
|
||||
return SDValue(N, 0);
|
||||
}
|
||||
|
||||
SDValue SystemZDAGToDAGISel::convertTo(SDLoc DL, EVT VT, SDValue N) {
|
||||
SDValue SystemZDAGToDAGISel::convertTo(SDLoc DL, EVT VT, SDValue N) const {
|
||||
if (N.getValueType() == MVT::i32 && VT == MVT::i64)
|
||||
return CurDAG->getTargetInsertSubreg(SystemZ::subreg_32bit,
|
||||
DL, VT, getUNDEF64(DL), N);
|
||||
@ -970,10 +983,10 @@ bool SystemZDAGToDAGISel::storeLoadCanUseMVC(SDNode *N) const {
|
||||
uint64_t Size = Load->getMemoryVT().getStoreSize();
|
||||
if (Size > 1 && Size <= 8) {
|
||||
// Prefer LHRL, LRL and LGRL.
|
||||
if (Load->getBasePtr().getOpcode() == SystemZISD::PCREL_WRAPPER)
|
||||
if (SystemZISD::isPCREL(Load->getBasePtr().getOpcode()))
|
||||
return false;
|
||||
// Prefer STHRL, STRL and STGRL.
|
||||
if (Store->getBasePtr().getOpcode() == SystemZISD::PCREL_WRAPPER)
|
||||
if (SystemZISD::isPCREL(Store->getBasePtr().getOpcode()))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1440,18 +1440,18 @@ SDValue SystemZTargetLowering::lowerGlobalAddress(GlobalAddressSDNode *Node,
|
||||
|
||||
SDValue Result;
|
||||
if (Subtarget.isPC32DBLSymbol(GV, RM, CM)) {
|
||||
// Make sure that the offset is aligned to a halfword. If it isn't,
|
||||
// create an "anchor" at the previous 12-bit boundary.
|
||||
// FIXME check whether there is a better way of handling this.
|
||||
if (Offset & 1) {
|
||||
Result = DAG.getTargetGlobalAddress(GV, DL, PtrVT,
|
||||
Offset & ~uint64_t(0xfff));
|
||||
Offset &= 0xfff;
|
||||
} else {
|
||||
Result = DAG.getTargetGlobalAddress(GV, DL, PtrVT, Offset);
|
||||
// Assign anchors at 1<<12 byte boundaries.
|
||||
uint64_t Anchor = Offset & ~uint64_t(0xfff);
|
||||
Result = DAG.getTargetGlobalAddress(GV, DL, PtrVT, Anchor);
|
||||
Result = DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Result);
|
||||
|
||||
// The offset can be folded into the address if it is aligned to a halfword.
|
||||
Offset -= Anchor;
|
||||
if (Offset != 0 && (Offset & 1) == 0) {
|
||||
SDValue Full = DAG.getTargetGlobalAddress(GV, DL, PtrVT, Anchor + Offset);
|
||||
Result = DAG.getNode(SystemZISD::PCREL_OFFSET, DL, PtrVT, Full, Result);
|
||||
Offset = 0;
|
||||
}
|
||||
Result = DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Result);
|
||||
} else {
|
||||
Result = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, SystemZII::MO_GOT);
|
||||
Result = DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Result);
|
||||
@ -2046,6 +2046,7 @@ const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
||||
OPCODE(CALL);
|
||||
OPCODE(SIBCALL);
|
||||
OPCODE(PCREL_WRAPPER);
|
||||
OPCODE(PCREL_OFFSET);
|
||||
OPCODE(ICMP);
|
||||
OPCODE(FCMP);
|
||||
OPCODE(TM);
|
||||
|
@ -38,6 +38,13 @@ namespace SystemZISD {
|
||||
// accesses (LARL). Operand 0 is the address.
|
||||
PCREL_WRAPPER,
|
||||
|
||||
// Used in cases where an offset is applied to a TargetGlobalAddress.
|
||||
// Operand 0 is the full TargetGlobalAddress and operand 1 is a
|
||||
// PCREL_WRAPPER for an anchor point. This is used so that we can
|
||||
// cheaply refer to either the full address or the anchor point
|
||||
// as a register base.
|
||||
PCREL_OFFSET,
|
||||
|
||||
// Integer comparisons. There are three operands: the two values
|
||||
// to compare, and an integer of type SystemZICMP.
|
||||
ICMP,
|
||||
@ -163,6 +170,11 @@ namespace SystemZISD {
|
||||
// a store prefetch.
|
||||
PREFETCH
|
||||
};
|
||||
|
||||
// Return true if OPCODE is some kind of PC-relative address.
|
||||
inline bool isPCREL(unsigned Opcode) {
|
||||
return Opcode == PCREL_WRAPPER || Opcode == PCREL_OFFSET;
|
||||
}
|
||||
}
|
||||
|
||||
namespace SystemZICMP {
|
||||
|
@ -46,7 +46,8 @@ class PCRelOperand<ValueType vt, AsmOperandClass asmop> : Operand<vt> {
|
||||
// address with address size VT. SELF is the name of the operand and
|
||||
// ASMOP is the associated asm operand.
|
||||
class PCRelAddress<ValueType vt, string self, AsmOperandClass asmop>
|
||||
: ComplexPattern<vt, 1, "selectPCRelAddress", [z_pcrel_wrapper]>,
|
||||
: ComplexPattern<vt, 1, "selectPCRelAddress",
|
||||
[z_pcrel_wrapper, z_pcrel_offset]>,
|
||||
PCRelOperand<vt, asmop> {
|
||||
let MIOperandInfo = (ops !cast<Operand>(self));
|
||||
}
|
||||
|
@ -30,6 +30,10 @@ def SDT_ZSelectCCMask : SDTypeProfile<1, 4,
|
||||
def SDT_ZWrapPtr : SDTypeProfile<1, 1,
|
||||
[SDTCisSameAs<0, 1>,
|
||||
SDTCisPtrTy<0>]>;
|
||||
def SDT_ZWrapOffset : SDTypeProfile<1, 2,
|
||||
[SDTCisSameAs<0, 1>,
|
||||
SDTCisSameAs<0, 2>,
|
||||
SDTCisPtrTy<0>]>;
|
||||
def SDT_ZAdjDynAlloc : SDTypeProfile<1, 0, [SDTCisVT<0, i64>]>;
|
||||
def SDT_ZExtractAccess : SDTypeProfile<1, 1,
|
||||
[SDTCisVT<0, i32>,
|
||||
@ -97,6 +101,8 @@ def z_sibcall : SDNode<"SystemZISD::SIBCALL", SDT_ZCall,
|
||||
[SDNPHasChain, SDNPOutGlue, SDNPOptInGlue,
|
||||
SDNPVariadic]>;
|
||||
def z_pcrel_wrapper : SDNode<"SystemZISD::PCREL_WRAPPER", SDT_ZWrapPtr, []>;
|
||||
def z_pcrel_offset : SDNode<"SystemZISD::PCREL_OFFSET",
|
||||
SDT_ZWrapOffset, []>;
|
||||
def z_icmp : SDNode<"SystemZISD::ICMP", SDT_ZICmp, [SDNPOutGlue]>;
|
||||
def z_fcmp : SDNode<"SystemZISD::FCMP", SDT_ZCmp, [SDNPOutGlue]>;
|
||||
def z_tm : SDNode<"SystemZISD::TM", SDT_ZICmp, [SDNPOutGlue]>;
|
||||
|
@ -10,6 +10,8 @@
|
||||
@gsrc32u = global i32 1, align 2, section "foo"
|
||||
@gdst16u = global i16 2, align 1, section "foo"
|
||||
@gdst32u = global i32 2, align 2, section "foo"
|
||||
@garray8 = global [2 x i8] [i8 100, i8 101]
|
||||
@garray16 = global [2 x i16] [i16 102, i16 103]
|
||||
|
||||
; Check sign-extending loads from i16.
|
||||
define i32 @f1() {
|
||||
@ -97,3 +99,36 @@ define void @f8() {
|
||||
store i32 %val, i32 *@gdst32u, align 2
|
||||
ret void
|
||||
}
|
||||
|
||||
; Test a case where we want to use one LARL for accesses to two different
|
||||
; parts of a variable.
|
||||
define void @f9() {
|
||||
; CHECK-LABEL: f9:
|
||||
; CHECK: larl [[REG:%r[0-5]]], garray8
|
||||
; CHECK: llc [[VAL:%r[0-5]]], 0([[REG]])
|
||||
; CHECK: srl [[VAL]], 1
|
||||
; CHECK: stc [[VAL]], 1([[REG]])
|
||||
; CHECK: br %r14
|
||||
%ptr1 = getelementptr [2 x i8] *@garray8, i64 0, i64 0
|
||||
%ptr2 = getelementptr [2 x i8] *@garray8, i64 0, i64 1
|
||||
%val = load i8 *%ptr1
|
||||
%shr = lshr i8 %val, 1
|
||||
store i8 %shr, i8 *%ptr2
|
||||
ret void
|
||||
}
|
||||
|
||||
; Test a case where we want to use separate relative-long addresses for
|
||||
; two different parts of a variable.
|
||||
define void @f10() {
|
||||
; CHECK-LABEL: f10:
|
||||
; CHECK: llhrl [[VAL:%r[0-5]]], garray16
|
||||
; CHECK: srl [[VAL]], 1
|
||||
; CHECK: sthrl [[VAL]], garray16+2
|
||||
; CHECK: br %r14
|
||||
%ptr1 = getelementptr [2 x i16] *@garray16, i64 0, i64 0
|
||||
%ptr2 = getelementptr [2 x i16] *@garray16, i64 0, i64 1
|
||||
%val = load i16 *%ptr1
|
||||
%shr = lshr i16 %val, 1
|
||||
store i16 %shr, i16 *%ptr2
|
||||
ret void
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user