summaryrefslogtreecommitdiff
path: root/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/PowerPC/PPCISelLowering.cpp')
-rw-r--r--llvm/lib/Target/PowerPC/PPCISelLowering.cpp1558
1 files changed, 1368 insertions, 190 deletions
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 9215c17cb94b..37358176f35e 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -121,10 +121,10 @@ cl::desc("don't always align innermost loop to 32 bytes on ppc"), cl::Hidden);
static cl::opt<bool> UseAbsoluteJumpTables("ppc-use-absolute-jumptables",
cl::desc("use absolute jump tables on ppc"), cl::Hidden);
-// TODO - Remove this option if soft fp128 has been fully supported .
-static cl::opt<bool>
- EnableSoftFP128("enable-soft-fp128",
- cl::desc("temp option to enable soft fp128"), cl::Hidden);
+static cl::opt<bool> EnableQuadwordAtomics(
+ "ppc-quadword-atomics",
+ cl::desc("enable quadword lock-free atomic operations"), cl::init(false),
+ cl::Hidden);
STATISTIC(NumTailCalls, "Number of tail calls");
STATISTIC(NumSiblingCalls, "Number of sibling calls");
@@ -135,12 +135,18 @@ static bool isNByteElemShuffleMask(ShuffleVectorSDNode *, unsigned, int);
static SDValue widenVec(SelectionDAG &DAG, SDValue Vec, const SDLoc &dl);
+static const char AIXSSPCanaryWordName[] = "__ssp_canary_word";
+
// FIXME: Remove this once the bug has been fixed!
extern cl::opt<bool> ANDIGlueBug;
PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
const PPCSubtarget &STI)
: TargetLowering(TM), Subtarget(STI) {
+ // Initialize map that relates the PPC addressing modes to the computed flags
+ // of a load/store instruction. The map is used to determine the optimal
+ // addressing mode when selecting load and stores.
+ initializeAddrModeMap();
// On PPC32/64, arguments smaller than 4/8 bytes are extended, so all
// arguments are at least 4/8 bytes aligned.
bool isPPC64 = Subtarget.isPPC64();
@@ -167,6 +173,10 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
// Sub-word ATOMIC_CMP_SWAP need to ensure that the input is zero-extended.
setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i32, Custom);
+ // Custom lower inline assembly to check for special registers.
+ setOperationAction(ISD::INLINEASM, MVT::Other, Custom);
+ setOperationAction(ISD::INLINEASM_BR, MVT::Other, Custom);
+
// PowerPC has an i16 but no i8 (or i1) SEXTLOAD.
for (MVT VT : MVT::integer_valuetypes()) {
setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote);
@@ -324,14 +334,18 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
setOperationAction(ISD::STRICT_FSUB, MVT::f32, Legal);
setOperationAction(ISD::STRICT_FMUL, MVT::f32, Legal);
setOperationAction(ISD::STRICT_FDIV, MVT::f32, Legal);
- setOperationAction(ISD::STRICT_FMA, MVT::f32, Legal);
setOperationAction(ISD::STRICT_FP_ROUND, MVT::f32, Legal);
setOperationAction(ISD::STRICT_FADD, MVT::f64, Legal);
setOperationAction(ISD::STRICT_FSUB, MVT::f64, Legal);
setOperationAction(ISD::STRICT_FMUL, MVT::f64, Legal);
setOperationAction(ISD::STRICT_FDIV, MVT::f64, Legal);
- setOperationAction(ISD::STRICT_FMA, MVT::f64, Legal);
+
+ if (!Subtarget.hasSPE()) {
+ setOperationAction(ISD::STRICT_FMA, MVT::f32, Legal);
+ setOperationAction(ISD::STRICT_FMA, MVT::f64, Legal);
+ }
+
if (Subtarget.hasVSX()) {
setOperationAction(ISD::STRICT_FRINT, MVT::f32, Legal);
setOperationAction(ISD::STRICT_FRINT, MVT::f64, Legal);
@@ -413,7 +427,7 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
// to speed up scalar BSWAP64.
// CTPOP or CTTZ were introduced in P8/P9 respectively
setOperationAction(ISD::BSWAP, MVT::i32 , Expand);
- if (Subtarget.hasP9Vector())
+ if (Subtarget.hasP9Vector() && Subtarget.isPPC64())
setOperationAction(ISD::BSWAP, MVT::i64 , Custom);
else
setOperationAction(ISD::BSWAP, MVT::i64 , Expand);
@@ -477,6 +491,10 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
setOperationAction(ISD::FP_TO_SINT, MVT::i32, Legal);
setOperationAction(ISD::SINT_TO_FP, MVT::i32, Legal);
setOperationAction(ISD::UINT_TO_FP, MVT::i32, Legal);
+
+ // SPE supports signaling compare of f32/f64.
+ setOperationAction(ISD::STRICT_FSETCCS, MVT::f32, Legal);
+ setOperationAction(ISD::STRICT_FSETCCS, MVT::f64, Legal);
} else {
// PowerPC turns FP_TO_SINT into FCTIWZ and some load/stores.
setOperationAction(ISD::STRICT_FP_TO_SINT, MVT::i32, Custom);
@@ -878,6 +896,7 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
if (Subtarget.hasVSX()) {
setOperationAction(ISD::FDIV, MVT::v4f32, Legal);
setOperationAction(ISD::FSQRT, MVT::v4f32, Legal);
+ setOperationAction(ISD::INSERT_VECTOR_ELT, MVT::v2f64, Custom);
}
if (Subtarget.hasP8Altivec())
@@ -1065,8 +1084,7 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
setOperationAction(ISD::FCOPYSIGN, MVT::v4f32, Legal);
setOperationAction(ISD::FCOPYSIGN, MVT::v2f64, Legal);
- if (Subtarget.hasDirectMove())
- setOperationAction(ISD::BUILD_VECTOR, MVT::v2i64, Custom);
+ setOperationAction(ISD::BUILD_VECTOR, MVT::v2i64, Custom);
setOperationAction(ISD::BUILD_VECTOR, MVT::v2f64, Custom);
// Handle constrained floating-point operations of vector.
@@ -1101,6 +1119,23 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
setOperationAction(ISD::STRICT_FROUND, MVT::v2f64, Legal);
addRegisterClass(MVT::v2i64, &PPC::VSRCRegClass);
+ addRegisterClass(MVT::f128, &PPC::VRRCRegClass);
+
+ for (MVT FPT : MVT::fp_valuetypes())
+ setLoadExtAction(ISD::EXTLOAD, MVT::f128, FPT, Expand);
+
+ // Expand the SELECT to SELECT_CC
+ setOperationAction(ISD::SELECT, MVT::f128, Expand);
+
+ setTruncStoreAction(MVT::f128, MVT::f64, Expand);
+ setTruncStoreAction(MVT::f128, MVT::f32, Expand);
+
+ // No implementation for these ops for PowerPC.
+ setOperationAction(ISD::FSIN, MVT::f128, Expand);
+ setOperationAction(ISD::FCOS, MVT::f128, Expand);
+ setOperationAction(ISD::FPOW, MVT::f128, Expand);
+ setOperationAction(ISD::FPOWI, MVT::f128, Expand);
+ setOperationAction(ISD::FREM, MVT::f128, Expand);
}
if (Subtarget.hasP8Altivec()) {
@@ -1119,15 +1154,12 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
setOperationAction(ISD::SRL, MVT::v1i128, Legal);
setOperationAction(ISD::SRA, MVT::v1i128, Expand);
- addRegisterClass(MVT::f128, &PPC::VRRCRegClass);
setOperationAction(ISD::FADD, MVT::f128, Legal);
setOperationAction(ISD::FSUB, MVT::f128, Legal);
setOperationAction(ISD::FDIV, MVT::f128, Legal);
setOperationAction(ISD::FMUL, MVT::f128, Legal);
setOperationAction(ISD::FP_EXTEND, MVT::f128, Legal);
- // No extending loads to f128 on PPC.
- for (MVT FPT : MVT::fp_valuetypes())
- setLoadExtAction(ISD::EXTLOAD, MVT::f128, FPT, Expand);
+
setOperationAction(ISD::FMA, MVT::f128, Legal);
setCondCodeAction(ISD::SETULT, MVT::f128, Expand);
setCondCodeAction(ISD::SETUGT, MVT::f128, Expand);
@@ -1143,18 +1175,9 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
setOperationAction(ISD::FNEARBYINT, MVT::f128, Legal);
setOperationAction(ISD::FROUND, MVT::f128, Legal);
- setOperationAction(ISD::SELECT, MVT::f128, Expand);
setOperationAction(ISD::FP_ROUND, MVT::f64, Legal);
setOperationAction(ISD::FP_ROUND, MVT::f32, Legal);
- setTruncStoreAction(MVT::f128, MVT::f64, Expand);
- setTruncStoreAction(MVT::f128, MVT::f32, Expand);
setOperationAction(ISD::BITCAST, MVT::i128, Custom);
- // No implementation for these ops for PowerPC.
- setOperationAction(ISD::FSIN, MVT::f128, Expand);
- setOperationAction(ISD::FCOS, MVT::f128, Expand);
- setOperationAction(ISD::FPOW, MVT::f128, Expand);
- setOperationAction(ISD::FPOWI, MVT::f128, Expand);
- setOperationAction(ISD::FREM, MVT::f128, Expand);
// Handle constrained floating-point operations of fp128
setOperationAction(ISD::STRICT_FADD, MVT::f128, Legal);
@@ -1177,12 +1200,7 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
setOperationAction(ISD::BSWAP, MVT::v4i32, Legal);
setOperationAction(ISD::BSWAP, MVT::v2i64, Legal);
setOperationAction(ISD::BSWAP, MVT::v1i128, Legal);
- } else if (Subtarget.hasAltivec() && EnableSoftFP128) {
- addRegisterClass(MVT::f128, &PPC::VRRCRegClass);
-
- for (MVT FPT : MVT::fp_valuetypes())
- setLoadExtAction(ISD::EXTLOAD, MVT::f128, FPT, Expand);
-
+ } else if (Subtarget.hasVSX()) {
setOperationAction(ISD::LOAD, MVT::f128, Promote);
setOperationAction(ISD::STORE, MVT::f128, Promote);
@@ -1198,18 +1216,10 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
setOperationAction(ISD::FDIV, MVT::f128, Expand);
setOperationAction(ISD::FNEG, MVT::f128, Expand);
setOperationAction(ISD::FABS, MVT::f128, Expand);
- setOperationAction(ISD::FSIN, MVT::f128, Expand);
- setOperationAction(ISD::FCOS, MVT::f128, Expand);
- setOperationAction(ISD::FPOW, MVT::f128, Expand);
- setOperationAction(ISD::FPOWI, MVT::f128, Expand);
- setOperationAction(ISD::FREM, MVT::f128, Expand);
setOperationAction(ISD::FSQRT, MVT::f128, Expand);
setOperationAction(ISD::FMA, MVT::f128, Expand);
setOperationAction(ISD::FCOPYSIGN, MVT::f128, Expand);
- setTruncStoreAction(MVT::f128, MVT::f64, Expand);
- setTruncStoreAction(MVT::f128, MVT::f32, Expand);
-
// Expand the fp_extend if the target type is fp128.
setOperationAction(ISD::FP_EXTEND, MVT::f128, Expand);
setOperationAction(ISD::STRICT_FP_EXTEND, MVT::f128, Expand);
@@ -1219,6 +1229,19 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
setOperationAction(ISD::FP_ROUND, VT, Custom);
setOperationAction(ISD::STRICT_FP_ROUND, VT, Custom);
}
+
+ setOperationAction(ISD::SETCC, MVT::f128, Custom);
+ setOperationAction(ISD::STRICT_FSETCC, MVT::f128, Custom);
+ setOperationAction(ISD::STRICT_FSETCCS, MVT::f128, Custom);
+ setOperationAction(ISD::BR_CC, MVT::f128, Expand);
+
+ // Lower following f128 select_cc pattern:
+ // select_cc x, y, tv, fv, cc -> select_cc (setcc x, y, cc), 0, tv, fv, NE
+ setOperationAction(ISD::SELECT_CC, MVT::f128, Custom);
+
+ // We need to handle f128 SELECT_CC with integer result type.
+ setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
+ setOperationAction(ISD::SELECT_CC, MVT::i64, isPPC64 ? Custom : Expand);
}
if (Subtarget.hasP9Altivec()) {
@@ -1233,6 +1256,9 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::v2i32, Legal);
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::v2i64, Legal);
}
+
+ if (Subtarget.isISA3_1())
+ setOperationAction(ISD::INSERT_VECTOR_ELT, MVT::v2i64, Custom);
}
if (Subtarget.pairedVectorMemops()) {
@@ -1260,6 +1286,9 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
setOperationAction(ISD::ATOMIC_STORE, MVT::i64, Expand);
}
+ if (EnableQuadwordAtomics && Subtarget.hasQuadwordAtomics())
+ setMaxAtomicSizeInBitsSupported(128);
+
setBooleanContents(ZeroOrOneBooleanContent);
if (Subtarget.hasAltivec()) {
@@ -1412,6 +1441,84 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
PredictableSelectIsExpensive = Subtarget.isPredictableSelectIsExpensive();
}
+// *********************************** NOTE ************************************
+// For selecting load and store instructions, the addressing modes are defined
+// as ComplexPatterns in PPCInstrInfo.td, which are then utilized in the TD
+// patterns to match the load the store instructions.
+//
+// The TD definitions for the addressing modes correspond to their respective
+// Select<AddrMode>Form() function in PPCISelDAGToDAG.cpp. These functions rely
+// on SelectOptimalAddrMode(), which calls computeMOFlags() to compute the
+// address mode flags of a particular node. Afterwards, the computed address
+// flags are passed into getAddrModeForFlags() in order to retrieve the optimal
+// addressing mode. SelectOptimalAddrMode() then sets the Base and Displacement
+// accordingly, based on the preferred addressing mode.
+//
+// Within PPCISelLowering.h, there are two enums: MemOpFlags and AddrMode.
+// MemOpFlags contains all the possible flags that can be used to compute the
+// optimal addressing mode for load and store instructions.
+// AddrMode contains all the possible load and store addressing modes available
+// on Power (such as DForm, DSForm, DQForm, XForm, etc.)
+//
+// When adding new load and store instructions, it is possible that new address
+// flags may need to be added into MemOpFlags, and a new addressing mode will
+// need to be added to AddrMode. An entry of the new addressing mode (consisting
+// of the minimal and main distinguishing address flags for the new load/store
+// instructions) will need to be added into initializeAddrModeMap() below.
+// Finally, when adding new addressing modes, the getAddrModeForFlags() will
+// need to be updated to account for selecting the optimal addressing mode.
+// *****************************************************************************
+/// Initialize the map that relates the different addressing modes of the load
+/// and store instructions to a set of flags. This ensures the load/store
+/// instruction is correctly matched during instruction selection.
+void PPCTargetLowering::initializeAddrModeMap() {
+ AddrModesMap[PPC::AM_DForm] = {
+ // LWZ, STW
+ PPC::MOF_ZExt | PPC::MOF_RPlusSImm16 | PPC::MOF_WordInt,
+ PPC::MOF_ZExt | PPC::MOF_RPlusLo | PPC::MOF_WordInt,
+ PPC::MOF_ZExt | PPC::MOF_NotAddNorCst | PPC::MOF_WordInt,
+ PPC::MOF_ZExt | PPC::MOF_AddrIsSImm32 | PPC::MOF_WordInt,
+ // LBZ, LHZ, STB, STH
+ PPC::MOF_ZExt | PPC::MOF_RPlusSImm16 | PPC::MOF_SubWordInt,
+ PPC::MOF_ZExt | PPC::MOF_RPlusLo | PPC::MOF_SubWordInt,
+ PPC::MOF_ZExt | PPC::MOF_NotAddNorCst | PPC::MOF_SubWordInt,
+ PPC::MOF_ZExt | PPC::MOF_AddrIsSImm32 | PPC::MOF_SubWordInt,
+ // LHA
+ PPC::MOF_SExt | PPC::MOF_RPlusSImm16 | PPC::MOF_SubWordInt,
+ PPC::MOF_SExt | PPC::MOF_RPlusLo | PPC::MOF_SubWordInt,
+ PPC::MOF_SExt | PPC::MOF_NotAddNorCst | PPC::MOF_SubWordInt,
+ PPC::MOF_SExt | PPC::MOF_AddrIsSImm32 | PPC::MOF_SubWordInt,
+ // LFS, LFD, STFS, STFD
+ PPC::MOF_RPlusSImm16 | PPC::MOF_ScalarFloat | PPC::MOF_SubtargetBeforeP9,
+ PPC::MOF_RPlusLo | PPC::MOF_ScalarFloat | PPC::MOF_SubtargetBeforeP9,
+ PPC::MOF_NotAddNorCst | PPC::MOF_ScalarFloat | PPC::MOF_SubtargetBeforeP9,
+ PPC::MOF_AddrIsSImm32 | PPC::MOF_ScalarFloat | PPC::MOF_SubtargetBeforeP9,
+ };
+ AddrModesMap[PPC::AM_DSForm] = {
+ // LWA
+ PPC::MOF_SExt | PPC::MOF_RPlusSImm16Mult4 | PPC::MOF_WordInt,
+ PPC::MOF_SExt | PPC::MOF_NotAddNorCst | PPC::MOF_WordInt,
+ PPC::MOF_SExt | PPC::MOF_AddrIsSImm32 | PPC::MOF_WordInt,
+ // LD, STD
+ PPC::MOF_RPlusSImm16Mult4 | PPC::MOF_DoubleWordInt,
+ PPC::MOF_NotAddNorCst | PPC::MOF_DoubleWordInt,
+ PPC::MOF_AddrIsSImm32 | PPC::MOF_DoubleWordInt,
+ // DFLOADf32, DFLOADf64, DSTOREf32, DSTOREf64
+ PPC::MOF_RPlusSImm16Mult4 | PPC::MOF_ScalarFloat | PPC::MOF_SubtargetP9,
+ PPC::MOF_NotAddNorCst | PPC::MOF_ScalarFloat | PPC::MOF_SubtargetP9,
+ PPC::MOF_AddrIsSImm32 | PPC::MOF_ScalarFloat | PPC::MOF_SubtargetP9,
+ };
+ AddrModesMap[PPC::AM_DQForm] = {
+ // LXV, STXV
+ PPC::MOF_RPlusSImm16Mult16 | PPC::MOF_Vector | PPC::MOF_SubtargetP9,
+ PPC::MOF_NotAddNorCst | PPC::MOF_Vector | PPC::MOF_SubtargetP9,
+ PPC::MOF_AddrIsSImm32 | PPC::MOF_Vector | PPC::MOF_SubtargetP9,
+ PPC::MOF_RPlusSImm16Mult16 | PPC::MOF_Vector256 | PPC::MOF_SubtargetP10,
+ PPC::MOF_NotAddNorCst | PPC::MOF_Vector256 | PPC::MOF_SubtargetP10,
+ PPC::MOF_AddrIsSImm32 | PPC::MOF_Vector256 | PPC::MOF_SubtargetP10,
+ };
+}
+
/// getMaxByValAlign - Helper for getByValTypeAlignment to determine
/// the desired ByVal argument alignment.
static void getMaxByValAlign(Type *Ty, Align &MaxAlign, Align MaxMaxAlign) {
@@ -1567,6 +1674,7 @@ const char *PPCTargetLowering::getTargetNodeName(unsigned Opcode) const {
case PPCISD::ADDI_TLSGD_L: return "PPCISD::ADDI_TLSGD_L";
case PPCISD::GET_TLS_ADDR: return "PPCISD::GET_TLS_ADDR";
case PPCISD::ADDI_TLSGD_L_ADDR: return "PPCISD::ADDI_TLSGD_L_ADDR";
+ case PPCISD::TLSGD_AIX: return "PPCISD::TLSGD_AIX";
case PPCISD::ADDIS_TLSLD_HA: return "PPCISD::ADDIS_TLSLD_HA";
case PPCISD::ADDI_TLSLD_L: return "PPCISD::ADDI_TLSLD_L";
case PPCISD::GET_TLSLD_ADDR: return "PPCISD::GET_TLSLD_ADDR";
@@ -2423,6 +2531,20 @@ bool llvm::isIntS16Immediate(SDValue Op, int16_t &Imm) {
return isIntS16Immediate(Op.getNode(), Imm);
}
+/// Used when computing address flags for selecting loads and stores.
+/// If we have an OR, check if the LHS and RHS are provably disjoint.
+/// An OR of two provably disjoint values is equivalent to an ADD.
+/// Most PPC load/store instructions compute the effective address as a sum,
+/// so doing this conversion is useful.
+static bool provablyDisjointOr(SelectionDAG &DAG, const SDValue &N) {
+ if (N.getOpcode() != ISD::OR)
+ return false;
+ KnownBits LHSKnown = DAG.computeKnownBits(N.getOperand(0));
+ if (!LHSKnown.Zero.getBoolValue())
+ return false;
+ KnownBits RHSKnown = DAG.computeKnownBits(N.getOperand(1));
+ return (~(LHSKnown.Zero | RHSKnown.Zero) == 0);
+}
/// SelectAddressEVXRegReg - Given the specified address, check to see if it can
/// be represented as an indexed [r+r] operation.
@@ -3112,6 +3234,41 @@ SDValue PPCTargetLowering::LowerBlockAddress(SDValue Op,
SDValue PPCTargetLowering::LowerGlobalTLSAddress(SDValue Op,
SelectionDAG &DAG) const {
+ if (Subtarget.isAIXABI())
+ return LowerGlobalTLSAddressAIX(Op, DAG);
+
+ return LowerGlobalTLSAddressLinux(Op, DAG);
+}
+
+SDValue PPCTargetLowering::LowerGlobalTLSAddressAIX(SDValue Op,
+ SelectionDAG &DAG) const {
+ GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op);
+
+ if (DAG.getTarget().useEmulatedTLS())
+ report_fatal_error("Emulated TLS is not yet supported on AIX");
+
+ SDLoc dl(GA);
+ const GlobalValue *GV = GA->getGlobal();
+ EVT PtrVT = getPointerTy(DAG.getDataLayout());
+
+ // The general-dynamic model is the only access model supported for now, so
+ // all the GlobalTLSAddress nodes are lowered with this model.
+ // We need to generate two TOC entries, one for the variable offset, one for
+ // the region handle. The global address for the TOC entry of the region
+ // handle is created with the MO_TLSGDM_FLAG flag and the global address
+ // for the TOC entry of the variable offset is created with MO_TLSGD_FLAG.
+ SDValue VariableOffsetTGA =
+ DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, PPCII::MO_TLSGD_FLAG);
+ SDValue RegionHandleTGA =
+ DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, PPCII::MO_TLSGDM_FLAG);
+ SDValue VariableOffset = getTOCEntry(DAG, dl, VariableOffsetTGA);
+ SDValue RegionHandle = getTOCEntry(DAG, dl, RegionHandleTGA);
+ return DAG.getNode(PPCISD::TLSGD_AIX, dl, PtrVT, VariableOffset,
+ RegionHandle);
+}
+
+SDValue PPCTargetLowering::LowerGlobalTLSAddressLinux(SDValue Op,
+ SelectionDAG &DAG) const {
// FIXME: TLS addresses currently use medium model code sequences,
// which is the most useful form. Eventually support for small and
// large models could be added if users need it, at the cost of
@@ -3290,21 +3447,43 @@ SDValue PPCTargetLowering::LowerGlobalAddress(SDValue Op,
}
SDValue PPCTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
- ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(2))->get();
+ bool IsStrict = Op->isStrictFPOpcode();
+ ISD::CondCode CC =
+ cast<CondCodeSDNode>(Op.getOperand(IsStrict ? 3 : 2))->get();
+ SDValue LHS = Op.getOperand(IsStrict ? 1 : 0);
+ SDValue RHS = Op.getOperand(IsStrict ? 2 : 1);
+ SDValue Chain = IsStrict ? Op.getOperand(0) : SDValue();
+ EVT LHSVT = LHS.getValueType();
SDLoc dl(Op);
+ // Soften the setcc with libcall if it is fp128.
+ if (LHSVT == MVT::f128) {
+ assert(!Subtarget.hasP9Vector() &&
+ "SETCC for f128 is already legal under Power9!");
+ softenSetCCOperands(DAG, LHSVT, LHS, RHS, CC, dl, LHS, RHS, Chain,
+ Op->getOpcode() == ISD::STRICT_FSETCCS);
+ if (RHS.getNode())
+ LHS = DAG.getNode(ISD::SETCC, dl, Op.getValueType(), LHS, RHS,
+ DAG.getCondCode(CC));
+ if (IsStrict)
+ return DAG.getMergeValues({LHS, Chain}, dl);
+ return LHS;
+ }
+
+ assert(!IsStrict && "Don't know how to handle STRICT_FSETCC!");
+
if (Op.getValueType() == MVT::v2i64) {
// When the operands themselves are v2i64 values, we need to do something
// special because VSX has no underlying comparison operations for these.
- if (Op.getOperand(0).getValueType() == MVT::v2i64) {
+ if (LHS.getValueType() == MVT::v2i64) {
// Equality can be handled by casting to the legal type for Altivec
// comparisons, everything else needs to be expanded.
if (CC == ISD::SETEQ || CC == ISD::SETNE) {
- return DAG.getNode(ISD::BITCAST, dl, MVT::v2i64,
- DAG.getSetCC(dl, MVT::v4i32,
- DAG.getNode(ISD::BITCAST, dl, MVT::v4i32, Op.getOperand(0)),
- DAG.getNode(ISD::BITCAST, dl, MVT::v4i32, Op.getOperand(1)),
- CC));
+ return DAG.getNode(
+ ISD::BITCAST, dl, MVT::v2i64,
+ DAG.getSetCC(dl, MVT::v4i32,
+ DAG.getNode(ISD::BITCAST, dl, MVT::v4i32, LHS),
+ DAG.getNode(ISD::BITCAST, dl, MVT::v4i32, RHS), CC));
}
return SDValue();
@@ -3320,7 +3499,7 @@ SDValue PPCTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
if (SDValue V = lowerCmpEqZeroToCtlzSrl(Op, DAG))
return V;
- if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op.getOperand(1))) {
+ if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS)) {
// Leave comparisons against 0 and -1 alone for now, since they're usually
// optimized. FIXME: revisit this when we can custom lower all setcc
// optimizations.
@@ -3333,11 +3512,9 @@ SDValue PPCTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
// condition register, reading it back out, and masking the correct bit. The
// normal approach here uses sub to do this instead of xor. Using xor exposes
// the result to other bit-twiddling opportunities.
- EVT LHSVT = Op.getOperand(0).getValueType();
if (LHSVT.isInteger() && (CC == ISD::SETEQ || CC == ISD::SETNE)) {
EVT VT = Op.getValueType();
- SDValue Sub = DAG.getNode(ISD::XOR, dl, LHSVT, Op.getOperand(0),
- Op.getOperand(1));
+ SDValue Sub = DAG.getNode(ISD::XOR, dl, LHSVT, LHS, RHS);
return DAG.getSetCC(dl, VT, Sub, DAG.getConstant(0, dl, LHSVT), CC);
}
return SDValue();
@@ -3461,6 +3638,57 @@ SDValue PPCTargetLowering::LowerADJUST_TRAMPOLINE(SDValue Op,
return Op.getOperand(0);
}
+SDValue PPCTargetLowering::LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const {
+ MachineFunction &MF = DAG.getMachineFunction();
+ PPCFunctionInfo &MFI = *MF.getInfo<PPCFunctionInfo>();
+
+ assert((Op.getOpcode() == ISD::INLINEASM ||
+ Op.getOpcode() == ISD::INLINEASM_BR) &&
+ "Expecting Inline ASM node.");
+
+ // If an LR store is already known to be required then there is not point in
+ // checking this ASM as well.
+ if (MFI.isLRStoreRequired())
+ return Op;
+
+ // Inline ASM nodes have an optional last operand that is an incoming Flag of
+ // type MVT::Glue. We want to ignore this last operand if that is the case.
+ unsigned NumOps = Op.getNumOperands();
+ if (Op.getOperand(NumOps - 1).getValueType() == MVT::Glue)
+ --NumOps;
+
+ // Check all operands that may contain the LR.
+ for (unsigned i = InlineAsm::Op_FirstOperand; i != NumOps;) {
+ unsigned Flags = cast<ConstantSDNode>(Op.getOperand(i))->getZExtValue();
+ unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags);
+ ++i; // Skip the ID value.
+
+ switch (InlineAsm::getKind(Flags)) {
+ default:
+ llvm_unreachable("Bad flags!");
+ case InlineAsm::Kind_RegUse:
+ case InlineAsm::Kind_Imm:
+ case InlineAsm::Kind_Mem:
+ i += NumVals;
+ break;
+ case InlineAsm::Kind_Clobber:
+ case InlineAsm::Kind_RegDef:
+ case InlineAsm::Kind_RegDefEarlyClobber: {
+ for (; NumVals; --NumVals, ++i) {
+ Register Reg = cast<RegisterSDNode>(Op.getOperand(i))->getReg();
+ if (Reg != PPC::LR && Reg != PPC::LR8)
+ continue;
+ MFI.setLRStoreRequired();
+ return Op;
+ }
+ break;
+ }
+ }
+ }
+
+ return Op;
+}
+
SDValue PPCTargetLowering::LowerINIT_TRAMPOLINE(SDValue Op,
SelectionDAG &DAG) const {
if (Subtarget.isAIXABI())
@@ -4924,7 +5152,7 @@ static bool isIndirectCall(const SDValue &Callee, SelectionDAG &DAG,
if (isPatchPoint)
return false;
- if (isFunctionGlobalAddress(Callee) || dyn_cast<ExternalSymbolSDNode>(Callee))
+ if (isFunctionGlobalAddress(Callee) || isa<ExternalSymbolSDNode>(Callee))
return false;
// Darwin, and 32-bit ELF can use a BLA. The descriptor based ABIs can not
@@ -5049,8 +5277,8 @@ static SDValue transformCallee(const SDValue &Callee, SelectionDAG &DAG,
const auto getExternalFunctionEntryPointSymbol = [&](StringRef SymName) {
auto &Context = DAG.getMachineFunction().getMMI().getContext();
MCSectionXCOFF *Sec = Context.getXCOFFSection(
- (Twine(".") + Twine(SymName)).str(), XCOFF::XMC_PR, XCOFF::XTY_ER,
- SectionKind::getMetadata());
+ (Twine(".") + Twine(SymName)).str(), SectionKind::getMetadata(),
+ XCOFF::CsectProperties(XCOFF::XMC_PR, XCOFF::XTY_ER));
return Sec->getQualNameSymbol();
};
@@ -6257,21 +6485,49 @@ SDValue PPCTargetLowering::LowerCall_64SVR4(
Callee, SPDiff, NumBytes, Ins, InVals, CB);
}
+// Returns true when the shadow of a general purpose argument register
+// in the parameter save area is aligned to at least 'RequiredAlign'.
+static bool isGPRShadowAligned(MCPhysReg Reg, Align RequiredAlign) {
+ assert(RequiredAlign.value() <= 16 &&
+ "Required alignment greater than stack alignment.");
+ switch (Reg) {
+ default:
+ report_fatal_error("called on invalid register.");
+ case PPC::R5:
+ case PPC::R9:
+ case PPC::X3:
+ case PPC::X5:
+ case PPC::X7:
+ case PPC::X9:
+ // These registers are 16 byte aligned which is the most strict aligment
+ // we can support.
+ return true;
+ case PPC::R3:
+ case PPC::R7:
+ case PPC::X4:
+ case PPC::X6:
+ case PPC::X8:
+ case PPC::X10:
+ // The shadow of these registers in the PSA is 8 byte aligned.
+ return RequiredAlign <= 8;
+ case PPC::R4:
+ case PPC::R6:
+ case PPC::R8:
+ case PPC::R10:
+ return RequiredAlign <= 4;
+ }
+}
+
static bool CC_AIX(unsigned ValNo, MVT ValVT, MVT LocVT,
CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
- CCState &State) {
-
+ CCState &S) {
+ AIXCCState &State = static_cast<AIXCCState &>(S);
const PPCSubtarget &Subtarget = static_cast<const PPCSubtarget &>(
State.getMachineFunction().getSubtarget());
const bool IsPPC64 = Subtarget.isPPC64();
const Align PtrAlign = IsPPC64 ? Align(8) : Align(4);
const MVT RegVT = IsPPC64 ? MVT::i64 : MVT::i32;
- if (ValVT.isVector() && !State.getMachineFunction()
- .getTarget()
- .Options.EnableAIXExtendedAltivecABI)
- report_fatal_error("the default Altivec AIX ABI is not yet supported");
-
if (ValVT == MVT::f128)
report_fatal_error("f128 is unimplemented on AIX.");
@@ -6392,15 +6648,96 @@ static bool CC_AIX(unsigned ValNo, MVT ValVT, MVT LocVT,
case MVT::v2i64:
case MVT::v2f64:
case MVT::v1i128: {
- if (State.isVarArg())
- report_fatal_error(
- "variadic arguments for vector types are unimplemented for AIX");
+ const unsigned VecSize = 16;
+ const Align VecAlign(VecSize);
- if (unsigned VReg = State.AllocateReg(VR))
- State.addLoc(CCValAssign::getReg(ValNo, ValVT, VReg, LocVT, LocInfo));
- else {
- report_fatal_error(
- "passing vector parameters to the stack is unimplemented for AIX");
+ if (!State.isVarArg()) {
+ // If there are vector registers remaining we don't consume any stack
+ // space.
+ if (unsigned VReg = State.AllocateReg(VR)) {
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, VReg, LocVT, LocInfo));
+ return false;
+ }
+ // Vectors passed on the stack do not shadow GPRs or FPRs even though they
+ // might be allocated in the portion of the PSA that is shadowed by the
+ // GPRs.
+ const unsigned Offset = State.AllocateStack(VecSize, VecAlign);
+ State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
+ return false;
+ }
+
+ const unsigned PtrSize = IsPPC64 ? 8 : 4;
+ ArrayRef<MCPhysReg> GPRs = IsPPC64 ? GPR_64 : GPR_32;
+
+ unsigned NextRegIndex = State.getFirstUnallocated(GPRs);
+ // Burn any underaligned registers and their shadowed stack space until
+ // we reach the required alignment.
+ while (NextRegIndex != GPRs.size() &&
+ !isGPRShadowAligned(GPRs[NextRegIndex], VecAlign)) {
+ // Shadow allocate register and its stack shadow.
+ unsigned Reg = State.AllocateReg(GPRs);
+ State.AllocateStack(PtrSize, PtrAlign);
+ assert(Reg && "Allocating register unexpectedly failed.");
+ (void)Reg;
+ NextRegIndex = State.getFirstUnallocated(GPRs);
+ }
+
+ // Vectors that are passed as fixed arguments are handled differently.
+ // They are passed in VRs if any are available (unlike arguments passed
+ // through ellipses) and shadow GPRs (unlike arguments to non-vaarg
+ // functions)
+ if (State.isFixed(ValNo)) {
+ if (unsigned VReg = State.AllocateReg(VR)) {
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, VReg, LocVT, LocInfo));
+ // Shadow allocate GPRs and stack space even though we pass in a VR.
+ for (unsigned I = 0; I != VecSize; I += PtrSize)
+ State.AllocateReg(GPRs);
+ State.AllocateStack(VecSize, VecAlign);
+ return false;
+ }
+ // No vector registers remain so pass on the stack.
+ const unsigned Offset = State.AllocateStack(VecSize, VecAlign);
+ State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
+ return false;
+ }
+
+ // If all GPRS are consumed then we pass the argument fully on the stack.
+ if (NextRegIndex == GPRs.size()) {
+ const unsigned Offset = State.AllocateStack(VecSize, VecAlign);
+ State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
+ return false;
+ }
+
+ // Corner case for 32-bit codegen. We have 2 registers to pass the first
+ // half of the argument, and then need to pass the remaining half on the
+ // stack.
+ if (GPRs[NextRegIndex] == PPC::R9) {
+ const unsigned Offset = State.AllocateStack(VecSize, VecAlign);
+ State.addLoc(
+ CCValAssign::getCustomMem(ValNo, ValVT, Offset, LocVT, LocInfo));
+
+ const unsigned FirstReg = State.AllocateReg(PPC::R9);
+ const unsigned SecondReg = State.AllocateReg(PPC::R10);
+ assert(FirstReg && SecondReg &&
+ "Allocating R9 or R10 unexpectedly failed.");
+ State.addLoc(
+ CCValAssign::getCustomReg(ValNo, ValVT, FirstReg, RegVT, LocInfo));
+ State.addLoc(
+ CCValAssign::getCustomReg(ValNo, ValVT, SecondReg, RegVT, LocInfo));
+ return false;
+ }
+
+ // We have enough GPRs to fully pass the vector argument, and we have
+ // already consumed any underaligned registers. Start with the custom
+ // MemLoc and then the custom RegLocs.
+ const unsigned Offset = State.AllocateStack(VecSize, VecAlign);
+ State.addLoc(
+ CCValAssign::getCustomMem(ValNo, ValVT, Offset, LocVT, LocInfo));
+ for (unsigned I = 0; I != VecSize; I += PtrSize) {
+ const unsigned Reg = State.AllocateReg(GPRs);
+ assert(Reg && "Failed to allocated register for vararg vector argument");
+ State.addLoc(
+ CCValAssign::getCustomReg(ValNo, ValVT, Reg, RegVT, LocInfo));
}
return false;
}
@@ -6408,8 +6745,11 @@ static bool CC_AIX(unsigned ValNo, MVT ValVT, MVT LocVT,
return true;
}
+// So far, this function is only used by LowerFormalArguments_AIX()
static const TargetRegisterClass *getRegClassForSVT(MVT::SimpleValueType SVT,
- bool IsPPC64) {
+ bool IsPPC64,
+ bool HasP8Vector,
+ bool HasVSX) {
assert((IsPPC64 || SVT != MVT::i64) &&
"i64 should have been split for 32-bit codegen.");
@@ -6421,9 +6761,9 @@ static const TargetRegisterClass *getRegClassForSVT(MVT::SimpleValueType SVT,
case MVT::i64:
return IsPPC64 ? &PPC::G8RCRegClass : &PPC::GPRCRegClass;
case MVT::f32:
- return &PPC::F4RCRegClass;
+ return HasP8Vector ? &PPC::VSSRCRegClass : &PPC::F4RCRegClass;
case MVT::f64:
- return &PPC::F8RCRegClass;
+ return HasVSX ? &PPC::VSFRCRegClass : &PPC::F8RCRegClass;
case MVT::v4f32:
case MVT::v4i32:
case MVT::v8i16:
@@ -6535,7 +6875,7 @@ SDValue PPCTargetLowering::LowerFormalArguments_AIX(
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo &MFI = MF.getFrameInfo();
PPCFunctionInfo *FuncInfo = MF.getInfo<PPCFunctionInfo>();
- CCState CCInfo(CallConv, isVarArg, MF, ArgLocs, *DAG.getContext());
+ AIXCCState CCInfo(CallConv, isVarArg, MF, ArgLocs, *DAG.getContext());
const EVT PtrVT = getPointerTy(MF.getDataLayout());
// Reserve space for the linkage area on the stack.
@@ -6548,27 +6888,116 @@ SDValue PPCTargetLowering::LowerFormalArguments_AIX(
for (size_t I = 0, End = ArgLocs.size(); I != End; /* No increment here */) {
CCValAssign &VA = ArgLocs[I++];
MVT LocVT = VA.getLocVT();
+ MVT ValVT = VA.getValVT();
ISD::ArgFlagsTy Flags = Ins[VA.getValNo()].Flags;
- if (VA.isMemLoc() && VA.getValVT().isVector())
- report_fatal_error(
- "passing vector parameters to the stack is unimplemented for AIX");
-
// For compatibility with the AIX XL compiler, the float args in the
// parameter save area are initialized even if the argument is available
// in register. The caller is required to initialize both the register
// and memory, however, the callee can choose to expect it in either.
// The memloc is dismissed here because the argument is retrieved from
// the register.
- if (VA.isMemLoc() && VA.needsCustom())
+ if (VA.isMemLoc() && VA.needsCustom() && ValVT.isFloatingPoint())
+ continue;
+
+ auto HandleMemLoc = [&]() {
+ const unsigned LocSize = LocVT.getStoreSize();
+ const unsigned ValSize = ValVT.getStoreSize();
+ assert((ValSize <= LocSize) &&
+ "Object size is larger than size of MemLoc");
+ int CurArgOffset = VA.getLocMemOffset();
+ // Objects are right-justified because AIX is big-endian.
+ if (LocSize > ValSize)
+ CurArgOffset += LocSize - ValSize;
+ // Potential tail calls could cause overwriting of argument stack slots.
+ const bool IsImmutable =
+ !(getTargetMachine().Options.GuaranteedTailCallOpt &&
+ (CallConv == CallingConv::Fast));
+ int FI = MFI.CreateFixedObject(ValSize, CurArgOffset, IsImmutable);
+ SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
+ SDValue ArgValue =
+ DAG.getLoad(ValVT, dl, Chain, FIN, MachinePointerInfo());
+ InVals.push_back(ArgValue);
+ };
+
+ // Vector arguments to VaArg functions are passed both on the stack, and
+ // in any available GPRs. Load the value from the stack and add the GPRs
+ // as live ins.
+ if (VA.isMemLoc() && VA.needsCustom()) {
+ assert(ValVT.isVector() && "Unexpected Custom MemLoc type.");
+ assert(isVarArg && "Only use custom memloc for vararg.");
+ // ValNo of the custom MemLoc, so we can compare it to the ValNo of the
+ // matching custom RegLocs.
+ const unsigned OriginalValNo = VA.getValNo();
+ (void)OriginalValNo;
+
+ auto HandleCustomVecRegLoc = [&]() {
+ assert(I != End && ArgLocs[I].isRegLoc() && ArgLocs[I].needsCustom() &&
+ "Missing custom RegLoc.");
+ VA = ArgLocs[I++];
+ assert(VA.getValVT().isVector() &&
+ "Unexpected Val type for custom RegLoc.");
+ assert(VA.getValNo() == OriginalValNo &&
+ "ValNo mismatch between custom MemLoc and RegLoc.");
+ MVT::SimpleValueType SVT = VA.getLocVT().SimpleTy;
+ MF.addLiveIn(VA.getLocReg(),
+ getRegClassForSVT(SVT, IsPPC64, Subtarget.hasP8Vector(),
+ Subtarget.hasVSX()));
+ };
+
+ HandleMemLoc();
+ // In 64-bit there will be exactly 2 custom RegLocs that follow, and in
+ // in 32-bit there will be 2 custom RegLocs if we are passing in R9 and
+ // R10.
+ HandleCustomVecRegLoc();
+ HandleCustomVecRegLoc();
+
+ // If we are targeting 32-bit, there might be 2 extra custom RegLocs if
+ // we passed the vector in R5, R6, R7 and R8.
+ if (I != End && ArgLocs[I].isRegLoc() && ArgLocs[I].needsCustom()) {
+ assert(!IsPPC64 &&
+ "Only 2 custom RegLocs expected for 64-bit codegen.");
+ HandleCustomVecRegLoc();
+ HandleCustomVecRegLoc();
+ }
+
continue;
+ }
if (VA.isRegLoc()) {
if (VA.getValVT().isScalarInteger())
FuncInfo->appendParameterType(PPCFunctionInfo::FixedType);
- else if (VA.getValVT().isFloatingPoint() && !VA.getValVT().isVector())
- FuncInfo->appendParameterType(VA.getValVT().SimpleTy == MVT::f32
- ? PPCFunctionInfo::ShortFloatPoint
- : PPCFunctionInfo::LongFloatPoint);
+ else if (VA.getValVT().isFloatingPoint() && !VA.getValVT().isVector()) {
+ switch (VA.getValVT().SimpleTy) {
+ default:
+ report_fatal_error("Unhandled value type for argument.");
+ case MVT::f32:
+ FuncInfo->appendParameterType(PPCFunctionInfo::ShortFloatingPoint);
+ break;
+ case MVT::f64:
+ FuncInfo->appendParameterType(PPCFunctionInfo::LongFloatingPoint);
+ break;
+ }
+ } else if (VA.getValVT().isVector()) {
+ switch (VA.getValVT().SimpleTy) {
+ default:
+ report_fatal_error("Unhandled value type for argument.");
+ case MVT::v16i8:
+ FuncInfo->appendParameterType(PPCFunctionInfo::VectorChar);
+ break;
+ case MVT::v8i16:
+ FuncInfo->appendParameterType(PPCFunctionInfo::VectorShort);
+ break;
+ case MVT::v4i32:
+ case MVT::v2i64:
+ case MVT::v1i128:
+ FuncInfo->appendParameterType(PPCFunctionInfo::VectorInt);
+ break;
+ case MVT::v4f32:
+ case MVT::v2f64:
+ FuncInfo->appendParameterType(PPCFunctionInfo::VectorFloat);
+ break;
+ }
+ }
}
if (Flags.isByVal() && VA.isMemLoc()) {
@@ -6649,11 +7078,12 @@ SDValue PPCTargetLowering::LowerFormalArguments_AIX(
continue;
}
- EVT ValVT = VA.getValVT();
if (VA.isRegLoc() && !VA.needsCustom()) {
- MVT::SimpleValueType SVT = ValVT.getSimpleVT().SimpleTy;
- unsigned VReg =
- MF.addLiveIn(VA.getLocReg(), getRegClassForSVT(SVT, IsPPC64));
+ MVT::SimpleValueType SVT = ValVT.SimpleTy;
+ Register VReg =
+ MF.addLiveIn(VA.getLocReg(),
+ getRegClassForSVT(SVT, IsPPC64, Subtarget.hasP8Vector(),
+ Subtarget.hasVSX()));
SDValue ArgValue = DAG.getCopyFromReg(Chain, dl, VReg, LocVT);
if (ValVT.isScalarInteger() &&
(ValVT.getFixedSizeInBits() < LocVT.getFixedSizeInBits())) {
@@ -6664,23 +7094,7 @@ SDValue PPCTargetLowering::LowerFormalArguments_AIX(
continue;
}
if (VA.isMemLoc()) {
- const unsigned LocSize = LocVT.getStoreSize();
- const unsigned ValSize = ValVT.getStoreSize();
- assert((ValSize <= LocSize) &&
- "Object size is larger than size of MemLoc");
- int CurArgOffset = VA.getLocMemOffset();
- // Objects are right-justified because AIX is big-endian.
- if (LocSize > ValSize)
- CurArgOffset += LocSize - ValSize;
- // Potential tail calls could cause overwriting of argument stack slots.
- const bool IsImmutable =
- !(getTargetMachine().Options.GuaranteedTailCallOpt &&
- (CallConv == CallingConv::Fast));
- int FI = MFI.CreateFixedObject(ValSize, CurArgOffset, IsImmutable);
- SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
- SDValue ArgValue =
- DAG.getLoad(ValVT, dl, Chain, FIN, MachinePointerInfo());
- InVals.push_back(ArgValue);
+ HandleMemLoc();
continue;
}
}
@@ -6761,8 +7175,8 @@ SDValue PPCTargetLowering::LowerCall_AIX(
MachineFunction &MF = DAG.getMachineFunction();
SmallVector<CCValAssign, 16> ArgLocs;
- CCState CCInfo(CFlags.CallConv, CFlags.IsVarArg, MF, ArgLocs,
- *DAG.getContext());
+ AIXCCState CCInfo(CFlags.CallConv, CFlags.IsVarArg, MF, ArgLocs,
+ *DAG.getContext());
// Reserve space for the linkage save area (LSA) on the stack.
// In both PPC32 and PPC64 there are 6 reserved slots in the LSA:
@@ -6903,10 +7317,6 @@ SDValue PPCTargetLowering::LowerCall_AIX(
const MVT LocVT = VA.getLocVT();
const MVT ValVT = VA.getValVT();
- if (VA.isMemLoc() && VA.getValVT().isVector())
- report_fatal_error(
- "passing vector parameters to the stack is unimplemented for AIX");
-
switch (VA.getLocInfo()) {
default:
report_fatal_error("Unexpected argument extension type.");
@@ -6925,6 +7335,52 @@ SDValue PPCTargetLowering::LowerCall_AIX(
continue;
}
+ // Vector arguments passed to VarArg functions need custom handling when
+ // they are passed (at least partially) in GPRs.
+ if (VA.isMemLoc() && VA.needsCustom() && ValVT.isVector()) {
+ assert(CFlags.IsVarArg && "Custom MemLocs only used for Vector args.");
+ // Store value to its stack slot.
+ SDValue PtrOff =
+ DAG.getConstant(VA.getLocMemOffset(), dl, StackPtr.getValueType());
+ PtrOff = DAG.getNode(ISD::ADD, dl, PtrVT, StackPtr, PtrOff);
+ SDValue Store =
+ DAG.getStore(Chain, dl, Arg, PtrOff, MachinePointerInfo());
+ MemOpChains.push_back(Store);
+ const unsigned OriginalValNo = VA.getValNo();
+ // Then load the GPRs from the stack
+ unsigned LoadOffset = 0;
+ auto HandleCustomVecRegLoc = [&]() {
+ assert(I != E && "Unexpected end of CCvalAssigns.");
+ assert(ArgLocs[I].isRegLoc() && ArgLocs[I].needsCustom() &&
+ "Expected custom RegLoc.");
+ CCValAssign RegVA = ArgLocs[I++];
+ assert(RegVA.getValNo() == OriginalValNo &&
+ "Custom MemLoc ValNo and custom RegLoc ValNo must match.");
+ SDValue Add = DAG.getNode(ISD::ADD, dl, PtrVT, PtrOff,
+ DAG.getConstant(LoadOffset, dl, PtrVT));
+ SDValue Load = DAG.getLoad(PtrVT, dl, Store, Add, MachinePointerInfo());
+ MemOpChains.push_back(Load.getValue(1));
+ RegsToPass.push_back(std::make_pair(RegVA.getLocReg(), Load));
+ LoadOffset += PtrByteSize;
+ };
+
+ // In 64-bit there will be exactly 2 custom RegLocs that follow, and in
+ // in 32-bit there will be 2 custom RegLocs if we are passing in R9 and
+ // R10.
+ HandleCustomVecRegLoc();
+ HandleCustomVecRegLoc();
+
+ if (I != E && ArgLocs[I].isRegLoc() && ArgLocs[I].needsCustom() &&
+ ArgLocs[I].getValNo() == OriginalValNo) {
+ assert(!IsPPC64 &&
+ "Only 2 custom RegLocs expected for 64-bit codegen.");
+ HandleCustomVecRegLoc();
+ HandleCustomVecRegLoc();
+ }
+
+ continue;
+ }
+
if (VA.isMemLoc()) {
SDValue PtrOff =
DAG.getConstant(VA.getLocMemOffset(), dl, StackPtr.getValueType());
@@ -6935,11 +7391,15 @@ SDValue PPCTargetLowering::LowerCall_AIX(
continue;
}
+ if (!ValVT.isFloatingPoint())
+ report_fatal_error(
+ "Unexpected register handling for calling convention.");
+
// Custom handling is used for GPR initializations for vararg float
// arguments.
assert(VA.isRegLoc() && VA.needsCustom() && CFlags.IsVarArg &&
- ValVT.isFloatingPoint() && LocVT.isInteger() &&
- "Unexpected register handling for calling convention.");
+ LocVT.isInteger() &&
+ "Custom register handling only expected for VarArg.");
SDValue ArgAsInt =
DAG.getBitcast(MVT::getIntegerVT(ValVT.getSizeInBits()), Arg);
@@ -7370,18 +7830,29 @@ SDValue PPCTargetLowering::LowerTRUNCATEVector(SDValue Op,
/// LowerSELECT_CC - Lower floating point select_cc's into fsel instruction when
/// possible.
SDValue PPCTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const {
- // Not FP, or using SPE? Not a fsel.
- if (!Op.getOperand(0).getValueType().isFloatingPoint() ||
- !Op.getOperand(2).getValueType().isFloatingPoint() || Subtarget.hasSPE())
- return Op;
-
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
-
EVT ResVT = Op.getValueType();
EVT CmpVT = Op.getOperand(0).getValueType();
SDValue LHS = Op.getOperand(0), RHS = Op.getOperand(1);
SDValue TV = Op.getOperand(2), FV = Op.getOperand(3);
SDLoc dl(Op);
+
+ // Without power9-vector, we don't have native instruction for f128 comparison.
+ // Following transformation to libcall is needed for setcc:
+ // select_cc lhs, rhs, tv, fv, cc -> select_cc (setcc cc, x, y), 0, tv, fv, NE
+ if (!Subtarget.hasP9Vector() && CmpVT == MVT::f128) {
+ SDValue Z = DAG.getSetCC(
+ dl, getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), CmpVT),
+ LHS, RHS, CC);
+ SDValue Zero = DAG.getConstant(0, dl, Z.getValueType());
+ return DAG.getSelectCC(dl, Z, Zero, TV, FV, ISD::SETNE);
+ }
+
+ // Not FP, or using SPE? Not a fsel.
+ if (!CmpVT.isFloatingPoint() || !TV.getValueType().isFloatingPoint() ||
+ Subtarget.hasSPE())
+ return Op;
+
SDNodeFlags Flags = Op.getNode()->getFlags();
// We have xsmaxcdp/xsmincdp which are OK to emit even in the
@@ -8583,6 +9054,18 @@ bool llvm::convertToNonDenormSingle(APInt &ArgAPInt) {
return Success;
}
+// Nondestructive check for convertTonNonDenormSingle.
+bool llvm::checkConvertToNonDenormSingle(APFloat &ArgAPFloat) {
+ // Only convert if it loses info, since XXSPLTIDP should
+ // handle the other case.
+ APFloat APFloatToConvert = ArgAPFloat;
+ bool LosesInfo = true;
+ APFloatToConvert.convert(APFloat::IEEEsingle(), APFloat::rmNearestTiesToEven,
+ &LosesInfo);
+
+ return (!LosesInfo && !APFloatToConvert.isDenormal());
+}
+
// If this is a case we can't handle, return null and let the default
// expansion code take care of it. If we CAN select this case, and if it
// selects to a single instruction, return Op. Otherwise, if we can codegen
@@ -8604,16 +9087,20 @@ SDValue PPCTargetLowering::LowerBUILD_VECTOR(SDValue Op,
// If it is a splat of a double, check if we can shrink it to a 32 bit
// non-denormal float which when converted back to double gives us the same
- // double. This is to exploit the XXSPLTIDP instruction.+ // If we lose precision, we use XXSPLTI32DX.
+ // double. This is to exploit the XXSPLTIDP instruction.
+ // If we lose precision, we use XXSPLTI32DX.
if (BVNIsConstantSplat && (SplatBitSize == 64) &&
Subtarget.hasPrefixInstrs()) {
- if (convertToNonDenormSingle(APSplatBits) &&
- (Op->getValueType(0) == MVT::v2f64)) {
+ // Check the type first to short-circuit so we don't modify APSplatBits if
+ // this block isn't executed.
+ if ((Op->getValueType(0) == MVT::v2f64) &&
+ convertToNonDenormSingle(APSplatBits)) {
SDValue SplatNode = DAG.getNode(
PPCISD::XXSPLTI_SP_TO_DP, dl, MVT::v2f64,
DAG.getTargetConstant(APSplatBits.getZExtValue(), dl, MVT::i32));
return DAG.getBitcast(Op.getValueType(), SplatNode);
- } else { // We may lose precision, so we have to use XXSPLTI32DX.
+ } else {
+ // We may lose precision, so we have to use XXSPLTI32DX.
uint32_t Hi =
(uint32_t)((APSplatBits.getZExtValue() & 0xFFFFFFFF00000000LL) >> 32);
@@ -9279,7 +9766,8 @@ SDValue PPCTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op,
// which is strictly wider than the loaded value by 8 bytes. So we need to
// adjust the splat index to point to the correct address in memory.
if (IsPermutedLoad) {
- assert(isLittleEndian && "Unexpected permuted load on big endian target");
+ assert((isLittleEndian || IsFourByte) &&
+ "Unexpected size for permuted load on big endian target");
SplatIdx += IsFourByte ? 2 : 1;
assert((SplatIdx < (IsFourByte ? 4 : 2)) &&
"Splat of a value outside of the loaded memory");
@@ -9294,6 +9782,11 @@ SDValue PPCTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op,
else
Offset = isLittleEndian ? (1 - SplatIdx) * 8 : SplatIdx * 8;
+ // If the width of the load is the same as the width of the splat,
+ // loading with an offset would load the wrong memory.
+ if (LD->getValueType(0).getSizeInBits() == (IsFourByte ? 32 : 64))
+ Offset = 0;
+
SDValue BasePtr = LD->getBasePtr();
if (Offset != 0)
BasePtr = DAG.getNode(ISD::ADD, dl, getPointerTy(DAG.getDataLayout()),
@@ -9587,7 +10080,7 @@ static bool getVectorCompareInfo(SDValue Intrin, int &CompareOpc,
isDot = true;
break;
case Intrinsic::ppc_altivec_vcmpequd_p:
- if (Subtarget.hasP8Altivec()) {
+ if (Subtarget.hasVSX() || Subtarget.hasP8Altivec()) {
CompareOpc = 199;
isDot = true;
} else
@@ -9647,7 +10140,7 @@ static bool getVectorCompareInfo(SDValue Intrin, int &CompareOpc,
isDot = true;
break;
case Intrinsic::ppc_altivec_vcmpgtsd_p:
- if (Subtarget.hasP8Altivec()) {
+ if (Subtarget.hasVSX() || Subtarget.hasP8Altivec()) {
CompareOpc = 967;
isDot = true;
} else
@@ -9666,7 +10159,7 @@ static bool getVectorCompareInfo(SDValue Intrin, int &CompareOpc,
isDot = true;
break;
case Intrinsic::ppc_altivec_vcmpgtud_p:
- if (Subtarget.hasP8Altivec()) {
+ if (Subtarget.hasVSX() || Subtarget.hasP8Altivec()) {
CompareOpc = 711;
isDot = true;
} else
@@ -9870,7 +10363,7 @@ SDValue PPCTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
PPCISD::EXTRACT_VSX_REG, dl, MVT::v16i8, WideVec,
DAG.getConstant(Subtarget.isLittleEndian() ? NumVecs - 1 - VecNo
: VecNo,
- dl, MVT::i64));
+ dl, getPointerTy(DAG.getDataLayout())));
RetOps.push_back(Extract);
}
return DAG.getMergeValues(RetOps, dl);
@@ -9965,6 +10458,8 @@ SDValue PPCTargetLowering::LowerINTRINSIC_VOID(SDValue Op,
// Lower scalar BSWAP64 to xxbrd.
SDValue PPCTargetLowering::LowerBSWAP(SDValue Op, SelectionDAG &DAG) const {
SDLoc dl(Op);
+ if (!Subtarget.isPPC64())
+ return Op;
// MTVSRDD
Op = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v2i64, Op.getOperand(0),
Op.getOperand(0));
@@ -10037,14 +10532,39 @@ SDValue PPCTargetLowering::LowerINSERT_VECTOR_ELT(SDValue Op,
"Should only be called for ISD::INSERT_VECTOR_ELT");
ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op.getOperand(2));
- // We have legal lowering for constant indices but not for variable ones.
- if (!C)
- return SDValue();
EVT VT = Op.getValueType();
SDLoc dl(Op);
SDValue V1 = Op.getOperand(0);
SDValue V2 = Op.getOperand(1);
+ SDValue V3 = Op.getOperand(2);
+
+ if (VT == MVT::v2f64 && C)
+ return Op;
+
+ if (Subtarget.isISA3_1()) {
+ if ((VT == MVT::v2i64 || VT == MVT::v2f64) && !Subtarget.isPPC64())
+ return SDValue();
+ // On P10, we have legal lowering for constant and variable indices for
+ // integer vectors.
+ if (VT == MVT::v16i8 || VT == MVT::v8i16 || VT == MVT::v4i32 ||
+ VT == MVT::v2i64)
+ return DAG.getNode(PPCISD::VECINSERT, dl, VT, V1, V2, V3);
+ // For f32 and f64 vectors, we have legal lowering for variable indices.
+ // For f32 we also have legal lowering when the element is loaded from
+ // memory.
+ if (VT == MVT::v4f32 || VT == MVT::v2f64) {
+ if (!C || (VT == MVT::v4f32 && dyn_cast<LoadSDNode>(V2)))
+ return DAG.getNode(PPCISD::VECINSERT, dl, VT, V1, V2, V3);
+ return Op;
+ }
+ }
+
+ // Before P10, we have legal lowering for constant indices but not for
+ // variable ones.
+ if (!C)
+ return SDValue();
+
// We can use MTVSRZ + VECINSERT for v8i16 and v16i8 types.
if (VT == MVT::v8i16 || VT == MVT::v16i8) {
SDValue Mtvsrz = DAG.getNode(PPCISD::MTVSRZ, dl, VT, V2);
@@ -10134,7 +10654,7 @@ SDValue PPCTargetLowering::LowerVectorStore(SDValue Op,
for (unsigned Idx = 0; Idx < NumVecs; ++Idx) {
unsigned VecNum = Subtarget.isLittleEndian() ? NumVecs - 1 - Idx : Idx;
SDValue Elt = DAG.getNode(PPCISD::EXTRACT_VSX_REG, dl, MVT::v16i8, Value,
- DAG.getConstant(VecNum, dl, MVT::i64));
+ DAG.getConstant(VecNum, dl, getPointerTy(DAG.getDataLayout())));
SDValue Store =
DAG.getStore(StoreChain, dl, Elt, BasePtr,
SN->getPointerInfo().getWithOffset(Idx * 16),
@@ -10308,10 +10828,14 @@ SDValue PPCTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG);
case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG);
case ISD::JumpTable: return LowerJumpTable(Op, DAG);
+ case ISD::STRICT_FSETCC:
+ case ISD::STRICT_FSETCCS:
case ISD::SETCC: return LowerSETCC(Op, DAG);
case ISD::INIT_TRAMPOLINE: return LowerINIT_TRAMPOLINE(Op, DAG);
case ISD::ADJUST_TRAMPOLINE: return LowerADJUST_TRAMPOLINE(Op, DAG);
+ case ISD::INLINEASM:
+ case ISD::INLINEASM_BR: return LowerINLINEASM(Op, DAG);
// Variable argument lowering.
case ISD::VASTART: return LowerVASTART(Op, DAG);
case ISD::VAARG: return LowerVAARG(Op, DAG);
@@ -10464,7 +10988,7 @@ void PPCTargetLowering::ReplaceNodeResults(SDNode *N,
// Other Lowering Code
//===----------------------------------------------------------------------===//
-static Instruction* callIntrinsic(IRBuilder<> &Builder, Intrinsic::ID Id) {
+static Instruction *callIntrinsic(IRBuilderBase &Builder, Intrinsic::ID Id) {
Module *M = Builder.GetInsertBlock()->getParent()->getParent();
Function *Func = Intrinsic::getDeclaration(M, Id);
return Builder.CreateCall(Func, {});
@@ -10472,7 +10996,7 @@ static Instruction* callIntrinsic(IRBuilder<> &Builder, Intrinsic::ID Id) {
// The mappings for emitLeading/TrailingFence is taken from
// http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
-Instruction *PPCTargetLowering::emitLeadingFence(IRBuilder<> &Builder,
+Instruction *PPCTargetLowering::emitLeadingFence(IRBuilderBase &Builder,
Instruction *Inst,
AtomicOrdering Ord) const {
if (Ord == AtomicOrdering::SequentiallyConsistent)
@@ -10482,7 +11006,7 @@ Instruction *PPCTargetLowering::emitLeadingFence(IRBuilder<> &Builder,
return nullptr;
}
-Instruction *PPCTargetLowering::emitTrailingFence(IRBuilder<> &Builder,
+Instruction *PPCTargetLowering::emitTrailingFence(IRBuilderBase &Builder,
Instruction *Inst,
AtomicOrdering Ord) const {
if (Inst->hasAtomicLoad() && isAcquireOrStronger(Ord)) {
@@ -10745,6 +11269,7 @@ MachineBasicBlock *PPCTargetLowering::EmitPartwordAtomicBinary(
Register Tmp3Reg = RegInfo.createVirtualRegister(GPRC);
Register Tmp4Reg = RegInfo.createVirtualRegister(GPRC);
Register TmpDestReg = RegInfo.createVirtualRegister(GPRC);
+ Register SrwDestReg = RegInfo.createVirtualRegister(GPRC);
Register Ptr1Reg;
Register TmpReg =
(!BinOpcode) ? Incr2Reg : RegInfo.createVirtualRegister(GPRC);
@@ -10772,7 +11297,8 @@ MachineBasicBlock *PPCTargetLowering::EmitPartwordAtomicBinary(
// stwcx. tmp4, ptr
// bne- loopMBB
// fallthrough --> exitMBB
- // srw dest, tmpDest, shift
+ // srw SrwDest, tmpDest, shift
+ // rlwinm SrwDest, SrwDest, 0, 24 [16], 31
if (ptrA != ZeroReg) {
Ptr1Reg = RegInfo.createVirtualRegister(RC);
BuildMI(BB, dl, TII->get(is64bit ? PPC::ADD8 : PPC::ADD4), Ptr1Reg)
@@ -10874,7 +11400,14 @@ MachineBasicBlock *PPCTargetLowering::EmitPartwordAtomicBinary(
// exitMBB:
// ...
BB = exitMBB;
- BuildMI(*BB, BB->begin(), dl, TII->get(PPC::SRW), dest)
+ // Since the shift amount is not a constant, we need to clear
+ // the upper bits with a separate RLWINM.
+ BuildMI(*BB, BB->begin(), dl, TII->get(PPC::RLWINM), dest)
+ .addReg(SrwDestReg)
+ .addImm(0)
+ .addImm(is8bit ? 24 : 16)
+ .addImm(31);
+ BuildMI(*BB, BB->begin(), dl, TII->get(PPC::SRW), SrwDestReg)
.addReg(TmpDestReg)
.addReg(ShiftReg);
return BB;
@@ -12103,6 +12636,17 @@ PPCTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
} else if (MI.getOpcode() == PPC::PROBED_ALLOCA_32 ||
MI.getOpcode() == PPC::PROBED_ALLOCA_64) {
return emitProbedAlloca(MI, BB);
+ } else if (MI.getOpcode() == PPC::SPLIT_QUADWORD) {
+ DebugLoc DL = MI.getDebugLoc();
+ Register Src = MI.getOperand(2).getReg();
+ Register Lo = MI.getOperand(0).getReg();
+ Register Hi = MI.getOperand(1).getReg();
+ BuildMI(*BB, MI, DL, TII->get(TargetOpcode::COPY))
+ .addDef(Lo)
+ .addUse(Src, 0, PPC::sub_gp8_x1);
+ BuildMI(*BB, MI, DL, TII->get(TargetOpcode::COPY))
+ .addDef(Hi)
+ .addUse(Src, 0, PPC::sub_gp8_x0);
} else {
llvm_unreachable("Unexpected instr type to insert");
}
@@ -13434,7 +13978,7 @@ static SDValue combineBVZEXTLOAD(SDNode *N, SelectionDAG &DAG) {
if (Operand.getOpcode() != ISD::LOAD)
return SDValue();
- LoadSDNode *LD = dyn_cast<LoadSDNode>(Operand);
+ auto *LD = cast<LoadSDNode>(Operand);
EVT MemoryType = LD->getMemoryVT();
// This transformation is only valid if the we are loading either a byte,
@@ -13811,6 +14355,9 @@ SDValue PPCTargetLowering::combineStoreFPToInt(SDNode *N,
(Op1VT == MVT::i32 || Op1VT == MVT::i64 ||
(Subtarget.hasP9Vector() && (Op1VT == MVT::i16 || Op1VT == MVT::i8)));
+ if (ResVT == MVT::f128 && !Subtarget.hasP9Vector())
+ return SDValue();
+
if (ResVT == MVT::ppcf128 || !Subtarget.hasP8Vector() ||
cast<StoreSDNode>(N)->isTruncatingStore() || !ValidTypeForStoreFltAsInt)
return SDValue();
@@ -13889,13 +14436,24 @@ static SDValue isScalarToVec(SDValue Op) {
return SDValue();
}
+// Fix up the shuffle mask to account for the fact that the result of
+// scalar_to_vector is not in lane zero. This just takes all values in
+// the ranges specified by the min/max indices and adds the number of
+// elements required to ensure each element comes from the respective
+// position in the valid lane.
+// On little endian, that's just the corresponding element in the other
+// half of the vector. On big endian, it is in the same half but right
+// justified rather than left justified in that half.
static void fixupShuffleMaskForPermutedSToV(SmallVectorImpl<int> &ShuffV,
int LHSMaxIdx, int RHSMinIdx,
- int RHSMaxIdx, int HalfVec) {
+ int RHSMaxIdx, int HalfVec,
+ unsigned ValidLaneWidth,
+ const PPCSubtarget &Subtarget) {
for (int i = 0, e = ShuffV.size(); i < e; i++) {
int Idx = ShuffV[i];
if ((Idx >= 0 && Idx < LHSMaxIdx) || (Idx >= RHSMinIdx && Idx < RHSMaxIdx))
- ShuffV[i] += HalfVec;
+ ShuffV[i] +=
+ Subtarget.isLittleEndian() ? HalfVec : HalfVec - ValidLaneWidth;
}
}
@@ -13904,7 +14462,8 @@ static void fixupShuffleMaskForPermutedSToV(SmallVectorImpl<int> &ShuffV,
// (<n x Ty> (scalar_to_vector (Ty (extract_elt <n x Ty> %a, C))))
// In such a case, just change the shuffle mask to extract the element
// from the permuted index.
-static SDValue getSToVPermuted(SDValue OrigSToV, SelectionDAG &DAG) {
+static SDValue getSToVPermuted(SDValue OrigSToV, SelectionDAG &DAG,
+ const PPCSubtarget &Subtarget) {
SDLoc dl(OrigSToV);
EVT VT = OrigSToV.getValueType();
assert(OrigSToV.getOpcode() == ISD::SCALAR_TO_VECTOR &&
@@ -13918,8 +14477,14 @@ static SDValue getSToVPermuted(SDValue OrigSToV, SelectionDAG &DAG) {
// Can't handle non-const element indices or different vector types
// for the input to the extract and the output of the scalar_to_vector.
if (Idx && VT == OrigVector.getValueType()) {
- SmallVector<int, 16> NewMask(VT.getVectorNumElements(), -1);
- NewMask[VT.getVectorNumElements() / 2] = Idx->getZExtValue();
+ unsigned NumElts = VT.getVectorNumElements();
+ assert(
+ NumElts > 1 &&
+ "Cannot produce a permuted scalar_to_vector for one element vector");
+ SmallVector<int, 16> NewMask(NumElts, -1);
+ unsigned ResultInElt = NumElts / 2;
+ ResultInElt -= Subtarget.isLittleEndian() ? 0 : 1;
+ NewMask[ResultInElt] = Idx->getZExtValue();
return DAG.getVectorShuffle(VT, dl, OrigVector, OrigVector, NewMask);
}
}
@@ -13935,6 +14500,10 @@ static SDValue getSToVPermuted(SDValue OrigSToV, SelectionDAG &DAG) {
// Furthermore, SCALAR_TO_VECTOR on little endian always involves a permute
// to put the value into element zero. Adjust the shuffle mask so that the
// vector can remain in permuted form (to prevent a swap prior to a shuffle).
+// On big endian targets, this is still useful for SCALAR_TO_VECTOR
+// nodes with elements smaller than doubleword because all the ways
+// of getting scalar data into a vector register put the value in the
+// rightmost element of the left half of the vector.
SDValue PPCTargetLowering::combineVectorShuffle(ShuffleVectorSDNode *SVN,
SelectionDAG &DAG) const {
SDValue LHS = SVN->getOperand(0);
@@ -13943,10 +14512,14 @@ SDValue PPCTargetLowering::combineVectorShuffle(ShuffleVectorSDNode *SVN,
int NumElts = LHS.getValueType().getVectorNumElements();
SDValue Res(SVN, 0);
SDLoc dl(SVN);
+ bool IsLittleEndian = Subtarget.isLittleEndian();
- // None of these combines are useful on big endian systems since the ISA
- // already has a big endian bias.
- if (!Subtarget.isLittleEndian() || !Subtarget.hasVSX())
+ // On big endian targets this is only useful for subtargets with direct moves.
+ // On little endian targets it would be useful for all subtargets with VSX.
+ // However adding special handling for LE subtargets without direct moves
+ // would be wasted effort since the minimum arch for LE is ISA 2.07 (Power8)
+ // which includes direct moves.
+ if (!Subtarget.hasDirectMove())
return Res;
// If this is not a shuffle of a shuffle and the first element comes from
@@ -13969,6 +14542,15 @@ SDValue PPCTargetLowering::combineVectorShuffle(ShuffleVectorSDNode *SVN,
int NumEltsIn = SToVLHS ? SToVLHS.getValueType().getVectorNumElements()
: SToVRHS.getValueType().getVectorNumElements();
int NumEltsOut = ShuffV.size();
+ // The width of the "valid lane" (i.e. the lane that contains the value that
+ // is vectorized) needs to be expressed in terms of the number of elements
+ // of the shuffle. It is thereby the ratio of the values before and after
+ // any bitcast.
+ unsigned ValidLaneWidth =
+ SToVLHS ? SToVLHS.getValueType().getScalarSizeInBits() /
+ LHS.getValueType().getScalarSizeInBits()
+ : SToVRHS.getValueType().getScalarSizeInBits() /
+ RHS.getValueType().getScalarSizeInBits();
// Initially assume that neither input is permuted. These will be adjusted
// accordingly if either input is.
@@ -13979,18 +14561,26 @@ SDValue PPCTargetLowering::combineVectorShuffle(ShuffleVectorSDNode *SVN,
// Get the permuted scalar to vector nodes for the source(s) that come from
// ISD::SCALAR_TO_VECTOR.
+ // On big endian systems, this only makes sense for element sizes smaller
+ // than 64 bits since for 64-bit elements, all instructions already put
+ // the value into element zero. Since scalar size of LHS and RHS may differ
+ // after isScalarToVec, this should be checked using their own sizes.
if (SToVLHS) {
+ if (!IsLittleEndian && SToVLHS.getValueType().getScalarSizeInBits() >= 64)
+ return Res;
// Set up the values for the shuffle vector fixup.
LHSMaxIdx = NumEltsOut / NumEltsIn;
- SToVLHS = getSToVPermuted(SToVLHS, DAG);
+ SToVLHS = getSToVPermuted(SToVLHS, DAG, Subtarget);
if (SToVLHS.getValueType() != LHS.getValueType())
SToVLHS = DAG.getBitcast(LHS.getValueType(), SToVLHS);
LHS = SToVLHS;
}
if (SToVRHS) {
+ if (!IsLittleEndian && SToVRHS.getValueType().getScalarSizeInBits() >= 64)
+ return Res;
RHSMinIdx = NumEltsOut;
RHSMaxIdx = NumEltsOut / NumEltsIn + RHSMinIdx;
- SToVRHS = getSToVPermuted(SToVRHS, DAG);
+ SToVRHS = getSToVPermuted(SToVRHS, DAG, Subtarget);
if (SToVRHS.getValueType() != RHS.getValueType())
SToVRHS = DAG.getBitcast(RHS.getValueType(), SToVRHS);
RHS = SToVRHS;
@@ -14000,10 +14590,9 @@ SDValue PPCTargetLowering::combineVectorShuffle(ShuffleVectorSDNode *SVN,
// The minimum and maximum indices that correspond to element zero for both
// the LHS and RHS are computed and will control which shuffle mask entries
// are to be changed. For example, if the RHS is permuted, any shuffle mask
- // entries in the range [RHSMinIdx,RHSMaxIdx) will be incremented by
- // HalfVec to refer to the corresponding element in the permuted vector.
+ // entries in the range [RHSMinIdx,RHSMaxIdx) will be adjusted.
fixupShuffleMaskForPermutedSToV(ShuffV, LHSMaxIdx, RHSMinIdx, RHSMaxIdx,
- HalfVec);
+ HalfVec, ValidLaneWidth, Subtarget);
Res = DAG.getVectorShuffle(SVN->getValueType(0), dl, LHS, RHS, ShuffV);
// We may have simplified away the shuffle. We won't be able to do anything
@@ -14013,12 +14602,13 @@ SDValue PPCTargetLowering::combineVectorShuffle(ShuffleVectorSDNode *SVN,
Mask = cast<ShuffleVectorSDNode>(Res)->getMask();
}
+ SDValue TheSplat = IsLittleEndian ? RHS : LHS;
// The common case after we commuted the shuffle is that the RHS is a splat
// and we have elements coming in from the splat at indices that are not
// conducive to using a merge.
// Example:
// vector_shuffle<0,17,1,19,2,21,3,23,4,25,5,27,6,29,7,31> t1, <zero>
- if (!isSplatBV(RHS))
+ if (!isSplatBV(TheSplat))
return Res;
// We are looking for a mask such that all even elements are from
@@ -14028,24 +14618,41 @@ SDValue PPCTargetLowering::combineVectorShuffle(ShuffleVectorSDNode *SVN,
// Adjust the mask so we are pulling in the same index from the splat
// as the index from the interesting vector in consecutive elements.
- // Example (even elements from first vector):
- // vector_shuffle<0,16,1,17,2,18,3,19,4,20,5,21,6,22,7,23> t1, <zero>
- if (Mask[0] < NumElts)
- for (int i = 1, e = Mask.size(); i < e; i += 2)
- ShuffV[i] = (ShuffV[i - 1] + NumElts);
- // Example (odd elements from first vector):
- // vector_shuffle<16,0,17,1,18,2,19,3,20,4,21,5,22,6,23,7> t1, <zero>
- else
- for (int i = 0, e = Mask.size(); i < e; i += 2)
- ShuffV[i] = (ShuffV[i + 1] + NumElts);
+ if (IsLittleEndian) {
+ // Example (even elements from first vector):
+ // vector_shuffle<0,16,1,17,2,18,3,19,4,20,5,21,6,22,7,23> t1, <zero>
+ if (Mask[0] < NumElts)
+ for (int i = 1, e = Mask.size(); i < e; i += 2)
+ ShuffV[i] = (ShuffV[i - 1] + NumElts);
+ // Example (odd elements from first vector):
+ // vector_shuffle<16,0,17,1,18,2,19,3,20,4,21,5,22,6,23,7> t1, <zero>
+ else
+ for (int i = 0, e = Mask.size(); i < e; i += 2)
+ ShuffV[i] = (ShuffV[i + 1] + NumElts);
+ } else {
+ // Example (even elements from first vector):
+ // vector_shuffle<0,16,1,17,2,18,3,19,4,20,5,21,6,22,7,23> <zero>, t1
+ if (Mask[0] < NumElts)
+ for (int i = 0, e = Mask.size(); i < e; i += 2)
+ ShuffV[i] = ShuffV[i + 1] - NumElts;
+ // Example (odd elements from first vector):
+ // vector_shuffle<16,0,17,1,18,2,19,3,20,4,21,5,22,6,23,7> <zero>, t1
+ else
+ for (int i = 1, e = Mask.size(); i < e; i += 2)
+ ShuffV[i] = ShuffV[i - 1] - NumElts;
+ }
// If the RHS has undefs, we need to remove them since we may have created
// a shuffle that adds those instead of the splat value.
- SDValue SplatVal = cast<BuildVectorSDNode>(RHS.getNode())->getSplatValue();
- RHS = DAG.getSplatBuildVector(RHS.getValueType(), dl, SplatVal);
+ SDValue SplatVal =
+ cast<BuildVectorSDNode>(TheSplat.getNode())->getSplatValue();
+ TheSplat = DAG.getSplatBuildVector(TheSplat.getValueType(), dl, SplatVal);
- Res = DAG.getVectorShuffle(SVN->getValueType(0), dl, LHS, RHS, ShuffV);
- return Res;
+ if (IsLittleEndian)
+ RHS = TheSplat;
+ else
+ LHS = TheSplat;
+ return DAG.getVectorShuffle(SVN->getValueType(0), dl, LHS, RHS, ShuffV);
}
SDValue PPCTargetLowering::combineVReverseMemOP(ShuffleVectorSDNode *SVN,
@@ -14084,7 +14691,15 @@ SDValue PPCTargetLowering::combineVReverseMemOP(ShuffleVectorSDNode *SVN,
return SDValue();
if (LSBase->getOpcode() == ISD::LOAD) {
- SDLoc dl(SVN);
+ // If the load return value 0 has more than one user except the
+ // shufflevector instruction, it is not profitable to replace the
+ // shufflevector with a reverse load.
+ for (SDNode::use_iterator UI = LSBase->use_begin(), UE = LSBase->use_end();
+ UI != UE; ++UI)
+ if (UI.getUse().getResNo() == 0 && UI->getOpcode() != ISD::VECTOR_SHUFFLE)
+ return SDValue();
+
+ SDLoc dl(LSBase);
SDValue LoadOps[] = {LSBase->getChain(), LSBase->getBasePtr()};
return DAG.getMemIntrinsicNode(
PPCISD::LOAD_VEC_BE, dl, DAG.getVTList(VT, MVT::Other), LoadOps,
@@ -14092,6 +14707,12 @@ SDValue PPCTargetLowering::combineVReverseMemOP(ShuffleVectorSDNode *SVN,
}
if (LSBase->getOpcode() == ISD::STORE) {
+ // If there are other uses of the shuffle, the swap cannot be avoided.
+ // Forcing the use of an X-Form (since swapped stores only have
+ // X-Forms) without removing the swap is unprofitable.
+ if (!SVN->hasOneUse())
+ return SDValue();
+
SDLoc dl(LSBase);
SDValue StoreOps[] = {LSBase->getChain(), SVN->getOperand(0),
LSBase->getBasePtr()};
@@ -14606,13 +15227,17 @@ SDValue PPCTargetLowering::PerformDAGCombine(SDNode *N,
}
}
break;
- case ISD::BSWAP:
+ case ISD::BSWAP: {
// Turn BSWAP (LOAD) -> lhbrx/lwbrx.
- if (ISD::isNON_EXTLoad(N->getOperand(0).getNode()) &&
- N->getOperand(0).hasOneUse() &&
+ // For subtargets without LDBRX, we can still do better than the default
+ // expansion even for 64-bit BSWAP (LOAD).
+ bool Is64BitBswapOn64BitTgt =
+ Subtarget.isPPC64() && N->getValueType(0) == MVT::i64;
+ bool IsSingleUseNormalLd = ISD::isNormalLoad(N->getOperand(0).getNode()) &&
+ N->getOperand(0).hasOneUse();
+ if (IsSingleUseNormalLd &&
(N->getValueType(0) == MVT::i32 || N->getValueType(0) == MVT::i16 ||
- (Subtarget.hasLDBRX() && Subtarget.isPPC64() &&
- N->getValueType(0) == MVT::i64))) {
+ (Subtarget.hasLDBRX() && Is64BitBswapOn64BitTgt))) {
SDValue Load = N->getOperand(0);
LoadSDNode *LD = cast<LoadSDNode>(Load);
// Create the byte-swapping load.
@@ -14643,7 +15268,37 @@ SDValue PPCTargetLowering::PerformDAGCombine(SDNode *N,
// Return N so it doesn't get rechecked!
return SDValue(N, 0);
}
- break;
+ // Convert this to two 32-bit bswap loads and a BUILD_PAIR. Do this only
+ // before legalization so that the BUILD_PAIR is handled correctly.
+ if (!DCI.isBeforeLegalize() || !Is64BitBswapOn64BitTgt ||
+ !IsSingleUseNormalLd)
+ return SDValue();
+ LoadSDNode *LD = cast<LoadSDNode>(N->getOperand(0));
+
+ // Can't split volatile or atomic loads.
+ if (!LD->isSimple())
+ return SDValue();
+ SDValue BasePtr = LD->getBasePtr();
+ SDValue Lo = DAG.getLoad(MVT::i32, dl, LD->getChain(), BasePtr,
+ LD->getPointerInfo(), LD->getAlignment());
+ Lo = DAG.getNode(ISD::BSWAP, dl, MVT::i32, Lo);
+ BasePtr = DAG.getNode(ISD::ADD, dl, BasePtr.getValueType(), BasePtr,
+ DAG.getIntPtrConstant(4, dl));
+ MachineMemOperand *NewMMO = DAG.getMachineFunction().getMachineMemOperand(
+ LD->getMemOperand(), 4, 4);
+ SDValue Hi = DAG.getLoad(MVT::i32, dl, LD->getChain(), BasePtr, NewMMO);
+ Hi = DAG.getNode(ISD::BSWAP, dl, MVT::i32, Hi);
+ SDValue Res;
+ if (Subtarget.isLittleEndian())
+ Res = DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Hi, Lo);
+ else
+ Res = DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Lo, Hi);
+ SDValue TF =
+ DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
+ Hi.getOperand(0).getValue(1), Lo.getOperand(0).getValue(1));
+ DAG.ReplaceAllUsesOfValueWith(SDValue(LD, 1), TF);
+ return Res;
+ }
case PPCISD::VCMP:
// If a VCMP_rec node already exists with exactly the same operands as this
// node, use its result instead of this node (VCMP_rec computes both a CR6
@@ -15080,25 +15735,57 @@ PPCTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
} else if ((Constraint == "wa" || Constraint == "wd" ||
Constraint == "wf" || Constraint == "wi") &&
Subtarget.hasVSX()) {
- return std::make_pair(0U, &PPC::VSRCRegClass);
+ // A VSX register for either a scalar (FP) or vector. There is no
+ // support for single precision scalars on subtargets prior to Power8.
+ if (VT.isVector())
+ return std::make_pair(0U, &PPC::VSRCRegClass);
+ if (VT == MVT::f32 && Subtarget.hasP8Vector())
+ return std::make_pair(0U, &PPC::VSSRCRegClass);
+ return std::make_pair(0U, &PPC::VSFRCRegClass);
} else if ((Constraint == "ws" || Constraint == "ww") && Subtarget.hasVSX()) {
if (VT == MVT::f32 && Subtarget.hasP8Vector())
return std::make_pair(0U, &PPC::VSSRCRegClass);
else
return std::make_pair(0U, &PPC::VSFRCRegClass);
+ } else if (Constraint == "lr") {
+ if (VT == MVT::i64)
+ return std::make_pair(0U, &PPC::LR8RCRegClass);
+ else
+ return std::make_pair(0U, &PPC::LRRCRegClass);
}
- // If we name a VSX register, we can't defer to the base class because it
- // will not recognize the correct register (their names will be VSL{0-31}
- // and V{0-31} so they won't match). So we match them here.
- if (Constraint.size() > 3 && Constraint[1] == 'v' && Constraint[2] == 's') {
- int VSNum = atoi(Constraint.data() + 3);
- assert(VSNum >= 0 && VSNum <= 63 &&
- "Attempted to access a vsr out of range");
- if (VSNum < 32)
- return std::make_pair(PPC::VSL0 + VSNum, &PPC::VSRCRegClass);
- return std::make_pair(PPC::V0 + VSNum - 32, &PPC::VSRCRegClass);
+ // Handle special cases of physical registers that are not properly handled
+ // by the base class.
+ if (Constraint[0] == '{' && Constraint[Constraint.size() - 1] == '}') {
+ // If we name a VSX register, we can't defer to the base class because it
+ // will not recognize the correct register (their names will be VSL{0-31}
+ // and V{0-31} so they won't match). So we match them here.
+ if (Constraint.size() > 3 && Constraint[1] == 'v' && Constraint[2] == 's') {
+ int VSNum = atoi(Constraint.data() + 3);
+ assert(VSNum >= 0 && VSNum <= 63 &&
+ "Attempted to access a vsr out of range");
+ if (VSNum < 32)
+ return std::make_pair(PPC::VSL0 + VSNum, &PPC::VSRCRegClass);
+ return std::make_pair(PPC::V0 + VSNum - 32, &PPC::VSRCRegClass);
+ }
+
+ // For float registers, we can't defer to the base class as it will match
+ // the SPILLTOVSRRC class.
+ if (Constraint.size() > 3 && Constraint[1] == 'f') {
+ int RegNum = atoi(Constraint.data() + 2);
+ if (RegNum > 31 || RegNum < 0)
+ report_fatal_error("Invalid floating point register number");
+ if (VT == MVT::f32 || VT == MVT::i32)
+ return Subtarget.hasSPE()
+ ? std::make_pair(PPC::R0 + RegNum, &PPC::GPRCRegClass)
+ : std::make_pair(PPC::F0 + RegNum, &PPC::F4RCRegClass);
+ if (VT == MVT::f64 || VT == MVT::i64)
+ return Subtarget.hasSPE()
+ ? std::make_pair(PPC::S0 + RegNum, &PPC::SPERCRegClass)
+ : std::make_pair(PPC::F0 + RegNum, &PPC::F8RCRegClass);
+ }
}
+
std::pair<unsigned, const TargetRegisterClass *> R =
TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
@@ -15115,10 +15802,19 @@ PPCTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
&PPC::G8RCRegClass);
// GCC accepts 'cc' as an alias for 'cr0', and we need to do the same.
- if (!R.second && StringRef("{cc}").equals_lower(Constraint)) {
+ if (!R.second && StringRef("{cc}").equals_insensitive(Constraint)) {
R.first = PPC::CR0;
R.second = &PPC::CRRCRegClass;
}
+ // FIXME: This warning should ideally be emitted in the front end.
+ const auto &TM = getTargetMachine();
+ if (Subtarget.isAIXABI() && !TM.getAIXExtendedAltivecABI()) {
+ if (((R.first >= PPC::V20 && R.first <= PPC::V31) ||
+ (R.first >= PPC::VF20 && R.first <= PPC::VF31)) &&
+ (R.second == &PPC::VSRCRegClass || R.second == &PPC::VSFRCRegClass))
+ errs() << "warning: vector registers 20 to 32 are reserved in the "
+ "default AIX AltiVec ABI and cannot be used\n";
+ }
return R;
}
@@ -15365,6 +16061,22 @@ bool PPCTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
MachineFunction &MF,
unsigned Intrinsic) const {
switch (Intrinsic) {
+ case Intrinsic::ppc_atomicrmw_xchg_i128:
+ case Intrinsic::ppc_atomicrmw_add_i128:
+ case Intrinsic::ppc_atomicrmw_sub_i128:
+ case Intrinsic::ppc_atomicrmw_nand_i128:
+ case Intrinsic::ppc_atomicrmw_and_i128:
+ case Intrinsic::ppc_atomicrmw_or_i128:
+ case Intrinsic::ppc_atomicrmw_xor_i128:
+ case Intrinsic::ppc_cmpxchg_i128:
+ Info.opc = ISD::INTRINSIC_W_CHAIN;
+ Info.memVT = MVT::i128;
+ Info.ptrVal = I.getArgOperand(0);
+ Info.offset = 0;
+ Info.align = Align(16);
+ Info.flags = MachineMemOperand::MOLoad | MachineMemOperand::MOStore |
+ MachineMemOperand::MOVolatile;
+ return true;
case Intrinsic::ppc_altivec_lvx:
case Intrinsic::ppc_altivec_lvxl:
case Intrinsic::ppc_altivec_lvebx:
@@ -15535,9 +16247,7 @@ bool PPCTargetLowering::isLegalAddImmediate(int64_t Imm) const {
return isInt<16>(Imm) || isUInt<16>(Imm);
}
-bool PPCTargetLowering::allowsMisalignedMemoryAccesses(EVT VT,
- unsigned,
- unsigned,
+bool PPCTargetLowering::allowsMisalignedMemoryAccesses(EVT VT, unsigned, Align,
MachineMemOperand::Flags,
bool *Fast) const {
if (DisablePPCUnaligned)
@@ -15807,12 +16517,24 @@ bool PPCTargetLowering::useLoadStackGuardNode() const {
return true;
}
-// Override to disable global variable loading on Linux.
+// Override to disable global variable loading on Linux and insert AIX canary
+// word declaration.
void PPCTargetLowering::insertSSPDeclarations(Module &M) const {
+ if (Subtarget.isAIXABI()) {
+ M.getOrInsertGlobal(AIXSSPCanaryWordName,
+ Type::getInt8PtrTy(M.getContext()));
+ return;
+ }
if (!Subtarget.isTargetLinux())
return TargetLowering::insertSSPDeclarations(M);
}
+Value *PPCTargetLowering::getSDagStackGuard(const Module &M) const {
+ if (Subtarget.isAIXABI())
+ return M.getGlobalVariable(AIXSSPCanaryWordName);
+ return TargetLowering::getSDagStackGuard(M);
+}
+
bool PPCTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
bool ForCodeSize) const {
if (!VT.isSimple() || !Subtarget.hasVSX())
@@ -15826,10 +16548,8 @@ bool PPCTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
case MVT::f32:
case MVT::f64:
if (Subtarget.hasPrefixInstrs()) {
- // With prefixed instructions, we can materialize anything that can be
- // represented with a 32-bit immediate, not just positive zero.
- APFloat APFloatOfImm = Imm;
- return convertToNonDenormSingle(APFloatOfImm);
+ // we can materialize all immediatess via XXSPLTI32DX and XXSPLTIDP.
+ return true;
}
LLVM_FALLTHROUGH;
case MVT::ppcf128:
@@ -15960,9 +16680,7 @@ static SDValue combineADDToADDZE(SDNode *N, SelectionDAG &DAG,
SDVTList VTs = DAG.getVTList(MVT::i64, MVT::Glue);
SDValue Cmp = RHS.getOperand(0);
SDValue Z = Cmp.getOperand(0);
- auto *Constant = dyn_cast<ConstantSDNode>(Cmp.getOperand(1));
-
- assert(Constant && "Constant Should not be a null pointer.");
+ auto *Constant = cast<ConstantSDNode>(Cmp.getOperand(1));
int64_t NegConstant = 0 - Constant->getSExtValue();
switch(cast<CondCodeSDNode>(Cmp.getOperand(2))->get()) {
@@ -16411,3 +17129,463 @@ SDValue PPCTargetLowering::combineVSelect(SDNode *N,
return SDValue();
}
+
+/// getAddrModeForFlags - Based on the set of address flags, select the most
+/// optimal instruction format to match by.
+PPC::AddrMode PPCTargetLowering::getAddrModeForFlags(unsigned Flags) const {
+ // This is not a node we should be handling here.
+ if (Flags == PPC::MOF_None)
+ return PPC::AM_None;
+ // Unaligned D-Forms are tried first, followed by the aligned D-Forms.
+ for (auto FlagSet : AddrModesMap.at(PPC::AM_DForm))
+ if ((Flags & FlagSet) == FlagSet)
+ return PPC::AM_DForm;
+ for (auto FlagSet : AddrModesMap.at(PPC::AM_DSForm))
+ if ((Flags & FlagSet) == FlagSet)
+ return PPC::AM_DSForm;
+ for (auto FlagSet : AddrModesMap.at(PPC::AM_DQForm))
+ if ((Flags & FlagSet) == FlagSet)
+ return PPC::AM_DQForm;
+ // If no other forms are selected, return an X-Form as it is the most
+ // general addressing mode.
+ return PPC::AM_XForm;
+}
+
+/// Set alignment flags based on whether or not the Frame Index is aligned.
+/// Utilized when computing flags for address computation when selecting
+/// load and store instructions.
+static void setAlignFlagsForFI(SDValue N, unsigned &FlagSet,
+ SelectionDAG &DAG) {
+ bool IsAdd = ((N.getOpcode() == ISD::ADD) || (N.getOpcode() == ISD::OR));
+ FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(IsAdd ? N.getOperand(0) : N);
+ if (!FI)
+ return;
+ const MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ unsigned FrameIndexAlign = MFI.getObjectAlign(FI->getIndex()).value();
+ // If this is (add $FI, $S16Imm), the alignment flags are already set
+ // based on the immediate. We just need to clear the alignment flags
+ // if the FI alignment is weaker.
+ if ((FrameIndexAlign % 4) != 0)
+ FlagSet &= ~PPC::MOF_RPlusSImm16Mult4;
+ if ((FrameIndexAlign % 16) != 0)
+ FlagSet &= ~PPC::MOF_RPlusSImm16Mult16;
+ // If the address is a plain FrameIndex, set alignment flags based on
+ // FI alignment.
+ if (!IsAdd) {
+ if ((FrameIndexAlign % 4) == 0)
+ FlagSet |= PPC::MOF_RPlusSImm16Mult4;
+ if ((FrameIndexAlign % 16) == 0)
+ FlagSet |= PPC::MOF_RPlusSImm16Mult16;
+ }
+}
+
+/// Given a node, compute flags that are used for address computation when
+/// selecting load and store instructions. The flags computed are stored in
+/// FlagSet. This function takes into account whether the node is a constant,
+/// an ADD, OR, or a constant, and computes the address flags accordingly.
+static void computeFlagsForAddressComputation(SDValue N, unsigned &FlagSet,
+ SelectionDAG &DAG) {
+ // Set the alignment flags for the node depending on if the node is
+ // 4-byte or 16-byte aligned.
+ auto SetAlignFlagsForImm = [&](uint64_t Imm) {
+ if ((Imm & 0x3) == 0)
+ FlagSet |= PPC::MOF_RPlusSImm16Mult4;
+ if ((Imm & 0xf) == 0)
+ FlagSet |= PPC::MOF_RPlusSImm16Mult16;
+ };
+
+ if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N)) {
+ // All 32-bit constants can be computed as LIS + Disp.
+ const APInt &ConstImm = CN->getAPIntValue();
+ if (ConstImm.isSignedIntN(32)) { // Flag to handle 32-bit constants.
+ FlagSet |= PPC::MOF_AddrIsSImm32;
+ SetAlignFlagsForImm(ConstImm.getZExtValue());
+ setAlignFlagsForFI(N, FlagSet, DAG);
+ }
+ if (ConstImm.isSignedIntN(34)) // Flag to handle 34-bit constants.
+ FlagSet |= PPC::MOF_RPlusSImm34;
+ else // Let constant materialization handle large constants.
+ FlagSet |= PPC::MOF_NotAddNorCst;
+ } else if (N.getOpcode() == ISD::ADD || provablyDisjointOr(DAG, N)) {
+ // This address can be represented as an addition of:
+ // - Register + Imm16 (possibly a multiple of 4/16)
+ // - Register + Imm34
+ // - Register + PPCISD::Lo
+ // - Register + Register
+ // In any case, we won't have to match this as Base + Zero.
+ SDValue RHS = N.getOperand(1);
+ if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(RHS)) {
+ const APInt &ConstImm = CN->getAPIntValue();
+ if (ConstImm.isSignedIntN(16)) {
+ FlagSet |= PPC::MOF_RPlusSImm16; // Signed 16-bit immediates.
+ SetAlignFlagsForImm(ConstImm.getZExtValue());
+ setAlignFlagsForFI(N, FlagSet, DAG);
+ }
+ if (ConstImm.isSignedIntN(34))
+ FlagSet |= PPC::MOF_RPlusSImm34; // Signed 34-bit immediates.
+ else
+ FlagSet |= PPC::MOF_RPlusR; // Register.
+ } else if (RHS.getOpcode() == PPCISD::Lo &&
+ !cast<ConstantSDNode>(RHS.getOperand(1))->getZExtValue())
+ FlagSet |= PPC::MOF_RPlusLo; // PPCISD::Lo.
+ else
+ FlagSet |= PPC::MOF_RPlusR;
+ } else { // The address computation is not a constant or an addition.
+ setAlignFlagsForFI(N, FlagSet, DAG);
+ FlagSet |= PPC::MOF_NotAddNorCst;
+ }
+}
+
+/// computeMOFlags - Given a node N and it's Parent (a MemSDNode), compute
+/// the address flags of the load/store instruction that is to be matched.
+unsigned PPCTargetLowering::computeMOFlags(const SDNode *Parent, SDValue N,
+ SelectionDAG &DAG) const {
+ unsigned FlagSet = PPC::MOF_None;
+
+ // Compute subtarget flags.
+ if (!Subtarget.hasP9Vector())
+ FlagSet |= PPC::MOF_SubtargetBeforeP9;
+ else {
+ FlagSet |= PPC::MOF_SubtargetP9;
+ if (Subtarget.hasPrefixInstrs())
+ FlagSet |= PPC::MOF_SubtargetP10;
+ }
+ if (Subtarget.hasSPE())
+ FlagSet |= PPC::MOF_SubtargetSPE;
+
+ // Mark this as something we don't want to handle here if it is atomic
+ // or pre-increment instruction.
+ if (const LSBaseSDNode *LSB = dyn_cast<LSBaseSDNode>(Parent))
+ if (LSB->isIndexed())
+ return PPC::MOF_None;
+
+ // Compute in-memory type flags. This is based on if there are scalars,
+ // floats or vectors.
+ const MemSDNode *MN = dyn_cast<MemSDNode>(Parent);
+ assert(MN && "Parent should be a MemSDNode!");
+ EVT MemVT = MN->getMemoryVT();
+ unsigned Size = MemVT.getSizeInBits();
+ if (MemVT.isScalarInteger()) {
+ assert(Size <= 64 && "Not expecting scalar integers larger than 8 bytes!");
+ if (Size < 32)
+ FlagSet |= PPC::MOF_SubWordInt;
+ else if (Size == 32)
+ FlagSet |= PPC::MOF_WordInt;
+ else
+ FlagSet |= PPC::MOF_DoubleWordInt;
+ } else if (MemVT.isVector() && !MemVT.isFloatingPoint()) { // Integer vectors.
+ if (Size == 128)
+ FlagSet |= PPC::MOF_Vector;
+ else if (Size == 256)
+ FlagSet |= PPC::MOF_Vector256;
+ else
+ llvm_unreachable("Not expecting illegal vectors!");
+ } else { // Floating point type: can be scalar, f128 or vector types.
+ if (Size == 32 || Size == 64)
+ FlagSet |= PPC::MOF_ScalarFloat;
+ else if (MemVT == MVT::f128 || MemVT.isVector())
+ FlagSet |= PPC::MOF_Vector;
+ else
+ llvm_unreachable("Not expecting illegal scalar floats!");
+ }
+
+ // Compute flags for address computation.
+ computeFlagsForAddressComputation(N, FlagSet, DAG);
+
+ // Compute type extension flags.
+ if (const LoadSDNode *LN = dyn_cast<LoadSDNode>(Parent)) {
+ switch (LN->getExtensionType()) {
+ case ISD::SEXTLOAD:
+ FlagSet |= PPC::MOF_SExt;
+ break;
+ case ISD::EXTLOAD:
+ case ISD::ZEXTLOAD:
+ FlagSet |= PPC::MOF_ZExt;
+ break;
+ case ISD::NON_EXTLOAD:
+ FlagSet |= PPC::MOF_NoExt;
+ break;
+ }
+ } else
+ FlagSet |= PPC::MOF_NoExt;
+
+ // For integers, no extension is the same as zero extension.
+ // We set the extension mode to zero extension so we don't have
+ // to add separate entries in AddrModesMap for loads and stores.
+ if (MemVT.isScalarInteger() && (FlagSet & PPC::MOF_NoExt)) {
+ FlagSet |= PPC::MOF_ZExt;
+ FlagSet &= ~PPC::MOF_NoExt;
+ }
+
+ // If we don't have prefixed instructions, 34-bit constants should be
+ // treated as PPC::MOF_NotAddNorCst so they can match D-Forms.
+ bool IsNonP1034BitConst =
+ ((PPC::MOF_RPlusSImm34 | PPC::MOF_AddrIsSImm32 | PPC::MOF_SubtargetP10) &
+ FlagSet) == PPC::MOF_RPlusSImm34;
+ if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::OR &&
+ IsNonP1034BitConst)
+ FlagSet |= PPC::MOF_NotAddNorCst;
+
+ return FlagSet;
+}
+
+/// SelectForceXFormMode - Given the specified address, force it to be
+/// represented as an indexed [r+r] operation (an XForm instruction).
+PPC::AddrMode PPCTargetLowering::SelectForceXFormMode(SDValue N, SDValue &Disp,
+ SDValue &Base,
+ SelectionDAG &DAG) const {
+
+ PPC::AddrMode Mode = PPC::AM_XForm;
+ int16_t ForceXFormImm = 0;
+ if (provablyDisjointOr(DAG, N) &&
+ !isIntS16Immediate(N.getOperand(1), ForceXFormImm)) {
+ Disp = N.getOperand(0);
+ Base = N.getOperand(1);
+ return Mode;
+ }
+
+ // If the address is the result of an add, we will utilize the fact that the
+ // address calculation includes an implicit add. However, we can reduce
+ // register pressure if we do not materialize a constant just for use as the
+ // index register. We only get rid of the add if it is not an add of a
+ // value and a 16-bit signed constant and both have a single use.
+ if (N.getOpcode() == ISD::ADD &&
+ (!isIntS16Immediate(N.getOperand(1), ForceXFormImm) ||
+ !N.getOperand(1).hasOneUse() || !N.getOperand(0).hasOneUse())) {
+ Disp = N.getOperand(0);
+ Base = N.getOperand(1);
+ return Mode;
+ }
+
+ // Otherwise, use R0 as the base register.
+ Disp = DAG.getRegister(Subtarget.isPPC64() ? PPC::ZERO8 : PPC::ZERO,
+ N.getValueType());
+ Base = N;
+
+ return Mode;
+}
+
+// If we happen to match to an aligned D-Form, check if the Frame Index is
+// adequately aligned. If it is not, reset the mode to match to X-Form.
+static void setXFormForUnalignedFI(SDValue N, unsigned Flags,
+ PPC::AddrMode &Mode) {
+ if (!isa<FrameIndexSDNode>(N))
+ return;
+ if ((Mode == PPC::AM_DSForm && !(Flags & PPC::MOF_RPlusSImm16Mult4)) ||
+ (Mode == PPC::AM_DQForm && !(Flags & PPC::MOF_RPlusSImm16Mult16)))
+ Mode = PPC::AM_XForm;
+}
+
+/// SelectOptimalAddrMode - Based on a node N and it's Parent (a MemSDNode),
+/// compute the address flags of the node, get the optimal address mode based
+/// on the flags, and set the Base and Disp based on the address mode.
+PPC::AddrMode PPCTargetLowering::SelectOptimalAddrMode(const SDNode *Parent,
+ SDValue N, SDValue &Disp,
+ SDValue &Base,
+ SelectionDAG &DAG,
+ MaybeAlign Align) const {
+ SDLoc DL(Parent);
+
+ // Compute the address flags.
+ unsigned Flags = computeMOFlags(Parent, N, DAG);
+
+ // Get the optimal address mode based on the Flags.
+ PPC::AddrMode Mode = getAddrModeForFlags(Flags);
+
+ // If the address mode is DS-Form or DQ-Form, check if the FI is aligned.
+ // Select an X-Form load if it is not.
+ setXFormForUnalignedFI(N, Flags, Mode);
+
+ // Set Base and Disp accordingly depending on the address mode.
+ switch (Mode) {
+ case PPC::AM_DForm:
+ case PPC::AM_DSForm:
+ case PPC::AM_DQForm: {
+ // This is a register plus a 16-bit immediate. The base will be the
+ // register and the displacement will be the immediate unless it
+ // isn't sufficiently aligned.
+ if (Flags & PPC::MOF_RPlusSImm16) {
+ SDValue Op0 = N.getOperand(0);
+ SDValue Op1 = N.getOperand(1);
+ int16_t Imm = cast<ConstantSDNode>(Op1)->getAPIntValue().getZExtValue();
+ if (!Align || isAligned(*Align, Imm)) {
+ Disp = DAG.getTargetConstant(Imm, DL, N.getValueType());
+ Base = Op0;
+ if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Op0)) {
+ Base = DAG.getTargetFrameIndex(FI->getIndex(), N.getValueType());
+ fixupFuncForFI(DAG, FI->getIndex(), N.getValueType());
+ }
+ break;
+ }
+ }
+ // This is a register plus the @lo relocation. The base is the register
+ // and the displacement is the global address.
+ else if (Flags & PPC::MOF_RPlusLo) {
+ Disp = N.getOperand(1).getOperand(0); // The global address.
+ assert(Disp.getOpcode() == ISD::TargetGlobalAddress ||
+ Disp.getOpcode() == ISD::TargetGlobalTLSAddress ||
+ Disp.getOpcode() == ISD::TargetConstantPool ||
+ Disp.getOpcode() == ISD::TargetJumpTable);
+ Base = N.getOperand(0);
+ break;
+ }
+ // This is a constant address at most 32 bits. The base will be
+ // zero or load-immediate-shifted and the displacement will be
+ // the low 16 bits of the address.
+ else if (Flags & PPC::MOF_AddrIsSImm32) {
+ auto *CN = cast<ConstantSDNode>(N);
+ EVT CNType = CN->getValueType(0);
+ uint64_t CNImm = CN->getZExtValue();
+ // If this address fits entirely in a 16-bit sext immediate field, codegen
+ // this as "d, 0".
+ int16_t Imm;
+ if (isIntS16Immediate(CN, Imm) && (!Align || isAligned(*Align, Imm))) {
+ Disp = DAG.getTargetConstant(Imm, DL, CNType);
+ Base = DAG.getRegister(Subtarget.isPPC64() ? PPC::ZERO8 : PPC::ZERO,
+ CNType);
+ break;
+ }
+ // Handle 32-bit sext immediate with LIS + Addr mode.
+ if ((CNType == MVT::i32 || isInt<32>(CNImm)) &&
+ (!Align || isAligned(*Align, CNImm))) {
+ int32_t Addr = (int32_t)CNImm;
+ // Otherwise, break this down into LIS + Disp.
+ Disp = DAG.getTargetConstant((int16_t)Addr, DL, MVT::i32);
+ Base =
+ DAG.getTargetConstant((Addr - (int16_t)Addr) >> 16, DL, MVT::i32);
+ uint32_t LIS = CNType == MVT::i32 ? PPC::LIS : PPC::LIS8;
+ Base = SDValue(DAG.getMachineNode(LIS, DL, CNType, Base), 0);
+ break;
+ }
+ }
+ // Otherwise, the PPC:MOF_NotAdd flag is set. Load/Store is Non-foldable.
+ Disp = DAG.getTargetConstant(0, DL, getPointerTy(DAG.getDataLayout()));
+ if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N)) {
+ Base = DAG.getTargetFrameIndex(FI->getIndex(), N.getValueType());
+ fixupFuncForFI(DAG, FI->getIndex(), N.getValueType());
+ } else
+ Base = N;
+ break;
+ }
+ case PPC::AM_None:
+ break;
+ default: { // By default, X-Form is always available to be selected.
+ // When a frame index is not aligned, we also match by XForm.
+ FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N);
+ Base = FI ? N : N.getOperand(1);
+ Disp = FI ? DAG.getRegister(Subtarget.isPPC64() ? PPC::ZERO8 : PPC::ZERO,
+ N.getValueType())
+ : N.getOperand(0);
+ break;
+ }
+ }
+ return Mode;
+}
+
+CCAssignFn *PPCTargetLowering::ccAssignFnForCall(CallingConv::ID CC,
+ bool Return,
+ bool IsVarArg) const {
+ switch (CC) {
+ case CallingConv::Cold:
+ return (Return ? RetCC_PPC_Cold : CC_PPC64_ELF_FIS);
+ default:
+ return CC_PPC64_ELF_FIS;
+ }
+}
+
+TargetLowering::AtomicExpansionKind
+PPCTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
+ unsigned Size = AI->getType()->getPrimitiveSizeInBits();
+ if (EnableQuadwordAtomics && Subtarget.hasQuadwordAtomics() && Size == 128)
+ return AtomicExpansionKind::MaskedIntrinsic;
+ return TargetLowering::shouldExpandAtomicRMWInIR(AI);
+}
+
+TargetLowering::AtomicExpansionKind
+PPCTargetLowering::shouldExpandAtomicCmpXchgInIR(AtomicCmpXchgInst *AI) const {
+ unsigned Size = AI->getPointerOperand()
+ ->getType()
+ ->getPointerElementType()
+ ->getPrimitiveSizeInBits();
+ if (EnableQuadwordAtomics && Subtarget.hasQuadwordAtomics() && Size == 128)
+ return AtomicExpansionKind::MaskedIntrinsic;
+ return TargetLowering::shouldExpandAtomicCmpXchgInIR(AI);
+}
+
+static Intrinsic::ID
+getIntrinsicForAtomicRMWBinOp128(AtomicRMWInst::BinOp BinOp) {
+ switch (BinOp) {
+ default:
+ llvm_unreachable("Unexpected AtomicRMW BinOp");
+ case AtomicRMWInst::Xchg:
+ return Intrinsic::ppc_atomicrmw_xchg_i128;
+ case AtomicRMWInst::Add:
+ return Intrinsic::ppc_atomicrmw_add_i128;
+ case AtomicRMWInst::Sub:
+ return Intrinsic::ppc_atomicrmw_sub_i128;
+ case AtomicRMWInst::And:
+ return Intrinsic::ppc_atomicrmw_and_i128;
+ case AtomicRMWInst::Or:
+ return Intrinsic::ppc_atomicrmw_or_i128;
+ case AtomicRMWInst::Xor:
+ return Intrinsic::ppc_atomicrmw_xor_i128;
+ case AtomicRMWInst::Nand:
+ return Intrinsic::ppc_atomicrmw_nand_i128;
+ }
+}
+
+Value *PPCTargetLowering::emitMaskedAtomicRMWIntrinsic(
+ IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr,
+ Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const {
+ assert(EnableQuadwordAtomics && Subtarget.hasQuadwordAtomics() &&
+ "Only support quadword now");
+ Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+ Type *ValTy = cast<PointerType>(AlignedAddr->getType())->getElementType();
+ assert(ValTy->getPrimitiveSizeInBits() == 128);
+ Function *RMW = Intrinsic::getDeclaration(
+ M, getIntrinsicForAtomicRMWBinOp128(AI->getOperation()));
+ Type *Int64Ty = Type::getInt64Ty(M->getContext());
+ Value *IncrLo = Builder.CreateTrunc(Incr, Int64Ty, "incr_lo");
+ Value *IncrHi =
+ Builder.CreateTrunc(Builder.CreateLShr(Incr, 64), Int64Ty, "incr_hi");
+ Value *Addr =
+ Builder.CreateBitCast(AlignedAddr, Type::getInt8PtrTy(M->getContext()));
+ Value *LoHi = Builder.CreateCall(RMW, {Addr, IncrLo, IncrHi});
+ Value *Lo = Builder.CreateExtractValue(LoHi, 0, "lo");
+ Value *Hi = Builder.CreateExtractValue(LoHi, 1, "hi");
+ Lo = Builder.CreateZExt(Lo, ValTy, "lo64");
+ Hi = Builder.CreateZExt(Hi, ValTy, "hi64");
+ return Builder.CreateOr(
+ Lo, Builder.CreateShl(Hi, ConstantInt::get(ValTy, 64)), "val64");
+}
+
+Value *PPCTargetLowering::emitMaskedAtomicCmpXchgIntrinsic(
+ IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr,
+ Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const {
+ assert(EnableQuadwordAtomics && Subtarget.hasQuadwordAtomics() &&
+ "Only support quadword now");
+ Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+ Type *ValTy = cast<PointerType>(AlignedAddr->getType())->getElementType();
+ assert(ValTy->getPrimitiveSizeInBits() == 128);
+ Function *IntCmpXchg =
+ Intrinsic::getDeclaration(M, Intrinsic::ppc_cmpxchg_i128);
+ Type *Int64Ty = Type::getInt64Ty(M->getContext());
+ Value *CmpLo = Builder.CreateTrunc(CmpVal, Int64Ty, "cmp_lo");
+ Value *CmpHi =
+ Builder.CreateTrunc(Builder.CreateLShr(CmpVal, 64), Int64Ty, "cmp_hi");
+ Value *NewLo = Builder.CreateTrunc(NewVal, Int64Ty, "new_lo");
+ Value *NewHi =
+ Builder.CreateTrunc(Builder.CreateLShr(NewVal, 64), Int64Ty, "new_hi");
+ Value *Addr =
+ Builder.CreateBitCast(AlignedAddr, Type::getInt8PtrTy(M->getContext()));
+ emitLeadingFence(Builder, CI, Ord);
+ Value *LoHi =
+ Builder.CreateCall(IntCmpXchg, {Addr, CmpLo, CmpHi, NewLo, NewHi});
+ emitTrailingFence(Builder, CI, Ord);
+ Value *Lo = Builder.CreateExtractValue(LoHi, 0, "lo");
+ Value *Hi = Builder.CreateExtractValue(LoHi, 1, "hi");
+ Lo = Builder.CreateZExt(Lo, ValTy, "lo64");
+ Hi = Builder.CreateZExt(Hi, ValTy, "hi64");
+ return Builder.CreateOr(
+ Lo, Builder.CreateShl(Hi, ConstantInt::get(ValTy, 64)), "val64");
+}