summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target
diff options
context:
space:
mode:
authorMartin Storsjo <martin@martin.st>2018-02-17 14:26:32 +0000
committerMartin Storsjo <martin@martin.st>2018-02-17 14:26:32 +0000
commita63a5b993ee90e7da6afc052c6702709f39dd9eb (patch)
tree1954c2a5283c29b7ed422e0ac11d563450ca542d /llvm/lib/Target
parent63db6690134a7b64e3d2e9f584c6417539e2ebe3 (diff)
downloadbcm5719-llvm-a63a5b993ee90e7da6afc052c6702709f39dd9eb.tar.gz
bcm5719-llvm-a63a5b993ee90e7da6afc052c6702709f39dd9eb.zip
[AArch64] Implement dynamic stack probing for windows
This makes sure that alloca() function calls properly probe the stack as needed. Differential Revision: https://reviews.llvm.org/D42356 llvm-svn: 325433
Diffstat (limited to 'llvm/lib/Target')
-rw-r--r--llvm/lib/Target/AArch64/AArch64CallingConvention.td4
-rw-r--r--llvm/lib/Target/AArch64/AArch64ISelLowering.cpp69
-rw-r--r--llvm/lib/Target/AArch64/AArch64ISelLowering.h4
-rw-r--r--llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp4
-rw-r--r--llvm/lib/Target/AArch64/AArch64RegisterInfo.h3
5 files changed, 83 insertions, 1 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64CallingConvention.td b/llvm/lib/Target/AArch64/AArch64CallingConvention.td
index 93a68449de8..e5767313289 100644
--- a/llvm/lib/Target/AArch64/AArch64CallingConvention.td
+++ b/llvm/lib/Target/AArch64/AArch64CallingConvention.td
@@ -345,3 +345,7 @@ def CSR_AArch64_NoRegs : CalleeSavedRegs<(add)>;
def CSR_AArch64_RT_MostRegs : CalleeSavedRegs<(add CSR_AArch64_AAPCS,
(sequence "X%u", 9, 15))>;
+def CSR_AArch64_StackProbe_Windows
+ : CalleeSavedRegs<(add (sequence "X%u", 0, 15),
+ (sequence "X%u", 18, 28), FP, SP,
+ (sequence "Q%u", 0, 31))>;
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index fe2161039cd..9330d7cbbe4 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -253,7 +253,11 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
// Variable-sized objects.
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
- setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Expand);
+
+ if (Subtarget->isTargetWindows())
+ setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Custom);
+ else
+ setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Expand);
// Constant pool entries
setOperationAction(ISD::ConstantPool, MVT::i64, Custom);
@@ -2687,6 +2691,8 @@ SDValue AArch64TargetLowering::LowerOperation(SDValue Op,
return LowerATOMIC_LOAD_SUB(Op, DAG);
case ISD::ATOMIC_LOAD_AND:
return LowerATOMIC_LOAD_AND(Op, DAG);
+ case ISD::DYNAMIC_STACKALLOC:
+ return LowerDYNAMIC_STACKALLOC(Op, DAG);
}
}
@@ -7415,6 +7421,67 @@ SDValue AArch64TargetLowering::LowerATOMIC_LOAD_AND(SDValue Op,
AN->getMemOperand());
}
+SDValue AArch64TargetLowering::LowerWindowsDYNAMIC_STACKALLOC(
+ SDValue Op, SDValue Chain, SDValue &Size, SelectionDAG &DAG) const {
+ SDLoc dl(Op);
+ EVT PtrVT = getPointerTy(DAG.getDataLayout());
+ SDValue Callee = DAG.getTargetExternalSymbol("__chkstk", PtrVT, 0);
+
+ const uint32_t *Mask =
+ Subtarget->getRegisterInfo()->getWindowsStackProbePreservedMask();
+
+ Size = DAG.getNode(ISD::SRL, dl, MVT::i64, Size,
+ DAG.getConstant(4, dl, MVT::i64));
+ Chain = DAG.getCopyToReg(Chain, dl, AArch64::X15, Size, SDValue());
+ Chain =
+ DAG.getNode(AArch64ISD::CALL, dl, DAG.getVTList(MVT::Other, MVT::Glue),
+ Chain, Callee, DAG.getRegister(AArch64::X15, MVT::i64),
+ DAG.getRegisterMask(Mask), Chain.getValue(1));
+ // To match the actual intent better, we should read the output from X15 here
+ // again (instead of potentially spilling it to the stack), but rereading Size
+ // from X15 here doesn't work at -O0, since it thinks that X15 is undefined
+ // here.
+
+ Size = DAG.getNode(ISD::SHL, dl, MVT::i64, Size,
+ DAG.getConstant(4, dl, MVT::i64));
+ return Chain;
+}
+
+SDValue
+AArch64TargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
+ SelectionDAG &DAG) const {
+ assert(Subtarget->isTargetWindows() &&
+ "Only Windows alloca probing supported");
+ SDLoc dl(Op);
+ // Get the inputs.
+ SDNode *Node = Op.getNode();
+ SDValue Chain = Op.getOperand(0);
+ SDValue Size = Op.getOperand(1);
+ unsigned Align = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue();
+ EVT VT = Node->getValueType(0);
+
+ Chain = DAG.getCALLSEQ_START(Chain, 0, 0, dl);
+
+ Chain = LowerWindowsDYNAMIC_STACKALLOC(Op, Chain, Size, DAG);
+
+ SDValue SP = DAG.getCopyFromReg(Chain, dl, AArch64::SP, MVT::i64);
+ Chain = SP.getValue(1);
+ SP = DAG.getNode(ISD::SUB, dl, MVT::i64, SP, Size);
+ Chain = DAG.getCopyToReg(Chain, dl, AArch64::SP, SP);
+
+ if (Align) {
+ SP = DAG.getNode(ISD::AND, dl, VT, SP.getValue(0),
+ DAG.getConstant(-(uint64_t)Align, dl, VT));
+ Chain = DAG.getCopyToReg(Chain, dl, AArch64::SP, SP);
+ }
+
+ Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(0, dl, true),
+ DAG.getIntPtrConstant(0, dl, true), SDValue(), dl);
+
+ SDValue Ops[2] = {SP, Chain};
+ return DAG.getMergeValues(Ops, dl);
+}
+
/// getTgtMemIntrinsic - Represent NEON load and store intrinsics as
/// MemIntrinsicNodes. The associated MachineMemOperands record the alignment
/// specified in the intrinsic calls.
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
index 2003196f780..23bf4fef7e1 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -598,6 +598,10 @@ private:
SDValue LowerVECREDUCE(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerATOMIC_LOAD_SUB(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerATOMIC_LOAD_AND(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerWindowsDYNAMIC_STACKALLOC(SDValue Op, SDValue Chain,
+ SDValue &Size,
+ SelectionDAG &DAG) const;
SDValue BuildSDIVPow2(SDNode *N, const APInt &Divisor, SelectionDAG &DAG,
std::vector<SDNode *> *Created) const override;
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
index 360b39125b7..933cd819706 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
@@ -114,6 +114,10 @@ AArch64RegisterInfo::getThisReturnPreservedMask(const MachineFunction &MF,
return CSR_AArch64_AAPCS_ThisReturn_RegMask;
}
+const uint32_t *AArch64RegisterInfo::getWindowsStackProbePreservedMask() const {
+ return CSR_AArch64_StackProbe_Windows_RegMask;
+}
+
BitVector
AArch64RegisterInfo::getReservedRegs(const MachineFunction &MF) const {
const AArch64FrameLowering *TFI = getFrameLowering(MF);
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.h b/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
index 37d65e66435..799d8c81af0 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
@@ -61,6 +61,9 @@ public:
const uint32_t *getThisReturnPreservedMask(const MachineFunction &MF,
CallingConv::ID) const;
+ /// Stack probing calls preserve different CSRs to the normal CC.
+ const uint32_t *getWindowsStackProbePreservedMask() const;
+
BitVector getReservedRegs(const MachineFunction &MF) const override;
bool isConstantPhysReg(unsigned PhysReg) const override;
const TargetRegisterClass *
OpenPOWER on IntegriCloud