1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-18 18:42:46 +02:00

[clang][AArch32] Correctly align HA arguments when passed on the stack

Analogously to https://reviews.llvm.org/D98794 this patch uses the
`alignstack` attribute to fix incorrect passing of homogeneous
aggregate (HA) arguments on AArch32. The EABI/AAPCS was recently
updated to clarify how VFP co-processor candidates are aligned:
4488e34998

Differential Revision: https://reviews.llvm.org/D100853
This commit is contained in:
Momchil Velikov 2021-05-10 14:53:21 +01:00
parent c4e864aeaf
commit fc3a821968
3 changed files with 541 additions and 4 deletions

View File

@ -256,22 +256,26 @@ static bool CC_ARM_AAPCS_Custom_Aggregate(unsigned ValNo, MVT ValVT,
}
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<ARMSubtarget>().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

View File

@ -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" }

View File

@ -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" }