aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
diff options
context:
space:
mode:
authorMomchil Velikov <momchil.velikov@arm.com>2021-04-15 19:58:54 +0100
committerMomchil Velikov <momchil.velikov@arm.com>2021-04-15 22:58:14 +0100
commitf9d932e6735afe73117e142a12443449f2197e69 (patch)
tree9012dbe4dbc43d99e5f7738ebfa916bf352d40ae /llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
parent4b414b84a971c60c0119b9301b7fcee6c0098f01 (diff)
downloadllvm-f9d932e6735afe73117e142a12443449f2197e69.zip
llvm-f9d932e6735afe73117e142a12443449f2197e69.tar.gz
llvm-f9d932e6735afe73117e142a12443449f2197e69.tar.bz2
[clang][AArch64] Correctly align HFA arguments when passed on the stack
When we pass a AArch64 Homogeneous Floating-Point Aggregate (HFA) argument with increased alignment requirements, for example struct S { __attribute__ ((__aligned__(16))) double v[4]; }; Clang uses `[4 x double]` for the parameter, which is passed on the stack at alignment 8, whereas it should be at alignment 16, following Rule C.4 in AAPCS (https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst#642parameter-passing-rules) Currently we don't have a way to express in LLVM IR the alignment requirements of the function arguments. The align attribute is applicable to pointers only, and only for some special ways of passing arguments (e..g byval). When implementing AAPCS32/AAPCS64, clang resorts to dubious hacks of coercing to types, which naturally have the needed alignment. We don't have enough types to cover all the cases, though. This patch introduces a new use of the stackalign attribute to control stack slot alignment, when and if an argument is passed in memory. The attribute align is left as an optimizer hint - it still applies to pointer types only and pertains to the content of the pointer, whereas the alignment of the pointer itself is determined by the stackalign attribute. For byval arguments, the stackalign attribute assumes the role, previously perfomed by align, falling back to align if stackalign` is absent. On the clang side, when passing arguments using the "direct" style (cf. `ABIArgInfo::Kind`), now we can optionally specify an alignment, which is emitted as the new `stackalign` attribute. Patch by Momchil Velikov and Lucas Prates. Differential Revision: https://reviews.llvm.org/D98794
Diffstat (limited to 'llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp')
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp48
1 files changed, 29 insertions, 19 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 9e14e85..6b112ee 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -9425,6 +9425,7 @@ TargetLowering::LowerCallTo(TargetLowering::CallLoweringInfo &CLI) const {
// for a type depending on the context. Give the target a chance to
// specify the alignment it wants.
const Align OriginalAlignment(getABIAlignmentForCallingConv(ArgTy, DL));
+ Flags.setOrigAlign(OriginalAlignment);
if (Args[i].Ty->isPointerTy()) {
Flags.setPointer();
@@ -9478,6 +9479,7 @@ TargetLowering::LowerCallTo(TargetLowering::CallLoweringInfo &CLI) const {
// in the various CC lowering callbacks.
Flags.setByVal();
}
+ Align MemAlign;
if (Args[i].IsByVal || Args[i].IsInAlloca || Args[i].IsPreallocated) {
PointerType *Ty = cast<PointerType>(Args[i].Ty);
Type *ElementTy = Ty->getElementType();
@@ -9487,18 +9489,20 @@ TargetLowering::LowerCallTo(TargetLowering::CallLoweringInfo &CLI) const {
Flags.setByValSize(FrameSize);
// info is not there but there are cases it cannot get right.
- Align FrameAlign;
if (auto MA = Args[i].Alignment)
- FrameAlign = *MA;
+ MemAlign = *MA;
else
- FrameAlign = Align(getByValTypeAlignment(ElementTy, DL));
- Flags.setByValAlign(FrameAlign);
+ MemAlign = Align(getByValTypeAlignment(ElementTy, DL));
+ } else if (auto MA = Args[i].Alignment) {
+ MemAlign = *MA;
+ } else {
+ MemAlign = OriginalAlignment;
}
+ Flags.setMemAlign(MemAlign);
if (Args[i].IsNest)
Flags.setNest();
if (NeedsRegBlock)
Flags.setInConsecutiveRegs();
- Flags.setOrigAlign(OriginalAlignment);
MVT PartVT = getRegisterTypeForCallingConv(CLI.RetTy->getContext(),
CLI.CallConv, VT);
@@ -9960,11 +9964,6 @@ void SelectionDAGISel::LowerArguments(const Function &F) {
Type *ArgTy = VT.getTypeForEVT(*DAG.getContext());
ISD::ArgFlagsTy Flags;
- // Certain targets (such as MIPS), may have a different ABI alignment
- // for a type depending on the context. Give the target a chance to
- // specify the alignment it wants.
- const Align OriginalAlignment(
- TLI->getABIAlignmentForCallingConv(ArgTy, DL));
if (Arg.getType()->isPointerTy()) {
Flags.setPointer();
@@ -10017,6 +10016,14 @@ void SelectionDAGISel::LowerArguments(const Function &F) {
Flags.setByVal();
}
+ // Certain targets (such as MIPS), may have a different ABI alignment
+ // for a type depending on the context. Give the target a chance to
+ // specify the alignment it wants.
+ const Align OriginalAlignment(
+ TLI->getABIAlignmentForCallingConv(ArgTy, DL));
+ Flags.setOrigAlign(OriginalAlignment);
+
+ Align MemAlign;
Type *ArgMemTy = nullptr;
if (Flags.isByVal() || Flags.isInAlloca() || Flags.isPreallocated() ||
Flags.isByRef()) {
@@ -10028,24 +10035,27 @@ void SelectionDAGISel::LowerArguments(const Function &F) {
// For in-memory arguments, size and alignment should be passed from FE.
// BE will guess if this info is not there but there are cases it cannot
// get right.
- MaybeAlign MemAlign = Arg.getParamAlign();
- if (!MemAlign)
+ if (auto ParamAlign = Arg.getParamStackAlign())
+ MemAlign = *ParamAlign;
+ else if ((ParamAlign = Arg.getParamAlign()))
+ MemAlign = *ParamAlign;
+ else
MemAlign = Align(TLI->getByValTypeAlignment(ArgMemTy, DL));
-
- if (Flags.isByRef()) {
+ if (Flags.isByRef())
Flags.setByRefSize(MemSize);
- Flags.setByRefAlign(*MemAlign);
- } else {
+ else
Flags.setByValSize(MemSize);
- Flags.setByValAlign(*MemAlign);
- }
+ } else if (auto ParamAlign = Arg.getParamStackAlign()) {
+ MemAlign = *ParamAlign;
+ } else {
+ MemAlign = OriginalAlignment;
}
+ Flags.setMemAlign(MemAlign);
if (Arg.hasAttribute(Attribute::Nest))
Flags.setNest();
if (NeedsRegBlock)
Flags.setInConsecutiveRegs();
- Flags.setOrigAlign(OriginalAlignment);
if (ArgCopyElisionCandidates.count(&Arg))
Flags.setCopyElisionCandidate();
if (Arg.hasAttribute(Attribute::Returned))