Revert "[ARM] musttail fixes"
committed by accident, see #104795
This reverts commit a2088a24da.
This commit is contained in:
@@ -5086,7 +5086,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
||||
RawAddress SRetAlloca = RawAddress::invalid();
|
||||
llvm::Value *UnusedReturnSizePtr = nullptr;
|
||||
if (RetAI.isIndirect() || RetAI.isInAlloca() || RetAI.isCoerceAndExpand()) {
|
||||
if ((IsVirtualFunctionPointerThunk || IsMustTail) && RetAI.isIndirect()) {
|
||||
if (IsVirtualFunctionPointerThunk && RetAI.isIndirect()) {
|
||||
SRetPtr = makeNaturalAddressForPointer(CurFn->arg_begin() +
|
||||
IRFunctionArgs.getSRetArgNo(),
|
||||
RetTy, CharUnits::fromQuantity(1));
|
||||
|
||||
@@ -540,8 +540,6 @@ public:
|
||||
});
|
||||
}
|
||||
|
||||
void dump() const;
|
||||
|
||||
private:
|
||||
/// MarkAllocated - Mark a register and all of its aliases as allocated.
|
||||
void MarkAllocated(MCPhysReg Reg);
|
||||
|
||||
@@ -290,64 +290,3 @@ bool CCState::resultsCompatible(CallingConv::ID CalleeCC,
|
||||
return std::equal(RVLocs1.begin(), RVLocs1.end(), RVLocs2.begin(),
|
||||
RVLocs2.end(), AreCompatible);
|
||||
}
|
||||
|
||||
void CCState::dump() const {
|
||||
dbgs() << "CCState:\n";
|
||||
for (const CCValAssign &Loc : Locs) {
|
||||
if (Loc.isRegLoc()) {
|
||||
dbgs() << " Reg " << TRI.getName(Loc.getLocReg());
|
||||
} else if (Loc.isMemLoc()) {
|
||||
dbgs() << " Mem " << Loc.getLocMemOffset();
|
||||
} else {
|
||||
assert(Loc.isPendingLoc());
|
||||
dbgs() << " Pend " << Loc.getExtraInfo();
|
||||
}
|
||||
|
||||
dbgs() << " ValVT:" << Loc.getValVT();
|
||||
dbgs() << " LocVT:" << Loc.getLocVT();
|
||||
|
||||
if (Loc.needsCustom())
|
||||
dbgs() << " custom";
|
||||
|
||||
switch (Loc.getLocInfo()) {
|
||||
case CCValAssign::Full:
|
||||
dbgs() << " Full";
|
||||
break;
|
||||
case CCValAssign::SExt:
|
||||
dbgs() << " SExt";
|
||||
break;
|
||||
case CCValAssign::ZExt:
|
||||
dbgs() << " ZExt";
|
||||
break;
|
||||
case CCValAssign::AExt:
|
||||
dbgs() << " AExt";
|
||||
break;
|
||||
case CCValAssign::SExtUpper:
|
||||
dbgs() << " SExtUpper";
|
||||
break;
|
||||
case CCValAssign::ZExtUpper:
|
||||
dbgs() << " ZExtUpper";
|
||||
break;
|
||||
case CCValAssign::AExtUpper:
|
||||
dbgs() << " AExtUpper";
|
||||
break;
|
||||
case CCValAssign::BCvt:
|
||||
dbgs() << " BCvt";
|
||||
break;
|
||||
case CCValAssign::Trunc:
|
||||
dbgs() << " Trunc";
|
||||
break;
|
||||
case CCValAssign::VExt:
|
||||
dbgs() << " VExt";
|
||||
break;
|
||||
case CCValAssign::FPExt:
|
||||
dbgs() << " FPExt";
|
||||
break;
|
||||
case CCValAssign::Indirect:
|
||||
dbgs() << " Indirect";
|
||||
break;
|
||||
}
|
||||
|
||||
dbgs() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2407,8 +2407,8 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
|
||||
isTailCall = false;
|
||||
|
||||
// For both the non-secure calls and the returns from a CMSE entry function,
|
||||
// the function needs to do some extra work after the call, or before the
|
||||
// return, respectively, thus it cannot end with a tail call
|
||||
// the function needs to do some extra work afte r the call, or before the
|
||||
// return, respectively, thus it cannot end with atail call
|
||||
if (isCmseNSCall || AFI->isCmseNSEntryFunction())
|
||||
isTailCall = false;
|
||||
|
||||
@@ -2960,6 +2960,50 @@ void ARMTargetLowering::HandleByVal(CCState *State, unsigned &Size,
|
||||
Size = std::max<int>(Size - Excess, 0);
|
||||
}
|
||||
|
||||
/// MatchingStackOffset - Return true if the given stack call argument is
|
||||
/// already available in the same position (relatively) of the caller's
|
||||
/// incoming argument stack.
|
||||
static
|
||||
bool MatchingStackOffset(SDValue Arg, unsigned Offset, ISD::ArgFlagsTy Flags,
|
||||
MachineFrameInfo &MFI, const MachineRegisterInfo *MRI,
|
||||
const TargetInstrInfo *TII) {
|
||||
unsigned Bytes = Arg.getValueSizeInBits() / 8;
|
||||
int FI = std::numeric_limits<int>::max();
|
||||
if (Arg.getOpcode() == ISD::CopyFromReg) {
|
||||
Register VR = cast<RegisterSDNode>(Arg.getOperand(1))->getReg();
|
||||
if (!VR.isVirtual())
|
||||
return false;
|
||||
MachineInstr *Def = MRI->getVRegDef(VR);
|
||||
if (!Def)
|
||||
return false;
|
||||
if (!Flags.isByVal()) {
|
||||
if (!TII->isLoadFromStackSlot(*Def, FI))
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if (LoadSDNode *Ld = dyn_cast<LoadSDNode>(Arg)) {
|
||||
if (Flags.isByVal())
|
||||
// ByVal argument is passed in as a pointer but it's now being
|
||||
// dereferenced. e.g.
|
||||
// define @foo(%struct.X* %A) {
|
||||
// tail call @bar(%struct.X* byval %A)
|
||||
// }
|
||||
return false;
|
||||
SDValue Ptr = Ld->getBasePtr();
|
||||
FrameIndexSDNode *FINode = dyn_cast<FrameIndexSDNode>(Ptr);
|
||||
if (!FINode)
|
||||
return false;
|
||||
FI = FINode->getIndex();
|
||||
} else
|
||||
return false;
|
||||
|
||||
assert(FI != std::numeric_limits<int>::max());
|
||||
if (!MFI.isFixedObjectIndex(FI))
|
||||
return false;
|
||||
return Offset == MFI.getObjectOffset(FI) && Bytes == MFI.getObjectSize(FI);
|
||||
}
|
||||
|
||||
/// IsEligibleForTailCallOptimization - Check whether the call is eligible
|
||||
/// for tail call optimization. Targets which want to do tail call
|
||||
/// optimization should implement this function. Note that this function also
|
||||
@@ -3001,10 +3045,8 @@ bool ARMTargetLowering::IsEligibleForTailCallOptimization(
|
||||
for (const CCValAssign &AL : ArgLocs)
|
||||
if (AL.isRegLoc())
|
||||
AddressRegisters.erase(AL.getLocReg());
|
||||
if (AddressRegisters.empty()) {
|
||||
LLVM_DEBUG(dbgs() << "false (no space for target address)\n");
|
||||
if (AddressRegisters.empty())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Look for obvious safe cases to perform tail call optimization that do not
|
||||
@@ -3013,26 +3055,18 @@ bool ARMTargetLowering::IsEligibleForTailCallOptimization(
|
||||
// Exception-handling functions need a special set of instructions to indicate
|
||||
// a return to the hardware. Tail-calling another function would probably
|
||||
// break this.
|
||||
if (CallerF.hasFnAttribute("interrupt")) {
|
||||
LLVM_DEBUG(dbgs() << "false (interrupt attribute)\n");
|
||||
if (CallerF.hasFnAttribute("interrupt"))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (canGuaranteeTCO(CalleeCC,
|
||||
getTargetMachine().Options.GuaranteedTailCallOpt)) {
|
||||
LLVM_DEBUG(dbgs() << (CalleeCC == CallerCC ? "true" : "false")
|
||||
<< " (guaranteed tail-call CC)\n");
|
||||
if (canGuaranteeTCO(CalleeCC, getTargetMachine().Options.GuaranteedTailCallOpt))
|
||||
return CalleeCC == CallerCC;
|
||||
}
|
||||
|
||||
// Also avoid sibcall optimization if only one of caller or callee uses
|
||||
// struct return semantics.
|
||||
// Also avoid sibcall optimization if either caller or callee uses struct
|
||||
// return semantics.
|
||||
bool isCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet();
|
||||
bool isCallerStructRet = MF.getFunction().hasStructRetAttr();
|
||||
if (isCalleeStructRet != isCallerStructRet) {
|
||||
LLVM_DEBUG(dbgs() << "false (struct-ret)\n");
|
||||
if (isCalleeStructRet || isCallerStructRet)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Externally-defined functions with weak linkage should not be
|
||||
// tail-called on ARM when the OS does not support dynamic
|
||||
@@ -3045,11 +3079,8 @@ bool ARMTargetLowering::IsEligibleForTailCallOptimization(
|
||||
const GlobalValue *GV = G->getGlobal();
|
||||
const Triple &TT = getTargetMachine().getTargetTriple();
|
||||
if (GV->hasExternalWeakLinkage() &&
|
||||
(!TT.isOSWindows() || TT.isOSBinFormatELF() ||
|
||||
TT.isOSBinFormatMachO())) {
|
||||
LLVM_DEBUG(dbgs() << "false (external weak linkage)\n");
|
||||
(!TT.isOSWindows() || TT.isOSBinFormatELF() || TT.isOSBinFormatMachO()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the call results are passed in the same way.
|
||||
@@ -3058,44 +3089,70 @@ bool ARMTargetLowering::IsEligibleForTailCallOptimization(
|
||||
getEffectiveCallingConv(CalleeCC, isVarArg),
|
||||
getEffectiveCallingConv(CallerCC, CallerF.isVarArg()), MF, C, Ins,
|
||||
CCAssignFnForReturn(CalleeCC, isVarArg),
|
||||
CCAssignFnForReturn(CallerCC, CallerF.isVarArg()))) {
|
||||
LLVM_DEBUG(dbgs() << "false (incompatible results)\n");
|
||||
CCAssignFnForReturn(CallerCC, CallerF.isVarArg())))
|
||||
return false;
|
||||
}
|
||||
// The callee has to preserve all registers the caller needs to preserve.
|
||||
const ARMBaseRegisterInfo *TRI = Subtarget->getRegisterInfo();
|
||||
const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC);
|
||||
if (CalleeCC != CallerCC) {
|
||||
const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC);
|
||||
if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved)) {
|
||||
LLVM_DEBUG(dbgs() << "false (not all registers preserved)\n");
|
||||
if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If Caller's vararg argument has been split between registers and
|
||||
// If Caller's vararg or byval argument has been split between registers and
|
||||
// stack, do not perform tail call, since part of the argument is in caller's
|
||||
// local frame.
|
||||
const ARMFunctionInfo *AFI_Caller = MF.getInfo<ARMFunctionInfo>();
|
||||
if (CLI.IsVarArg && AFI_Caller->getArgRegsSaveSize()) {
|
||||
LLVM_DEBUG(dbgs() << "false (vararg arg reg save area)\n");
|
||||
if (AFI_Caller->getArgRegsSaveSize())
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the callee takes no arguments then go on to check the results of the
|
||||
// call.
|
||||
const MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
if (!parametersInCSRMatch(MRI, CallerPreserved, ArgLocs, OutVals)) {
|
||||
LLVM_DEBUG(dbgs() << "false (parameters in CSRs do not match)\n");
|
||||
return false;
|
||||
if (!Outs.empty()) {
|
||||
if (CCInfo.getStackSize()) {
|
||||
// Check if the arguments are already laid out in the right way as
|
||||
// the caller's fixed stack objects.
|
||||
MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
const MachineRegisterInfo *MRI = &MF.getRegInfo();
|
||||
const TargetInstrInfo *TII = Subtarget->getInstrInfo();
|
||||
for (unsigned i = 0, realArgIdx = 0, e = ArgLocs.size();
|
||||
i != e;
|
||||
++i, ++realArgIdx) {
|
||||
CCValAssign &VA = ArgLocs[i];
|
||||
EVT RegVT = VA.getLocVT();
|
||||
SDValue Arg = OutVals[realArgIdx];
|
||||
ISD::ArgFlagsTy Flags = Outs[realArgIdx].Flags;
|
||||
if (VA.getLocInfo() == CCValAssign::Indirect)
|
||||
return false;
|
||||
if (VA.needsCustom() && (RegVT == MVT::f64 || RegVT == MVT::v2f64)) {
|
||||
// f64 and vector types are split into multiple registers or
|
||||
// register/stack-slot combinations. The types will not match
|
||||
// the registers; give up on memory f64 refs until we figure
|
||||
// out what to do about this.
|
||||
if (!VA.isRegLoc())
|
||||
return false;
|
||||
if (!ArgLocs[++i].isRegLoc())
|
||||
return false;
|
||||
if (RegVT == MVT::v2f64) {
|
||||
if (!ArgLocs[++i].isRegLoc())
|
||||
return false;
|
||||
if (!ArgLocs[++i].isRegLoc())
|
||||
return false;
|
||||
}
|
||||
} else if (!VA.isRegLoc()) {
|
||||
if (!MatchingStackOffset(Arg, VA.getLocMemOffset(), Flags,
|
||||
MFI, MRI, TII))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
if (!parametersInCSRMatch(MRI, CallerPreserved, ArgLocs, OutVals))
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the stack arguments for this call do not fit into our own save area then
|
||||
// the call cannot be made tail.
|
||||
if (CCInfo.getStackSize() > AFI_Caller->getArgumentStackSize())
|
||||
return false;
|
||||
|
||||
LLVM_DEBUG(dbgs() << "true\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,11 +12,17 @@ define void @check227(
|
||||
; arg1 --> SP+188
|
||||
|
||||
entry:
|
||||
; CHECK: sub sp, sp, #12
|
||||
; CHECK: stm sp, {r1, r2, r3}
|
||||
; CHECK: ldr r0, [sp, #200]
|
||||
; CHECK: add sp, sp, #12
|
||||
; CHECK: b useInt
|
||||
|
||||
;CHECK: sub sp, sp, #12
|
||||
;CHECK: push {r11, lr}
|
||||
;CHECK: sub sp, sp, #4
|
||||
;CHECK: add r0, sp, #12
|
||||
;CHECK: stm r0, {r1, r2, r3}
|
||||
;CHECK: ldr r0, [sp, #212]
|
||||
;CHECK: bl useInt
|
||||
;CHECK: add sp, sp, #4
|
||||
;CHECK: pop {r11, lr}
|
||||
;CHECK: add sp, sp, #12
|
||||
|
||||
%0 = ptrtoint ptr %arg1 to i32
|
||||
tail call void @useInt(i32 %0)
|
||||
|
||||
@@ -7,11 +7,14 @@
|
||||
define void @foo(ptr byval(%struct4bytes) %p0, ; --> R0
|
||||
ptr byval(%struct20bytes) %p1 ; --> R1,R2,R3, [SP+0 .. SP+8)
|
||||
) {
|
||||
;CHECK: sub sp, sp, #16
|
||||
;CHECK: stm sp, {r0, r1, r2, r3}
|
||||
;CHECK: add r0, sp, #4
|
||||
;CHECK: add sp, sp, #16
|
||||
;CHECK: b useInt
|
||||
;CHECK: sub sp, sp, #16
|
||||
;CHECK: push {r11, lr}
|
||||
;CHECK: add r12, sp, #8
|
||||
;CHECK: stm r12, {r0, r1, r2, r3}
|
||||
;CHECK: add r0, sp, #12
|
||||
;CHECK: bl useInt
|
||||
;CHECK: pop {r11, lr}
|
||||
;CHECK: add sp, sp, #16
|
||||
|
||||
%1 = ptrtoint ptr %p1 to i32
|
||||
tail call void @useInt(i32 %1)
|
||||
|
||||
@@ -3,28 +3,6 @@
|
||||
; CHECK: function1
|
||||
; CHECK-NOT: vmov
|
||||
define double @function1(double %a, double %b, double %c, double %d, double %e, double %f) nounwind noinline ssp {
|
||||
; CHECK-LABEL: function1:
|
||||
; CHECK: @ %bb.0: @ %entry
|
||||
; CHECK-NEXT: .save {r4, r5, r11, lr}
|
||||
; CHECK-NEXT: push {r4, r5, r11, lr}
|
||||
; CHECK-NEXT: vldr d16, [sp, #40]
|
||||
; CHECK-NEXT: vldr d17, [sp, #32]
|
||||
; CHECK-NEXT: vmov r12, lr, d16
|
||||
; CHECK-NEXT: vldr d16, [sp, #16]
|
||||
; CHECK-NEXT: vmov r4, r5, d17
|
||||
; CHECK-NEXT: vldr d17, [sp, #24]
|
||||
; CHECK-NEXT: str r3, [sp, #36]
|
||||
; CHECK-NEXT: str r2, [sp, #32]
|
||||
; CHECK-NEXT: str r1, [sp, #44]
|
||||
; CHECK-NEXT: str r0, [sp, #40]
|
||||
; CHECK-NEXT: vstr d17, [sp, #16]
|
||||
; CHECK-NEXT: vstr d16, [sp, #24]
|
||||
; CHECK-NEXT: mov r0, r12
|
||||
; CHECK-NEXT: mov r1, lr
|
||||
; CHECK-NEXT: mov r2, r4
|
||||
; CHECK-NEXT: mov r3, r5
|
||||
; CHECK-NEXT: pop {r4, r5, r11, lr}
|
||||
; CHECK-NEXT: b function2
|
||||
entry:
|
||||
%call = tail call double @function2(double %f, double %e, double %d, double %c, double %b, double %a) nounwind
|
||||
ret double %call
|
||||
|
||||
@@ -145,21 +145,26 @@ entry:
|
||||
define void @many_args_test(double, float, i16, <4 x half>, <8 x half>, <8 x half>, <8 x half>) {
|
||||
; SOFT-LABEL: many_args_test:
|
||||
; SOFT: @ %bb.0: @ %entry
|
||||
; SOFT-NEXT: add r12, sp, #40
|
||||
; SOFT-NEXT: push {r11, lr}
|
||||
; SOFT-NEXT: sub sp, sp, #32
|
||||
; SOFT-NEXT: add r12, sp, #80
|
||||
; SOFT-NEXT: vld1.64 {d16, d17}, [r12]
|
||||
; SOFT-NEXT: add r12, sp, #8
|
||||
; SOFT-NEXT: add r12, sp, #48
|
||||
; SOFT-NEXT: vabs.f16 q8, q8
|
||||
; SOFT-NEXT: vld1.64 {d18, d19}, [r12]
|
||||
; SOFT-NEXT: add r12, sp, #24
|
||||
; SOFT-NEXT: add r12, sp, #64
|
||||
; SOFT-NEXT: vadd.f16 q8, q8, q9
|
||||
; SOFT-NEXT: vld1.64 {d18, d19}, [r12]
|
||||
; SOFT-NEXT: add r12, sp, #16
|
||||
; SOFT-NEXT: vmul.f16 q8, q9, q8
|
||||
; SOFT-NEXT: vst1.64 {d16, d17}, [r12]
|
||||
; SOFT-NEXT: vldr d16, [sp]
|
||||
; SOFT-NEXT: vstr d16, [sp]
|
||||
; SOFT-NEXT: str r3, [sp, #8]
|
||||
; SOFT-NEXT: b use
|
||||
; SOFT-NEXT: mov r12, sp
|
||||
; SOFT-NEXT: vldr d16, [sp, #40]
|
||||
; SOFT-NEXT: vst1.16 {d16}, [r12:64]!
|
||||
; SOFT-NEXT: str r3, [r12]
|
||||
; SOFT-NEXT: bl use
|
||||
; SOFT-NEXT: add sp, sp, #32
|
||||
; SOFT-NEXT: pop {r11, pc}
|
||||
;
|
||||
; HARD-LABEL: many_args_test:
|
||||
; HARD: @ %bb.0: @ %entry
|
||||
@@ -172,25 +177,33 @@ define void @many_args_test(double, float, i16, <4 x half>, <8 x half>, <8 x hal
|
||||
;
|
||||
; SOFTEB-LABEL: many_args_test:
|
||||
; SOFTEB: @ %bb.0: @ %entry
|
||||
; SOFTEB-NEXT: add r12, sp, #40
|
||||
; SOFTEB-NEXT: .save {r11, lr}
|
||||
; SOFTEB-NEXT: push {r11, lr}
|
||||
; SOFTEB-NEXT: .pad #32
|
||||
; SOFTEB-NEXT: sub sp, sp, #32
|
||||
; SOFTEB-NEXT: add r12, sp, #80
|
||||
; SOFTEB-NEXT: mov lr, sp
|
||||
; SOFTEB-NEXT: vld1.64 {d16, d17}, [r12]
|
||||
; SOFTEB-NEXT: add r12, sp, #8
|
||||
; SOFTEB-NEXT: add r12, sp, #48
|
||||
; SOFTEB-NEXT: vrev64.16 q8, q8
|
||||
; SOFTEB-NEXT: vabs.f16 q8, q8
|
||||
; SOFTEB-NEXT: vld1.64 {d18, d19}, [r12]
|
||||
; SOFTEB-NEXT: add r12, sp, #24
|
||||
; SOFTEB-NEXT: add r12, sp, #64
|
||||
; SOFTEB-NEXT: vrev64.16 q9, q9
|
||||
; SOFTEB-NEXT: vadd.f16 q8, q8, q9
|
||||
; SOFTEB-NEXT: vld1.64 {d18, d19}, [r12]
|
||||
; SOFTEB-NEXT: add r12, sp, #16
|
||||
; SOFTEB-NEXT: vrev64.16 q9, q9
|
||||
; SOFTEB-NEXT: vmul.f16 q8, q9, q8
|
||||
; SOFTEB-NEXT: vldr d18, [sp]
|
||||
; SOFTEB-NEXT: vldr d18, [sp, #40]
|
||||
; SOFTEB-NEXT: vrev64.16 d18, d18
|
||||
; SOFTEB-NEXT: vst1.16 {d18}, [lr:64]!
|
||||
; SOFTEB-NEXT: str r3, [lr]
|
||||
; SOFTEB-NEXT: vrev64.16 q8, q8
|
||||
; SOFTEB-NEXT: vst1.64 {d16, d17}, [r12]
|
||||
; SOFTEB-NEXT: vstr d18, [sp]
|
||||
; SOFTEB-NEXT: str r3, [sp, #8]
|
||||
; SOFTEB-NEXT: b use
|
||||
; SOFTEB-NEXT: bl use
|
||||
; SOFTEB-NEXT: add sp, sp, #32
|
||||
; SOFTEB-NEXT: pop {r11, pc}
|
||||
;
|
||||
; HARDEB-LABEL: many_args_test:
|
||||
; HARDEB: @ %bb.0: @ %entry
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
|
||||
; RUN: llc < %s -mtriple=armv7-apple-ios6.0 | FileCheck %s
|
||||
; RUN: llc < %s -mtriple=thumbv7-apple-ios6.0 | FileCheck %s
|
||||
; RUN: llc < %s -mtriple=armv7-unknown-nacl-gnueabi | FileCheck %s -check-prefix=NACL
|
||||
@@ -11,122 +10,11 @@
|
||||
%struct.LargeStruct = type { i32, [1001 x i8], [300 x i32] }
|
||||
|
||||
define i32 @f() nounwind ssp {
|
||||
; NACL-LABEL: f:
|
||||
; NACL: @ %bb.0: @ %entry
|
||||
; NACL-NEXT: .save {r4, lr}
|
||||
; NACL-NEXT: push {r4, lr}
|
||||
; NACL-NEXT: .pad #152
|
||||
; NACL-NEXT: sub sp, sp, #152
|
||||
; NACL-NEXT: movw r0, :lower16:__stack_chk_guard
|
||||
; NACL-NEXT: add r3, sp, #72
|
||||
; NACL-NEXT: movt r0, :upper16:__stack_chk_guard
|
||||
; NACL-NEXT: mov lr, sp
|
||||
; NACL-NEXT: ldr r0, [r0]
|
||||
; NACL-NEXT: str r0, [sp, #148]
|
||||
; NACL-NEXT: add r0, sp, #72
|
||||
; NACL-NEXT: add r12, r0, #16
|
||||
; NACL-NEXT: ldm r3, {r0, r1, r2, r3}
|
||||
; NACL-NEXT: ldr r4, [r12], #4
|
||||
; NACL-NEXT: str r4, [lr], #4
|
||||
; NACL-NEXT: ldr r4, [r12], #4
|
||||
; NACL-NEXT: str r4, [lr], #4
|
||||
; NACL-NEXT: ldr r4, [r12], #4
|
||||
; NACL-NEXT: str r4, [lr], #4
|
||||
; NACL-NEXT: ldr r4, [r12], #4
|
||||
; NACL-NEXT: str r4, [lr], #4
|
||||
; NACL-NEXT: ldr r4, [r12], #4
|
||||
; NACL-NEXT: str r4, [lr], #4
|
||||
; NACL-NEXT: ldr r4, [r12], #4
|
||||
; NACL-NEXT: str r4, [lr], #4
|
||||
; NACL-NEXT: ldr r4, [r12], #4
|
||||
; NACL-NEXT: str r4, [lr], #4
|
||||
; NACL-NEXT: ldr r4, [r12], #4
|
||||
; NACL-NEXT: str r4, [lr], #4
|
||||
; NACL-NEXT: ldr r4, [r12], #4
|
||||
; NACL-NEXT: str r4, [lr], #4
|
||||
; NACL-NEXT: ldr r4, [r12], #4
|
||||
; NACL-NEXT: str r4, [lr], #4
|
||||
; NACL-NEXT: ldr r4, [r12], #4
|
||||
; NACL-NEXT: str r4, [lr], #4
|
||||
; NACL-NEXT: ldr r4, [r12], #4
|
||||
; NACL-NEXT: str r4, [lr], #4
|
||||
; NACL-NEXT: ldr r4, [r12], #4
|
||||
; NACL-NEXT: str r4, [lr], #4
|
||||
; NACL-NEXT: ldr r4, [r12], #4
|
||||
; NACL-NEXT: str r4, [lr], #4
|
||||
; NACL-NEXT: ldr r4, [r12], #4
|
||||
; NACL-NEXT: str r4, [lr], #4
|
||||
; NACL-NEXT: bl e1
|
||||
; NACL-NEXT: movw r1, :lower16:__stack_chk_guard
|
||||
; NACL-NEXT: ldr r0, [sp, #148]
|
||||
; NACL-NEXT: movt r1, :upper16:__stack_chk_guard
|
||||
; NACL-NEXT: ldr r1, [r1]
|
||||
; NACL-NEXT: cmp r1, r0
|
||||
; NACL-NEXT: moveq r0, #0
|
||||
; NACL-NEXT: addeq sp, sp, #152
|
||||
; NACL-NEXT: popeq {r4, pc}
|
||||
; NACL-NEXT: .LBB0_1: @ %entry
|
||||
; NACL-NEXT: bl __stack_chk_fail
|
||||
;
|
||||
; NOMOVT-LABEL: f:
|
||||
; NOMOVT: @ %bb.0: @ %entry
|
||||
; NOMOVT-NEXT: .save {r11, lr}
|
||||
; NOMOVT-NEXT: push {r11, lr}
|
||||
; NOMOVT-NEXT: .pad #144
|
||||
; NOMOVT-NEXT: sub sp, sp, #144
|
||||
; NOMOVT-NEXT: ldr r0, .LCPI0_0
|
||||
; NOMOVT-NEXT: mov r1, sp
|
||||
; NOMOVT-NEXT: add r3, sp, #64
|
||||
; NOMOVT-NEXT: ldr r0, [r0]
|
||||
; NOMOVT-NEXT: str r0, [sp, #140]
|
||||
; NOMOVT-NEXT: add r0, sp, #64
|
||||
; NOMOVT-NEXT: add r0, r0, #16
|
||||
; NOMOVT-NEXT: ldr r2, [r0], #4
|
||||
; NOMOVT-NEXT: str r2, [r1], #4
|
||||
; NOMOVT-NEXT: ldr r2, [r0], #4
|
||||
; NOMOVT-NEXT: str r2, [r1], #4
|
||||
; NOMOVT-NEXT: ldr r2, [r0], #4
|
||||
; NOMOVT-NEXT: str r2, [r1], #4
|
||||
; NOMOVT-NEXT: ldr r2, [r0], #4
|
||||
; NOMOVT-NEXT: str r2, [r1], #4
|
||||
; NOMOVT-NEXT: ldr r2, [r0], #4
|
||||
; NOMOVT-NEXT: str r2, [r1], #4
|
||||
; NOMOVT-NEXT: ldr r2, [r0], #4
|
||||
; NOMOVT-NEXT: str r2, [r1], #4
|
||||
; NOMOVT-NEXT: ldr r2, [r0], #4
|
||||
; NOMOVT-NEXT: str r2, [r1], #4
|
||||
; NOMOVT-NEXT: ldr r2, [r0], #4
|
||||
; NOMOVT-NEXT: str r2, [r1], #4
|
||||
; NOMOVT-NEXT: ldr r2, [r0], #4
|
||||
; NOMOVT-NEXT: str r2, [r1], #4
|
||||
; NOMOVT-NEXT: ldr r2, [r0], #4
|
||||
; NOMOVT-NEXT: str r2, [r1], #4
|
||||
; NOMOVT-NEXT: ldr r2, [r0], #4
|
||||
; NOMOVT-NEXT: str r2, [r1], #4
|
||||
; NOMOVT-NEXT: ldr r2, [r0], #4
|
||||
; NOMOVT-NEXT: str r2, [r1], #4
|
||||
; NOMOVT-NEXT: ldr r2, [r0], #4
|
||||
; NOMOVT-NEXT: str r2, [r1], #4
|
||||
; NOMOVT-NEXT: ldr r2, [r0], #4
|
||||
; NOMOVT-NEXT: str r2, [r1], #4
|
||||
; NOMOVT-NEXT: ldr r2, [r0], #4
|
||||
; NOMOVT-NEXT: str r2, [r1], #4
|
||||
; NOMOVT-NEXT: ldm r3, {r0, r1, r2, r3}
|
||||
; NOMOVT-NEXT: bl e1
|
||||
; NOMOVT-NEXT: ldr r0, [sp, #140]
|
||||
; NOMOVT-NEXT: ldr r1, .LCPI0_0
|
||||
; NOMOVT-NEXT: ldr r1, [r1]
|
||||
; NOMOVT-NEXT: cmp r1, r0
|
||||
; NOMOVT-NEXT: moveq r0, #0
|
||||
; NOMOVT-NEXT: addeq sp, sp, #144
|
||||
; NOMOVT-NEXT: popeq {r11, pc}
|
||||
; NOMOVT-NEXT: .LBB0_1: @ %entry
|
||||
; NOMOVT-NEXT: bl __stack_chk_fail
|
||||
; NOMOVT-NEXT: .p2align 2
|
||||
; NOMOVT-NEXT: @ %bb.2:
|
||||
; NOMOVT-NEXT: .LCPI0_0:
|
||||
; NOMOVT-NEXT: .long __stack_chk_guard
|
||||
entry:
|
||||
; CHECK-LABEL: f:
|
||||
; CHECK: ldr
|
||||
; CHECK: str
|
||||
; CHECK-NOT:bne
|
||||
%st = alloca %struct.SmallStruct, align 4
|
||||
%call = call i32 @e1(ptr byval(%struct.SmallStruct) %st)
|
||||
ret i32 0
|
||||
@@ -134,95 +22,20 @@ entry:
|
||||
|
||||
; Generate a loop for large struct byval
|
||||
define i32 @g() nounwind ssp {
|
||||
; NACL-LABEL: g:
|
||||
; NACL: @ %bb.0: @ %entry
|
||||
; NACL-NEXT: .save {r4, r5, r11, lr}
|
||||
; NACL-NEXT: push {r4, r5, r11, lr}
|
||||
; NACL-NEXT: .pad #2224
|
||||
; NACL-NEXT: sub sp, sp, #2224
|
||||
; NACL-NEXT: movw r0, :lower16:__stack_chk_guard
|
||||
; NACL-NEXT: movt r0, :upper16:__stack_chk_guard
|
||||
; NACL-NEXT: ldr r0, [r0]
|
||||
; NACL-NEXT: str r0, [sp, #2220]
|
||||
; NACL-NEXT: sub sp, sp, #2192
|
||||
; NACL-NEXT: add lr, sp, #2048
|
||||
; NACL-NEXT: ldr r1, [sp, #2208]
|
||||
; NACL-NEXT: add r0, lr, #156
|
||||
; NACL-NEXT: ldr r2, [sp, #2212]
|
||||
; NACL-NEXT: add r12, r0, #16
|
||||
; NACL-NEXT: ldr r0, [sp, #2204]
|
||||
; NACL-NEXT: ldr r3, [sp, #2216]
|
||||
; NACL-NEXT: movw lr, #2192
|
||||
; NACL-NEXT: mov r4, sp
|
||||
; NACL-NEXT: .LBB1_1: @ %entry
|
||||
; NACL-NEXT: @ =>This Inner Loop Header: Depth=1
|
||||
; NACL-NEXT: ldr r5, [r12], #4
|
||||
; NACL-NEXT: subs lr, lr, #4
|
||||
; NACL-NEXT: str r5, [r4], #4
|
||||
; NACL-NEXT: bne .LBB1_1
|
||||
; NACL-NEXT: @ %bb.2: @ %entry
|
||||
; NACL-NEXT: bl e2
|
||||
; NACL-NEXT: add sp, sp, #2192
|
||||
; NACL-NEXT: movw r1, :lower16:__stack_chk_guard
|
||||
; NACL-NEXT: ldr r0, [sp, #2220]
|
||||
; NACL-NEXT: movt r1, :upper16:__stack_chk_guard
|
||||
; NACL-NEXT: ldr r1, [r1]
|
||||
; NACL-NEXT: cmp r1, r0
|
||||
; NACL-NEXT: moveq r0, #0
|
||||
; NACL-NEXT: addeq sp, sp, #2224
|
||||
; NACL-NEXT: popeq {r4, r5, r11, pc}
|
||||
; NACL-NEXT: .LBB1_3: @ %entry
|
||||
; NACL-NEXT: bl __stack_chk_fail
|
||||
;
|
||||
; NOMOVT-LABEL: g:
|
||||
; NOMOVT: @ %bb.0: @ %entry
|
||||
; NOMOVT-NEXT: .save {r11, lr}
|
||||
; NOMOVT-NEXT: push {r11, lr}
|
||||
; NOMOVT-NEXT: .pad #168
|
||||
; NOMOVT-NEXT: sub sp, sp, #168
|
||||
; NOMOVT-NEXT: .pad #2048
|
||||
; NOMOVT-NEXT: sub sp, sp, #2048
|
||||
; NOMOVT-NEXT: ldr r0, .LCPI1_1
|
||||
; NOMOVT-NEXT: ldr r0, [r0]
|
||||
; NOMOVT-NEXT: str r0, [sp, #2212]
|
||||
; NOMOVT-NEXT: sub sp, sp, #2192
|
||||
; NOMOVT-NEXT: add lr, sp, #2048
|
||||
; NOMOVT-NEXT: ldr r1, .LCPI1_0
|
||||
; NOMOVT-NEXT: add r0, lr, #148
|
||||
; NOMOVT-NEXT: mov r2, sp
|
||||
; NOMOVT-NEXT: add r0, r0, #16
|
||||
; NOMOVT-NEXT: .LBB1_1: @ %entry
|
||||
; NOMOVT-NEXT: @ =>This Inner Loop Header: Depth=1
|
||||
; NOMOVT-NEXT: ldr r3, [r0], #4
|
||||
; NOMOVT-NEXT: subs r1, r1, #4
|
||||
; NOMOVT-NEXT: str r3, [r2], #4
|
||||
; NOMOVT-NEXT: bne .LBB1_1
|
||||
; NOMOVT-NEXT: @ %bb.2: @ %entry
|
||||
; NOMOVT-NEXT: ldr r0, [sp, #2196]
|
||||
; NOMOVT-NEXT: ldr r1, [sp, #2200]
|
||||
; NOMOVT-NEXT: ldr r2, [sp, #2204]
|
||||
; NOMOVT-NEXT: ldr r3, [sp, #2208]
|
||||
; NOMOVT-NEXT: bl e2
|
||||
; NOMOVT-NEXT: add sp, sp, #2192
|
||||
; NOMOVT-NEXT: ldr r0, [sp, #2212]
|
||||
; NOMOVT-NEXT: ldr r1, .LCPI1_1
|
||||
; NOMOVT-NEXT: ldr r1, [r1]
|
||||
; NOMOVT-NEXT: cmp r1, r0
|
||||
; NOMOVT-NEXT: moveq r0, #0
|
||||
; NOMOVT-NEXT: addeq sp, sp, #168
|
||||
; NOMOVT-NEXT: addeq sp, sp, #2048
|
||||
; NOMOVT-NEXT: popeq {r11, pc}
|
||||
; NOMOVT-NEXT: .LBB1_3: @ %entry
|
||||
; NOMOVT-NEXT: bl __stack_chk_fail
|
||||
; NOMOVT-NEXT: .p2align 2
|
||||
; NOMOVT-NEXT: @ %bb.4:
|
||||
; NOMOVT-NEXT: .LCPI1_0:
|
||||
; NOMOVT-NEXT: .long 2192 @ 0x890
|
||||
; NOMOVT-NEXT: .LCPI1_1:
|
||||
; NOMOVT-NEXT: .long __stack_chk_guard
|
||||
entry:
|
||||
; CHECK-LABEL: g:
|
||||
; CHECK: ldr
|
||||
; CHECK: sub
|
||||
; CHECK: str
|
||||
; CHECK: bne
|
||||
; NACL-LABEL: g:
|
||||
; Ensure that use movw instead of constpool for the loop trip count. But don't
|
||||
; match the __stack_chk_guard movw
|
||||
; NACL: movw {{r[0-9]+|lr}}, #
|
||||
; NACL: ldr
|
||||
; NACL: sub
|
||||
; NACL: str
|
||||
; NACL: bne
|
||||
%st = alloca %struct.LargeStruct, align 4
|
||||
%call = call i32 @e2(ptr byval(%struct.LargeStruct) %st)
|
||||
ret i32 0
|
||||
@@ -230,90 +43,17 @@ entry:
|
||||
|
||||
; Generate a loop using NEON instructions
|
||||
define i32 @h() nounwind ssp {
|
||||
; NACL-LABEL: h:
|
||||
; NACL: @ %bb.0: @ %entry
|
||||
; NACL-NEXT: .save {r4, r5, r6, r7, r8, lr}
|
||||
; NACL-NEXT: push {r4, r5, r6, r7, r8, lr}
|
||||
; NACL-NEXT: .pad #168
|
||||
; NACL-NEXT: sub sp, sp, #168
|
||||
; NACL-NEXT: .pad #2048
|
||||
; NACL-NEXT: sub sp, sp, #2048
|
||||
; NACL-NEXT: movw r0, :lower16:__stack_chk_guard
|
||||
; NACL-NEXT: movt r0, :upper16:__stack_chk_guard
|
||||
; NACL-NEXT: ldr r0, [r0]
|
||||
; NACL-NEXT: str r0, [sp, #2212]
|
||||
; NACL-NEXT: sub sp, sp, #2192
|
||||
; NACL-NEXT: add r3, sp, #2192
|
||||
; NACL-NEXT: add r0, sp, #2192
|
||||
; NACL-NEXT: add r12, r0, #16
|
||||
; NACL-NEXT: movw lr, #2192
|
||||
; NACL-NEXT: ldm r3, {r0, r1, r2, r3}
|
||||
; NACL-NEXT: mov r4, sp
|
||||
; NACL-NEXT: .LBB2_1: @ %entry
|
||||
; NACL-NEXT: @ =>This Inner Loop Header: Depth=1
|
||||
; NACL-NEXT: vld1.32 {d16, d17}, [r12]!
|
||||
; NACL-NEXT: subs lr, lr, #16
|
||||
; NACL-NEXT: vst1.32 {d16, d17}, [r4]!
|
||||
; NACL-NEXT: bne .LBB2_1
|
||||
; NACL-NEXT: @ %bb.2: @ %entry
|
||||
; NACL-NEXT: bl e3
|
||||
; NACL-NEXT: add sp, sp, #2192
|
||||
; NACL-NEXT: movw r1, :lower16:__stack_chk_guard
|
||||
; NACL-NEXT: ldr r0, [sp, #2212]
|
||||
; NACL-NEXT: movt r1, :upper16:__stack_chk_guard
|
||||
; NACL-NEXT: ldr r1, [r1]
|
||||
; NACL-NEXT: cmp r1, r0
|
||||
; NACL-NEXT: moveq r0, #0
|
||||
; NACL-NEXT: addeq sp, sp, #168
|
||||
; NACL-NEXT: addeq sp, sp, #2048
|
||||
; NACL-NEXT: popeq {r4, r5, r6, r7, r8, pc}
|
||||
; NACL-NEXT: .LBB2_3: @ %entry
|
||||
; NACL-NEXT: bl __stack_chk_fail
|
||||
;
|
||||
; NOMOVT-LABEL: h:
|
||||
; NOMOVT: @ %bb.0: @ %entry
|
||||
; NOMOVT-NEXT: .save {r6, r10, r11, lr}
|
||||
; NOMOVT-NEXT: push {r6, r10, r11, lr}
|
||||
; NOMOVT-NEXT: .setfp r11, sp, #8
|
||||
; NOMOVT-NEXT: add r11, sp, #8
|
||||
; NOMOVT-NEXT: .pad #2224
|
||||
; NOMOVT-NEXT: sub sp, sp, #2224
|
||||
; NOMOVT-NEXT: bic sp, sp, #15
|
||||
; NOMOVT-NEXT: ldr r0, .LCPI2_1
|
||||
; NOMOVT-NEXT: mov r6, sp
|
||||
; NOMOVT-NEXT: ldr r0, [r0]
|
||||
; NOMOVT-NEXT: str r0, [r6, #2220]
|
||||
; NOMOVT-NEXT: sub sp, sp, #2192
|
||||
; NOMOVT-NEXT: mov r0, r6
|
||||
; NOMOVT-NEXT: ldr r1, .LCPI2_0
|
||||
; NOMOVT-NEXT: add r0, r0, #16
|
||||
; NOMOVT-NEXT: mov r2, sp
|
||||
; NOMOVT-NEXT: .LBB2_1: @ %entry
|
||||
; NOMOVT-NEXT: @ =>This Inner Loop Header: Depth=1
|
||||
; NOMOVT-NEXT: ldr r3, [r0], #4
|
||||
; NOMOVT-NEXT: subs r1, r1, #4
|
||||
; NOMOVT-NEXT: str r3, [r2], #4
|
||||
; NOMOVT-NEXT: bne .LBB2_1
|
||||
; NOMOVT-NEXT: @ %bb.2: @ %entry
|
||||
; NOMOVT-NEXT: ldm r6, {r0, r1, r2, r3}
|
||||
; NOMOVT-NEXT: bl e3
|
||||
; NOMOVT-NEXT: add sp, sp, #2192
|
||||
; NOMOVT-NEXT: ldr r0, [r6, #2220]
|
||||
; NOMOVT-NEXT: ldr r1, .LCPI2_1
|
||||
; NOMOVT-NEXT: ldr r1, [r1]
|
||||
; NOMOVT-NEXT: cmp r1, r0
|
||||
; NOMOVT-NEXT: moveq r0, #0
|
||||
; NOMOVT-NEXT: subeq sp, r11, #8
|
||||
; NOMOVT-NEXT: popeq {r6, r10, r11, pc}
|
||||
; NOMOVT-NEXT: .LBB2_3: @ %entry
|
||||
; NOMOVT-NEXT: bl __stack_chk_fail
|
||||
; NOMOVT-NEXT: .p2align 2
|
||||
; NOMOVT-NEXT: @ %bb.4:
|
||||
; NOMOVT-NEXT: .LCPI2_0:
|
||||
; NOMOVT-NEXT: .long 2192 @ 0x890
|
||||
; NOMOVT-NEXT: .LCPI2_1:
|
||||
; NOMOVT-NEXT: .long __stack_chk_guard
|
||||
entry:
|
||||
; CHECK-LABEL: h:
|
||||
; CHECK: vld1
|
||||
; CHECK: sub
|
||||
; CHECK: vst1
|
||||
; CHECK: bne
|
||||
; NACL: movw {{r[0-9]+|lr}}, #
|
||||
; NACL: vld1
|
||||
; NACL: sub
|
||||
; NACL: vst1
|
||||
; NACL: bne
|
||||
%st = alloca %struct.LargeStruct, align 16
|
||||
%call = call i32 @e3(ptr byval(%struct.LargeStruct) align 16 %st)
|
||||
ret i32 0
|
||||
@@ -327,50 +67,16 @@ declare i32 @e3(ptr nocapture byval(%struct.LargeStruct) align 16 %in) nounwind
|
||||
; We can't do tail call since address of s is passed to the callee and part of
|
||||
; s is in caller's local frame.
|
||||
define void @f3(ptr nocapture byval(%struct.SmallStruct) %s) nounwind optsize {
|
||||
; NACL-LABEL: f3:
|
||||
; NACL: @ %bb.0: @ %entry
|
||||
; NACL-NEXT: .pad #16
|
||||
; NACL-NEXT: sub sp, sp, #16
|
||||
; NACL-NEXT: stm sp, {r0, r1, r2, r3}
|
||||
; NACL-NEXT: mov r0, sp
|
||||
; NACL-NEXT: mov r1, #80
|
||||
; NACL-NEXT: add sp, sp, #16
|
||||
; NACL-NEXT: b consumestruct
|
||||
;
|
||||
; NOMOVT-LABEL: f3:
|
||||
; NOMOVT: @ %bb.0: @ %entry
|
||||
; NOMOVT-NEXT: .pad #16
|
||||
; NOMOVT-NEXT: sub sp, sp, #16
|
||||
; NOMOVT-NEXT: stm sp, {r0, r1, r2, r3}
|
||||
; NOMOVT-NEXT: mov r0, sp
|
||||
; NOMOVT-NEXT: mov r1, #80
|
||||
; NOMOVT-NEXT: add sp, sp, #16
|
||||
; NOMOVT-NEXT: b consumestruct
|
||||
; CHECK-LABEL: f3
|
||||
; CHECK: bl _consumestruct
|
||||
entry:
|
||||
tail call void @consumestruct(ptr %s, i32 80) optsize
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f4(ptr nocapture byval(%struct.SmallStruct) %s) nounwind optsize {
|
||||
; NACL-LABEL: f4:
|
||||
; NACL: @ %bb.0: @ %entry
|
||||
; NACL-NEXT: .pad #16
|
||||
; NACL-NEXT: sub sp, sp, #16
|
||||
; NACL-NEXT: stm sp, {r0, r1, r2, r3}
|
||||
; NACL-NEXT: mov r0, sp
|
||||
; NACL-NEXT: mov r1, #80
|
||||
; NACL-NEXT: add sp, sp, #16
|
||||
; NACL-NEXT: b consumestruct
|
||||
;
|
||||
; NOMOVT-LABEL: f4:
|
||||
; NOMOVT: @ %bb.0: @ %entry
|
||||
; NOMOVT-NEXT: .pad #16
|
||||
; NOMOVT-NEXT: sub sp, sp, #16
|
||||
; NOMOVT-NEXT: stm sp, {r0, r1, r2, r3}
|
||||
; NOMOVT-NEXT: mov r0, sp
|
||||
; NOMOVT-NEXT: mov r1, #80
|
||||
; NOMOVT-NEXT: add sp, sp, #16
|
||||
; NOMOVT-NEXT: b consumestruct
|
||||
; CHECK-LABEL: f4
|
||||
; CHECK: bl _consumestruct
|
||||
entry:
|
||||
tail call void @consumestruct(ptr %s, i32 80) optsize
|
||||
ret void
|
||||
@@ -378,34 +84,16 @@ entry:
|
||||
|
||||
; We can do tail call here since s is in the incoming argument area.
|
||||
define void @f5(i32 %a, i32 %b, i32 %c, i32 %d, ptr nocapture byval(%struct.SmallStruct) %s) nounwind optsize {
|
||||
; NACL-LABEL: f5:
|
||||
; NACL: @ %bb.0: @ %entry
|
||||
; NACL-NEXT: mov r0, sp
|
||||
; NACL-NEXT: mov r1, #80
|
||||
; NACL-NEXT: b consumestruct
|
||||
;
|
||||
; NOMOVT-LABEL: f5:
|
||||
; NOMOVT: @ %bb.0: @ %entry
|
||||
; NOMOVT-NEXT: mov r0, sp
|
||||
; NOMOVT-NEXT: mov r1, #80
|
||||
; NOMOVT-NEXT: b consumestruct
|
||||
; CHECK-LABEL: f5
|
||||
; CHECK: b{{(\.w)?}} _consumestruct
|
||||
entry:
|
||||
tail call void @consumestruct(ptr %s, i32 80) optsize
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f6(i32 %a, i32 %b, i32 %c, i32 %d, ptr nocapture byval(%struct.SmallStruct) %s) nounwind optsize {
|
||||
; NACL-LABEL: f6:
|
||||
; NACL: @ %bb.0: @ %entry
|
||||
; NACL-NEXT: mov r0, sp
|
||||
; NACL-NEXT: mov r1, #80
|
||||
; NACL-NEXT: b consumestruct
|
||||
;
|
||||
; NOMOVT-LABEL: f6:
|
||||
; NOMOVT: @ %bb.0: @ %entry
|
||||
; NOMOVT-NEXT: mov r0, sp
|
||||
; NOMOVT-NEXT: mov r1, #80
|
||||
; NOMOVT-NEXT: b consumestruct
|
||||
; CHECK-LABEL: f6
|
||||
; CHECK: b{{(\.w)?}} _consumestruct
|
||||
entry:
|
||||
tail call void @consumestruct(ptr %s, i32 80) optsize
|
||||
ret void
|
||||
@@ -418,81 +106,10 @@ declare void @consumestruct(ptr nocapture %structp, i32 %structsize) nounwind
|
||||
|
||||
declare void @use_I(ptr byval(%struct.I.8))
|
||||
define void @test_I_16() {
|
||||
; NACL-LABEL: test_I_16:
|
||||
; NACL: @ %bb.0: @ %entry
|
||||
; NACL-NEXT: .save {r11, lr}
|
||||
; NACL-NEXT: push {r11, lr}
|
||||
; NACL-NEXT: .pad #40
|
||||
; NACL-NEXT: sub sp, sp, #40
|
||||
; NACL-NEXT: ldr r0, [r0]
|
||||
; NACL-NEXT: mov r1, sp
|
||||
; NACL-NEXT: vld1.32 {d16, d17}, [r2]!
|
||||
; NACL-NEXT: vst1.32 {d16, d17}, [r1]!
|
||||
; NACL-NEXT: ldrb r3, [r2], #1
|
||||
; NACL-NEXT: strb r3, [r1], #1
|
||||
; NACL-NEXT: ldrb r3, [r2], #1
|
||||
; NACL-NEXT: strb r3, [r1], #1
|
||||
; NACL-NEXT: ldrb r3, [r2], #1
|
||||
; NACL-NEXT: strb r3, [r1], #1
|
||||
; NACL-NEXT: ldrb r3, [r2], #1
|
||||
; NACL-NEXT: strb r3, [r1], #1
|
||||
; NACL-NEXT: ldrb r3, [r2], #1
|
||||
; NACL-NEXT: strb r3, [r1], #1
|
||||
; NACL-NEXT: ldrb r3, [r2], #1
|
||||
; NACL-NEXT: strb r3, [r1], #1
|
||||
; NACL-NEXT: ldrb r3, [r2], #1
|
||||
; NACL-NEXT: strb r3, [r1], #1
|
||||
; NACL-NEXT: ldrb r3, [r2], #1
|
||||
; NACL-NEXT: strb r3, [r1], #1
|
||||
; NACL-NEXT: ldrb r3, [r2], #1
|
||||
; NACL-NEXT: strb r3, [r1], #1
|
||||
; NACL-NEXT: ldrb r3, [r2], #1
|
||||
; NACL-NEXT: strb r3, [r1], #1
|
||||
; NACL-NEXT: ldrb r3, [r2], #1
|
||||
; NACL-NEXT: strb r3, [r1], #1
|
||||
; NACL-NEXT: ldrb r3, [r2], #1
|
||||
; NACL-NEXT: strb r3, [r1], #1
|
||||
; NACL-NEXT: mov r2, r0
|
||||
; NACL-NEXT: mov r1, r0
|
||||
; NACL-NEXT: mov r3, r0
|
||||
; NACL-NEXT: bl use_I
|
||||
; NACL-NEXT: add sp, sp, #40
|
||||
; NACL-NEXT: pop {r11, pc}
|
||||
;
|
||||
; NOMOVT-LABEL: test_I_16:
|
||||
; NOMOVT: @ %bb.0: @ %entry
|
||||
; NOMOVT-NEXT: .save {r11, lr}
|
||||
; NOMOVT-NEXT: push {r11, lr}
|
||||
; NOMOVT-NEXT: .setfp r11, sp
|
||||
; NOMOVT-NEXT: mov r11, sp
|
||||
; NOMOVT-NEXT: .pad #40
|
||||
; NOMOVT-NEXT: sub sp, sp, #40
|
||||
; NOMOVT-NEXT: bic sp, sp, #15
|
||||
; NOMOVT-NEXT: ldr r0, [r1], #4
|
||||
; NOMOVT-NEXT: mov r2, sp
|
||||
; NOMOVT-NEXT: str r0, [r2], #4
|
||||
; NOMOVT-NEXT: ldr r0, [r1], #4
|
||||
; NOMOVT-NEXT: str r0, [r2], #4
|
||||
; NOMOVT-NEXT: ldr r0, [r1], #4
|
||||
; NOMOVT-NEXT: str r0, [r2], #4
|
||||
; NOMOVT-NEXT: ldr r0, [r1], #4
|
||||
; NOMOVT-NEXT: str r0, [r2], #4
|
||||
; NOMOVT-NEXT: ldr r0, [r1], #4
|
||||
; NOMOVT-NEXT: str r0, [r2], #4
|
||||
; NOMOVT-NEXT: ldr r0, [r1], #4
|
||||
; NOMOVT-NEXT: str r0, [r2], #4
|
||||
; NOMOVT-NEXT: ldr r0, [r1], #4
|
||||
; NOMOVT-NEXT: str r0, [r2], #4
|
||||
; NOMOVT-NEXT: ldr r0, [r0]
|
||||
; NOMOVT-NEXT: mov r1, r0
|
||||
; NOMOVT-NEXT: mov r2, r0
|
||||
; NOMOVT-NEXT: mov r3, r0
|
||||
; NOMOVT-NEXT: bl use_I
|
||||
; NOMOVT-NEXT: mov sp, r11
|
||||
; NOMOVT-NEXT: pop {r11, pc}
|
||||
; CHECK-LABEL: test_I_16
|
||||
; CHECK: ldrb
|
||||
; CHECK: strb
|
||||
entry:
|
||||
call void @use_I(ptr byval(%struct.I.8) align 16 undef)
|
||||
ret void
|
||||
}
|
||||
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
|
||||
; CHECK: {{.*}}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
|
||||
; RUN: llc -mtriple armv7 -target-abi aapcs -float-abi soft -O0 -o - < %s \
|
||||
; RUN: | FileCheck %s -check-prefix CHECK-SOFT -check-prefix CHECK
|
||||
; RUN: llc -mtriple armv7 -target-abi aapcs -float-abi hard -O0 -o - < %s \
|
||||
@@ -13,42 +12,16 @@ declare i1 @non_variadic_big(float, float, float, float, float, float)
|
||||
declare i1 @variadic(float, ...)
|
||||
|
||||
define void @non_variadic_fp(float %x, float %y) {
|
||||
; CHECK-SOFT-LABEL: non_variadic_fp:
|
||||
; CHECK-SOFT: @ %bb.0: @ %entry
|
||||
; CHECK-SOFT-NEXT: mov r3, r1
|
||||
; CHECK-SOFT-NEXT: mov r2, r0
|
||||
; CHECK-SOFT-NEXT: mov r0, r3
|
||||
; CHECK-SOFT-NEXT: mov r1, r2
|
||||
; CHECK-SOFT-NEXT: b non_variadic
|
||||
;
|
||||
; CHECK-HARD-LABEL: non_variadic_fp:
|
||||
; CHECK-HARD: @ %bb.0: @ %entry
|
||||
; CHECK-HARD-NEXT: vmov.f32 s3, s1
|
||||
; CHECK-HARD-NEXT: vmov.f32 s2, s0
|
||||
; CHECK-HARD-NEXT: vmov.f32 s0, s3
|
||||
; CHECK-HARD-NEXT: vmov.f32 s1, s2
|
||||
; CHECK-HARD-NEXT: b non_variadic
|
||||
; CHECK-LABEL: non_variadic_fp:
|
||||
; CHECK: b non_variadic
|
||||
entry:
|
||||
%call = tail call i1 (float, float, float, float) @non_variadic(float %y, float %x, float %x, float %y)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @variadic_fp(float %x, float %y) {
|
||||
; CHECK-SOFT-LABEL: variadic_fp:
|
||||
; CHECK-SOFT: @ %bb.0: @ %entry
|
||||
; CHECK-SOFT-NEXT: mov r3, r1
|
||||
; CHECK-SOFT-NEXT: mov r2, r0
|
||||
; CHECK-SOFT-NEXT: mov r0, r3
|
||||
; CHECK-SOFT-NEXT: mov r1, r2
|
||||
; CHECK-SOFT-NEXT: b variadic
|
||||
;
|
||||
; CHECK-HARD-LABEL: variadic_fp:
|
||||
; CHECK-HARD: @ %bb.0: @ %entry
|
||||
; CHECK-HARD-NEXT: vmov r2, s0
|
||||
; CHECK-HARD-NEXT: vmov r3, s1
|
||||
; CHECK-HARD-NEXT: mov r0, r3
|
||||
; CHECK-HARD-NEXT: mov r1, r2
|
||||
; CHECK-HARD-NEXT: b variadic
|
||||
; CHECK-LABEL: variadic_fp:
|
||||
; CHECK: b variadic
|
||||
entry:
|
||||
%call = tail call i1 (float, ...) @variadic(float %y, float %x, float %x, float %y)
|
||||
ret void
|
||||
@@ -58,32 +31,9 @@ entry:
|
||||
; of them to handle the 6 arguments. With hard-float, we have plenty of regs
|
||||
; (s0-s15) to pass FP arguments.
|
||||
define void @non_variadic_fp_big(float %x, float %y) {
|
||||
; CHECK-SOFT-LABEL: non_variadic_fp_big:
|
||||
; CHECK-SOFT: @ %bb.0: @ %entry
|
||||
; CHECK-SOFT-NEXT: push {r11, lr}
|
||||
; CHECK-SOFT-NEXT: sub sp, sp, #8
|
||||
; CHECK-SOFT-NEXT: mov r3, r1
|
||||
; CHECK-SOFT-NEXT: mov r2, r0
|
||||
; CHECK-SOFT-NEXT: vmov s0, r3
|
||||
; CHECK-SOFT-NEXT: vmov s0, r2
|
||||
; CHECK-SOFT-NEXT: mov r0, sp
|
||||
; CHECK-SOFT-NEXT: str r3, [r0, #4]
|
||||
; CHECK-SOFT-NEXT: str r2, [r0]
|
||||
; CHECK-SOFT-NEXT: mov r0, r3
|
||||
; CHECK-SOFT-NEXT: mov r1, r2
|
||||
; CHECK-SOFT-NEXT: bl non_variadic_big
|
||||
; CHECK-SOFT-NEXT: add sp, sp, #8
|
||||
; CHECK-SOFT-NEXT: pop {r11, pc}
|
||||
;
|
||||
; CHECK-HARD-LABEL: non_variadic_fp_big:
|
||||
; CHECK-HARD: @ %bb.0: @ %entry
|
||||
; CHECK-HARD-NEXT: vmov.f32 s5, s1
|
||||
; CHECK-HARD-NEXT: vmov.f32 s4, s0
|
||||
; CHECK-HARD-NEXT: vmov.f32 s0, s5
|
||||
; CHECK-HARD-NEXT: vmov.f32 s1, s4
|
||||
; CHECK-HARD-NEXT: vmov.f32 s2, s4
|
||||
; CHECK-HARD-NEXT: vmov.f32 s3, s5
|
||||
; CHECK-HARD-NEXT: b non_variadic_big
|
||||
; CHECK-LABEL: non_variadic_fp_big:
|
||||
; CHECK-SOFT: bl non_variadic_big
|
||||
; CHECK-HARD: b non_variadic_big
|
||||
entry:
|
||||
%call = tail call i1 (float, float, float, float, float, float) @non_variadic_big(float %y, float %x, float %x, float %y, float %x, float %y)
|
||||
ret void
|
||||
@@ -91,40 +41,9 @@ entry:
|
||||
|
||||
; Variadic functions cannot use FP regs to pass arguments; only GP regs.
|
||||
define void @variadic_fp_big(float %x, float %y) {
|
||||
; CHECK-SOFT-LABEL: variadic_fp_big:
|
||||
; CHECK-SOFT: @ %bb.0: @ %entry
|
||||
; CHECK-SOFT-NEXT: push {r11, lr}
|
||||
; CHECK-SOFT-NEXT: sub sp, sp, #8
|
||||
; CHECK-SOFT-NEXT: mov r3, r1
|
||||
; CHECK-SOFT-NEXT: mov r2, r0
|
||||
; CHECK-SOFT-NEXT: vmov s0, r3
|
||||
; CHECK-SOFT-NEXT: vmov s0, r2
|
||||
; CHECK-SOFT-NEXT: mov r0, sp
|
||||
; CHECK-SOFT-NEXT: str r3, [r0, #4]
|
||||
; CHECK-SOFT-NEXT: str r2, [r0]
|
||||
; CHECK-SOFT-NEXT: mov r0, r3
|
||||
; CHECK-SOFT-NEXT: mov r1, r2
|
||||
; CHECK-SOFT-NEXT: bl variadic
|
||||
; CHECK-SOFT-NEXT: add sp, sp, #8
|
||||
; CHECK-SOFT-NEXT: pop {r11, pc}
|
||||
;
|
||||
; CHECK-HARD-LABEL: variadic_fp_big:
|
||||
; CHECK-HARD: @ %bb.0: @ %entry
|
||||
; CHECK-HARD-NEXT: push {r11, lr}
|
||||
; CHECK-HARD-NEXT: sub sp, sp, #8
|
||||
; CHECK-HARD-NEXT: mov r0, sp
|
||||
; CHECK-HARD-NEXT: vstr s1, [r0, #4]
|
||||
; CHECK-HARD-NEXT: vstr s0, [r0]
|
||||
; CHECK-HARD-NEXT: vmov r2, s0
|
||||
; CHECK-HARD-NEXT: vmov r3, s1
|
||||
; CHECK-HARD-NEXT: mov r0, r3
|
||||
; CHECK-HARD-NEXT: mov r1, r2
|
||||
; CHECK-HARD-NEXT: bl variadic
|
||||
; CHECK-HARD-NEXT: add sp, sp, #8
|
||||
; CHECK-HARD-NEXT: pop {r11, pc}
|
||||
; CHECK-LABEL: variadic_fp_big:
|
||||
; CHECK: bl variadic
|
||||
entry:
|
||||
%call = tail call i1 (float, ...) @variadic(float %y, float %x, float %x, float %y, float %x, float %y)
|
||||
ret void
|
||||
}
|
||||
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
|
||||
; CHECK: {{.*}}
|
||||
|
||||
Reference in New Issue
Block a user