mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-03 00:47:07 +00:00
Swift Calling Convention: swifterror target support.
Differential Revision: http://reviews.llvm.org/D18716 llvm-svn: 265997
This commit is contained in:
parent
e345ecd143
commit
e6636caf43
@ -86,6 +86,8 @@ def RetCC_AArch64_AAPCS : CallingConv<[
|
||||
CCIfType<[v2f32], CCBitConvertToType<v2i32>>,
|
||||
CCIfType<[v2f64, v4f32], CCBitConvertToType<v2i64>>,
|
||||
|
||||
CCIfSwiftError<CCIfType<[i64], CCAssignToRegWithShadow<[X19], [W19]>>>,
|
||||
|
||||
// Big endian vectors must be passed as if they were 1-element vectors so that
|
||||
// their lanes are in a consistent order.
|
||||
CCIfBigEndian<CCIfType<[v2i32, v2f32, v4i16, v4f16, v8i8],
|
||||
@ -129,6 +131,9 @@ def CC_AArch64_DarwinPCS : CallingConv<[
|
||||
// A SwiftSelf is passed in X9.
|
||||
CCIfSwiftSelf<CCIfType<[i64], CCAssignToRegWithShadow<[X9], [W9]>>>,
|
||||
|
||||
// A SwiftError is passed in X19.
|
||||
CCIfSwiftError<CCIfType<[i64], CCAssignToRegWithShadow<[X19], [W19]>>>,
|
||||
|
||||
CCIfConsecutiveRegs<CCCustom<"CC_AArch64_Custom_Block">>,
|
||||
|
||||
// Handle i1, i8, i16, i32, i64, f32, f64 and v2f64 by passing in registers,
|
||||
@ -273,6 +278,9 @@ def CSR_AArch64_AAPCS : CalleeSavedRegs<(add LR, FP, X19, X20, X21, X22,
|
||||
// case)
|
||||
def CSR_AArch64_AAPCS_ThisReturn : CalleeSavedRegs<(add CSR_AArch64_AAPCS, X0)>;
|
||||
|
||||
def CSR_AArch64_AAPCS_SwiftError
|
||||
: CalleeSavedRegs<(sub CSR_AArch64_AAPCS, X19)>;
|
||||
|
||||
// The function used by Darwin to obtain the address of a thread-local variable
|
||||
// guarantees more than a normal AAPCS function. x16 and x17 are used on the
|
||||
// fast path for calculation, but other registers except X0 (argument/return)
|
||||
|
@ -1900,6 +1900,21 @@ bool AArch64FastISel::selectLoad(const Instruction *I) {
|
||||
cast<LoadInst>(I)->isAtomic())
|
||||
return false;
|
||||
|
||||
const Value *SV = I->getOperand(0);
|
||||
if (TLI.supportSwiftError()) {
|
||||
// Swifterror values can come from either a function parameter with
|
||||
// swifterror attribute or an alloca with swifterror attribute.
|
||||
if (const Argument *Arg = dyn_cast<Argument>(SV)) {
|
||||
if (Arg->hasSwiftErrorAttr())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (const AllocaInst *Alloca = dyn_cast<AllocaInst>(SV)) {
|
||||
if (Alloca->isSwiftError())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// See if we can handle this address.
|
||||
Address Addr;
|
||||
if (!computeAddress(I->getOperand(0), Addr, I->getType()))
|
||||
@ -2064,6 +2079,21 @@ bool AArch64FastISel::selectStore(const Instruction *I) {
|
||||
cast<StoreInst>(I)->isAtomic())
|
||||
return false;
|
||||
|
||||
const Value *PtrV = I->getOperand(1);
|
||||
if (TLI.supportSwiftError()) {
|
||||
// Swifterror values can come from either a function parameter with
|
||||
// swifterror attribute or an alloca with swifterror attribute.
|
||||
if (const Argument *Arg = dyn_cast<Argument>(PtrV)) {
|
||||
if (Arg->hasSwiftErrorAttr())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (const AllocaInst *Alloca = dyn_cast<AllocaInst>(PtrV)) {
|
||||
if (Alloca->isSwiftError())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the value to be stored into a register. Use the zero register directly
|
||||
// when possible to avoid an unnecessary copy and a wasted register.
|
||||
unsigned SrcReg = 0;
|
||||
@ -2810,6 +2840,7 @@ bool AArch64FastISel::fastLowerArguments() {
|
||||
F->getAttributes().hasAttribute(Idx, Attribute::InReg) ||
|
||||
F->getAttributes().hasAttribute(Idx, Attribute::StructRet) ||
|
||||
F->getAttributes().hasAttribute(Idx, Attribute::SwiftSelf) ||
|
||||
F->getAttributes().hasAttribute(Idx, Attribute::SwiftError) ||
|
||||
F->getAttributes().hasAttribute(Idx, Attribute::Nest))
|
||||
return false;
|
||||
|
||||
@ -3062,7 +3093,7 @@ bool AArch64FastISel::fastLowerCall(CallLoweringInfo &CLI) {
|
||||
|
||||
for (auto Flag : CLI.OutFlags)
|
||||
if (Flag.isInReg() || Flag.isSRet() || Flag.isNest() || Flag.isByVal() ||
|
||||
Flag.isSwiftSelf())
|
||||
Flag.isSwiftSelf() || Flag.isSwiftError())
|
||||
return false;
|
||||
|
||||
// Set up the argument vectors.
|
||||
@ -3644,6 +3675,10 @@ bool AArch64FastISel::selectRet(const Instruction *I) {
|
||||
if (F.isVarArg())
|
||||
return false;
|
||||
|
||||
if (TLI.supportSwiftError() &&
|
||||
F.getAttributes().hasAttrSomewhere(Attribute::SwiftError))
|
||||
return false;
|
||||
|
||||
if (TLI.supportSplitCSR(FuncInfo.MF))
|
||||
return false;
|
||||
|
||||
|
@ -706,6 +706,15 @@ static unsigned getPrologueDeath(MachineFunction &MF, unsigned Reg) {
|
||||
return getKillRegState(LRKill);
|
||||
}
|
||||
|
||||
static bool produceCompactUnwindFrame(MachineFunction &MF) {
|
||||
const AArch64Subtarget &Subtarget = MF.getSubtarget<AArch64Subtarget>();
|
||||
AttributeSet Attrs = MF.getFunction()->getAttributes();
|
||||
return Subtarget.isTargetMachO() &&
|
||||
!(Subtarget.getTargetLowering()->supportSwiftError() &&
|
||||
Attrs.hasAttrSomewhere(Attribute::SwiftError));
|
||||
}
|
||||
|
||||
|
||||
struct RegPairInfo {
|
||||
RegPairInfo() : Reg1(AArch64::NoRegister), Reg2(AArch64::NoRegister) {}
|
||||
unsigned Reg1;
|
||||
@ -730,7 +739,7 @@ static void computeCalleeSaveRegisterPairs(
|
||||
(void)CC;
|
||||
// MachO's compact unwind format relies on all registers being stored in
|
||||
// pairs.
|
||||
assert((!MF.getSubtarget<AArch64Subtarget>().isTargetMachO() ||
|
||||
assert((!produceCompactUnwindFrame(MF) ||
|
||||
CC == CallingConv::PreserveMost ||
|
||||
(Count & 1) == 0) &&
|
||||
"Odd number of callee-saved regs to spill!");
|
||||
@ -764,7 +773,7 @@ static void computeCalleeSaveRegisterPairs(
|
||||
|
||||
// MachO's compact unwind format relies on all registers being stored in
|
||||
// adjacent register pairs.
|
||||
assert((!MF.getSubtarget<AArch64Subtarget>().isTargetMachO() ||
|
||||
assert((!produceCompactUnwindFrame(MF) ||
|
||||
CC == CallingConv::PreserveMost ||
|
||||
(RPI.isPaired() &&
|
||||
((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) ||
|
||||
@ -954,7 +963,6 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
|
||||
const AArch64RegisterInfo *RegInfo = static_cast<const AArch64RegisterInfo *>(
|
||||
MF.getSubtarget().getRegisterInfo());
|
||||
AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
|
||||
const AArch64Subtarget &Subtarget = MF.getSubtarget<AArch64Subtarget>();
|
||||
unsigned UnspilledCSGPR = AArch64::NoRegister;
|
||||
unsigned UnspilledCSGPRPaired = AArch64::NoRegister;
|
||||
|
||||
@ -992,7 +1000,7 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
|
||||
// MachO's compact unwind format relies on all registers being stored in
|
||||
// pairs.
|
||||
// FIXME: the usual format is actually better if unwinding isn't needed.
|
||||
if (Subtarget.isTargetMachO() && !SavedRegs.test(PairedReg)) {
|
||||
if (produceCompactUnwindFrame(MF) && !SavedRegs.test(PairedReg)) {
|
||||
SavedRegs.set(PairedReg);
|
||||
ExtraCSSpill = true;
|
||||
}
|
||||
@ -1035,7 +1043,7 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
|
||||
// MachO's compact unwind format relies on all registers being stored in
|
||||
// pairs, so if we need to spill one extra for BigStack, then we need to
|
||||
// store the pair.
|
||||
if (Subtarget.isTargetMachO())
|
||||
if (produceCompactUnwindFrame(MF))
|
||||
SavedRegs.set(UnspilledCSGPRPaired);
|
||||
ExtraCSSpill = true;
|
||||
NumRegsSpilled = SavedRegs.count();
|
||||
|
@ -400,6 +400,10 @@ public:
|
||||
MachineBasicBlock *Entry,
|
||||
const SmallVectorImpl<MachineBasicBlock *> &Exits) const override;
|
||||
|
||||
bool supportSwiftError() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool isExtFreeImpl(const Instruction *Ext) const override;
|
||||
|
||||
|
@ -51,6 +51,11 @@ AArch64RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
|
||||
return MF->getInfo<AArch64FunctionInfo>()->isSplitCSR() ?
|
||||
CSR_AArch64_CXX_TLS_Darwin_PE_SaveList :
|
||||
CSR_AArch64_CXX_TLS_Darwin_SaveList;
|
||||
if (MF->getSubtarget<AArch64Subtarget>().getTargetLowering()
|
||||
->supportSwiftError() &&
|
||||
MF->getFunction()->getAttributes().hasAttrSomewhere(
|
||||
Attribute::SwiftError))
|
||||
return CSR_AArch64_AAPCS_SwiftError_SaveList;
|
||||
if (MF->getFunction()->getCallingConv() == CallingConv::PreserveMost)
|
||||
return CSR_AArch64_RT_MostRegs_SaveList;
|
||||
else
|
||||
@ -76,6 +81,10 @@ AArch64RegisterInfo::getCallPreservedMask(const MachineFunction &MF,
|
||||
return CSR_AArch64_AllRegs_RegMask;
|
||||
if (CC == CallingConv::CXX_FAST_TLS)
|
||||
return CSR_AArch64_CXX_TLS_Darwin_RegMask;
|
||||
if (MF.getSubtarget<AArch64Subtarget>().getTargetLowering()
|
||||
->supportSwiftError() &&
|
||||
MF.getFunction()->getAttributes().hasAttrSomewhere(Attribute::SwiftError))
|
||||
return CSR_AArch64_AAPCS_SwiftError_RegMask;
|
||||
if (CC == CallingConv::PreserveMost)
|
||||
return CSR_AArch64_RT_MostRegs_RegMask;
|
||||
else
|
||||
|
@ -87,6 +87,10 @@ ARMBaseRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
|
||||
}
|
||||
}
|
||||
|
||||
if (STI.isTargetDarwin() && STI.getTargetLowering()->supportSwiftError() &&
|
||||
F->getAttributes().hasAttrSomewhere(Attribute::SwiftError))
|
||||
return CSR_iOS_SwiftError_SaveList;
|
||||
|
||||
if (STI.isTargetDarwin() && F->getCallingConv() == CallingConv::CXX_FAST_TLS)
|
||||
return MF->getInfo<ARMFunctionInfo>()->isSplitCSR()
|
||||
? CSR_iOS_CXX_TLS_PE_SaveList
|
||||
@ -110,6 +114,11 @@ ARMBaseRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
|
||||
if (CC == CallingConv::GHC)
|
||||
// This is academic becase all GHC calls are (supposed to be) tail calls
|
||||
return CSR_NoRegs_RegMask;
|
||||
|
||||
if (STI.isTargetDarwin() && STI.getTargetLowering()->supportSwiftError() &&
|
||||
MF.getFunction()->getAttributes().hasAttrSomewhere(Attribute::SwiftError))
|
||||
return CSR_iOS_SwiftError_RegMask;
|
||||
|
||||
if (STI.isTargetDarwin() && CC == CallingConv::CXX_FAST_TLS)
|
||||
return CSR_iOS_CXX_TLS_RegMask;
|
||||
return STI.isTargetDarwin() ? CSR_iOS_RegMask : CSR_AAPCS_RegMask;
|
||||
|
@ -26,6 +26,9 @@ def CC_ARM_APCS : CallingConv<[
|
||||
// A SwiftSelf is passed in R9.
|
||||
CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R9]>>>,
|
||||
|
||||
// A SwiftError is passed in R6.
|
||||
CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R6]>>>,
|
||||
|
||||
// Handle all vector types as either f64 or v2f64.
|
||||
CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType<f64>>,
|
||||
CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType<v2f64>>,
|
||||
@ -45,6 +48,9 @@ def RetCC_ARM_APCS : CallingConv<[
|
||||
CCIfType<[i1, i8, i16], CCPromoteToType<i32>>,
|
||||
CCIfType<[f32], CCBitConvertToType<i32>>,
|
||||
|
||||
// A SwiftError is returned in R6.
|
||||
CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R6]>>>,
|
||||
|
||||
// Handle all vector types as either f64 or v2f64.
|
||||
CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType<f64>>,
|
||||
CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType<v2f64>>,
|
||||
@ -157,6 +163,9 @@ def CC_ARM_AAPCS : CallingConv<[
|
||||
// A SwiftSelf is passed in R9.
|
||||
CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R9]>>>,
|
||||
|
||||
// A SwiftError is passed in R6.
|
||||
CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R6]>>>,
|
||||
|
||||
CCIfType<[f64, v2f64], CCCustom<"CC_ARM_AAPCS_Custom_f64">>,
|
||||
CCIfType<[f32], CCBitConvertToType<i32>>,
|
||||
CCDelegateTo<CC_ARM_AAPCS_Common>
|
||||
@ -167,6 +176,9 @@ def RetCC_ARM_AAPCS : CallingConv<[
|
||||
CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType<f64>>,
|
||||
CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType<v2f64>>,
|
||||
|
||||
// A SwiftError is returned in R6.
|
||||
CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R6]>>>,
|
||||
|
||||
CCIfType<[f64, v2f64], CCCustom<"RetCC_ARM_AAPCS_Custom_f64">>,
|
||||
CCIfType<[f32], CCBitConvertToType<i32>>,
|
||||
CCDelegateTo<RetCC_ARM_AAPCS_Common>
|
||||
@ -188,6 +200,9 @@ def CC_ARM_AAPCS_VFP : CallingConv<[
|
||||
// A SwiftSelf is passed in R9.
|
||||
CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R9]>>>,
|
||||
|
||||
// A SwiftError is passed in R6.
|
||||
CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R6]>>>,
|
||||
|
||||
// HFAs are passed in a contiguous block of registers, or on the stack
|
||||
CCIfConsecutiveRegs<CCCustom<"CC_ARM_AAPCS_Custom_Aggregate">>,
|
||||
|
||||
@ -203,6 +218,9 @@ def RetCC_ARM_AAPCS_VFP : CallingConv<[
|
||||
CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType<f64>>,
|
||||
CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType<v2f64>>,
|
||||
|
||||
// A SwiftError is returned in R6.
|
||||
CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R6]>>>,
|
||||
|
||||
CCIfType<[v2f64], CCAssignToReg<[Q0, Q1, Q2, Q3]>>,
|
||||
CCIfType<[f64], CCAssignToReg<[D0, D1, D2, D3, D4, D5, D6, D7]>>,
|
||||
CCIfType<[f32], CCAssignToReg<[S0, S1, S2, S3, S4, S5, S6, S7, S8,
|
||||
@ -231,6 +249,9 @@ def CSR_AAPCS_ThisReturn : CalleeSavedRegs<(add LR, R11, R10, R9, R8, R7, R6,
|
||||
// Also save R7-R4 first to match the stack frame fixed spill areas.
|
||||
def CSR_iOS : CalleeSavedRegs<(add LR, R7, R6, R5, R4, (sub CSR_AAPCS, R9))>;
|
||||
|
||||
// R6 is used to pass swifterror, remove it from CSR.
|
||||
def CSR_iOS_SwiftError : CalleeSavedRegs<(sub CSR_iOS, R6)>;
|
||||
|
||||
def CSR_iOS_ThisReturn : CalleeSavedRegs<(add LR, R7, R6, R5, R4,
|
||||
(sub CSR_AAPCS_ThisReturn, R9))>;
|
||||
|
||||
|
@ -1062,6 +1062,21 @@ bool ARMFastISel::SelectLoad(const Instruction *I) {
|
||||
if (cast<LoadInst>(I)->isAtomic())
|
||||
return false;
|
||||
|
||||
const Value *SV = I->getOperand(0);
|
||||
if (TLI.supportSwiftError()) {
|
||||
// Swifterror values can come from either a function parameter with
|
||||
// swifterror attribute or an alloca with swifterror attribute.
|
||||
if (const Argument *Arg = dyn_cast<Argument>(SV)) {
|
||||
if (Arg->hasSwiftErrorAttr())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (const AllocaInst *Alloca = dyn_cast<AllocaInst>(SV)) {
|
||||
if (Alloca->isSwiftError())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify we have a legal type before going any further.
|
||||
MVT VT;
|
||||
if (!isLoadTypeLegal(I->getType(), VT))
|
||||
@ -1177,6 +1192,21 @@ bool ARMFastISel::SelectStore(const Instruction *I) {
|
||||
if (cast<StoreInst>(I)->isAtomic())
|
||||
return false;
|
||||
|
||||
const Value *PtrV = I->getOperand(1);
|
||||
if (TLI.supportSwiftError()) {
|
||||
// Swifterror values can come from either a function parameter with
|
||||
// swifterror attribute or an alloca with swifterror attribute.
|
||||
if (const Argument *Arg = dyn_cast<Argument>(PtrV)) {
|
||||
if (Arg->hasSwiftErrorAttr())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (const AllocaInst *Alloca = dyn_cast<AllocaInst>(PtrV)) {
|
||||
if (Alloca->isSwiftError())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify we have a legal type before going any further.
|
||||
MVT VT;
|
||||
if (!isLoadTypeLegal(I->getOperand(0)->getType(), VT))
|
||||
@ -2085,6 +2115,10 @@ bool ARMFastISel::SelectRet(const Instruction *I) {
|
||||
if (!FuncInfo.CanLowerReturn)
|
||||
return false;
|
||||
|
||||
if (TLI.supportSwiftError() &&
|
||||
F.getAttributes().hasAttrSomewhere(Attribute::SwiftError))
|
||||
return false;
|
||||
|
||||
if (TLI.supportSplitCSR(FuncInfo.MF))
|
||||
return false;
|
||||
|
||||
@ -2347,6 +2381,7 @@ bool ARMFastISel::SelectCall(const Instruction *I,
|
||||
if (CS.paramHasAttr(AttrInd, Attribute::InReg) ||
|
||||
CS.paramHasAttr(AttrInd, Attribute::StructRet) ||
|
||||
CS.paramHasAttr(AttrInd, Attribute::SwiftSelf) ||
|
||||
CS.paramHasAttr(AttrInd, Attribute::SwiftError) ||
|
||||
CS.paramHasAttr(AttrInd, Attribute::Nest) ||
|
||||
CS.paramHasAttr(AttrInd, Attribute::ByVal))
|
||||
return false;
|
||||
@ -3023,6 +3058,7 @@ bool ARMFastISel::fastLowerArguments() {
|
||||
if (F->getAttributes().hasAttribute(Idx, Attribute::InReg) ||
|
||||
F->getAttributes().hasAttribute(Idx, Attribute::StructRet) ||
|
||||
F->getAttributes().hasAttribute(Idx, Attribute::SwiftSelf) ||
|
||||
F->getAttributes().hasAttribute(Idx, Attribute::SwiftError) ||
|
||||
F->getAttributes().hasAttribute(Idx, Attribute::ByVal))
|
||||
return false;
|
||||
|
||||
|
@ -470,6 +470,10 @@ namespace llvm {
|
||||
bool isCheapToSpeculateCttz() const override;
|
||||
bool isCheapToSpeculateCtlz() const override;
|
||||
|
||||
bool supportSwiftError() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::pair<const TargetRegisterClass *, uint8_t>
|
||||
findRepresentativeClass(const TargetRegisterInfo *TRI,
|
||||
|
@ -162,6 +162,9 @@ def RetCC_X86_64_C : CallingConv<[
|
||||
|
||||
// MMX vector types are always returned in XMM0.
|
||||
CCIfType<[x86mmx], CCAssignToReg<[XMM0, XMM1]>>,
|
||||
|
||||
CCIfSwiftError<CCIfType<[i64], CCAssignToReg<[R12]>>>,
|
||||
|
||||
CCDelegateTo<RetCC_X86Common>
|
||||
]>;
|
||||
|
||||
@ -297,6 +300,9 @@ def CC_X86_64_C : CallingConv<[
|
||||
// A SwiftSelf is passed in R10.
|
||||
CCIfSwiftSelf<CCIfType<[i64], CCAssignToReg<[R10]>>>,
|
||||
|
||||
// A SwiftError is passed in R12.
|
||||
CCIfSwiftError<CCIfType<[i64], CCAssignToReg<[R12]>>>,
|
||||
|
||||
// The first 6 integer arguments are passed in integer registers.
|
||||
CCIfType<[i32], CCAssignToReg<[EDI, ESI, EDX, ECX, R8D, R9D]>>,
|
||||
CCIfType<[i64], CCAssignToReg<[RDI, RSI, RDX, RCX, R8 , R9 ]>>,
|
||||
@ -845,6 +851,8 @@ def CSR_NoRegs : CalleeSavedRegs<(add)>;
|
||||
def CSR_32 : CalleeSavedRegs<(add ESI, EDI, EBX, EBP)>;
|
||||
def CSR_64 : CalleeSavedRegs<(add RBX, R12, R13, R14, R15, RBP)>;
|
||||
|
||||
def CSR_64_SwiftError : CalleeSavedRegs<(sub CSR_64, R12)>;
|
||||
|
||||
def CSR_32EHRet : CalleeSavedRegs<(add EAX, EDX, CSR_32)>;
|
||||
def CSR_64EHRet : CalleeSavedRegs<(add RAX, RDX, CSR_64)>;
|
||||
|
||||
|
@ -972,6 +972,21 @@ bool X86FastISel::X86SelectStore(const Instruction *I) {
|
||||
if (S->isAtomic())
|
||||
return false;
|
||||
|
||||
const Value *PtrV = I->getOperand(1);
|
||||
if (TLI.supportSwiftError()) {
|
||||
// Swifterror values can come from either a function parameter with
|
||||
// swifterror attribute or an alloca with swifterror attribute.
|
||||
if (const Argument *Arg = dyn_cast<Argument>(PtrV)) {
|
||||
if (Arg->hasSwiftErrorAttr())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (const AllocaInst *Alloca = dyn_cast<AllocaInst>(PtrV)) {
|
||||
if (Alloca->isSwiftError())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const Value *Val = S->getValueOperand();
|
||||
const Value *Ptr = S->getPointerOperand();
|
||||
|
||||
@ -1002,6 +1017,10 @@ bool X86FastISel::X86SelectRet(const Instruction *I) {
|
||||
if (!FuncInfo.CanLowerReturn)
|
||||
return false;
|
||||
|
||||
if (TLI.supportSwiftError() &&
|
||||
F.getAttributes().hasAttrSomewhere(Attribute::SwiftError))
|
||||
return false;
|
||||
|
||||
if (TLI.supportSplitCSR(FuncInfo.MF))
|
||||
return false;
|
||||
|
||||
@ -1133,6 +1152,21 @@ bool X86FastISel::X86SelectLoad(const Instruction *I) {
|
||||
if (LI->isAtomic())
|
||||
return false;
|
||||
|
||||
const Value *SV = I->getOperand(0);
|
||||
if (TLI.supportSwiftError()) {
|
||||
// Swifterror values can come from either a function parameter with
|
||||
// swifterror attribute or an alloca with swifterror attribute.
|
||||
if (const Argument *Arg = dyn_cast<Argument>(SV)) {
|
||||
if (Arg->hasSwiftErrorAttr())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (const AllocaInst *Alloca = dyn_cast<AllocaInst>(SV)) {
|
||||
if (Alloca->isSwiftError())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
MVT VT;
|
||||
if (!isTypeLegal(LI->getType(), VT, /*AllowI1=*/true))
|
||||
return false;
|
||||
@ -2745,6 +2779,7 @@ bool X86FastISel::fastLowerArguments() {
|
||||
F->getAttributes().hasAttribute(Idx, Attribute::InReg) ||
|
||||
F->getAttributes().hasAttribute(Idx, Attribute::StructRet) ||
|
||||
F->getAttributes().hasAttribute(Idx, Attribute::SwiftSelf) ||
|
||||
F->getAttributes().hasAttribute(Idx, Attribute::SwiftError) ||
|
||||
F->getAttributes().hasAttribute(Idx, Attribute::Nest))
|
||||
return false;
|
||||
|
||||
@ -2877,6 +2912,10 @@ bool X86FastISel::fastLowerCall(CallLoweringInfo &CLI) {
|
||||
if (CLI.CS && CLI.CS->hasInAllocaArgument())
|
||||
return false;
|
||||
|
||||
for (auto Flag : CLI.OutFlags)
|
||||
if (Flag.isSwiftError())
|
||||
return false;
|
||||
|
||||
// Fast-isel doesn't know about callee-pop yet.
|
||||
if (X86::isCalleePop(CC, Subtarget->is64Bit(), IsVarArg,
|
||||
TM.Options.GuaranteedTailCallOpt))
|
||||
|
@ -2227,7 +2227,26 @@ X86TargetLowering::LowerReturn(SDValue Chain,
|
||||
// false, then an sret argument may be implicitly inserted in the SelDAG. In
|
||||
// either case FuncInfo->setSRetReturnReg() will have been called.
|
||||
if (unsigned SRetReg = FuncInfo->getSRetReturnReg()) {
|
||||
SDValue Val = DAG.getCopyFromReg(Chain, dl, SRetReg,
|
||||
// When we have both sret and another return value, we should use the
|
||||
// original Chain stored in RetOps[0], instead of the current Chain updated
|
||||
// in the above loop. If we only have sret, RetOps[0] equals to Chain.
|
||||
|
||||
// For the case of sret and another return value, we have
|
||||
// Chain_0 at the function entry
|
||||
// Chain_1 = getCopyToReg(Chain_0) in the above loop
|
||||
// If we use Chain_1 in getCopyFromReg, we will have
|
||||
// Val = getCopyFromReg(Chain_1)
|
||||
// Chain_2 = getCopyToReg(Chain_1, Val) from below
|
||||
|
||||
// getCopyToReg(Chain_0) will be glued together with
|
||||
// getCopyToReg(Chain_1, Val) into Unit A, getCopyFromReg(Chain_1) will be
|
||||
// in Unit B, and we will have cyclic dependency between Unit A and Unit B:
|
||||
// Data dependency from Unit B to Unit A due to usage of Val in
|
||||
// getCopyToReg(Chain_1, Val)
|
||||
// Chain dependency from Unit A to Unit B
|
||||
|
||||
// So here, we use RetOps[0] (i.e Chain_0) for getCopyFromReg.
|
||||
SDValue Val = DAG.getCopyFromReg(RetOps[0], dl, SRetReg,
|
||||
getPointerTy(MF.getDataLayout()));
|
||||
|
||||
unsigned RetValReg
|
||||
|
@ -984,6 +984,10 @@ namespace llvm {
|
||||
|
||||
bool isIntDivCheap(EVT VT, AttributeSet Attr) const override;
|
||||
|
||||
bool supportSwiftError() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::pair<const TargetRegisterClass *, uint8_t>
|
||||
findRepresentativeClass(const TargetRegisterInfo *TRI,
|
||||
|
@ -299,6 +299,10 @@ X86RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
|
||||
return CSR_Win64_SaveList;
|
||||
if (CallsEHReturn)
|
||||
return CSR_64EHRet_SaveList;
|
||||
if (Subtarget.getTargetLowering()->supportSwiftError() &&
|
||||
MF->getFunction()->getAttributes().hasAttrSomewhere(
|
||||
Attribute::SwiftError))
|
||||
return CSR_64_SwiftError_SaveList;
|
||||
return CSR_64_SaveList;
|
||||
}
|
||||
if (CallsEHReturn)
|
||||
@ -385,6 +389,10 @@ X86RegisterInfo::getCallPreservedMask(const MachineFunction &MF,
|
||||
if (Is64Bit) {
|
||||
if (IsWin64)
|
||||
return CSR_Win64_RegMask;
|
||||
if (Subtarget.getTargetLowering()->supportSwiftError() &&
|
||||
MF.getFunction()->getAttributes().hasAttrSomewhere(
|
||||
Attribute::SwiftError))
|
||||
return CSR_64_SwiftError_RegMask;
|
||||
return CSR_64_RegMask;
|
||||
}
|
||||
return CSR_32_RegMask;
|
||||
|
385
test/CodeGen/AArch64/swifterror.ll
Normal file
385
test/CodeGen/AArch64/swifterror.ll
Normal file
@ -0,0 +1,385 @@
|
||||
; RUN: llc -verify-machineinstrs < %s -mtriple=aarch64-apple-ios -disable-post-ra | FileCheck --check-prefix=CHECK-APPLE %s
|
||||
; RUN: llc -verify-machineinstrs -O0 < %s -mtriple=aarch64-apple-ios -disable-post-ra | FileCheck --check-prefix=CHECK-O0 %s
|
||||
|
||||
declare i8* @malloc(i64)
|
||||
declare void @free(i8*)
|
||||
%swift_error = type {i64, i8}
|
||||
|
||||
; This tests the basic usage of a swifterror parameter. "foo" is the function
|
||||
; that takes a swifterror parameter and "caller" is the caller of "foo".
|
||||
define float @foo(%swift_error** swifterror %error_ptr_ref) {
|
||||
; CHECK-APPLE-LABEL: foo:
|
||||
; CHECK-APPLE: orr w0, wzr, #0x10
|
||||
; CHECK-APPLE: malloc
|
||||
; CHECK-APPLE: orr [[ID:w[0-9]+]], wzr, #0x1
|
||||
; CHECK-APPLE: strb [[ID]], [x0, #8]
|
||||
; CHECK-APPLE: mov x19, x0
|
||||
; CHECK-APPLE-NOT: x19
|
||||
|
||||
; CHECK-O0-LABEL: foo:
|
||||
; CHECK-O0: orr w{{.*}}, wzr, #0x10
|
||||
; CHECK-O0: malloc
|
||||
; CHECK-O0: mov [[ID2:x[0-9]+]], x0
|
||||
; CHECK-O0: orr [[ID:w[0-9]+]], wzr, #0x1
|
||||
; CHECK-O0: strb [[ID]], [x0, #8]
|
||||
; CHECK-O0: mov x19, [[ID2]]
|
||||
; CHECK-O0-NOT: x19
|
||||
entry:
|
||||
%call = call i8* @malloc(i64 16)
|
||||
%call.0 = bitcast i8* %call to %swift_error*
|
||||
store %swift_error* %call.0, %swift_error** %error_ptr_ref
|
||||
%tmp = getelementptr inbounds i8, i8* %call, i64 8
|
||||
store i8 1, i8* %tmp
|
||||
ret float 1.0
|
||||
}
|
||||
|
||||
; "caller" calls "foo" that takes a swifterror parameter.
|
||||
define float @caller(i8* %error_ref) {
|
||||
; CHECK-APPLE-LABEL: caller:
|
||||
; CHECK-APPLE: mov [[ID:x[0-9]+]], x0
|
||||
; CHECK-APPLE: mov x19, xzr
|
||||
; CHECK-APPLE: bl {{.*}}foo
|
||||
; CHECK-APPLE: cbnz x19
|
||||
; Access part of the error object and save it to error_ref
|
||||
; CHECK-APPLE: ldrb [[CODE:w[0-9]+]], [x19, #8]
|
||||
; CHECK-APPLE: strb [[CODE]], [{{.*}}[[ID]]]
|
||||
; CHECK-APPLE: mov x0, x19
|
||||
; CHECK_APPLE: bl {{.*}}free
|
||||
|
||||
; CHECK-O0-LABEL: caller:
|
||||
; CHECK-O0: mov x19
|
||||
; CHECK-O0: bl {{.*}}foo
|
||||
; CHECK-O0: mov [[ID:x[0-9]+]], x19
|
||||
; CHECK-O0: cbnz [[ID]]
|
||||
entry:
|
||||
%error_ptr_ref = alloca swifterror %swift_error*
|
||||
store %swift_error* null, %swift_error** %error_ptr_ref
|
||||
%call = call float @foo(%swift_error** swifterror %error_ptr_ref)
|
||||
%error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
|
||||
%had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
|
||||
%tmp = bitcast %swift_error* %error_from_foo to i8*
|
||||
br i1 %had_error_from_foo, label %handler, label %cont
|
||||
cont:
|
||||
%v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
|
||||
%t = load i8, i8* %v1
|
||||
store i8 %t, i8* %error_ref
|
||||
br label %handler
|
||||
handler:
|
||||
call void @free(i8* %tmp)
|
||||
ret float 1.0
|
||||
}
|
||||
|
||||
; "caller2" is the caller of "foo", it calls "foo" inside a loop.
|
||||
define float @caller2(i8* %error_ref) {
|
||||
; CHECK-APPLE-LABEL: caller2:
|
||||
; CHECK-APPLE: mov [[ID:x[0-9]+]], x0
|
||||
; CHECK-APPLE: fmov [[CMP:s[0-9]+]], #1.0
|
||||
; CHECK-APPLE: mov x19, xzr
|
||||
; CHECK-APPLE: bl {{.*}}foo
|
||||
; CHECK-APPLE: cbnz x19
|
||||
; CHECK-APPLE: fcmp s0, [[CMP]]
|
||||
; CHECK-APPLE: b.le
|
||||
; Access part of the error object and save it to error_ref
|
||||
; CHECK-APPLE: ldrb [[CODE:w[0-9]+]], [x19, #8]
|
||||
; CHECK-APPLE: strb [[CODE]], [{{.*}}[[ID]]]
|
||||
; CHECK-APPLE: mov x0, x19
|
||||
; CHECK_APPLE: bl {{.*}}free
|
||||
|
||||
; CHECK-O0-LABEL: caller2:
|
||||
; CHECK-O0: mov x19
|
||||
; CHECK-O0: bl {{.*}}foo
|
||||
; CHECK-O0: mov [[ID:x[0-9]+]], x19
|
||||
; CHECK-O0: cbnz [[ID]]
|
||||
entry:
|
||||
%error_ptr_ref = alloca swifterror %swift_error*
|
||||
br label %bb_loop
|
||||
bb_loop:
|
||||
store %swift_error* null, %swift_error** %error_ptr_ref
|
||||
%call = call float @foo(%swift_error** swifterror %error_ptr_ref)
|
||||
%error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
|
||||
%had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
|
||||
%tmp = bitcast %swift_error* %error_from_foo to i8*
|
||||
br i1 %had_error_from_foo, label %handler, label %cont
|
||||
cont:
|
||||
%cmp = fcmp ogt float %call, 1.000000e+00
|
||||
br i1 %cmp, label %bb_end, label %bb_loop
|
||||
bb_end:
|
||||
%v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
|
||||
%t = load i8, i8* %v1
|
||||
store i8 %t, i8* %error_ref
|
||||
br label %handler
|
||||
handler:
|
||||
call void @free(i8* %tmp)
|
||||
ret float 1.0
|
||||
}
|
||||
|
||||
; "foo_if" is a function that takes a swifterror parameter, it sets swifterror
|
||||
; under a certain condition.
|
||||
define float @foo_if(%swift_error** swifterror %error_ptr_ref, i32 %cc) {
|
||||
; CHECK-APPLE-LABEL: foo_if:
|
||||
; CHECK-APPLE: cbz w0
|
||||
; CHECK-APPLE: orr w0, wzr, #0x10
|
||||
; CHECK-APPLE: malloc
|
||||
; CHECK-APPLE: orr [[ID:w[0-9]+]], wzr, #0x1
|
||||
; CHECK-APPLE: strb [[ID]], [x0, #8]
|
||||
; CHECK-APPLE: mov x19, x0
|
||||
; CHECK-APPLE-NOT: x19
|
||||
; CHECK-APPLE: ret
|
||||
|
||||
; CHECK-O0-LABEL: foo_if:
|
||||
; spill x19
|
||||
; CHECK-O0: str x19
|
||||
; CHECK-O0: cbz w0
|
||||
; CHECK-O0: orr w{{.*}}, wzr, #0x10
|
||||
; CHECK-O0: malloc
|
||||
; CHECK-O0: mov [[ID:x[0-9]+]], x0
|
||||
; CHECK-O0: orr [[ID2:w[0-9]+]], wzr, #0x1
|
||||
; CHECK-O0: strb [[ID2]], [x0, #8]
|
||||
; CHECK-O0: mov x19, [[ID]]
|
||||
; CHECK-O0: ret
|
||||
; reload from stack
|
||||
; CHECK-O0: ldr x19
|
||||
; CHECK-O0: ret
|
||||
entry:
|
||||
%cond = icmp ne i32 %cc, 0
|
||||
br i1 %cond, label %gen_error, label %normal
|
||||
|
||||
gen_error:
|
||||
%call = call i8* @malloc(i64 16)
|
||||
%call.0 = bitcast i8* %call to %swift_error*
|
||||
store %swift_error* %call.0, %swift_error** %error_ptr_ref
|
||||
%tmp = getelementptr inbounds i8, i8* %call, i64 8
|
||||
store i8 1, i8* %tmp
|
||||
ret float 1.0
|
||||
|
||||
normal:
|
||||
ret float 0.0
|
||||
}
|
||||
|
||||
; "foo_loop" is a function that takes a swifterror parameter, it sets swifterror
|
||||
; under a certain condition inside a loop.
|
||||
define float @foo_loop(%swift_error** swifterror %error_ptr_ref, i32 %cc, float %cc2) {
|
||||
; CHECK-APPLE-LABEL: foo_loop:
|
||||
; CHECK-APPLE: mov x0, x19
|
||||
; CHECK-APPLE: cbz
|
||||
; CHECK-APPLE: orr w0, wzr, #0x10
|
||||
; CHECK-APPLE: malloc
|
||||
; CHECK-APPLE: strb w{{.*}}, [x0, #8]
|
||||
; CHECK-APPLE: fcmp
|
||||
; CHECK-APPLE: b.le
|
||||
; CHECK-APPLE: mov x19, x0
|
||||
; CHECK-APPLE: ret
|
||||
|
||||
; CHECK-O0-LABEL: foo_loop:
|
||||
; spill x19
|
||||
; CHECK-O0: str x19
|
||||
; CHECk-O0: cbz
|
||||
; CHECK-O0: orr w{{.*}}, wzr, #0x10
|
||||
; CHECK-O0: malloc
|
||||
; CHECK-O0: mov [[ID:x[0-9]+]], x0
|
||||
; CHECK-O0: strb w{{.*}}, [{{.*}}[[ID]], #8]
|
||||
; spill x0
|
||||
; CHECK-O0: str x0
|
||||
; CHECK-O0: fcmp
|
||||
; CHECK-O0: b.le
|
||||
; reload from stack
|
||||
; CHECK-O0: ldr x19
|
||||
; CHECK-O0: ret
|
||||
entry:
|
||||
br label %bb_loop
|
||||
|
||||
bb_loop:
|
||||
%cond = icmp ne i32 %cc, 0
|
||||
br i1 %cond, label %gen_error, label %bb_cont
|
||||
|
||||
gen_error:
|
||||
%call = call i8* @malloc(i64 16)
|
||||
%call.0 = bitcast i8* %call to %swift_error*
|
||||
store %swift_error* %call.0, %swift_error** %error_ptr_ref
|
||||
%tmp = getelementptr inbounds i8, i8* %call, i64 8
|
||||
store i8 1, i8* %tmp
|
||||
br label %bb_cont
|
||||
|
||||
bb_cont:
|
||||
%cmp = fcmp ogt float %cc2, 1.000000e+00
|
||||
br i1 %cmp, label %bb_end, label %bb_loop
|
||||
bb_end:
|
||||
ret float 0.0
|
||||
}
|
||||
|
||||
%struct.S = type { i32, i32, i32, i32, i32, i32 }
|
||||
|
||||
; "foo_sret" is a function that takes a swifterror parameter, it also has a sret
|
||||
; parameter.
|
||||
define void @foo_sret(%struct.S* sret %agg.result, i32 %val1, %swift_error** swifterror %error_ptr_ref) {
|
||||
; CHECK-APPLE-LABEL: foo_sret:
|
||||
; CHECK-APPLE: mov [[SRET:x[0-9]+]], x8
|
||||
; CHECK-APPLE: orr w0, wzr, #0x10
|
||||
; CHECK-APPLE: malloc
|
||||
; CHECK-APPLE: orr [[ID:w[0-9]+]], wzr, #0x1
|
||||
; CHECK-APPLE: strb [[ID]], [x0, #8]
|
||||
; CHECK-APPLE: str w{{.*}}, [{{.*}}[[SRET]], #4]
|
||||
; CHECK-APPLE: mov x19, x0
|
||||
; CHECK-APPLE-NOT: x19
|
||||
|
||||
; CHECK-O0-LABEL: foo_sret:
|
||||
; CHECK-O0: orr w{{.*}}, wzr, #0x10
|
||||
; spill x8
|
||||
; CHECK-O0-DAG: str x8
|
||||
; spill x19
|
||||
; CHECK-O0-DAG: str x19
|
||||
; CHECK-O0: malloc
|
||||
; CHECK-O0: orr [[ID:w[0-9]+]], wzr, #0x1
|
||||
; CHECK-O0: strb [[ID]], [x0, #8]
|
||||
; reload from stack
|
||||
; CHECK-O0: ldr [[SRET:x[0-9]+]]
|
||||
; CHECK-O0: str w{{.*}}, [{{.*}}[[SRET]], #4]
|
||||
; CHECK-O0: mov x19
|
||||
; CHECK-O0-NOT: x19
|
||||
entry:
|
||||
%call = call i8* @malloc(i64 16)
|
||||
%call.0 = bitcast i8* %call to %swift_error*
|
||||
store %swift_error* %call.0, %swift_error** %error_ptr_ref
|
||||
%tmp = getelementptr inbounds i8, i8* %call, i64 8
|
||||
store i8 1, i8* %tmp
|
||||
%v2 = getelementptr inbounds %struct.S, %struct.S* %agg.result, i32 0, i32 1
|
||||
store i32 %val1, i32* %v2
|
||||
ret void
|
||||
}
|
||||
|
||||
; "caller3" calls "foo_sret" that takes a swifterror parameter.
|
||||
define float @caller3(i8* %error_ref) {
|
||||
; CHECK-APPLE-LABEL: caller3:
|
||||
; CHECK-APPLE: mov [[ID:x[0-9]+]], x0
|
||||
; CHECK-APPLE: mov x19, xzr
|
||||
; CHECK-APPLE: bl {{.*}}foo_sret
|
||||
; CHECK-APPLE: cbnz x19
|
||||
; Access part of the error object and save it to error_ref
|
||||
; CHECK-APPLE: ldrb [[CODE:w[0-9]+]], [x19, #8]
|
||||
; CHECK-APPLE: strb [[CODE]], [{{.*}}[[ID]]]
|
||||
; CHECK-APPLE: mov x0, x19
|
||||
; CHECK_APPLE: bl {{.*}}free
|
||||
|
||||
; CHECK-O0-LABEL: caller3:
|
||||
; spill x0
|
||||
; CHECK-O0: str x0
|
||||
; CHECK-O0: mov x19
|
||||
; CHECK-O0: bl {{.*}}foo_sret
|
||||
; CHECK-O0: mov [[ID2:x[0-9]+]], x19
|
||||
; CHECK-O0: cbnz [[ID2]]
|
||||
; Access part of the error object and save it to error_ref
|
||||
; reload from stack
|
||||
; CHECK-O0: ldrb [[CODE:w[0-9]+]]
|
||||
; CHECK-O0: ldr [[ID:x[0-9]+]]
|
||||
; CHECK-O0: strb [[CODE]], [{{.*}}[[ID]]]
|
||||
; CHECK_O0: bl {{.*}}free
|
||||
entry:
|
||||
%s = alloca %struct.S, align 8
|
||||
%error_ptr_ref = alloca swifterror %swift_error*
|
||||
store %swift_error* null, %swift_error** %error_ptr_ref
|
||||
call void @foo_sret(%struct.S* sret %s, i32 1, %swift_error** swifterror %error_ptr_ref)
|
||||
%error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
|
||||
%had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
|
||||
%tmp = bitcast %swift_error* %error_from_foo to i8*
|
||||
br i1 %had_error_from_foo, label %handler, label %cont
|
||||
cont:
|
||||
%v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
|
||||
%t = load i8, i8* %v1
|
||||
store i8 %t, i8* %error_ref
|
||||
br label %handler
|
||||
handler:
|
||||
call void @free(i8* %tmp)
|
||||
ret float 1.0
|
||||
}
|
||||
|
||||
; "foo_vararg" is a function that takes a swifterror parameter, it also has
|
||||
; variable number of arguments.
|
||||
declare void @llvm.va_start(i8*) nounwind
|
||||
define float @foo_vararg(%swift_error** swifterror %error_ptr_ref, ...) {
|
||||
; CHECK-APPLE-LABEL: foo_vararg:
|
||||
; CHECK-APPLE: orr w0, wzr, #0x10
|
||||
; CHECK-APPLE: malloc
|
||||
; CHECK-APPLE: orr [[ID:w[0-9]+]], wzr, #0x1
|
||||
; CHECK-FIXMEAPPLE: add [[ARGS:x[0-9]+]], [[TMP:x[0-9]+]], #16
|
||||
; CHECK-APPLE: strb [[ID]], [x0, #8]
|
||||
|
||||
; First vararg
|
||||
; CHECK-FIXMEAPPLE-DAG: orr {{x[0-9]+}}, [[ARGS]], #0x8
|
||||
; CHECK-FIXMEAPPLE-DAG: ldr {{w[0-9]+}}, [{{.*}}[[TMP]], #16]
|
||||
; CHECK-APPLE: add {{x[0-9]+}}, {{x[0-9]+}}, #8
|
||||
; Second vararg
|
||||
; CHECK-APPLE: ldr {{w[0-9]+}}, [{{x[0-9]+}}]
|
||||
; CHECK-APPLE: add {{x[0-9]+}}, {{x[0-9]+}}, #8
|
||||
; Third vararg
|
||||
; CHECK-APPLE: ldr {{w[0-9]+}}, [{{x[0-9]+}}]
|
||||
|
||||
; CHECK-APPLE: mov x19, x0
|
||||
; CHECK-APPLE-NOT: x19
|
||||
entry:
|
||||
%call = call i8* @malloc(i64 16)
|
||||
%call.0 = bitcast i8* %call to %swift_error*
|
||||
store %swift_error* %call.0, %swift_error** %error_ptr_ref
|
||||
%tmp = getelementptr inbounds i8, i8* %call, i64 8
|
||||
store i8 1, i8* %tmp
|
||||
|
||||
%args = alloca i8*, align 8
|
||||
%a10 = alloca i32, align 4
|
||||
%a11 = alloca i32, align 4
|
||||
%a12 = alloca i32, align 4
|
||||
%v10 = bitcast i8** %args to i8*
|
||||
call void @llvm.va_start(i8* %v10)
|
||||
%v11 = va_arg i8** %args, i32
|
||||
store i32 %v11, i32* %a10, align 4
|
||||
%v12 = va_arg i8** %args, i32
|
||||
store i32 %v12, i32* %a11, align 4
|
||||
%v13 = va_arg i8** %args, i32
|
||||
store i32 %v13, i32* %a12, align 4
|
||||
|
||||
ret float 1.0
|
||||
}
|
||||
|
||||
; "caller4" calls "foo_vararg" that takes a swifterror parameter.
|
||||
define float @caller4(i8* %error_ref) {
|
||||
; CHECK-APPLE-LABEL: caller4:
|
||||
|
||||
; CHECK-APPLE: mov [[ID:x[0-9]+]], x0
|
||||
; CHECK-APPLE: stp {{x[0-9]+}}, {{x[0-9]+}}, [sp, #8]
|
||||
; CHECK-APPLE: str {{x[0-9]+}}, [sp]
|
||||
|
||||
; CHECK-APPLE: mov x19, xzr
|
||||
; CHECK-APPLE: bl {{.*}}foo_vararg
|
||||
; CHECK-APPLE: cbnz x19
|
||||
; Access part of the error object and save it to error_ref
|
||||
; CHECK-APPLE: ldrb [[CODE:w[0-9]+]], [x19, #8]
|
||||
; CHECK-APPLE: strb [[CODE]], [{{.*}}[[ID]]]
|
||||
; CHECK-APPLE: mov x0, x19
|
||||
; CHECK_APPLE: bl {{.*}}free
|
||||
entry:
|
||||
%error_ptr_ref = alloca swifterror %swift_error*
|
||||
store %swift_error* null, %swift_error** %error_ptr_ref
|
||||
|
||||
%a10 = alloca i32, align 4
|
||||
%a11 = alloca i32, align 4
|
||||
%a12 = alloca i32, align 4
|
||||
store i32 10, i32* %a10, align 4
|
||||
store i32 11, i32* %a11, align 4
|
||||
store i32 12, i32* %a12, align 4
|
||||
%v10 = load i32, i32* %a10, align 4
|
||||
%v11 = load i32, i32* %a11, align 4
|
||||
%v12 = load i32, i32* %a12, align 4
|
||||
|
||||
%call = call float (%swift_error**, ...) @foo_vararg(%swift_error** swifterror %error_ptr_ref, i32 %v10, i32 %v11, i32 %v12)
|
||||
%error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
|
||||
%had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
|
||||
%tmp = bitcast %swift_error* %error_from_foo to i8*
|
||||
br i1 %had_error_from_foo, label %handler, label %cont
|
||||
|
||||
cont:
|
||||
%v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
|
||||
%t = load i8, i8* %v1
|
||||
store i8 %t, i8* %error_ref
|
||||
br label %handler
|
||||
handler:
|
||||
call void @free(i8* %tmp)
|
||||
ret float 1.0
|
||||
}
|
381
test/CodeGen/ARM/swifterror.ll
Normal file
381
test/CodeGen/ARM/swifterror.ll
Normal file
@ -0,0 +1,381 @@
|
||||
; RUN: llc -verify-machineinstrs < %s -mtriple=armv7-apple-ios | FileCheck --check-prefix=CHECK-APPLE %s
|
||||
; RUN: llc -verify-machineinstrs -O0 < %s -mtriple=armv7-apple-ios | FileCheck --check-prefix=CHECK-O0 %s
|
||||
|
||||
declare i8* @malloc(i64)
|
||||
declare void @free(i8*)
|
||||
%swift_error = type { i64, i8 }
|
||||
%struct.S = type { i32, i32, i32, i32, i32, i32 }
|
||||
|
||||
; This tests the basic usage of a swifterror parameter. "foo" is the function
|
||||
; that takes a swifterror parameter and "caller" is the caller of "foo".
|
||||
define float @foo(%swift_error** swifterror %error_ptr_ref) {
|
||||
; CHECK-APPLE-LABEL: foo:
|
||||
; CHECK-APPLE: mov r0, #16
|
||||
; CHECK-APPLE: malloc
|
||||
; CHECK-APPLE-DAG: mov [[ID:r[0-9]+]], #1
|
||||
; CHECK-APPLE-DAG: mov r6, r{{.*}}
|
||||
; CHECK-APPLE-DAG: strb [[ID]], [r{{.*}}, #8]
|
||||
|
||||
; CHECK-O0-LABEL: foo:
|
||||
; CHECK-O0: mov r{{.*}}, #16
|
||||
; CHECK-O0: malloc
|
||||
; CHECK-O0: mov [[ID2:r[0-9]+]], r0
|
||||
; CHECK-O0: mov [[ID:r[0-9]+]], #1
|
||||
; CHECK-O0: strb [[ID]], [r0, #8]
|
||||
; CHECK-O0: mov r6, [[ID2]]
|
||||
entry:
|
||||
%call = call i8* @malloc(i64 16)
|
||||
%call.0 = bitcast i8* %call to %swift_error*
|
||||
store %swift_error* %call.0, %swift_error** %error_ptr_ref
|
||||
%tmp = getelementptr inbounds i8, i8* %call, i64 8
|
||||
store i8 1, i8* %tmp
|
||||
ret float 1.0
|
||||
}
|
||||
|
||||
; "caller" calls "foo" that takes a swifterror parameter.
|
||||
define float @caller(i8* %error_ref) {
|
||||
; CHECK-APPLE-LABEL: caller:
|
||||
; CHECK-APPLE-DAG: mov [[ID:r[0-9]+]], r0
|
||||
; CHECK-APPLE-DAG: mov r6, #0
|
||||
; CHECK-APPLE: bl {{.*}}foo
|
||||
; CHECK-APPLE: cmp r6, #0
|
||||
; Access part of the error object and save it to error_ref
|
||||
; CHECK-APPLE: ldrbeq [[CODE:r[0-9]+]], [r6, #8]
|
||||
; CHECK-APPLE: strbeq [[CODE]], [{{.*}}[[ID]]]
|
||||
; CHECK-APPLE: mov r0, r6
|
||||
; CHECK_APPLE: bl {{.*}}free
|
||||
|
||||
; CHECK-O0-LABEL: caller:
|
||||
; spill r0
|
||||
; CHECK-O0-DAG: str r0,
|
||||
; CHECK-O0-DAG: mov r6, #0
|
||||
; CHECK-O0: bl {{.*}}foo
|
||||
; CHECK-O0: mov r{{.*}}, r6
|
||||
; CHECK-O0: bne
|
||||
; CHECK-O0: ldrb [[CODE:r[0-9]+]], [r0, #8]
|
||||
; reload r0
|
||||
; CHECK-O0: ldr [[ID:r[0-9]+]],
|
||||
; CHECK-O0: strb [[CODE]], [{{.*}}[[ID]]]
|
||||
; CHECK-O0: mov r0,
|
||||
; CHECK-O0: free
|
||||
entry:
|
||||
%error_ptr_ref = alloca swifterror %swift_error*
|
||||
store %swift_error* null, %swift_error** %error_ptr_ref
|
||||
%call = call float @foo(%swift_error** swifterror %error_ptr_ref)
|
||||
%error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
|
||||
%had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
|
||||
%tmp = bitcast %swift_error* %error_from_foo to i8*
|
||||
br i1 %had_error_from_foo, label %handler, label %cont
|
||||
cont:
|
||||
%v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
|
||||
%t = load i8, i8* %v1
|
||||
store i8 %t, i8* %error_ref
|
||||
br label %handler
|
||||
handler:
|
||||
call void @free(i8* %tmp)
|
||||
ret float 1.0
|
||||
}
|
||||
|
||||
; "caller2" is the caller of "foo", it calls "foo" inside a loop.
|
||||
define float @caller2(i8* %error_ref) {
|
||||
; CHECK-APPLE-LABEL: caller2:
|
||||
; CHECK-APPLE-DAG: mov [[ID:r[0-9]+]], r0
|
||||
; CHECK-APPLE-DAG: mov r6, #0
|
||||
; CHECK-APPLE: bl {{.*}}foo
|
||||
; CHECK-APPLE: cmp r6, #0
|
||||
; CHECK-APPLE: bne
|
||||
; Access part of the error object and save it to error_ref
|
||||
; CHECK-APPLE: ldrb [[CODE:r[0-9]+]], [r6, #8]
|
||||
; CHECK-APPLE: strb [[CODE]], [{{.*}}[[ID]]]
|
||||
; CHECK-APPLE: mov r0, r6
|
||||
; CHECK_APPLE: bl {{.*}}free
|
||||
|
||||
; CHECK-O0-LABEL: caller2:
|
||||
; spill r0
|
||||
; CHECK-O0-DAG: str r0,
|
||||
; CHECK-O0-DAG: mov r6, #0
|
||||
; CHECK-O0: bl {{.*}}foo
|
||||
; CHECK-O0: mov r{{.*}}, r6
|
||||
; CHECK-O0: bne
|
||||
; CHECK-O0: ble
|
||||
; CHECK-O0: ldrb [[CODE:r[0-9]+]], [r0, #8]
|
||||
; reload r0
|
||||
; CHECK-O0: ldr [[ID:r[0-9]+]],
|
||||
; CHECK-O0: strb [[CODE]], [{{.*}}[[ID]]]
|
||||
; CHECK-O0: mov r0,
|
||||
; CHECK-O0: free
|
||||
entry:
|
||||
%error_ptr_ref = alloca swifterror %swift_error*
|
||||
br label %bb_loop
|
||||
bb_loop:
|
||||
store %swift_error* null, %swift_error** %error_ptr_ref
|
||||
%call = call float @foo(%swift_error** swifterror %error_ptr_ref)
|
||||
%error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
|
||||
%had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
|
||||
%tmp = bitcast %swift_error* %error_from_foo to i8*
|
||||
br i1 %had_error_from_foo, label %handler, label %cont
|
||||
cont:
|
||||
%cmp = fcmp ogt float %call, 1.000000e+00
|
||||
br i1 %cmp, label %bb_end, label %bb_loop
|
||||
bb_end:
|
||||
%v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
|
||||
%t = load i8, i8* %v1
|
||||
store i8 %t, i8* %error_ref
|
||||
br label %handler
|
||||
handler:
|
||||
call void @free(i8* %tmp)
|
||||
ret float 1.0
|
||||
}
|
||||
|
||||
; "foo_if" is a function that takes a swifterror parameter, it sets swifterror
|
||||
; under a certain condition.
|
||||
define float @foo_if(%swift_error** swifterror %error_ptr_ref, i32 %cc) {
|
||||
; CHECK-APPLE-LABEL: foo_if:
|
||||
; CHECK-APPLE: cmp r0, #0
|
||||
; CHECK-APPLE: eq
|
||||
; CHECK-APPLE: mov r0, #16
|
||||
; CHECK-APPLE: malloc
|
||||
; CHECK-APPLE: mov [[ID:r[0-9]+]], #1
|
||||
; CHECK-APPLE-DAG: mov r6, r{{.*}}
|
||||
; CHECK-APPLE-DAG: strb [[ID]], [r{{.*}}, #8]
|
||||
|
||||
; CHECK-O0-LABEL: foo_if:
|
||||
; CHECK-O0: cmp r0, #0
|
||||
; spill to stack
|
||||
; CHECK-O0: str r6
|
||||
; CHECK-O0: beq
|
||||
; CHECK-O0: mov r0, #16
|
||||
; CHECK-O0: malloc
|
||||
; CHECK-O0: mov [[ID:r[0-9]+]], r0
|
||||
; CHECK-O0: mov [[ID2:[a-z0-9]+]], #1
|
||||
; CHECK-O0: strb [[ID2]], [r0, #8]
|
||||
; CHECK-O0: mov r6, [[ID]]
|
||||
; reload from stack
|
||||
; CHECK-O0: ldr r6
|
||||
entry:
|
||||
%cond = icmp ne i32 %cc, 0
|
||||
br i1 %cond, label %gen_error, label %normal
|
||||
|
||||
gen_error:
|
||||
%call = call i8* @malloc(i64 16)
|
||||
%call.0 = bitcast i8* %call to %swift_error*
|
||||
store %swift_error* %call.0, %swift_error** %error_ptr_ref
|
||||
%tmp = getelementptr inbounds i8, i8* %call, i64 8
|
||||
store i8 1, i8* %tmp
|
||||
ret float 1.0
|
||||
|
||||
normal:
|
||||
ret float 0.0
|
||||
}
|
||||
|
||||
; "foo_loop" is a function that takes a swifterror parameter, it sets swifterror
|
||||
; under a certain condition inside a loop.
|
||||
define float @foo_loop(%swift_error** swifterror %error_ptr_ref, i32 %cc, float %cc2) {
|
||||
; CHECK-APPLE-LABEL: foo_loop:
|
||||
; CHECK-APPLE: mov [[CODE:r[0-9]+]], r0
|
||||
; swifterror is kept in a register
|
||||
; CHECK-APPLE: mov [[ID:r[0-9]+]], r6
|
||||
; CHECK-APPLE: cmp [[CODE]], #0
|
||||
; CHECK-APPLE: beq
|
||||
; CHECK-APPLE: mov r0, #16
|
||||
; CHECK-APPLE: malloc
|
||||
; CHECK-APPLE: strb r{{.*}}, [{{.*}}[[ID]], #8]
|
||||
; CHECK-APPLE: ble
|
||||
; CHECK-APPLE: mov r6, [[ID]]
|
||||
|
||||
; CHECK-O0-LABEL: foo_loop:
|
||||
; CHECK-O0: mov r{{.*}}, r6
|
||||
; CHECK-O0: cmp r{{.*}}, #0
|
||||
; CHECK-O0: beq
|
||||
; CHECK-O0-DAG: movw r{{.*}}, #1
|
||||
; CHECK-O0-DAG: mov r{{.*}}, #16
|
||||
; CHECK-O0: malloc
|
||||
; CHECK-O0-DAG: mov [[ID:r[0-9]+]], r0
|
||||
; CHECK-O0-DAG: ldr [[ID2:r[0-9]+]], [sp{{.*}}]
|
||||
; CHECK-O0: strb [[ID2]], [{{.*}}[[ID]], #8]
|
||||
; spill r0
|
||||
; CHECK-O0: str r0, [sp{{.*}}]
|
||||
; CHECK-O0: vcmpe
|
||||
; CHECK-O0: ble
|
||||
; reload from stack
|
||||
; CHECK-O0: ldr r6
|
||||
entry:
|
||||
br label %bb_loop
|
||||
|
||||
bb_loop:
|
||||
%cond = icmp ne i32 %cc, 0
|
||||
br i1 %cond, label %gen_error, label %bb_cont
|
||||
|
||||
gen_error:
|
||||
%call = call i8* @malloc(i64 16)
|
||||
%call.0 = bitcast i8* %call to %swift_error*
|
||||
store %swift_error* %call.0, %swift_error** %error_ptr_ref
|
||||
%tmp = getelementptr inbounds i8, i8* %call, i64 8
|
||||
store i8 1, i8* %tmp
|
||||
br label %bb_cont
|
||||
|
||||
bb_cont:
|
||||
%cmp = fcmp ogt float %cc2, 1.000000e+00
|
||||
br i1 %cmp, label %bb_end, label %bb_loop
|
||||
bb_end:
|
||||
ret float 0.0
|
||||
}
|
||||
|
||||
; "foo_sret" is a function that takes a swifterror parameter, it also has a sret
|
||||
; parameter.
|
||||
define void @foo_sret(%struct.S* sret %agg.result, i32 %val1, %swift_error** swifterror %error_ptr_ref) {
|
||||
; CHECK-APPLE-LABEL: foo_sret:
|
||||
; CHECK-APPLE: mov [[SRET:r[0-9]+]], r0
|
||||
; CHECK-APPLE: mov r0, #16
|
||||
; CHECK-APPLE: malloc
|
||||
; CHECK-APPLE: mov [[REG:r[0-9]+]], #1
|
||||
; CHECK-APPLE-DAG: mov r6, r0
|
||||
; CHECK-APPLE-DAG: strb [[REG]], [r0, #8]
|
||||
; CHECK-APPLE-DAG: str r{{.*}}, [{{.*}}[[SRET]], #4]
|
||||
|
||||
; CHECK-O0-LABEL: foo_sret:
|
||||
; CHECK-O0: mov r{{.*}}, #16
|
||||
; spill to stack: sret and val1
|
||||
; CHECK-O0-DAG: str r0
|
||||
; CHECK-O0-DAG: str r1
|
||||
; CHECK-O0: malloc
|
||||
; CHECK-O0: mov [[ID:r[0-9]+]], #1
|
||||
; CHECK-O0: strb [[ID]], [r0, #8]
|
||||
; reload from stack: sret and val1
|
||||
; CHECK-O0: ldr
|
||||
; CHECK-O0: ldr
|
||||
; CHECK-O0: str r{{.*}}, [{{.*}}, #4]
|
||||
; CHECK-O0: mov r6
|
||||
entry:
|
||||
%call = call i8* @malloc(i64 16)
|
||||
%call.0 = bitcast i8* %call to %swift_error*
|
||||
store %swift_error* %call.0, %swift_error** %error_ptr_ref
|
||||
%tmp = getelementptr inbounds i8, i8* %call, i64 8
|
||||
store i8 1, i8* %tmp
|
||||
%v2 = getelementptr inbounds %struct.S, %struct.S* %agg.result, i32 0, i32 1
|
||||
store i32 %val1, i32* %v2
|
||||
ret void
|
||||
}
|
||||
|
||||
; "caller3" calls "foo_sret" that takes a swifterror parameter.
|
||||
define float @caller3(i8* %error_ref) {
|
||||
; CHECK-APPLE-LABEL: caller3:
|
||||
; CHECK-APPLE: mov [[ID:r[0-9]+]], r0
|
||||
; CHECK-APPLE: mov r6, #0
|
||||
; CHECK-APPLE: bl {{.*}}foo_sret
|
||||
; CHECK-APPLE: cmp r6, #0
|
||||
; Access part of the error object and save it to error_ref
|
||||
; CHECK-APPLE: ldrbeq [[CODE:r[0-9]+]], [r6, #8]
|
||||
; CHECK-APPLE: strbeq [[CODE]], [{{.*}}[[ID]]]
|
||||
; CHECK-APPLE: mov r0, r6
|
||||
; CHECK_APPLE: bl {{.*}}free
|
||||
|
||||
; CHECK-O0-LABEL: caller3:
|
||||
; CHECK-O0-DAG: mov r6, #0
|
||||
; CHECK-O0-DAG: mov r0
|
||||
; CHECK-O0-DAG: mov r1
|
||||
; CHECK-O0: bl {{.*}}foo_sret
|
||||
; CHECK-O0: mov [[ID2:r[0-9]+]], r6
|
||||
; CHECK-O0: cmp [[ID2]]
|
||||
; CHECK-O0: bne
|
||||
; Access part of the error object and save it to error_ref
|
||||
; CHECK-O0: ldrb [[CODE:r[0-9]+]]
|
||||
; CHECK-O0: ldr [[ID:r[0-9]+]]
|
||||
; CHECK-O0: strb [[CODE]], [{{.*}}[[ID]]]
|
||||
; CHECK-O0: mov r0,
|
||||
; CHECK_O0: bl {{.*}}free
|
||||
entry:
|
||||
%s = alloca %struct.S, align 8
|
||||
%error_ptr_ref = alloca swifterror %swift_error*
|
||||
store %swift_error* null, %swift_error** %error_ptr_ref
|
||||
call void @foo_sret(%struct.S* sret %s, i32 1, %swift_error** swifterror %error_ptr_ref)
|
||||
%error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
|
||||
%had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
|
||||
%tmp = bitcast %swift_error* %error_from_foo to i8*
|
||||
br i1 %had_error_from_foo, label %handler, label %cont
|
||||
cont:
|
||||
%v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
|
||||
%t = load i8, i8* %v1
|
||||
store i8 %t, i8* %error_ref
|
||||
br label %handler
|
||||
handler:
|
||||
call void @free(i8* %tmp)
|
||||
ret float 1.0
|
||||
}
|
||||
|
||||
; "foo_vararg" is a function that takes a swifterror parameter, it also has
|
||||
; variable number of arguments.
|
||||
declare void @llvm.va_start(i8*) nounwind
|
||||
define float @foo_vararg(%swift_error** swifterror %error_ptr_ref, ...) {
|
||||
; CHECK-APPLE-LABEL: foo_vararg:
|
||||
; CHECK-APPLE: mov r0, #16
|
||||
; CHECK-APPLE: malloc
|
||||
; CHECK-APPLE: mov [[REG:r[0-9]+]], r0
|
||||
; CHECK-APPLE: mov [[ID:r[0-9]+]], #1
|
||||
; CHECK-APPLE-DAG: strb [[ID]], [{{.*}}[[REG]], #8]
|
||||
; CHECK-APPLE-DAG: mov r6, [[REG]]
|
||||
|
||||
entry:
|
||||
%call = call i8* @malloc(i64 16)
|
||||
%call.0 = bitcast i8* %call to %swift_error*
|
||||
store %swift_error* %call.0, %swift_error** %error_ptr_ref
|
||||
%tmp = getelementptr inbounds i8, i8* %call, i64 8
|
||||
store i8 1, i8* %tmp
|
||||
|
||||
%args = alloca i8*, align 8
|
||||
%a10 = alloca i32, align 4
|
||||
%a11 = alloca i32, align 4
|
||||
%a12 = alloca i32, align 4
|
||||
%v10 = bitcast i8** %args to i8*
|
||||
call void @llvm.va_start(i8* %v10)
|
||||
%v11 = va_arg i8** %args, i32
|
||||
store i32 %v11, i32* %a10, align 4
|
||||
%v12 = va_arg i8** %args, i32
|
||||
store i32 %v12, i32* %a11, align 4
|
||||
%v13 = va_arg i8** %args, i32
|
||||
store i32 %v13, i32* %a12, align 4
|
||||
|
||||
ret float 1.0
|
||||
}
|
||||
|
||||
; "caller4" calls "foo_vararg" that takes a swifterror parameter.
|
||||
define float @caller4(i8* %error_ref) {
|
||||
; CHECK-APPLE-LABEL: caller4:
|
||||
; CHECK-APPLE: mov [[ID:r[0-9]+]], r0
|
||||
; CHECK-APPLE: mov r6, #0
|
||||
; CHECK-APPLE: bl {{.*}}foo_vararg
|
||||
; CHECK-APPLE: cmp r6, #0
|
||||
; Access part of the error object and save it to error_ref
|
||||
; CHECK-APPLE: ldrbeq [[CODE:r[0-9]+]], [r6, #8]
|
||||
; CHECK-APPLE: strbeq [[CODE]], [{{.*}}[[ID]]]
|
||||
; CHECK-APPLE: mov r0, r6
|
||||
; CHECK_APPLE: bl {{.*}}free
|
||||
entry:
|
||||
%error_ptr_ref = alloca swifterror %swift_error*
|
||||
store %swift_error* null, %swift_error** %error_ptr_ref
|
||||
|
||||
%a10 = alloca i32, align 4
|
||||
%a11 = alloca i32, align 4
|
||||
%a12 = alloca i32, align 4
|
||||
store i32 10, i32* %a10, align 4
|
||||
store i32 11, i32* %a11, align 4
|
||||
store i32 12, i32* %a12, align 4
|
||||
%v10 = load i32, i32* %a10, align 4
|
||||
%v11 = load i32, i32* %a11, align 4
|
||||
%v12 = load i32, i32* %a12, align 4
|
||||
|
||||
%call = call float (%swift_error**, ...) @foo_vararg(%swift_error** swifterror %error_ptr_ref, i32 %v10, i32 %v11, i32 %v12)
|
||||
%error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
|
||||
%had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
|
||||
%tmp = bitcast %swift_error* %error_from_foo to i8*
|
||||
br i1 %had_error_from_foo, label %handler, label %cont
|
||||
|
||||
cont:
|
||||
%v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
|
||||
%t = load i8, i8* %v1
|
||||
store i8 %t, i8* %error_ref
|
||||
br label %handler
|
||||
handler:
|
||||
call void @free(i8* %tmp)
|
||||
ret float 1.0
|
||||
}
|
359
test/CodeGen/X86/swifterror.ll
Normal file
359
test/CodeGen/X86/swifterror.ll
Normal file
@ -0,0 +1,359 @@
|
||||
; RUN: llc -verify-machineinstrs < %s -mtriple=x86_64-apple-darwin | FileCheck --check-prefix=CHECK-APPLE %s
|
||||
; RUN: llc -verify-machineinstrs -O0 < %s -mtriple=x86_64-apple-darwin | FileCheck --check-prefix=CHECK-O0 %s
|
||||
|
||||
declare i8* @malloc(i64)
|
||||
declare void @free(i8*)
|
||||
%swift_error = type {i64, i8}
|
||||
|
||||
; This tests the basic usage of a swifterror parameter. "foo" is the function
|
||||
; that takes a swifterror parameter and "caller" is the caller of "foo".
|
||||
define float @foo(%swift_error** swifterror %error_ptr_ref) {
|
||||
; CHECK-APPLE-LABEL: foo:
|
||||
; CHECK-APPLE: movl $16, %edi
|
||||
; CHECK-APPLE: malloc
|
||||
; CHECK-APPLE: movb $1, 8(%rax)
|
||||
; CHECK-APPLE: movq %rax, %r12
|
||||
|
||||
; CHECK-O0-LABEL: foo:
|
||||
; CHECK-O0: movl $16
|
||||
; CHECK-O0: malloc
|
||||
; CHECK-O0: movb $1, 8(%rax)
|
||||
; CHECK-O0: movq %{{.*}}, %r12
|
||||
entry:
|
||||
%call = call i8* @malloc(i64 16)
|
||||
%call.0 = bitcast i8* %call to %swift_error*
|
||||
store %swift_error* %call.0, %swift_error** %error_ptr_ref
|
||||
%tmp = getelementptr inbounds i8, i8* %call, i64 8
|
||||
store i8 1, i8* %tmp
|
||||
ret float 1.0
|
||||
}
|
||||
|
||||
; "caller" calls "foo" that takes a swifterror parameter.
|
||||
define float @caller(i8* %error_ref) {
|
||||
; CHECK-APPLE-LABEL: caller:
|
||||
; CHECK-APPLE: xorl %r12d, %r12d
|
||||
; CHECK-APPLE: callq {{.*}}foo
|
||||
; CHECK-APPLE: testq %r12, %r12
|
||||
; CHECK-APPLE: jne
|
||||
; Access part of the error object and save it to error_ref
|
||||
; CHECK-APPLE: movb 8(%r12)
|
||||
; CHECK-APPLE: movq %r12, %rdi
|
||||
; CHECK_APPLE: callq {{.*}}free
|
||||
|
||||
; CHECK-O0-LABEL: caller:
|
||||
; CHECK-O0: xorl
|
||||
; CHECK-O0: movl %{{.*}}, %r12d
|
||||
; CHECK-O0: callq {{.*}}foo
|
||||
; CHECK-O0: jne
|
||||
entry:
|
||||
%error_ptr_ref = alloca swifterror %swift_error*
|
||||
store %swift_error* null, %swift_error** %error_ptr_ref
|
||||
%call = call float @foo(%swift_error** swifterror %error_ptr_ref)
|
||||
%error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
|
||||
%had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
|
||||
%tmp = bitcast %swift_error* %error_from_foo to i8*
|
||||
br i1 %had_error_from_foo, label %handler, label %cont
|
||||
cont:
|
||||
%v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
|
||||
%t = load i8, i8* %v1
|
||||
store i8 %t, i8* %error_ref
|
||||
br label %handler
|
||||
handler:
|
||||
call void @free(i8* %tmp)
|
||||
ret float 1.0
|
||||
}
|
||||
|
||||
; "caller2" is the caller of "foo", it calls "foo" inside a loop.
|
||||
define float @caller2(i8* %error_ref) {
|
||||
; CHECK-APPLE-LABEL: caller2:
|
||||
; CHECK-APPLE: xorl %r12d, %r12d
|
||||
; CHECK-APPLE: callq {{.*}}foo
|
||||
; CHECK-APPLE: testq %r12, %r12
|
||||
; CHECK-APPLE: jne
|
||||
; CHECK-APPLE: ucomiss
|
||||
; CHECK-APPLE: jbe
|
||||
; Access part of the error object and save it to error_ref
|
||||
; CHECK-APPLE: movb 8(%r12)
|
||||
; CHECK-APPLE: movq %r12, %rdi
|
||||
; CHECK_APPLE: callq {{.*}}free
|
||||
|
||||
; CHECK-O0-LABEL: caller2:
|
||||
; CHECK-O0: xorl
|
||||
; CHECK-O0: movl %{{.*}}, %r12d
|
||||
; CHECK-O0: callq {{.*}}foo
|
||||
; CHECK-O0: movq %r12, [[ID:%[a-z]+]]
|
||||
; CHECK-O0: cmpq $0, [[ID]]
|
||||
; CHECK-O0: jne
|
||||
entry:
|
||||
%error_ptr_ref = alloca swifterror %swift_error*
|
||||
br label %bb_loop
|
||||
bb_loop:
|
||||
store %swift_error* null, %swift_error** %error_ptr_ref
|
||||
%call = call float @foo(%swift_error** swifterror %error_ptr_ref)
|
||||
%error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
|
||||
%had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
|
||||
%tmp = bitcast %swift_error* %error_from_foo to i8*
|
||||
br i1 %had_error_from_foo, label %handler, label %cont
|
||||
cont:
|
||||
%cmp = fcmp ogt float %call, 1.000000e+00
|
||||
br i1 %cmp, label %bb_end, label %bb_loop
|
||||
bb_end:
|
||||
%v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
|
||||
%t = load i8, i8* %v1
|
||||
store i8 %t, i8* %error_ref
|
||||
br label %handler
|
||||
handler:
|
||||
call void @free(i8* %tmp)
|
||||
ret float 1.0
|
||||
}
|
||||
|
||||
; "foo_if" is a function that takes a swifterror parameter, it sets swifterror
|
||||
; under a certain condition.
|
||||
define float @foo_if(%swift_error** swifterror %error_ptr_ref, i32 %cc) {
|
||||
; CHECK-APPLE-LABEL: foo_if:
|
||||
; CHECK-APPLE: testl %edi, %edi
|
||||
; CHECK-APPLE: je
|
||||
; CHECK-APPLE: movl $16, %edi
|
||||
; CHECK-APPLE: malloc
|
||||
; CHECK-APPLE: movb $1, 8(%rax)
|
||||
; CHECK-APPLE: movq %rax, %r12
|
||||
; CHECK-APPLE-NOT: %r12
|
||||
; CHECK-APPLE: ret
|
||||
|
||||
; CHECK-O0-LABEL: foo_if:
|
||||
; CHECK-O0: cmpl $0
|
||||
; spill to stack
|
||||
; CHECK-O0: movq %r12, {{.*}}(%rsp)
|
||||
; CHECK-O0: je
|
||||
; CHECK-O0: movl $16,
|
||||
; CHECK-O0: malloc
|
||||
; CHECK-O0: movq %rax, [[ID:%[a-z]+]]
|
||||
; CHECK-O0-DAG: movb $1, 8(%rax)
|
||||
; CHECK-O0-DAG: movq [[ID]], %r12
|
||||
; CHECK-O0: ret
|
||||
; reload from stack
|
||||
; CHECK-O0: movq {{.*}}(%rsp), %r12
|
||||
; CHECK-O0: ret
|
||||
entry:
|
||||
%cond = icmp ne i32 %cc, 0
|
||||
br i1 %cond, label %gen_error, label %normal
|
||||
|
||||
gen_error:
|
||||
%call = call i8* @malloc(i64 16)
|
||||
%call.0 = bitcast i8* %call to %swift_error*
|
||||
store %swift_error* %call.0, %swift_error** %error_ptr_ref
|
||||
%tmp = getelementptr inbounds i8, i8* %call, i64 8
|
||||
store i8 1, i8* %tmp
|
||||
ret float 1.0
|
||||
|
||||
normal:
|
||||
ret float 0.0
|
||||
}
|
||||
|
||||
; "foo_loop" is a function that takes a swifterror parameter, it sets swifterror
|
||||
; under a certain condition inside a loop.
|
||||
define float @foo_loop(%swift_error** swifterror %error_ptr_ref, i32 %cc, float %cc2) {
|
||||
; CHECK-APPLE-LABEL: foo_loop:
|
||||
; CHECK-APPLE: movq %r12, %rax
|
||||
; CHECK-APPLE: testl
|
||||
; CHECK-APPLE: je
|
||||
; CHECK-APPLE: movl $16, %edi
|
||||
; CHECK-APPLE: malloc
|
||||
; CHECK-APPLE: movb $1, 8(%rax)
|
||||
; CHECK-APPLE: ucomiss
|
||||
; CHECK-APPLE: jbe
|
||||
; CHECK-APPLE: movq %rax, %r12
|
||||
; CHECK-APPLE: ret
|
||||
|
||||
; CHECK-O0-LABEL: foo_loop:
|
||||
; spill to stack
|
||||
; CHECK-O0: movq %r12, {{.*}}(%rsp)
|
||||
; CHECK-O0: cmpl $0
|
||||
; CHECK-O0: je
|
||||
; CHECK-O0: movl $16,
|
||||
; CHECK-O0: malloc
|
||||
; CHECK-O0: movq %rax, [[ID:%[a-z]+]]
|
||||
; CHECK-O0: movb $1, 8([[ID]])
|
||||
; CHECK-O0: jbe
|
||||
; reload from stack
|
||||
; CHECK-O0: movq {{.*}}(%rsp), %r12
|
||||
; CHECK-O0: ret
|
||||
entry:
|
||||
br label %bb_loop
|
||||
|
||||
bb_loop:
|
||||
%cond = icmp ne i32 %cc, 0
|
||||
br i1 %cond, label %gen_error, label %bb_cont
|
||||
|
||||
gen_error:
|
||||
%call = call i8* @malloc(i64 16)
|
||||
%call.0 = bitcast i8* %call to %swift_error*
|
||||
store %swift_error* %call.0, %swift_error** %error_ptr_ref
|
||||
%tmp = getelementptr inbounds i8, i8* %call, i64 8
|
||||
store i8 1, i8* %tmp
|
||||
br label %bb_cont
|
||||
|
||||
bb_cont:
|
||||
%cmp = fcmp ogt float %cc2, 1.000000e+00
|
||||
br i1 %cmp, label %bb_end, label %bb_loop
|
||||
bb_end:
|
||||
ret float 0.0
|
||||
}
|
||||
|
||||
%struct.S = type { i32, i32, i32, i32, i32, i32 }
|
||||
|
||||
; "foo_sret" is a function that takes a swifterror parameter, it also has a sret
|
||||
; parameter.
|
||||
define void @foo_sret(%struct.S* sret %agg.result, i32 %val1, %swift_error** swifterror %error_ptr_ref) {
|
||||
; CHECK-APPLE-LABEL: foo_sret:
|
||||
; CHECK-APPLE: movq %rdi, %{{.*}}
|
||||
; CHECK-APPLE: movl $16, %edi
|
||||
; CHECK-APPLE: malloc
|
||||
; CHECK-APPLE: movb $1, 8(%rax)
|
||||
; CHECK-APPLE: movl %{{.*}}, 4(%{{.*}})
|
||||
; CHECK-APPLE: movq %rax, %r12
|
||||
; CHECK-APPLE: movq %{{.*}}, %rax
|
||||
; CHECK-APPLE-NOT: x19
|
||||
|
||||
; CHECK-O0-LABEL: foo_sret:
|
||||
; CHECK-O0: movl $16,
|
||||
; spill sret to stack
|
||||
; CHECK-O0: movq %rdi,
|
||||
; CHECK-O0: movq {{.*}}, %rdi
|
||||
; CHECK-O0: malloc
|
||||
; CHECK-O0: movb $1, 8(%rax)
|
||||
; CHECK-O0: movl %{{.*}}, 4(%{{.*}})
|
||||
; CHECK-O0: movq %{{.*}}, %r12
|
||||
; reload sret from stack
|
||||
; CHECK-O0: movq {{.*}}(%rsp), %rax
|
||||
; CHECK-O0: ret
|
||||
entry:
|
||||
%call = call i8* @malloc(i64 16)
|
||||
%call.0 = bitcast i8* %call to %swift_error*
|
||||
store %swift_error* %call.0, %swift_error** %error_ptr_ref
|
||||
%tmp = getelementptr inbounds i8, i8* %call, i64 8
|
||||
store i8 1, i8* %tmp
|
||||
%v2 = getelementptr inbounds %struct.S, %struct.S* %agg.result, i32 0, i32 1
|
||||
store i32 %val1, i32* %v2
|
||||
ret void
|
||||
}
|
||||
|
||||
; "caller3" calls "foo_sret" that takes a swifterror parameter.
|
||||
define float @caller3(i8* %error_ref) {
|
||||
; CHECK-APPLE-LABEL: caller3:
|
||||
; CHECK-APPLE: movl $1, %esi
|
||||
; CHECK-APPLE: xorl %r12d, %r12d
|
||||
; CHECK-APPLE: callq {{.*}}foo_sret
|
||||
; CHECK-APPLE: testq %r12, %r12
|
||||
; CHECK-APPLE: jne
|
||||
; Access part of the error object and save it to error_ref
|
||||
; CHECK-APPLE: movb 8(%r12),
|
||||
; CHECK-APPLE: movb %{{.*}},
|
||||
; CHECK-APPLE: movq %r12, %rdi
|
||||
; CHECK_APPLE: callq {{.*}}free
|
||||
|
||||
; CHECK-O0-LABEL: caller3:
|
||||
; CHECK-O0: xorl
|
||||
; CHECK-O0: movl {{.*}}, %r12d
|
||||
; CHECK-O0: movl $1, %esi
|
||||
; CHECK-O0: movq {{.*}}, %rdi
|
||||
; CHECK-O0: callq {{.*}}foo_sret
|
||||
; CHECK-O0: movq %r12,
|
||||
; CHECK-O0: cmpq $0
|
||||
; CHECK-O0: jne
|
||||
; Access part of the error object and save it to error_ref
|
||||
; CHECK-O0: movb 8(%{{.*}}),
|
||||
; CHECK-O0: movb %{{.*}},
|
||||
; reload from stack
|
||||
; CHECK-O0: movq {{.*}}(%rsp), %rdi
|
||||
; CHECK-O0: callq {{.*}}free
|
||||
entry:
|
||||
%s = alloca %struct.S, align 8
|
||||
%error_ptr_ref = alloca swifterror %swift_error*
|
||||
store %swift_error* null, %swift_error** %error_ptr_ref
|
||||
call void @foo_sret(%struct.S* sret %s, i32 1, %swift_error** swifterror %error_ptr_ref)
|
||||
%error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
|
||||
%had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
|
||||
%tmp = bitcast %swift_error* %error_from_foo to i8*
|
||||
br i1 %had_error_from_foo, label %handler, label %cont
|
||||
cont:
|
||||
%v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
|
||||
%t = load i8, i8* %v1
|
||||
store i8 %t, i8* %error_ref
|
||||
br label %handler
|
||||
handler:
|
||||
call void @free(i8* %tmp)
|
||||
ret float 1.0
|
||||
}
|
||||
|
||||
; This is a caller with multiple swifterror values, it calls "foo" twice, each
|
||||
; time with a different swifterror value, from "alloca swifterror".
|
||||
define float @caller_with_multiple_swifterror_values(i8* %error_ref, i8* %error_ref2) {
|
||||
; CHECK-APPLE-LABEL: caller_with_multiple_swifterror_values:
|
||||
|
||||
; The first swifterror value:
|
||||
; CHECK-APPLE: xorl %r12d, %r12d
|
||||
; CHECK-APPLE: callq {{.*}}foo
|
||||
; CHECK-APPLE: testq %r12, %r12
|
||||
; CHECK-APPLE: jne
|
||||
; Access part of the error object and save it to error_ref
|
||||
; CHECK-APPLE: movb 8(%r12)
|
||||
; CHECK-APPLE: movq %r12, %rdi
|
||||
; CHECK_APPLE: callq {{.*}}free
|
||||
|
||||
; The second swifterror value:
|
||||
; CHECK-APPLE: xorl %r12d, %r12d
|
||||
; CHECK-APPLE: callq {{.*}}foo
|
||||
; CHECK-APPLE: testq %r12, %r12
|
||||
; CHECK-APPLE: jne
|
||||
; Access part of the error object and save it to error_ref
|
||||
; CHECK-APPLE: movb 8(%r12)
|
||||
; CHECK-APPLE: movq %r12, %rdi
|
||||
; CHECK_APPLE: callq {{.*}}free
|
||||
|
||||
; CHECK-O0-LABEL: caller_with_multiple_swifterror_values:
|
||||
|
||||
; The first swifterror value:
|
||||
; CHECK-O0: xorl
|
||||
; CHECK-O0: movl %{{.*}}, %r12d
|
||||
; CHECK-O0: callq {{.*}}foo
|
||||
; CHECK-O0: jne
|
||||
|
||||
; The second swifterror value:
|
||||
; CHECK-O0: xorl
|
||||
; CHECK-O0: movl %{{.*}}, %r12d
|
||||
; CHECK-O0: callq {{.*}}foo
|
||||
; CHECK-O0: jne
|
||||
entry:
|
||||
%error_ptr_ref = alloca swifterror %swift_error*
|
||||
store %swift_error* null, %swift_error** %error_ptr_ref
|
||||
%call = call float @foo(%swift_error** swifterror %error_ptr_ref)
|
||||
%error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
|
||||
%had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
|
||||
%tmp = bitcast %swift_error* %error_from_foo to i8*
|
||||
br i1 %had_error_from_foo, label %handler, label %cont
|
||||
cont:
|
||||
%v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
|
||||
%t = load i8, i8* %v1
|
||||
store i8 %t, i8* %error_ref
|
||||
br label %handler
|
||||
handler:
|
||||
call void @free(i8* %tmp)
|
||||
|
||||
%error_ptr_ref2 = alloca swifterror %swift_error*
|
||||
store %swift_error* null, %swift_error** %error_ptr_ref2
|
||||
%call2 = call float @foo(%swift_error** swifterror %error_ptr_ref2)
|
||||
%error_from_foo2 = load %swift_error*, %swift_error** %error_ptr_ref2
|
||||
%had_error_from_foo2 = icmp ne %swift_error* %error_from_foo2, null
|
||||
%bitcast2 = bitcast %swift_error* %error_from_foo2 to i8*
|
||||
br i1 %had_error_from_foo2, label %handler2, label %cont2
|
||||
cont2:
|
||||
%v2 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo2, i64 0, i32 1
|
||||
%t2 = load i8, i8* %v2
|
||||
store i8 %t2, i8* %error_ref2
|
||||
br label %handler2
|
||||
handler2:
|
||||
call void @free(i8* %bitcast2)
|
||||
|
||||
ret float 1.0
|
||||
}
|
Loading…
Reference in New Issue
Block a user