Index: clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- clang/lib/CodeGen/TargetInfo.cpp +++ clang/lib/CodeGen/TargetInfo.cpp @@ -6428,7 +6428,16 @@ return ABIArgInfo::getDirect(Ty, 0, nullptr, false); } } - return ABIArgInfo::getDirect(nullptr, 0, nullptr, false); + unsigned Align = 0; + if (getABIKind() == ARMABIInfo::AAPCS || + getABIKind() == ARMABIInfo::AAPCS_VFP) { + // For alignment adjusted HFAs, cap the argument alignment to 8, leave it + // default otherwise. + Align = getContext().getTypeUnadjustedAlignInChars(Ty).getQuantity(); + unsigned BaseAlign = getContext().getTypeAlignInChars(Base).getQuantity(); + Align = (Align > BaseAlign && Align >= 8) ? 8 : 0; + } + return ABIArgInfo::getDirect(nullptr, 0, nullptr, false, Align); } ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic, Index: clang/test/CodeGen/arm-ha-alignstack.c =================================================================== --- /dev/null +++ clang/test/CodeGen/arm-ha-alignstack.c @@ -0,0 +1,114 @@ +// RUN: %clang_cc1 -triple armv7-eabi -emit-llvm %s -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-SOFT +// RUN: %clang_cc1 -triple armv7-eabi -target-abi aapcs -mfloat-abi hard -emit-llvm %s -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-HARD +// REQUIRES: arm-registered-target + +// CHECK: %struct.S0 = type { [4 x float] } +// CHECK: %struct.S1 = type { [2 x float] } +// CHECK: %struct.S2 = type { [4 x float] } +// CHECK: %struct.D0 = type { [2 x double] } +// CHECK: %struct.D1 = type { [2 x double] } +// CHECK: %struct.D2 = type { [4 x double] } + +typedef struct { + float v[4]; +} S0; + +float f0(S0 s) { +// CHECK-SOFT: define{{.*}} float @f0([4 x i32] %s.coerce) +// CHECK-HARD: define{{.*}} arm_aapcs_vfpcc float @f0(%struct.S0 %s.coerce) + return s.v[0]; +} + +float f0call() { + S0 s = {0.0f, }; + return f0(s); +// CHECK-SOFT: call float @f0([4 x i32] +// CHECK-HARD: call arm_aapcs_vfpcc float @f0(%struct.S0 +} + +typedef struct { + __attribute__((aligned(8))) float v[2]; +} S1; + +float f1(S1 s) { +// CHECK-SOFT: define{{.*}} float @f1([1 x i64] +// CHECK-HARD: define{{.*}} arm_aapcs_vfpcc float @f1(%struct.S1 alignstack(8) + return s.v[0]; +} + +float f1call() { + S1 s = {0.0f, }; + return f1(s); +// CHECK-SOFT: call float @f1([1 x i64 +// CHECK-HARD: call arm_aapcs_vfpcc float @f1(%struct.S1 alignstack(8) +} + +typedef struct { + __attribute__((aligned(16))) float v[4]; +} S2; + +float f2(S2 s) { +// CHECK-SOFT: define{{.*}} float @f2([2 x i64] +// CHECK-HARD: define{{.*}} arm_aapcs_vfpcc float @f2(%struct.S2 alignstack(8) + return s.v[0]; +} + +float f2call() { + S2 s = {0.0f, }; + return f2(s); +// CHECK-SOFT: call float @f2([2 x i64] +// CHECK-HARD: call arm_aapcs_vfpcc float @f2(%struct.S2 alignstack(8) +} + +typedef struct { + double v[2]; +} D0; + +double g0(D0 d) { +// CHECK-SOFT: define{{.*}} double @g0([2 x i64] +// CHECK-HARD: define{{.*}} arm_aapcs_vfpcc double @g0(%struct.D0 %d.coerce + return d.v[0]; +} + +double g0call() { + D0 d = {0.0, }; + return g0(d); +// CHECK-SOFT: call double @g0([2 x i64] +// CHECK-HARD: call arm_aapcs_vfpcc double @g0(%struct.D0 %1 +} + +typedef struct { + __attribute__((aligned(16))) double v[2]; +} D1; + +double g1(D1 d) { +// CHECK-SOFT: define{{.*}} double @g1([2 x i64] +// CHECK-HARD: define{{.*}} arm_aapcs_vfpcc double @g1(%struct.D1 alignstack(8) + return d.v[0]; +} + +double g1call() { + D1 d = {0.0, }; + return g1(d); +// CHECK-SOFT: call double @g1([2 x i64] +// CHECK-HARD: call arm_aapcs_vfpcc double @g1(%struct.D1 alignstack(8) +} + +typedef struct { + __attribute__((aligned(32))) double v[4]; +} D2; + +double g2(D2 d) { +// CHECK-SOFT: define{{.*}} double @g2([4 x i64] +// CHECK-HARD: define{{.*}} arm_aapcs_vfpcc double @g2(%struct.D2 alignstack(8) + return d.v[0]; +} + +double g2call() { + D2 d = {0.0, }; + return g2(d); +// CHECK-SOFT: call double @g2([4 x i64] +// CHECK-HARD: call arm_aapcs_vfpcc double @g2(%struct.D2 alignstack(8) +} Index: llvm/lib/Target/ARM/ARMCallingConv.cpp =================================================================== --- llvm/lib/Target/ARM/ARMCallingConv.cpp +++ llvm/lib/Target/ARM/ARMCallingConv.cpp @@ -256,22 +256,26 @@ } PendingMembers.clear(); return true; - } else if (LocVT != MVT::i32) + } + + if (LocVT != MVT::i32) RegList = SRegList; // Mark all regs as unavailable (AAPCS rule C.2.vfp for VFP, C.6 for core) for (auto Reg : RegList) State.AllocateReg(Reg); + // Clamp the alignment between 4 and 8. + if (State.getMachineFunction().getSubtarget().isTargetAEABI()) + Alignment = ArgFlags.getNonZeroMemAlign() <= 4 ? Align(4) : Align(8); + // After the first item has been allocated, the rest are packed as tightly as // possible. (E.g. an incoming i64 would have starting Align of 8, but we'll // be allocating a bunch of i32 slots). - const Align RestAlign = std::min(Alignment, Align(Size)); - for (auto &It : PendingMembers) { It.convertToMem(State.AllocateStack(Size, Alignment)); State.addLoc(It); - Alignment = RestAlign; + Alignment = Align(1); } // All pending members have now been allocated Index: llvm/test/CodeGen/ARM/ha-alignstack-call.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/ARM/ha-alignstack-call.ll @@ -0,0 +1,343 @@ +; RUN: llc --mtriple=armv7-eabihf %s -o - | FileCheck %s --enable-var-scope + +%struct.S0 = type { [4 x float] } +%struct.S1 = type { [2 x float] } +%struct.S2 = type { [4 x float] } +%struct.D0 = type { [2 x double] } +%struct.D1 = type { [2 x double] } +%struct.D2 = type { [4 x double] } + +; pass in regs +declare dso_local float @f0_0(double, double, double, double, double, double, %struct.S0) local_unnamed_addr #0 +define dso_local float @f0_0_call() local_unnamed_addr #0 { +entry: + %call = tail call float @f0_0(double 0.000000e+00, double 1.000000e-01, double 2.000000e-01, double 3.000000e-01, double 4.000000e-01, double 5.000000e-01, %struct.S0 { [4 x float] [float 0x3FE3333340000000, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00] }) #0 + ret float %call +} +; CHECK-LABEL: f0_0_call: +; CHECK: vldr s12, .L[[L:.*]] +; CHECK: b f0_0 +; CHECK: .L[[L]]: +; CHECK-NEXT: .long 0x3f19999a + +; pass in memory, no split +declare dso_local float @f0_1(double, double, double, double, double, double, float, %struct.S0) local_unnamed_addr #0 +define dso_local float @f0_1_call() local_unnamed_addr #0 { +entry: + %call = tail call float @f0_1(double 0.000000e+00, double 1.000000e-01, double 2.000000e-01, double 3.000000e-01, double 4.000000e-01, double 5.000000e-01, float 0x3FE3333340000000, %struct.S0 { [4 x float] [float 0x3FE6666660000000, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00] }) #0 + ret float %call +} +; CHECK-LABEL: f0_1_call: +; CHECK: movw r1, #13107 +; CHECK: mov r0, #0 +; CHECK: movt r1, #16179 +; CHECK-DAG: str r1, [sp] +; CHECK-DAG: str r0, [sp, #4] +; CHECK-DAG: str r0, [sp, #8] +; CHECK-DAG: str r0, [sp, #12] +; CHECK: bl f0_1 + +; pass memory, alignment 4 +declare dso_local float @f0_2(double, double, double, double, double, double, double, double, float, %struct.S0) local_unnamed_addr #0 +define dso_local float @f0_2_call() local_unnamed_addr #0 { +entry: + %call = tail call float @f0_2(double 0.000000e+00, double 1.000000e-01, double 2.000000e-01, double 3.000000e-01, double 4.000000e-01, double 5.000000e-01, double 6.000000e-01, double 0x3FE6666666666666, float 0x3FE99999A0000000, %struct.S0 { [4 x float] [float 0x3FECCCCCC0000000, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00] }) #0 + ret float %call +} +; CHECK-LABEL: f0_2_call: +; CHECK: movw r1, #26214 +; CHECK: movw r2, #52429 +; CHECK: mov r0, #0 +; CHECK: movt r1, #16230 +; CHECK: movt r2, #16204 +; CHECK-DAG: str r2, [sp] +; CHECK-DAG: str r1, [sp, #4] +; CHECK-DAG: str r0, [sp, #8] +; CHECK-DAG: str r0, [sp, #12] +; CHECK-DAG: str r0, [sp, #16] +; CHECK: bl f0_2 + +; pass in regs +declare dso_local float @f1_0(double, double, double, double, double, double, double, %struct.S1 alignstack(8)) local_unnamed_addr #0 +define dso_local float @f1_0_call() local_unnamed_addr #0 { +entry: + %call = tail call float @f1_0(double 0.000000e+00, double 1.000000e-01, double 2.000000e-01, double 3.000000e-01, double 4.000000e-01, double 5.000000e-01, double 6.000000e-01, %struct.S1 alignstack(8) { [2 x float] [float 0x3FE6666660000000, float 0.000000e+00] }) #0 + ret float %call +} +; CHECK-LABEL: f1_0_call: +; CHECK-DAG: vldr s14, .L[[L0:.*]] +; CHECK-DAG: vldr s15, .L[[L1:.*]] +; CHECK: b f1_0 +; CHECK: .L[[L0]]: +; CHECK-NEXT: .long 0x3f333333 +; CHECK: .L[[L1:.*]]: +; CHECK-NEXT: .long 0x00000000 + +; pass in memory, no split +declare dso_local float @f1_1(double, double, double, double, double, double, double, float, %struct.S1 alignstack(8)) local_unnamed_addr #0 +define dso_local float @f1_1_call() local_unnamed_addr #0 { +entry: + %call = tail call float @f1_1(double 0.000000e+00, double 1.000000e-01, double 2.000000e-01, double 3.000000e-01, double 4.000000e-01, double 5.000000e-01, double 6.000000e-01, float 0x3FE6666660000000, %struct.S1 alignstack(8) { [2 x float] [float 0x3FE99999A0000000, float 0.000000e+00] }) #0 + ret float %call +} +; CHECK-LABEL: f1_1_call: +; CHECK: movw r1, #52429 +; CHECK: mov r0, #0 +; CHECK: movt r1, #16204 +; CHECK-DAG: str r1, [sp] +; CHECK-DAG: str r0, [sp, #4] +; CHECK: bl f1_1 + +; pass in memory, alignment 8 +declare dso_local float @f1_2(double, double, double, double, double, double, double, double, float, %struct.S1 alignstack(8)) local_unnamed_addr #0 +define dso_local float @f1_2_call() local_unnamed_addr #0 { +entry: + %call = tail call float @f1_2(double 0.000000e+00, double 1.000000e-01, double 2.000000e-01, double 3.000000e-01, double 4.000000e-01, double 5.000000e-01, double 6.000000e-01, double 0x3FE6666666666666, float 0x3FE99999A0000000, %struct.S1 alignstack(8) { [2 x float] [float 0x3FECCCCCC0000000, float 0.000000e+00] }) #0 + ret float %call +} +; CHECK-LABEL: f1_2_call: +; CHECK-DAG: mov r0, #0 +; CHECK-DAG: movw r1, #26214 +; CHECK: str r0, [sp, #12] +; CHECK: movw r0, #52429 +; CHECK: movt r1, #16230 +; CHECK: movt r0, #16204 +; CHECK-DAG: str r1, [sp, #8] +; CHECK-DAG: str r0, [sp] +; CHECK: bl f1_2 + + +; pass in registers +declare dso_local float @f2_0(double, double, double, double, double, double, %struct.S2 alignstack(8)) local_unnamed_addr #0 +define dso_local float @f2_0_call() local_unnamed_addr #0 { +entry: + %call = tail call float @f2_0(double 0.000000e+00, double 1.000000e-01, double 2.000000e-01, double 3.000000e-01, double 4.000000e-01, double 5.000000e-01, %struct.S2 alignstack(8) { [4 x float] [float 0x3FE3333340000000, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00] }) #0 + ret float %call +} +; CHECK-LABEL: f2_0_call: +; CHECK-DAG: vldr s12, .L[[L0:.*]] +; CHECK-DAG: vldr s13, .L[[L1:.*]] +; CHECK-DAG: vmov.f32 s14, s13 +; CHECK-DAG: vmov.f32 s15, s13 +; CHECK: b f2_0 +; CHECK: .L[[L0]]: +; CHECK-NEXT: .long 0x3f19999a +; CHECK: .L[[L1]]: +; CHECK-NEXT: .long 0x00000000 + +; pass in memory, no split +declare dso_local float @f2_1(double, double, double, double, double, double, float, %struct.S2 alignstack(8)) local_unnamed_addr #0 +define dso_local float @f2_1_call() local_unnamed_addr #0 { +entry: + %call = tail call float @f2_1(double 0.000000e+00, double 1.000000e-01, double 2.000000e-01, double 3.000000e-01, double 4.000000e-01, double 5.000000e-01, float 0x3FE3333340000000, %struct.S2 alignstack(8) { [4 x float] [float 0x3FE6666660000000, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00] }) #0 + ret float %call +} +; CHECK-LABEL: f2_1_call: +; CHECK: movw r1, #13107 +; CHECK: mov r0, #0 +; CHECK: movt r1, #16179 +; CHECK: str r1, [sp] +; CHECK: str r0, [sp, #4] +; CHECK: vldr s12, .L[[L:.*]] +; CHECK: str r0, [sp, #8] +; CHECK: str r0, [sp, #12] +; CHECK: bl f2_1 +; CHECK: .L[[L]]: +; CHECK-NEXT: .long 0x3f19999a + +; pass in memory, alignment 8 +declare dso_local float @f2_2(double, double, double, double, double, double, double, double, float, %struct.S2 alignstack(8)) local_unnamed_addr #0 +define dso_local float @f2_2_call() local_unnamed_addr #0 { +entry: + %call = tail call float @f2_2(double 0.000000e+00, double 1.000000e-01, double 2.000000e-01, double 3.000000e-01, double 4.000000e-01, double 5.000000e-01, double 6.000000e-01, double 0x3FE6666666666666, float 0x3FE99999A0000000, %struct.S2 alignstack(8) { [4 x float] [float 0x3FECCCCCC0000000, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00] }) #0 + ret float %call +} +; CHECK-LABEL: f2_2_call: +; CHECK: mov r0, #0 +; CHECK: movw r1, #26214 +; CHECK: str r0, [sp, #12] +; CHECK: str r0, [sp, #16] +; CHECK: movt r1, #16230 +; CHECK: str r0, [sp, #20] +; CHECK: movw r0, #52429 +; CHECK: movt r0, #16204 +; CHECK: str r1, [sp, #8] +; CHECK: str r0, [sp] +; CHECK: bl f2_2 + +; pass in registers +declare dso_local double @g0_0(double, double, double, double, double, double, %struct.D0) local_unnamed_addr #0 +define dso_local double @g0_0_call() local_unnamed_addr #0 { +entry: + %call = tail call double @g0_0(double 0.000000e+00, double 1.000000e-01, double 2.000000e-01, double 3.000000e-01, double 4.000000e-01, double 5.000000e-01, %struct.D0 { [2 x double] [double 6.000000e-01, double 0.000000e+00] }) #0 + ret double %call +} +; CHECK-LABEL: g0_0_call: +; CHECK: vldr d6, .L[[L:.*]] +; CHECK: b g0_0 +; CHECK: .L[[L]] +; CHECK-NEXT: long 858993459 +; CHECK-NEXT: long 1071854387 + +; pass in memory, no split +declare dso_local double @g0_1(double, double, double, double, double, double, double, %struct.D0) local_unnamed_addr #0 +define dso_local double @g0_1_call() local_unnamed_addr #0 { +entry: + %call = tail call double @g0_1(double 0.000000e+00, double 1.000000e-01, double 2.000000e-01, double 3.000000e-01, double 4.000000e-01, double 5.000000e-01, double 6.000000e-01, %struct.D0 { [2 x double] [double 0x3FE6666666666666, double 0.000000e+00] }) #0 + ret double %call +} +; CHECK-LABEL: g0_1_call: +; CHECK: movw r0, #26214 +; CHECK: movw r1, #26214 +; CHECK: mov r2, #0 +; CHECK: movt r0, #16358 +; CHECK: movt r1, #26214 +; CHECK: str r1, [sp] +; CHECK: stmib sp, {r0, r2} +; CHECK: str r2, [sp, #12] +; CHECK: bl g0_1 + +; pass in memory, alignment 8 +declare dso_local double @g0_2(double, double, double, double, double, double, double, double, float, %struct.D0) local_unnamed_addr #0 +define dso_local double @g0_2_call() local_unnamed_addr #0 { +entry: + %call = tail call double @g0_2(double 0.000000e+00, double 1.000000e-01, double 2.000000e-01, double 3.000000e-01, double 4.000000e-01, double 5.000000e-01, double 6.000000e-01, double 0x3FE6666666666666, float 0x3FE99999A0000000, %struct.D0 { [2 x double] [double 9.000000e-01, double 0.000000e+00] }) #0 + ret double %call +} +; CHECK-LABEL: g0_2_call: +; CHECK: movw r0, #52428 +; CHECK: movt r0, #16364 +; CHECK: movw r1, #52429 +; CHECK: str r0, [sp, #12] +; CHECK: movw r0, #52429 +; CHECK: mov r2, #0 +; CHECK: movt r1, #52428 +; CHECK: movt r0, #16204 +; CHECK: str r1, [sp, #8] +; CHECK: str r2, [sp, #16] +; CHECK: str r2, [sp, #20] +; CHECK: str r0, [sp] +; CHECK: bl g0_2 + +; pass in registers +declare dso_local double @g1_0(double, double, double, double, double, double, %struct.D1 alignstack(8)) local_unnamed_addr #0 +define dso_local double @g1_0_call() local_unnamed_addr #0 { +entry: + %call = tail call double @g1_0(double 0.000000e+00, double 1.000000e-01, double 2.000000e-01, double 3.000000e-01, double 4.000000e-01, double 5.000000e-01, %struct.D1 alignstack(8) { [2 x double] [double 6.000000e-01, double 0.000000e+00] }) #0 + ret double %call +} +; CHECK-LABEL: g1_0_call: +; CHECK-DAG: vmov.i32 d7, #0x0 +; CHECK-DAG: vldr d6, .L[[L:.*]] +; CHECK: b g1_0 +; CHECK: .L[[L]]: +; CHECK-NEXT: .long 858993459 +; CHECK-NEXT: .long 107185438 + +; pass in memory, no split +declare dso_local double @g1_1(double, double, double, double, double, double, double, %struct.D1 alignstack(8)) local_unnamed_addr #0 +define dso_local double @g1_1_call() local_unnamed_addr #0 { +entry: + %call = tail call double @g1_1(double 0.000000e+00, double 1.000000e-01, double 2.000000e-01, double 3.000000e-01, double 4.000000e-01, double 5.000000e-01, double 6.000000e-01, %struct.D1 alignstack(8) { [2 x double] [double 0x3FE6666666666666, double 0.000000e+00] }) #0 + ret double %call +} +; CHECK-LABEL: g1_1_call: +; CHECK: movw r0, #26214 +; CHECK: movw r1, #26214 +; CHECK: mov r2, #0 +; CHECK: movt r0, #16358 +; CHECK: movt r1, #26214 +; CHECK: str r1, [sp] +; CHECK: stmib sp, {r0, r2} +; CHECK: str r2, [sp, #12] +; CHECK: bl g1_1 + +; pass in memory, alignment 8 +declare dso_local double @g1_2(double, double, double, double, double, double, double, double, float, %struct.D1 alignstack(8)) local_unnamed_addr #0 +define dso_local double @g1_2_call() local_unnamed_addr #0 { +entry: + %call = tail call double @g1_2(double 0.000000e+00, double 1.000000e-01, double 2.000000e-01, double 3.000000e-01, double 4.000000e-01, double 5.000000e-01, double 6.000000e-01, double 0x3FE6666666666666, float 0x3FE99999A0000000, %struct.D1 alignstack(8) { [2 x double] [double 9.000000e-01, double 0.000000e+00] }) #0 + ret double %call +} +; CHECK-LABEL: g1_2_call: +; CHECK: movw r0, #52428 +; CHECK: movt r0, #16364 +; CHECK: movw r1, #52429 +; CHECK: str r0, [sp, #12] +; CHECK: movw r0, #52429 +; CHECK: mov r2, #0 +; CHECK: movt r1, #52428 +; CHECK: movt r0, #16204 +; CHECK: str r1, [sp, #8] +; CHECK: str r2, [sp, #16] +; CHECK: str r2, [sp, #20] +; CHECK: str r0, [sp] +; CHECK: bl g1_2 + +; pass in registers +declare dso_local double @g2_0(double, double, double, double, %struct.D2 alignstack(8)) local_unnamed_addr #0 +define dso_local double @g2_0_call() local_unnamed_addr #0 { +entry: + %call = tail call double @g2_0(double 0.000000e+00, double 1.000000e-01, double 2.000000e-01, double 3.000000e-01, %struct.D2 alignstack(8) { [4 x double] [double 4.000000e-01, double 0.000000e+00, double 0.000000e+00, double 0.000000e+00] }) #0 + ret double %call +} +; CHECK-LABEL: g2_0_call: +; CHECK-DAG: vldr d4, .L[[L:.*]] +; CHECK-DAG: vmov.i32 d5, #0x0 +; CHECK-DAG: vmov.i32 d6, #0x0 +; CHECK-DAG: vmov.i32 d7, #0x0 +; CHECK: b g2_0 +; CHECK: .L[[L]]: +; CHECK-NEXT: .long 2576980378 +; CHECK-NEXT: .long 1071225241 + +; pass in memory, no split +; [sp] [sp + 4] = 0x00000000 0x3fe00000 = .5 +; [sp + 8] [sp + 12] = 0 0 = .0 +; ... +declare dso_local double @g2_1(double, double, double, double, double, %struct.D2 alignstack(8)) local_unnamed_addr #0 +define dso_local double @g2_1_call() local_unnamed_addr #0 { +entry: + %call = tail call double @g2_1(double 0.000000e+00, double 1.000000e-01, double 2.000000e-01, double 3.000000e-01, double 4.000000e-01, %struct.D2 alignstack(8) { [4 x double] [double 5.000000e-01, double 0.000000e+00, double 0.000000e+00, double 0.000000e+00] }) #0 + ret double %call +} +; CHECK-LABEL: g2_1_call: +; CHECK: movw r0, #0 +; CHECK: mov r1, #0 +; CHECK: movt r0, #16352 +; CHECK: str r1, [sp] +; CHECK: stmib sp, {r0, r1} +; CHECK: str r1, [sp, #12] +; CHECK: str r1, [sp, #16] +; CHECK: str r1, [sp, #20] +; CHECK: str r1, [sp, #24] +; CHECK: str r1, [sp, #28] +; CHECK: bl g2_1 + +; pass in memory, alignment 8 +declare dso_local double @g2_2(double, double, double, double, double, double, double, double, float, %struct.D2 alignstack(8)) local_unnamed_addr #0 +define dso_local double @g2_2call() local_unnamed_addr #0 { +entry: + %call = tail call double @g2_2(double 0.000000e+00, double 1.000000e-01, double 2.000000e-01, double 3.000000e-01, double 4.000000e-01, double 5.000000e-01, double 6.000000e-01, double 0x3FE6666666666666, float 0x3FE99999A0000000, %struct.D2 alignstack(8) { [4 x double] [double 9.000000e-01, double 0.000000e+00, double 0.000000e+00, double 0.000000e+00] }) #0 + ret double %call +} +; CHECK-LABEL: g2_2call: +; CHECK: movw r0, #52428 +; CHECK: movt r0, #16364 +; CHECK: movw r1, #52429 +; CHECK: str r0, [sp, #12] +; CHECK: movw r0, #52429 +; CHECK: mov r2, #0 +; CHECK: movt r1, #52428 +; CHECK: movt r0, #16204 +; CHECK: str r1, [sp, #8] +; CHECK: str r2, [sp, #16] +; CHECK: str r2, [sp, #20] +; CHECK: str r2, [sp, #24] +; CHECK: str r2, [sp, #28] +; CHECK: str r2, [sp, #32] +; CHECK: str r2, [sp, #36] +; CHECK: str r0, [sp] +; CHECK: bl g2_2 + +attributes #0 = { nounwind "target-cpu"="generic" "target-features"="+armv7-a,+d32,+dsp,+fp64,+neon,+strict-align,+vfp2,+vfp2sp,+vfp3,+vfp3d16,+vfp3d16sp,+vfp3sp,-thumb-mode" } Index: llvm/test/CodeGen/ARM/ha-alignstack.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/ARM/ha-alignstack.ll @@ -0,0 +1,190 @@ +; RUN: llc --mtriple armv7-eabihf %s -o - | FileCheck %s + +%struct.S0 = type { [4 x float] } +%struct.S1 = type { [2 x float] } +%struct.S2 = type { [4 x float] } +%struct.D0 = type { [2 x double] } +%struct.D1 = type { [2 x double] } +%struct.D2 = type { [4 x double] } + +; pass in registers +define dso_local float @f0_0(double %d0, double %d1, double %d2, double %d3, double %d4, double %d5, %struct.S0 %s.coerce) local_unnamed_addr #0 { +entry: + %s.coerce.fca.0.0.extract = extractvalue %struct.S0 %s.coerce, 0, 0 + ret float %s.coerce.fca.0.0.extract +} +; CHECK-LABEL: f0_0: +; CHECK: vmov.f32 s0, s12 +; CHECK-NEXT: bx lr + +; pass in memory, no memory/regs split +define dso_local float @f0_1(double %d0, double %d1, double %d2, double %d3, double %d4, double %d5, float %x, %struct.S0 %s.coerce) local_unnamed_addr #0 { +entry: + %s.coerce.fca.0.0.extract = extractvalue %struct.S0 %s.coerce, 0, 0 + ret float %s.coerce.fca.0.0.extract +} +; CHECK-LABEL: f0_1: +; CHECK: vldr s0, [sp] +; CHECK-NEXT: bx lr + +; pass in memory, alignment 4 +define dso_local float @f0_2(double %d0, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, double %d7, float %x, %struct.S0 %s.coerce) local_unnamed_addr #0 { +entry: + %s.coerce.fca.0.0.extract = extractvalue %struct.S0 %s.coerce, 0, 0 + ret float %s.coerce.fca.0.0.extract +} +; CHECK-LABEL: f0_2: +; CHECK: vldr s0, [sp, #4] +; CHECK-NEXT: bx lr + +; pass in registers +define dso_local float @f1_0(double %d0, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, %struct.S1 alignstack(8) %s.coerce) local_unnamed_addr #0 { +entry: + %s.coerce.fca.0.0.extract = extractvalue %struct.S1 %s.coerce, 0, 0 + ret float %s.coerce.fca.0.0.extract +} +; CHECK-LABEL: f1_0: +; CHECK: vmov.f32 s0, s14 +; CHECK-NEXT: bx lr + +; pass in memory, no memory/regs split +define dso_local float @f1_1(double %d0, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, float %x, %struct.S1 alignstack(8) %s.coerce) local_unnamed_addr #0 { +entry: + %s.coerce.fca.0.0.extract = extractvalue %struct.S1 %s.coerce, 0, 0 + ret float %s.coerce.fca.0.0.extract +} +; CHECK-LABEL: f1_1: +; CHECK: vldr s0, [sp] +; CHECK-NEXT: bx lr + +; pass in memory, alignment 8 +define dso_local float @f1_2(double %d0, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, double %d7, float %x, %struct.S1 alignstack(8) %s.coerce) local_unnamed_addr #0 { +entry: + %s.coerce.fca.0.0.extract = extractvalue %struct.S1 %s.coerce, 0, 0 + ret float %s.coerce.fca.0.0.extract +} +; CHECK-LABEL: f1_2: +; CHECK: vldr s0, [sp, #8] +; CHECK-NEXT: bx lr + +; pass in registers +define dso_local float @f2_0(double %d0, double %d1, double %d2, double %d3, double %d4, double %d5, %struct.S2 alignstack(8) %s.coerce) local_unnamed_addr #0 { +entry: + %s.coerce.fca.0.0.extract = extractvalue %struct.S2 %s.coerce, 0, 0 + ret float %s.coerce.fca.0.0.extract +} +; CHECK-LABEL: f2_0: +; CHECK: vmov.f32 s0, s12 +; CHECK-NEXT: bx lr + +; pass in memory, no memory/regs split +define dso_local float @f2_1(double %d0, double %d1, double %d2, double %d3, double %d4, double %d5, float %x, %struct.S2 alignstack(8) %s.coerce) local_unnamed_addr #0 { +entry: + %s.coerce.fca.0.0.extract = extractvalue %struct.S2 %s.coerce, 0, 0 + ret float %s.coerce.fca.0.0.extract +} +; CHECK-LABEL: f2_1: +; CHECK: vldr s0, [sp] +; CHECK-NEXT: bx lr + +; pass in memory, alignment 8 +define dso_local float @f2_2(double %d0, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, double %d7, float %x, %struct.S2 alignstack(8) %s.coerce) local_unnamed_addr #0 { +entry: + %s.coerce.fca.0.0.extract = extractvalue %struct.S2 %s.coerce, 0, 0 + ret float %s.coerce.fca.0.0.extract +} +; CHECK-LABEL: f2_2: +; CHECK: vldr s0, [sp, #8] +; CHECK-NEXT: bx lr + +; pass in registers +define dso_local double @g0_0(double %d0, double %d1, double %d2, double %d3, double %d4, double %d5, %struct.D0 %s.coerce) local_unnamed_addr #0 { +entry: + %s.coerce.fca.0.0.extract = extractvalue %struct.D0 %s.coerce, 0, 0 + ret double %s.coerce.fca.0.0.extract +} +; CHECK-LABEL: g0_0: +; CHECK: vmov.f64 d0, d6 +; CHECK-NEXT: bx lr + +; pass in memory, no memory/regs split +define dso_local double @g0_1(double %d0, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, %struct.D0 %s.coerce) local_unnamed_addr #0 { +entry: + %s.coerce.fca.0.0.extract = extractvalue %struct.D0 %s.coerce, 0, 0 + ret double %s.coerce.fca.0.0.extract +} +; CHECK-LABEL: g0_1: +; CHECK: vldr d0, [sp] +; CHECK-NEXT: bx lr + +; pass in memory, alignment 8 +define dso_local double @g0_2(double %d0, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, double %d7, float %x, %struct.D0 %s.coerce) local_unnamed_addr #0 { +entry: + %s.coerce.fca.0.0.extract = extractvalue %struct.D0 %s.coerce, 0, 0 + ret double %s.coerce.fca.0.0.extract +} +; CHECK-LABEL: g0_2: +; CHECK: vldr d0, [sp, #8] +; CHECK-NEXT: bx lr + +; pass in registers +define dso_local double @g1_0(double %d0, double %d1, double %d2, double %d3, double %d4, double %d5, %struct.D1 alignstack(8) %s.coerce) local_unnamed_addr #0 { +entry: + %s.coerce.fca.0.0.extract = extractvalue %struct.D1 %s.coerce, 0, 0 + ret double %s.coerce.fca.0.0.extract +} +; CHECK-LABEL: g1_0: +; CHECK: vmov.f64 d0, d6 +; CHECK-NEXT: bx lr + +; pass in memory, no memory/regs split +define dso_local double @g1_1(double %d0, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, %struct.D1 alignstack(8) %s.coerce) local_unnamed_addr #0 { +entry: + %s.coerce.fca.0.0.extract = extractvalue %struct.D1 %s.coerce, 0, 0 + ret double %s.coerce.fca.0.0.extract +} +; CHECK-LABEL: g1_1: +; CHECK: vldr d0, [sp] +; CHECK-NEXT: bx lr + +; pass in memory, alignment 8 +define dso_local double @g1_2(double %d0, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, double %d7, float %x, %struct.D1 alignstack(8) %s.coerce) local_unnamed_addr #0 { +entry: + %s.coerce.fca.0.0.extract = extractvalue %struct.D1 %s.coerce, 0, 0 + ret double %s.coerce.fca.0.0.extract +} +; CHECK-LABEL: g1_2: +; CHECK: vldr d0, [sp, #8] +; CHECK-NEXT: bx lr + +; pass in registers +define dso_local double @g2_0(double %d0, double %d1, double %d2, double %d3, %struct.D2 alignstack(8) %s.coerce) local_unnamed_addr #0 { +entry: + %s.coerce.fca.0.0.extract = extractvalue %struct.D2 %s.coerce, 0, 0 + ret double %s.coerce.fca.0.0.extract +} +; CHECK-LABEL: g2_0: +; CHECK: vmov.f64 d0, d4 +; CHECK-NEXT: bx lr + +; pass in memory, no memory/regs split +define dso_local double @g2_1(double %d0, double %d1, double %d2, double %d3, double %d4, %struct.D2 alignstack(8) %s.coerce) local_unnamed_addr #0 { +entry: + %s.coerce.fca.0.0.extract = extractvalue %struct.D2 %s.coerce, 0, 0 + ret double %s.coerce.fca.0.0.extract +} +; CHECK-LABEL: g2_1: +; CHECK: vldr d0, [sp] +; CHECK-NEXT: bx lr + +; pass in memory, alignment 8 +define dso_local double @g2_2(double %d0, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, double %d7, float %x, %struct.D2 alignstack(8) %s.coerce) local_unnamed_addr #0 { +entry: + %s.coerce.fca.0.0.extract = extractvalue %struct.D2 %s.coerce, 0, 0 + ret double %s.coerce.fca.0.0.extract +} +; CHECK-LABEL: g2_2: +; CHECK: vldr d0, [sp, #8] +; CHECK-NEXT: bx lr + +attributes #0 = { "target-cpu"="generic" "target-features"="+armv7-a,+d32,+dsp,+fp64,+neon,+strict-align,+vfp2,+vfp2sp,+vfp3,+vfp3d16,+vfp3d16sp,+vfp3sp,-thumb-mode" }