mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-14 11:32:34 +00:00
AArch64/ARM64: copy byval implementation from AArch64.
It's not actually used to handle C or C++ ABI rules on ARM64, but could well be emitted by other language front-ends, so it's as well to have a sensible implementation. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@206568 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
eea662fead
commit
2f5d14af9d
@ -26,6 +26,10 @@ def CC_ARM64_AAPCS : CallingConv<[
|
||||
// An SRet is passed in X8, not X0 like a normal pointer parameter.
|
||||
CCIfSRet<CCIfType<[i64], CCAssignToRegWithShadow<[X8], [W8]>>>,
|
||||
|
||||
// Put ByVal arguments directly on the stack. Minimum size and alignment of a
|
||||
// slot is 64-bit.
|
||||
CCIfByVal<CCPassByVal<8, 8>>,
|
||||
|
||||
// Handle i1, i8, i16, i32, i64, f32, f64 and v2f64 by passing in registers,
|
||||
// up to eight each of GPR and FPR.
|
||||
CCIfType<[i1, i8, i16], CCCustom<"CC_ARM64_Custom_i1i8i16_Reg">>,
|
||||
@ -89,6 +93,10 @@ def CC_ARM64_DarwinPCS : CallingConv<[
|
||||
// An SRet is passed in X8, not X0 like a normal pointer parameter.
|
||||
CCIfSRet<CCIfType<[i64], CCAssignToRegWithShadow<[X8], [W8]>>>,
|
||||
|
||||
// Put ByVal arguments directly on the stack. Minimum size and alignment of a
|
||||
// slot is 64-bit.
|
||||
CCIfByVal<CCPassByVal<8, 8>>,
|
||||
|
||||
// Handle i1, i8, i16, i32, i64, f32, f64 and v2f64 by passing in registers,
|
||||
// up to eight each of GPR and FPR.
|
||||
CCIfType<[i1, i8, i16], CCCustom<"CC_ARM64_Custom_i1i8i16_Reg">>,
|
||||
|
@ -1574,13 +1574,26 @@ SDValue ARM64TargetLowering::LowerFormalArguments(
|
||||
assert(!Res && "Call operand has unhandled type");
|
||||
(void)Res;
|
||||
}
|
||||
|
||||
assert(ArgLocs.size() == Ins.size());
|
||||
SmallVector<SDValue, 16> ArgValues;
|
||||
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
||||
CCValAssign &VA = ArgLocs[i];
|
||||
|
||||
// Arguments stored in registers.
|
||||
if (VA.isRegLoc()) {
|
||||
if (Ins[i].Flags.isByVal()) {
|
||||
// Byval is used for HFAs in the PCS, but the system should work in a
|
||||
// non-compliant manner for larger structs.
|
||||
EVT PtrTy = getPointerTy();
|
||||
int Size = Ins[i].Flags.getByValSize();
|
||||
unsigned NumRegs = (Size + 7) / 8;
|
||||
|
||||
unsigned FrameIdx =
|
||||
MFI->CreateFixedObject(8 * NumRegs, VA.getLocMemOffset(), false);
|
||||
SDValue FrameIdxN = DAG.getFrameIndex(FrameIdx, PtrTy);
|
||||
InVals.push_back(FrameIdxN);
|
||||
|
||||
continue;
|
||||
} if (VA.isRegLoc()) {
|
||||
// Arguments stored in registers.
|
||||
EVT RegVT = VA.getLocVT();
|
||||
|
||||
SDValue ArgValue;
|
||||
@ -1988,19 +2001,31 @@ SDValue ARM64TargetLowering::LowerCall(CallLoweringInfo &CLI,
|
||||
SDValue PtrOff = DAG.getIntPtrConstant(LocMemOffset);
|
||||
PtrOff = DAG.getNode(ISD::ADD, DL, getPointerTy(), StackPtr, PtrOff);
|
||||
|
||||
// Since we pass i1/i8/i16 as i1/i8/i16 on stack and Arg is already
|
||||
// promoted to a legal register type i32, we should truncate Arg back to
|
||||
// i1/i8/i16.
|
||||
if (Arg.getValueType().isSimple() &&
|
||||
Arg.getValueType().getSimpleVT() == MVT::i32 &&
|
||||
(VA.getLocVT() == MVT::i1 || VA.getLocVT() == MVT::i8 ||
|
||||
VA.getLocVT() == MVT::i16))
|
||||
Arg = DAG.getNode(ISD::TRUNCATE, DL, VA.getLocVT(), Arg);
|
||||
if (Outs[i].Flags.isByVal()) {
|
||||
SDValue SizeNode =
|
||||
DAG.getConstant(Outs[i].Flags.getByValSize(), MVT::i64);
|
||||
SDValue Cpy = DAG.getMemcpy(
|
||||
Chain, DL, PtrOff, Arg, SizeNode, Outs[i].Flags.getByValAlign(),
|
||||
/*isVolatile = */ false,
|
||||
/*alwaysInline = */ false,
|
||||
MachinePointerInfo::getStack(LocMemOffset), MachinePointerInfo());
|
||||
|
||||
SDValue Store = DAG.getStore(Chain, DL, Arg, PtrOff,
|
||||
MachinePointerInfo::getStack(LocMemOffset),
|
||||
false, false, 0);
|
||||
MemOpChains.push_back(Store);
|
||||
MemOpChains.push_back(Cpy);
|
||||
} else {
|
||||
// Since we pass i1/i8/i16 as i1/i8/i16 on stack and Arg is already
|
||||
// promoted to a legal register type i32, we should truncate Arg back to
|
||||
// i1/i8/i16.
|
||||
if (Arg.getValueType().isSimple() &&
|
||||
Arg.getValueType().getSimpleVT() == MVT::i32 &&
|
||||
(VA.getLocVT() == MVT::i1 || VA.getLocVT() == MVT::i8 ||
|
||||
VA.getLocVT() == MVT::i16))
|
||||
Arg = DAG.getNode(ISD::TRUNCATE, DL, VA.getLocVT(), Arg);
|
||||
|
||||
SDValue Store = DAG.getStore(Chain, DL, Arg, PtrOff,
|
||||
MachinePointerInfo::getStack(LocMemOffset),
|
||||
false, false, 0);
|
||||
MemOpChains.push_back(Store);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
; RUN: llc -verify-machineinstrs < %s -mtriple=aarch64-none-linux-gnu | FileCheck --check-prefix=CHECK --check-prefix=CHECK-LE %s
|
||||
; RUN: llc -verify-machineinstrs < %s -mtriple=aarch64-none-linux-gnu | FileCheck --check-prefix=CHECK --check-prefix=CHECK-AARCH64 --check-prefix=CHECK-LE %s
|
||||
; RUN: llc -verify-machineinstrs < %s -mtriple=aarch64-none-linux-gnu -mattr=-fp-armv8 | FileCheck --check-prefix=CHECK-NOFP %s
|
||||
; RUN: llc -verify-machineinstrs < %s -mtriple=aarch64_be-none-linux-gnu | FileCheck --check-prefix=CHECK --check-prefix=CHECK-BE %s
|
||||
; RUN: llc -verify-machineinstrs < %s -mtriple=aarch64_be-none-linux-gnu -mattr=-fp-armv8 | FileCheck --check-prefix=CHECK-NOFP %s
|
||||
; RUN: llc -verify-machineinstrs < %s -mtriple=arm64-none-linux-gnu | FileCheck --check-prefix=CHECK --check-prefix=CHECK-ARM64 %s
|
||||
|
||||
%myStruct = type { i64 , i8, i32 }
|
||||
|
||||
@ -18,7 +19,7 @@ define void @take_i8s(i8 %val1, i8 %val2) {
|
||||
store i8 %val2, i8* @var8
|
||||
; Not using w1 may be technically allowed, but it would indicate a
|
||||
; problem in itself.
|
||||
; CHECK: strb w1, [{{x[0-9]+}}, #:lo12:var8]
|
||||
; CHECK: strb w1, [{{x[0-9]+}}, {{#?}}:lo12:var8]
|
||||
ret void
|
||||
}
|
||||
|
||||
@ -28,7 +29,7 @@ define void @add_floats(float %val1, float %val2) {
|
||||
; CHECK: fadd [[ADDRES:s[0-9]+]], s0, s1
|
||||
; CHECK-NOFP-NOT: fadd
|
||||
store float %newval, float* @varfloat
|
||||
; CHECK: str [[ADDRES]], [{{x[0-9]+}}, #:lo12:varfloat]
|
||||
; CHECK: str [[ADDRES]], [{{x[0-9]+}}, {{#?}}:lo12:varfloat]
|
||||
ret void
|
||||
}
|
||||
|
||||
@ -43,12 +44,12 @@ define void @take_struct(%myStruct* byval %structval) {
|
||||
; Some weird move means x0 is used for one access
|
||||
; CHECK: ldr [[REG32:w[0-9]+]], [{{x[0-9]+|sp}}, #12]
|
||||
store volatile i32 %val0, i32* @var32
|
||||
; CHECK: str [[REG32]], [{{x[0-9]+}}, #:lo12:var32]
|
||||
; CHECK: str [[REG32]], [{{x[0-9]+}}, {{#?}}:lo12:var32]
|
||||
|
||||
%val1 = load volatile i64* %addr1
|
||||
; CHECK: ldr [[REG64:x[0-9]+]], [{{x[0-9]+|sp}}]
|
||||
store volatile i64 %val1, i64* @var64
|
||||
; CHECK: str [[REG64]], [{{x[0-9]+}}, #:lo12:var64]
|
||||
; CHECK: str [[REG64]], [{{x[0-9]+}}, {{#?}}:lo12:var64]
|
||||
|
||||
ret void
|
||||
}
|
||||
@ -62,15 +63,16 @@ define void @check_byval_align(i32* byval %ignore, %myStruct* byval align 16 %st
|
||||
|
||||
%val0 = load volatile i32* %addr0
|
||||
; Some weird move means x0 is used for one access
|
||||
; CHECK: add x[[STRUCTVAL_ADDR:[0-9]+]], sp, #16
|
||||
; CHECK: ldr [[REG32:w[0-9]+]], [x[[STRUCTVAL_ADDR]], #12]
|
||||
; CHECK-AARCH64: add x[[STRUCTVAL_ADDR:[0-9]+]], sp, #16
|
||||
; CHECK-AARCH64: ldr [[REG32:w[0-9]+]], [x[[STRUCTVAL_ADDR]], #12]
|
||||
; CHECK-ARM64: ldr [[REG32:w[0-9]+]], [sp, #28]
|
||||
store i32 %val0, i32* @var32
|
||||
; CHECK: str [[REG32]], [{{x[0-9]+}}, #:lo12:var32]
|
||||
; CHECK: str [[REG32]], [{{x[0-9]+}}, {{#?}}:lo12:var32]
|
||||
|
||||
%val1 = load volatile i64* %addr1
|
||||
; CHECK: ldr [[REG64:x[0-9]+]], [sp, #16]
|
||||
store i64 %val1, i64* @var64
|
||||
; CHECK: str [[REG64]], [{{x[0-9]+}}, #:lo12:var64]
|
||||
; CHECK: str [[REG64]], [{{x[0-9]+}}, {{#?}}:lo12:var64]
|
||||
|
||||
ret void
|
||||
}
|
||||
@ -79,7 +81,7 @@ define i32 @return_int() {
|
||||
; CHECK-LABEL: return_int:
|
||||
%val = load i32* @var32
|
||||
ret i32 %val
|
||||
; CHECK: ldr w0, [{{x[0-9]+}}, #:lo12:var32]
|
||||
; CHECK: ldr w0, [{{x[0-9]+}}, {{#?}}:lo12:var32]
|
||||
; Make sure epilogue follows
|
||||
; CHECK-NEXT: ret
|
||||
}
|
||||
@ -87,7 +89,7 @@ define i32 @return_int() {
|
||||
define double @return_double() {
|
||||
; CHECK-LABEL: return_double:
|
||||
ret double 3.14
|
||||
; CHECK: ldr d0, [{{x[0-9]+}}, #:lo12:.LCPI
|
||||
; CHECK: ldr d0, [{{x[0-9]+}}, {{#?}}:lo12:.LCPI
|
||||
; CHECK-NOFP-NOT: ldr d0,
|
||||
}
|
||||
|
||||
@ -99,10 +101,10 @@ define [2 x i64] @return_struct() {
|
||||
%addr = bitcast %myStruct* @varstruct to [2 x i64]*
|
||||
%val = load [2 x i64]* %addr
|
||||
ret [2 x i64] %val
|
||||
; CHECK: ldr x0, [{{x[0-9]+}}, #:lo12:varstruct]
|
||||
; CHECK-DAG: ldr x0, [{{x[0-9]+}}, {{#?}}:lo12:varstruct]
|
||||
; Odd register regex below disallows x0 which we want to be live now.
|
||||
; CHECK: add {{x[1-9][0-9]*}}, {{x[1-9][0-9]*}}, #:lo12:varstruct
|
||||
; CHECK-NEXT: ldr x1, [{{x[1-9][0-9]*}}, #8]
|
||||
; CHECK-DAG: add {{x[1-9][0-9]*}}, {{x[1-9][0-9]*}}, {{#?}}:lo12:varstruct
|
||||
; CHECK: ldr x1, [{{x[1-9][0-9]*}}, #8]
|
||||
; Make sure epilogue immediately follows
|
||||
; CHECK-NEXT: ret
|
||||
}
|
||||
@ -139,11 +141,11 @@ define i32 @struct_on_stack(i8 %var0, i16 %var1, i32 %var2, i64 %var3, i128 %var
|
||||
store volatile i64 %val64, i64* @var64
|
||||
; Currently nothing on local stack, so struct should be at sp
|
||||
; CHECK: ldr [[VAL64:x[0-9]+]], [sp]
|
||||
; CHECK: str [[VAL64]], [{{x[0-9]+}}, #:lo12:var64]
|
||||
; CHECK: str [[VAL64]], [{{x[0-9]+}}, {{#?}}:lo12:var64]
|
||||
|
||||
store volatile double %notstacked, double* @vardouble
|
||||
; CHECK-NOT: ldr d0
|
||||
; CHECK: str d0, [{{x[0-9]+}}, #:lo12:vardouble
|
||||
; CHECK: str d0, [{{x[0-9]+}}, {{#?}}:lo12:vardouble
|
||||
; CHECK-NOFP-NOT: str d0,
|
||||
|
||||
%retval = load volatile i32* %stacked
|
||||
@ -159,28 +161,28 @@ define void @stacked_fpu(float %var0, double %var1, float %var2, float %var3,
|
||||
store float %var8, float* @varfloat
|
||||
; Beware as above: the offset would be different on big-endian
|
||||
; machines if the first ldr were changed to use s-registers.
|
||||
; CHECK: ldr d[[VALFLOAT:[0-9]+]], [sp]
|
||||
; CHECK: str s[[VALFLOAT]], [{{x[0-9]+}}, #:lo12:varfloat]
|
||||
; CHECK: ldr {{[ds]}}[[VALFLOAT:[0-9]+]], [sp]
|
||||
; CHECK: str s[[VALFLOAT]], [{{x[0-9]+}}, {{#?}}:lo12:varfloat]
|
||||
|
||||
ret void
|
||||
}
|
||||
|
||||
; 128-bit integer types should be passed in xEVEN, xODD rather than
|
||||
; the reverse. In this case x2 and x3. Nothing should use x1.
|
||||
define i32 @check_i128_regalign(i32 %val0, i128 %val1, i32 %val2) {
|
||||
; CHECK: check_i128_regalign
|
||||
define i64 @check_i128_regalign(i32 %val0, i128 %val1, i64 %val2) {
|
||||
; CHECK-LABEL: check_i128_regalign
|
||||
store i128 %val1, i128* @var128
|
||||
; CHECK: str x2, [{{x[0-9]+}}, #:lo12:var128]
|
||||
; CHECK: str x3, [{{x[0-9]+}}, #8]
|
||||
; CHECK-DAG: str x2, [{{x[0-9]+}}, {{#?}}:lo12:var128]
|
||||
; CHECK-DAG: str x3, [{{x[0-9]+}}, #8]
|
||||
|
||||
ret i32 %val2
|
||||
ret i64 %val2
|
||||
; CHECK: mov x0, x4
|
||||
}
|
||||
|
||||
define void @check_i128_stackalign(i32 %val0, i32 %val1, i32 %val2, i32 %val3,
|
||||
i32 %val4, i32 %val5, i32 %val6, i32 %val7,
|
||||
i32 %stack1, i128 %stack2) {
|
||||
; CHECK: check_i128_stackalign
|
||||
; CHECK-LABEL: check_i128_stackalign
|
||||
store i128 %stack2, i128* @var128
|
||||
; Nothing local on stack in current codegen, so first stack is 16 away
|
||||
; CHECK-LE: add x[[REG:[0-9]+]], sp, #16
|
||||
@ -188,7 +190,9 @@ define void @check_i128_stackalign(i32 %val0, i32 %val1, i32 %val2, i32 %val3,
|
||||
; CHECK-BE: ldr {{x[0-9]+}}, [sp, #24]
|
||||
|
||||
; Important point is that we address sp+24 for second dword
|
||||
; CHECK: ldr {{x[0-9]+}}, [sp, #16]
|
||||
; CHECK-AARCH64: ldr {{x[0-9]+}}, [sp, #16]
|
||||
|
||||
; CHECK-ARM64: ldp {{x[0-9]+}}, {{x[0-9]+}}, [sp, #16]
|
||||
ret void
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
; RUN: llc -verify-machineinstrs < %s -mtriple=aarch64-none-linux-gnu | FileCheck %s
|
||||
; RUN: llc -verify-machineinstrs < %s -mtriple=aarch64-none-linux-gnu | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-AARCH64
|
||||
; RUN: llc -verify-machineinstrs < %s -mtriple=aarch64_be-none-linux-gnu | FileCheck --check-prefix=CHECK --check-prefix=CHECK-BE %s
|
||||
; RUN: llc -verify-machineinstrs < %s -mtriple=aarch64-none-linux-gnu -mattr=-fp-armv8 | FileCheck --check-prefix=CHECK-NOFP %s
|
||||
; RUN: llc -verify-machineinstrs < %s -mtriple=aarch64_be-none-linux-gnu -mattr=-fp-armv8 | FileCheck --check-prefix=CHECK-BE --check-prefix=CHECK-NOFP %s
|
||||
; RUN: llc -verify-machineinstrs < %s -mtriple=arm64-none-linux-gnu | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ARM64
|
||||
|
||||
%myStruct = type { i64 , i8, i32 }
|
||||
|
||||
@ -24,15 +25,15 @@ define void @simple_args() {
|
||||
%char1 = load i8* @var8
|
||||
%char2 = load i8* @var8_2
|
||||
call void @take_i8s(i8 %char1, i8 %char2)
|
||||
; CHECK-DAG: ldrb w0, [{{x[0-9]+}}, #:lo12:var8]
|
||||
; CHECK-DAG: ldrb w1, [{{x[0-9]+}}, #:lo12:var8_2]
|
||||
; CHECK-DAG: ldrb w0, [{{x[0-9]+}}, {{#?}}:lo12:var8]
|
||||
; CHECK-DAG: ldrb w1, [{{x[0-9]+}}, {{#?}}:lo12:var8_2]
|
||||
; CHECK: bl take_i8s
|
||||
|
||||
%float1 = load float* @varfloat
|
||||
%float2 = load float* @varfloat_2
|
||||
call void @take_floats(float %float1, float %float2)
|
||||
; CHECK-DAG: ldr s1, [{{x[0-9]+}}, #:lo12:varfloat_2]
|
||||
; CHECK-DAG: ldr s0, [{{x[0-9]+}}, #:lo12:varfloat]
|
||||
; CHECK-DAG: ldr s1, [{{x[0-9]+}}, {{#?}}:lo12:varfloat_2]
|
||||
; CHECK-DAG: ldr s0, [{{x[0-9]+}}, {{#?}}:lo12:varfloat]
|
||||
; CHECK: bl take_floats
|
||||
; CHECK-NOFP-NOT: ldr s1,
|
||||
; CHECK-NOFP-NOT: ldr s0,
|
||||
@ -51,22 +52,22 @@ define void @simple_rets() {
|
||||
%int = call i32 @return_int()
|
||||
store i32 %int, i32* @var32
|
||||
; CHECK: bl return_int
|
||||
; CHECK: str w0, [{{x[0-9]+}}, #:lo12:var32]
|
||||
; CHECK: str w0, [{{x[0-9]+}}, {{#?}}:lo12:var32]
|
||||
|
||||
%dbl = call double @return_double()
|
||||
store double %dbl, double* @vardouble
|
||||
; CHECK: bl return_double
|
||||
; CHECK: str d0, [{{x[0-9]+}}, #:lo12:vardouble]
|
||||
; CHECK: str d0, [{{x[0-9]+}}, {{#?}}:lo12:vardouble]
|
||||
; CHECK-NOFP-NOT: str d0,
|
||||
|
||||
%arr = call [2 x i64] @return_smallstruct()
|
||||
store [2 x i64] %arr, [2 x i64]* @varsmallstruct
|
||||
; CHECK: bl return_smallstruct
|
||||
; CHECK: str x1, [{{x[0-9]+}}, #8]
|
||||
; CHECK: str x0, [{{x[0-9]+}}, #:lo12:varsmallstruct]
|
||||
; CHECK: str x0, [{{x[0-9]+}}, {{#?}}:lo12:varsmallstruct]
|
||||
|
||||
call void @return_large_struct(%myStruct* sret @varstruct)
|
||||
; CHECK: add x8, {{x[0-9]+}}, #:lo12:varstruct
|
||||
; CHECK: add x8, {{x[0-9]+}}, {{#?}}:lo12:varstruct
|
||||
; CHECK: bl return_large_struct
|
||||
|
||||
ret void
|
||||
@ -88,19 +89,28 @@ define void @check_stack_args() {
|
||||
; Want to check that the final double is passed in registers and
|
||||
; that varstruct is passed on the stack. Rather dependent on how a
|
||||
; memcpy gets created, but the following works for now.
|
||||
; CHECK: mov x[[SPREG:[0-9]+]], sp
|
||||
; CHECK-DAG: str {{w[0-9]+}}, [x[[SPREG]]]
|
||||
; CHECK-DAG: str {{w[0-9]+}}, [x[[SPREG]], #12]
|
||||
; CHECK-DAG: fmov d0,
|
||||
; CHECK-AARCH64: mov x[[SPREG:[0-9]+]], sp
|
||||
; CHECK-AARCH64-DAG: str {{w[0-9]+}}, [x[[SPREG]]]
|
||||
; CHECK-AARCH64-DAG: str {{w[0-9]+}}, [x[[SPREG]], #12]
|
||||
; CHECK-AARCH64-DAG: fmov d0,
|
||||
|
||||
; CHECK-ARM64-DAG: str {{q[0-9]+}}, [sp]
|
||||
; CHECK-ARM64-DAG: fmov d[[FINAL_DOUBLE:[0-9]+]], #1.0
|
||||
; CHECK-ARM64: orr v0.16b, v[[FINAL_DOUBLE]].16b, v[[FINAL_DOUBLE]].16b
|
||||
|
||||
; CHECK: bl struct_on_stack
|
||||
; CHECK-NOFP-NOT: fmov
|
||||
|
||||
call void @stacked_fpu(float -1.0, double 1.0, float 4.0, float 2.0,
|
||||
float -2.0, float -8.0, float 16.0, float 1.0,
|
||||
float 64.0)
|
||||
; CHECK: ldr s[[STACKEDREG:[0-9]+]], [{{x[0-9]+}}, #:lo12:.LCPI
|
||||
; CHECK: mov x0, sp
|
||||
; CHECK: str d[[STACKEDREG]], [x0]
|
||||
; CHECK-AARCH64: ldr s[[STACKEDREG:[0-9]+]], [{{x[0-9]+}}, {{#?}}:lo12:.LCPI
|
||||
; CHECK-AARCH64: mov x0, sp
|
||||
; CHECK-AARCH64: str d[[STACKEDREG]], [x0]
|
||||
|
||||
; CHECK-ARM64: movz [[SIXTY_FOUR:w[0-9]+]], #17024, lsl #16
|
||||
; CHECK-ARM64: str [[SIXTY_FOUR]], [sp]
|
||||
|
||||
; CHECK: bl stacked_fpu
|
||||
ret void
|
||||
}
|
||||
@ -119,11 +129,12 @@ define void @check_i128_align() {
|
||||
call void @check_i128_stackalign(i32 0, i32 1, i32 2, i32 3,
|
||||
i32 4, i32 5, i32 6, i32 7,
|
||||
i32 42, i128 %val)
|
||||
; CHECK: ldr [[I128LO:x[0-9]+]], [{{x[0-9]+}}, #:lo12:var128]
|
||||
; CHECK: ldr [[I128LO:x[0-9]+]], [{{x[0-9]+}}, {{#?}}:lo12:var128]
|
||||
; CHECK: ldr [[I128HI:x[0-9]+]], [{{x[0-9]+}}, #8]
|
||||
; CHECK: mov x[[SPREG:[0-9]+]], sp
|
||||
; CHECK: str [[I128HI]], [x[[SPREG]], #24]
|
||||
; CHECK: str [[I128LO]], [x[[SPREG]], #16]
|
||||
; CHECK-AARCH64: mov x[[SPREG:[0-9]+]], sp
|
||||
; CHECK-AARCH64: str [[I128HI]], [x[[SPREG]], #24]
|
||||
; CHECK-AARCH64: str [[I128LO]], [x[[SPREG]], #16]
|
||||
; CHECK-ARM64: stp [[I128LO]], [[I128HI]], [sp, #16]
|
||||
; CHECK: bl check_i128_stackalign
|
||||
|
||||
call void @check_i128_regalign(i32 0, i128 42)
|
||||
@ -143,7 +154,7 @@ define void @check_indirect_call() {
|
||||
; CHECK-LABEL: check_indirect_call:
|
||||
%func = load void()** @fptr
|
||||
call void %func()
|
||||
; CHECK: ldr [[FPTR:x[0-9]+]], [{{x[0-9]+}}, #:lo12:fptr]
|
||||
; CHECK: ldr [[FPTR:x[0-9]+]], [{{x[0-9]+}}, {{#?}}:lo12:fptr]
|
||||
; CHECK: blr [[FPTR]]
|
||||
|
||||
ret void
|
||||
|
Loading…
Reference in New Issue
Block a user