mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-05 10:17:36 +00:00
[ARM64] [Windows] Handle funclets
This patch adds support for funclets in frame lowering and ISel lowering. Together with D50288 and D50166, it enables C++ exception handling. Patch by Sanjin Sijaric, with some fixes by me. Differential Revision: https://reviews.llvm.org/D51524 llvm-svn: 346568
This commit is contained in:
parent
9f3b55d70a
commit
f70ae59019
@ -204,6 +204,11 @@ bool AArch64FrameLowering::canUseRedZone(const MachineFunction &MF) const {
|
||||
bool AArch64FrameLowering::hasFP(const MachineFunction &MF) const {
|
||||
const MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
|
||||
// Win64 EH requires a frame pointer if funclets are present, as the locals
|
||||
// are accessed off the frame pointer in both the parent function and the
|
||||
// funclets.
|
||||
if (MF.hasEHFunclets())
|
||||
return true;
|
||||
// Retain behavior of always omitting the FP for leaf functions when possible.
|
||||
if (MFI.hasCalls() && MF.getTarget().Options.DisableFramePointerElim(MF))
|
||||
return true;
|
||||
@ -774,6 +779,12 @@ static bool ShouldSignWithAKey(MachineFunction &MF) {
|
||||
return Key.equals_lower("a_key");
|
||||
}
|
||||
|
||||
static bool needsWinCFI(const MachineFunction &MF) {
|
||||
const Function &F = MF.getFunction();
|
||||
return MF.getTarget().getMCAsmInfo()->usesWindowsCFI() &&
|
||||
F.needsUnwindTableEntry();
|
||||
}
|
||||
|
||||
void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
|
||||
MachineBasicBlock &MBB) const {
|
||||
MachineBasicBlock::iterator MBBI = MBB.begin();
|
||||
@ -787,9 +798,10 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
|
||||
bool needsFrameMoves = (MMI.hasDebugInfo() || F.needsUnwindTableEntry()) &&
|
||||
!MF.getTarget().getMCAsmInfo()->usesWindowsCFI();
|
||||
bool HasFP = hasFP(MF);
|
||||
bool NeedsWinCFI = MF.getTarget().getMCAsmInfo()->usesWindowsCFI() &&
|
||||
F.needsUnwindTableEntry();
|
||||
bool NeedsWinCFI = needsWinCFI(MF);
|
||||
MF.setHasWinCFI(NeedsWinCFI);
|
||||
bool IsFunclet = MBB.isEHFuncletEntry();
|
||||
|
||||
// At this point, we're going to decide whether or not the function uses a
|
||||
// redzone. In most cases, the function doesn't have a redzone so let's
|
||||
// assume that's false and set it to true in the case that there's a redzone.
|
||||
@ -811,7 +823,14 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
|
||||
if (MF.getFunction().getCallingConv() == CallingConv::GHC)
|
||||
return;
|
||||
|
||||
int NumBytes = (int)MFI.getStackSize();
|
||||
// getStackSize() includes all the locals in its size calculation. We don't
|
||||
// include these locals when computing the stack size of a funclet, as they
|
||||
// are allocated in the parent's stack frame and accessed via the frame
|
||||
// pointer from the funclet. We only save the callee saved registers in the
|
||||
// funclet, which are really the callee saved registers of the parent
|
||||
// function, including the funclet.
|
||||
int NumBytes = IsFunclet ? (int)getWinEHFuncletFrameSize(MF)
|
||||
: (int)MFI.getStackSize();
|
||||
if (!AFI->hasStackFrame() && !windowsRequiresStackProbe(MF, NumBytes)) {
|
||||
assert(!HasFP && "unexpected function without stack frame but with FP");
|
||||
// All of the stack allocation is for locals.
|
||||
@ -847,7 +866,10 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
|
||||
|
||||
bool IsWin64 =
|
||||
Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv());
|
||||
unsigned FixedObject = IsWin64 ? alignTo(AFI->getVarArgsGPRSize(), 16) : 0;
|
||||
// Var args are accounted for in the containing function, so don't
|
||||
// include them for funclets.
|
||||
unsigned FixedObject = (IsWin64 && !IsFunclet) ?
|
||||
alignTo(AFI->getVarArgsGPRSize(), 16) : 0;
|
||||
|
||||
auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject;
|
||||
// All of the remaining stack allocations are for locals.
|
||||
@ -875,6 +897,16 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
|
||||
++MBBI;
|
||||
}
|
||||
|
||||
// The code below is not applicable to funclets. We have emitted all the SEH
|
||||
// opcodes that we needed to emit. The FP and BP belong to the containing
|
||||
// function.
|
||||
if (IsFunclet) {
|
||||
if (NeedsWinCFI)
|
||||
BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PrologEnd))
|
||||
.setMIFlag(MachineInstr::FrameSetup);
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasFP) {
|
||||
// Only set up FP if we actually need to. Frame pointer is fp =
|
||||
// sp - fixedobject - 16.
|
||||
@ -1165,6 +1197,16 @@ static void InsertReturnAddressAuth(MachineFunction &MF,
|
||||
}
|
||||
}
|
||||
|
||||
static bool isFuncletReturnInstr(const MachineInstr &MI) {
|
||||
switch (MI.getOpcode()) {
|
||||
default:
|
||||
return false;
|
||||
case AArch64::CATCHRET:
|
||||
case AArch64::CLEANUPRET:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
|
||||
MachineBasicBlock &MBB) const {
|
||||
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
|
||||
@ -1173,8 +1215,8 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
|
||||
const TargetInstrInfo *TII = Subtarget.getInstrInfo();
|
||||
DebugLoc DL;
|
||||
bool IsTailCallReturn = false;
|
||||
bool NeedsWinCFI = MF.getTarget().getMCAsmInfo()->usesWindowsCFI() &&
|
||||
MF.getFunction().needsUnwindTableEntry();
|
||||
bool NeedsWinCFI = needsWinCFI(MF);
|
||||
bool IsFunclet = false;
|
||||
|
||||
if (MBB.end() != MBBI) {
|
||||
DL = MBBI->getDebugLoc();
|
||||
@ -1182,9 +1224,11 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
|
||||
IsTailCallReturn = RetOpcode == AArch64::TCRETURNdi ||
|
||||
RetOpcode == AArch64::TCRETURNri ||
|
||||
RetOpcode == AArch64::TCRETURNriBTI;
|
||||
IsFunclet = isFuncletReturnInstr(*MBBI);
|
||||
}
|
||||
|
||||
int NumBytes = MFI.getStackSize();
|
||||
int NumBytes = IsFunclet ? (int)getWinEHFuncletFrameSize(MF)
|
||||
: MFI.getStackSize();
|
||||
AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
|
||||
|
||||
// All calls are tail calls in GHC calling conv, and functions have no
|
||||
@ -1245,6 +1289,10 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
|
||||
|
||||
uint64_t AfterCSRPopSize = ArgumentPopSize;
|
||||
auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject;
|
||||
// Var args are accounted for in the containting function, so don't
|
||||
// include them for funclets.
|
||||
if (MF.hasEHFunclets())
|
||||
AFI->setLocalStackSize(NumBytes - PrologueSaveSize);
|
||||
bool CombineSPBump = shouldCombineCSRLocalStackBump(MF, NumBytes);
|
||||
// Assume we can't combine the last pop with the sp restore.
|
||||
|
||||
@ -1340,7 +1388,7 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
|
||||
// FIXME: Rather than doing the math here, we should instead just use
|
||||
// non-post-indexed loads for the restores if we aren't actually going to
|
||||
// be able to save any instructions.
|
||||
if (MFI.hasVarSizedObjects() || AFI->isStackRealigned())
|
||||
if (!IsFunclet && (MFI.hasVarSizedObjects() || AFI->isStackRealigned()))
|
||||
emitFrameOffset(MBB, LastPopI, DL, AArch64::SP, AArch64::FP,
|
||||
-AFI->getCalleeSavedStackSize() + 16, TII,
|
||||
MachineInstr::FrameDestroy, false, NeedsWinCFI);
|
||||
@ -1445,6 +1493,14 @@ int AArch64FrameLowering::resolveFrameIndexReference(const MachineFunction &MF,
|
||||
// being in range for direct access. If the FPOffset is positive,
|
||||
// that'll always be best, as the SP will be even further away.
|
||||
UseFP = true;
|
||||
} else if (MF.hasEHFunclets() && !RegInfo->hasBasePointer(MF)) {
|
||||
// Funclets access the locals contained in the parent's stack frame
|
||||
// via the frame pointer, so we have to use the FP in the parent
|
||||
// function.
|
||||
assert(
|
||||
Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv()) &&
|
||||
"Funclets should only be present on Win64");
|
||||
UseFP = true;
|
||||
} else {
|
||||
// We have the choice between FP and (SP or BP).
|
||||
if (FPOffsetFits && PreferFP) // If FP is the best fit, use it.
|
||||
@ -1538,8 +1594,7 @@ static void computeCalleeSaveRegisterPairs(
|
||||
if (CSI.empty())
|
||||
return;
|
||||
|
||||
bool NeedsWinCFI = MF.getTarget().getMCAsmInfo()->usesWindowsCFI() &&
|
||||
MF.getFunction().needsUnwindTableEntry();
|
||||
bool NeedsWinCFI = needsWinCFI(MF);
|
||||
AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
|
||||
MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
CallingConv::ID CC = MF.getFunction().getCallingConv();
|
||||
@ -1652,8 +1707,7 @@ bool AArch64FrameLowering::spillCalleeSavedRegisters(
|
||||
const TargetRegisterInfo *TRI) const {
|
||||
MachineFunction &MF = *MBB.getParent();
|
||||
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
|
||||
bool NeedsWinCFI = MF.getTarget().getMCAsmInfo()->usesWindowsCFI() &&
|
||||
MF.getFunction().needsUnwindTableEntry();
|
||||
bool NeedsWinCFI = needsWinCFI(MF);
|
||||
DebugLoc DL;
|
||||
SmallVector<RegPairInfo, 8> RegPairs;
|
||||
|
||||
@ -1765,8 +1819,7 @@ bool AArch64FrameLowering::restoreCalleeSavedRegisters(
|
||||
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
|
||||
DebugLoc DL;
|
||||
SmallVector<RegPairInfo, 8> RegPairs;
|
||||
bool NeedsWinCFI = MF.getTarget().getMCAsmInfo()->usesWindowsCFI() &&
|
||||
MF.getFunction().needsUnwindTableEntry();
|
||||
bool NeedsWinCFI = needsWinCFI(MF);
|
||||
|
||||
if (MI != MBB.end())
|
||||
DL = MI->getDebugLoc();
|
||||
@ -1998,3 +2051,69 @@ bool AArch64FrameLowering::enableStackSlotScavenging(
|
||||
const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
|
||||
return AFI->hasCalleeSaveStackFreeSpace();
|
||||
}
|
||||
|
||||
void AArch64FrameLowering::processFunctionBeforeFrameFinalized(
|
||||
MachineFunction &MF, RegScavenger *RS) const {
|
||||
// If this function isn't doing Win64-style C++ EH, we don't need to do
|
||||
// anything.
|
||||
if (!MF.hasEHFunclets())
|
||||
return;
|
||||
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
|
||||
MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
WinEHFuncInfo &EHInfo = *MF.getWinEHFuncInfo();
|
||||
|
||||
MachineBasicBlock &MBB = MF.front();
|
||||
auto MBBI = MBB.begin();
|
||||
while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup))
|
||||
++MBBI;
|
||||
|
||||
if (MBBI->isTerminator())
|
||||
return;
|
||||
|
||||
// Create an UnwindHelp object.
|
||||
int UnwindHelpFI =
|
||||
MFI.CreateStackObject(/*size*/8, /*alignment*/16, false);
|
||||
EHInfo.UnwindHelpFrameIdx = UnwindHelpFI;
|
||||
// We need to store -2 into the UnwindHelp object at the start of the
|
||||
// function.
|
||||
DebugLoc DL;
|
||||
RS->enterBasicBlock(MBB);
|
||||
unsigned DstReg = RS->scavengeRegister(&AArch64::GPR64RegClass, MBBI, 0);
|
||||
BuildMI(MBB, MBBI, DL, TII.get(AArch64::MOVi64imm), DstReg).addImm(-2);
|
||||
BuildMI(MBB, MBBI, DL, TII.get(AArch64::STURXi))
|
||||
.addReg(DstReg, getKillRegState(true))
|
||||
.addFrameIndex(UnwindHelpFI)
|
||||
.addImm(0);
|
||||
}
|
||||
|
||||
/// For Win64 AArch64 EH, the offset to the Unwind object is from the SP before
|
||||
/// the update. This is easily retrieved as it is exactly the offset that is set
|
||||
/// in processFunctionBeforeFrameFinalized.
|
||||
int AArch64FrameLowering::getFrameIndexReferencePreferSP(
|
||||
const MachineFunction &MF, int FI, unsigned &FrameReg,
|
||||
bool IgnoreSPUpdates) const {
|
||||
const MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
LLVM_DEBUG(dbgs() << "Offset from the SP for " << FI << " is "
|
||||
<< MFI.getObjectOffset(FI) << "\n");
|
||||
FrameReg = AArch64::SP;
|
||||
return MFI.getObjectOffset(FI);
|
||||
}
|
||||
|
||||
/// The parent frame offset (aka dispFrame) is only used on X86_64 to retrieve
|
||||
/// the parent's frame pointer
|
||||
unsigned AArch64FrameLowering::getWinEHParentFrameOffset(
|
||||
const MachineFunction &MF) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Funclets only need to account for space for the callee saved registers,
|
||||
/// as the locals are accounted for in the parent's stack frame.
|
||||
unsigned AArch64FrameLowering::getWinEHFuncletFrameSize(
|
||||
const MachineFunction &MF) const {
|
||||
// This is the size of the pushed CSRs.
|
||||
unsigned CSSize =
|
||||
MF.getInfo<AArch64FunctionInfo>()->getCalleeSavedStackSize();
|
||||
// This is the amount of stack a funclet needs to allocate.
|
||||
return alignTo(CSSize + MF.getFrameInfo().getMaxCallFrameSize(),
|
||||
getStackAlignment());
|
||||
}
|
||||
|
@ -69,6 +69,17 @@ public:
|
||||
|
||||
bool enableStackSlotScavenging(const MachineFunction &MF) const override;
|
||||
|
||||
void processFunctionBeforeFrameFinalized(MachineFunction &MF,
|
||||
RegScavenger *RS) const override;
|
||||
|
||||
unsigned getWinEHParentFrameOffset(const MachineFunction &MF) const override;
|
||||
|
||||
unsigned getWinEHFuncletFrameSize(const MachineFunction &MF) const;
|
||||
|
||||
int getFrameIndexReferencePreferSP(const MachineFunction &MF, int FI,
|
||||
unsigned &FrameReg,
|
||||
bool IgnoreSPUpdates) const override;
|
||||
|
||||
private:
|
||||
bool shouldCombineCSRLocalStackBump(MachineFunction &MF,
|
||||
unsigned StackBumpBytes) const;
|
||||
|
@ -1273,6 +1273,20 @@ AArch64TargetLowering::EmitF128CSEL(MachineInstr &MI,
|
||||
return EndBB;
|
||||
}
|
||||
|
||||
MachineBasicBlock *AArch64TargetLowering::EmitLoweredCatchRet(
|
||||
MachineInstr &MI, MachineBasicBlock *BB) const {
|
||||
assert(!isAsynchronousEHPersonality(classifyEHPersonality(
|
||||
BB->getParent()->getFunction().getPersonalityFn())) &&
|
||||
"SEH does not use catchret!");
|
||||
return BB;
|
||||
}
|
||||
|
||||
MachineBasicBlock *AArch64TargetLowering::EmitLoweredCatchPad(
|
||||
MachineInstr &MI, MachineBasicBlock *BB) const {
|
||||
MI.eraseFromParent();
|
||||
return BB;
|
||||
}
|
||||
|
||||
MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter(
|
||||
MachineInstr &MI, MachineBasicBlock *BB) const {
|
||||
switch (MI.getOpcode()) {
|
||||
@ -1288,6 +1302,11 @@ MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter(
|
||||
case TargetOpcode::STACKMAP:
|
||||
case TargetOpcode::PATCHPOINT:
|
||||
return emitPatchPoint(MI, BB);
|
||||
|
||||
case AArch64::CATCHRET:
|
||||
return EmitLoweredCatchRet(MI, BB);
|
||||
case AArch64::CATCHPAD:
|
||||
return EmitLoweredCatchPad(MI, BB);
|
||||
}
|
||||
}
|
||||
|
||||
@ -11805,3 +11824,8 @@ void AArch64TargetLowering::finalizeLowering(MachineFunction &MF) const {
|
||||
MF.getFrameInfo().computeMaxCallFrameSize(MF);
|
||||
TargetLoweringBase::finalizeLowering(MF);
|
||||
}
|
||||
|
||||
// Unlike X86, we let frame lowering assign offsets to all catch objects.
|
||||
bool AArch64TargetLowering::needsFixedCatchObjects() const {
|
||||
return false;
|
||||
}
|
||||
|
@ -302,6 +302,12 @@ public:
|
||||
MachineBasicBlock *EmitF128CSEL(MachineInstr &MI,
|
||||
MachineBasicBlock *BB) const;
|
||||
|
||||
MachineBasicBlock *EmitLoweredCatchRet(MachineInstr &MI,
|
||||
MachineBasicBlock *BB) const;
|
||||
|
||||
MachineBasicBlock *EmitLoweredCatchPad(MachineInstr &MI,
|
||||
MachineBasicBlock *BB) const;
|
||||
|
||||
MachineBasicBlock *
|
||||
EmitInstrWithCustomInserter(MachineInstr &MI,
|
||||
MachineBasicBlock *MBB) const override;
|
||||
@ -521,6 +527,8 @@ public:
|
||||
bool functionArgumentNeedsConsecutiveRegisters(Type *Ty,
|
||||
CallingConv::ID CallConv,
|
||||
bool isVarArg) const override;
|
||||
/// Used for exception handling on Win64.
|
||||
bool needsFixedCatchObjects() const override;
|
||||
private:
|
||||
/// Keep a pointer to the AArch64Subtarget around so that we can
|
||||
/// make the right decision when generating code for different targets.
|
||||
|
@ -66,7 +66,8 @@ static cl::opt<unsigned>
|
||||
cl::desc("Restrict range of Bcc instructions (DEBUG)"));
|
||||
|
||||
AArch64InstrInfo::AArch64InstrInfo(const AArch64Subtarget &STI)
|
||||
: AArch64GenInstrInfo(AArch64::ADJCALLSTACKDOWN, AArch64::ADJCALLSTACKUP),
|
||||
: AArch64GenInstrInfo(AArch64::ADJCALLSTACKDOWN, AArch64::ADJCALLSTACKUP,
|
||||
AArch64::CATCHRET),
|
||||
RI(STI.getTargetTriple()), Subtarget(STI) {}
|
||||
|
||||
/// GetInstSize - Return the number of bytes of code the specified
|
||||
@ -1657,11 +1658,36 @@ bool AArch64InstrInfo::substituteCmpToZero(
|
||||
}
|
||||
|
||||
bool AArch64InstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
|
||||
if (MI.getOpcode() != TargetOpcode::LOAD_STACK_GUARD)
|
||||
if (MI.getOpcode() != TargetOpcode::LOAD_STACK_GUARD &&
|
||||
MI.getOpcode() != AArch64::CATCHRET)
|
||||
return false;
|
||||
|
||||
MachineBasicBlock &MBB = *MI.getParent();
|
||||
DebugLoc DL = MI.getDebugLoc();
|
||||
|
||||
if (MI.getOpcode() == AArch64::CATCHRET) {
|
||||
// Skip to the first instruction before the epilog.
|
||||
const TargetInstrInfo *TII =
|
||||
MBB.getParent()->getSubtarget().getInstrInfo();
|
||||
MachineBasicBlock *TargetMBB = MI.getOperand(0).getMBB();
|
||||
auto MBBI = MachineBasicBlock::iterator(MI);
|
||||
MachineBasicBlock::iterator FirstEpilogSEH = std::prev(MBBI);
|
||||
while (FirstEpilogSEH->getFlag(MachineInstr::FrameDestroy) &&
|
||||
FirstEpilogSEH != MBB.begin())
|
||||
FirstEpilogSEH = std::prev(FirstEpilogSEH);
|
||||
if (FirstEpilogSEH != MBB.begin())
|
||||
FirstEpilogSEH = std::next(FirstEpilogSEH);
|
||||
BuildMI(MBB, FirstEpilogSEH, DL, TII->get(AArch64::ADRP))
|
||||
.addReg(AArch64::X0, RegState::Define)
|
||||
.addMBB(TargetMBB);
|
||||
BuildMI(MBB, FirstEpilogSEH, DL, TII->get(AArch64::ADDXri))
|
||||
.addReg(AArch64::X0, RegState::Define)
|
||||
.addReg(AArch64::X0)
|
||||
.addMBB(TargetMBB)
|
||||
.addImm(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned Reg = MI.getOperand(0).getReg();
|
||||
const GlobalValue *GV =
|
||||
cast<GlobalValue>((*MI.memoperands_begin())->getValue());
|
||||
|
@ -3175,6 +3175,20 @@ let isPseudo = 1 in {
|
||||
def SEH_EpilogEnd : Pseudo<(outs), (ins), []>, Sched<[]>;
|
||||
}
|
||||
|
||||
// Pseudo instructions for Windows EH
|
||||
//===----------------------------------------------------------------------===//
|
||||
let isTerminator = 1, hasSideEffects = 1, isBarrier = 1, hasCtrlDep = 1,
|
||||
isCodeGenOnly = 1, isReturn = 1, isEHScopeReturn = 1, isPseudo = 1 in {
|
||||
def CLEANUPRET : Pseudo<(outs), (ins), [(cleanupret)]>, Sched<[]>;
|
||||
let usesCustomInserter = 1 in
|
||||
def CATCHRET : Pseudo<(outs), (ins am_brcond:$dst, am_brcond:$src), [(catchret bb:$dst, bb:$src)]>,
|
||||
Sched<[]>;
|
||||
}
|
||||
|
||||
let hasSideEffects = 1, hasCtrlDep = 1, isCodeGenOnly = 1,
|
||||
usesCustomInserter = 1 in
|
||||
def CATCHPAD : Pseudo<(outs), (ins), [(catchpad)]>, Sched<[]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Floating point immediate move.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -269,4 +269,17 @@ void AArch64MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
|
||||
if (lowerOperand(MO, MCOp))
|
||||
OutMI.addOperand(MCOp);
|
||||
}
|
||||
|
||||
switch (OutMI.getOpcode()) {
|
||||
case AArch64::CATCHRET:
|
||||
OutMI = MCInst();
|
||||
OutMI.setOpcode(AArch64::RET);
|
||||
OutMI.addOperand(MCOperand::createReg(AArch64::LR));
|
||||
break;
|
||||
case AArch64::CLEANUPRET:
|
||||
OutMI = MCInst();
|
||||
OutMI.setOpcode(AArch64::RET);
|
||||
OutMI.addOperand(MCOperand::createReg(AArch64::LR));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -161,6 +161,10 @@ void AArch64RegisterInfo::UpdateCustomCallPreservedMask(MachineFunction &MF,
|
||||
*Mask = UpdatedMask;
|
||||
}
|
||||
|
||||
const uint32_t *AArch64RegisterInfo::getNoPreservedMask() const {
|
||||
return CSR_AArch64_NoRegs_RegMask;
|
||||
}
|
||||
|
||||
const uint32_t *
|
||||
AArch64RegisterInfo::getThisReturnPreservedMask(const MachineFunction &MF,
|
||||
CallingConv::ID CC) const {
|
||||
@ -251,14 +255,15 @@ unsigned AArch64RegisterInfo::getBaseRegister() const { return AArch64::X19; }
|
||||
bool AArch64RegisterInfo::hasBasePointer(const MachineFunction &MF) const {
|
||||
const MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
|
||||
// In the presence of variable sized objects, if the fixed stack size is
|
||||
// large enough that referencing from the FP won't result in things being
|
||||
// in range relatively often, we can use a base pointer to allow access
|
||||
// In the presence of variable sized objects or funclets, if the fixed stack
|
||||
// size is large enough that referencing from the FP won't result in things
|
||||
// being in range relatively often, we can use a base pointer to allow access
|
||||
// from the other direction like the SP normally works.
|
||||
//
|
||||
// Furthermore, if both variable sized objects are present, and the
|
||||
// stack needs to be dynamically re-aligned, the base pointer is the only
|
||||
// reliable way to reference the locals.
|
||||
if (MFI.hasVarSizedObjects()) {
|
||||
if (MFI.hasVarSizedObjects() || MF.hasEHFunclets()) {
|
||||
if (needsStackRealignment(MF))
|
||||
return true;
|
||||
// Conservatively estimate whether the negative offset from the frame
|
||||
|
@ -65,6 +65,9 @@ public:
|
||||
// normal calls, so they need a different mask to represent this.
|
||||
const uint32_t *getTLSCallPreservedMask() const;
|
||||
|
||||
// Funclets on ARM64 Windows don't preserve any registers.
|
||||
const uint32_t *getNoPreservedMask() const override;
|
||||
|
||||
/// getThisReturnPreservedMask - Returns a call preserved mask specific to the
|
||||
/// case that 'returned' is on an i64 first argument if the calling convention
|
||||
/// is one that can (partially) model this attribute with a preserved mask
|
||||
|
49
test/CodeGen/AArch64/wineh-try-catch-nobase.ll
Normal file
49
test/CodeGen/AArch64/wineh-try-catch-nobase.ll
Normal file
@ -0,0 +1,49 @@
|
||||
; RUN: llc -o - %s -mtriple=aarch64-windows -verify-machineinstrs | FileCheck %s
|
||||
|
||||
; Make sure we don't have a base pointer.
|
||||
; CHECK-LABEL: "?a@@YAXXZ":
|
||||
; CHECK-NOT: x19
|
||||
|
||||
; Check that we compute the address relative to fp.
|
||||
; CHECK-LABEL: "?catch$2@?0??a@@YAXXZ@4HA":
|
||||
; CHECK: stp x29, x30, [sp, #-16]! ; 16-byte Folded Spill
|
||||
; CHECK-NEXT: sub x0, x29, #16 ; =16
|
||||
; CHECK-NEXT: mov x1, xzr
|
||||
; CHECK-NEXT: bl "?bb@@YAXPEAHH@Z"
|
||||
; CHECK-NEXT: adrp x0, .LBB0_1
|
||||
; CHECK-NEXT: add x0, x0, .LBB0_1
|
||||
; CHECK-NEXT: ldp x29, x30, [sp], #16 ; 16-byte Folded Reload
|
||||
; CHECK-NEXT: ret
|
||||
|
||||
target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128"
|
||||
target triple = "aarch64-unknown-windows-msvc19.11.0"
|
||||
|
||||
define dso_local void @"?a@@YAXXZ"(i64 %p1) personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
|
||||
entry:
|
||||
%a = alloca i32, align 16
|
||||
%0 = bitcast i32* %a to i8*
|
||||
store i32 305419896, i32* %a, align 16
|
||||
invoke void @"?bb@@YAXPEAHH@Z"(i32* nonnull %a, i32* null)
|
||||
to label %try.cont unwind label %catch.dispatch
|
||||
|
||||
catch.dispatch: ; preds = %entry
|
||||
%1 = catchswitch within none [label %catch] unwind to caller
|
||||
|
||||
catch: ; preds = %catch.dispatch
|
||||
%2 = catchpad within %1 [i8* null, i32 64, i8* null]
|
||||
call void @"?bb@@YAXPEAHH@Z"(i32* nonnull %a, i32* null) [ "funclet"(token %2) ]
|
||||
catchret from %2 to label %try.cont
|
||||
|
||||
try.cont: ; preds = %entry, %catch
|
||||
call void @"?cc@@YAXXZ"()
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1)
|
||||
|
||||
declare dso_local void @"?bb@@YAXPEAHH@Z"(i32*, i32*)
|
||||
|
||||
declare dso_local i32 @__CxxFrameHandler3(...)
|
||||
|
||||
declare dso_local void @"?cc@@YAXXZ"()
|
||||
|
59
test/CodeGen/AArch64/wineh-try-catch-realign.ll
Normal file
59
test/CodeGen/AArch64/wineh-try-catch-realign.ll
Normal file
@ -0,0 +1,59 @@
|
||||
; RUN: llc -o - %s -mtriple=aarch64-windows -verify-machineinstrs | FileCheck %s
|
||||
|
||||
; Make sure we have a base pointer.
|
||||
; CHECK-LABEL: "?a@@YAXXZ":
|
||||
; CHECK: and sp, x9, #0xffffffffffffffc0
|
||||
; CHECK: mov x19, sp
|
||||
|
||||
; Make sure the funclet prologue/epilogue are correct: specifically,
|
||||
; it shouldn't access the parent's frame via sp, and the prologue and
|
||||
; epilogue should be symmetrical.
|
||||
; CHECK-LABEL: "?catch$2@?0??a@@YAXXZ@4HA":
|
||||
; CHECK: str x28, [sp, #-32]!
|
||||
; CHECK-NEXT: str x19, [sp, #8]
|
||||
; CHECK-NEXT: stp x29, x30, [sp, #16]
|
||||
; CHECK-NEXT: add x0, x19, #64
|
||||
; CHECK-NEXT: mov w1, wzr
|
||||
; CHECK-NEXT: bl "?bb@@YAXPEAHH@Z"
|
||||
; CHECK-NEXT: adrp x0, .LBB0_1
|
||||
; CHECK-NEXT: add x0, x0, .LBB0_1
|
||||
; CHECK-NEXT: ldp x29, x30, [sp, #16]
|
||||
; CHECK-NEXT: ldr x19, [sp, #8]
|
||||
; CHECK-NEXT: ldr x28, [sp], #32
|
||||
; CHECK-NEXT: ret
|
||||
|
||||
|
||||
target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128"
|
||||
target triple = "aarch64-unknown-windows-msvc19.11.0"
|
||||
|
||||
define dso_local void @"?a@@YAXXZ"() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
|
||||
entry:
|
||||
%a = alloca [100 x i32], align 64
|
||||
%0 = bitcast [100 x i32]* %a to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* nonnull align 64 %0, i8 0, i64 400, i1 false)
|
||||
%1 = getelementptr inbounds [100 x i32], [100 x i32]* %a, i64 0, i64 0
|
||||
store i32 305419896, i32* %1, align 64
|
||||
invoke void @"?bb@@YAXPEAHH@Z"(i32* nonnull %1, i32 1)
|
||||
to label %try.cont unwind label %catch.dispatch
|
||||
|
||||
catch.dispatch: ; preds = %entry
|
||||
%2 = catchswitch within none [label %catch] unwind to caller
|
||||
|
||||
catch: ; preds = %catch.dispatch
|
||||
%3 = catchpad within %2 [i8* null, i32 64, i8* null]
|
||||
call void @"?bb@@YAXPEAHH@Z"(i32* nonnull %1, i32 0) [ "funclet"(token %3) ]
|
||||
catchret from %3 to label %try.cont
|
||||
|
||||
try.cont: ; preds = %entry, %catch
|
||||
call void @"?cc@@YAXXZ"()
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1)
|
||||
|
||||
declare dso_local void @"?bb@@YAXPEAHH@Z"(i32*, i32)
|
||||
|
||||
declare dso_local i32 @__CxxFrameHandler3(...)
|
||||
|
||||
declare dso_local void @"?cc@@YAXXZ"()
|
||||
|
52
test/CodeGen/AArch64/wineh-try-catch-vla.ll
Normal file
52
test/CodeGen/AArch64/wineh-try-catch-vla.ll
Normal file
@ -0,0 +1,52 @@
|
||||
; RUN: llc -o - %s -mtriple=aarch64-windows -verify-machineinstrs | FileCheck %s
|
||||
|
||||
; Check we don't have a base pointer.
|
||||
; CHECK-LABEL: "?a@@YAXXZ":
|
||||
; CHECK-NOT: x19
|
||||
|
||||
; Make sure the prologue and epilogue are sane. Make sure the
|
||||
; frame index is relative to the FP, since there is no base pointer.
|
||||
; (Funclets aren't allowed to contain dynamic allocas.)
|
||||
; CHECK-LABEL: "?catch$2@?0??a@@YAXXZ@4HA":
|
||||
; CHECK: stp x29, x30, [sp, #-16]!
|
||||
; CHECK-NEXT: ldur x0, [x29, #-8]
|
||||
; CHECK-NEXT: mov x1, x0
|
||||
; CHECK-NEXT: bl "?bb@@YAXPEAHH@Z"
|
||||
; CHECK-NEXT: adrp x0, .LBB0_1
|
||||
; CHECK-NEXT: add x0, x0, .LBB0_1
|
||||
; CHECK-NEXT: ldp x29, x30, [sp], #16
|
||||
; CHECK-NEXT: ret
|
||||
|
||||
target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128"
|
||||
target triple = "aarch64-unknown-windows-msvc19.11.0"
|
||||
|
||||
define dso_local void @"?a@@YAXXZ"(i64 %p1) personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
|
||||
entry:
|
||||
%a = alloca i32, i64 %p1, align 16
|
||||
%0 = bitcast i32* %a to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* nonnull align 16 %0, i8 0, i64 400, i1 false)
|
||||
store i32 305419896, i32* %a, align 16
|
||||
invoke void @"?bb@@YAXPEAHH@Z"(i32* nonnull %a, i32* null)
|
||||
to label %try.cont unwind label %catch.dispatch
|
||||
|
||||
catch.dispatch: ; preds = %entry
|
||||
%1 = catchswitch within none [label %catch] unwind to caller
|
||||
|
||||
catch: ; preds = %catch.dispatch
|
||||
%2 = catchpad within %1 [i8* null, i32 64, i8* null]
|
||||
call void @"?bb@@YAXPEAHH@Z"(i32* nonnull %a, i32* %a) [ "funclet"(token %2) ]
|
||||
catchret from %2 to label %try.cont
|
||||
|
||||
try.cont: ; preds = %entry, %catch
|
||||
call void @"?cc@@YAXXZ"()
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1)
|
||||
|
||||
declare dso_local void @"?bb@@YAXPEAHH@Z"(i32*, i32*)
|
||||
|
||||
declare dso_local i32 @__CxxFrameHandler3(...)
|
||||
|
||||
declare dso_local void @"?cc@@YAXXZ"()
|
||||
|
197
test/CodeGen/AArch64/wineh-try-catch.ll
Normal file
197
test/CodeGen/AArch64/wineh-try-catch.ll
Normal file
@ -0,0 +1,197 @@
|
||||
; RUN: llc -o - %s -mtriple=aarch64-windows -verify-machineinstrs | FileCheck %s
|
||||
; RUN: llc -o %t -filetype=obj %s -mtriple=aarch64-windows
|
||||
; RUN: llvm-readobj -unwind %t | FileCheck %s -check-prefix=UNWIND
|
||||
|
||||
; We test the following
|
||||
; 1) That the unwind help object is created and that its offset from the stack
|
||||
; pointer on entry is patched into the table fed to __CxxFrameHandler3
|
||||
; 2) That the stack update for the catch funclet only includes the callee saved
|
||||
; registers
|
||||
; 3) That the locals are accessed using the frame pointer in both the funclet
|
||||
; and the parent function.
|
||||
|
||||
; The following checks that the unwind help object has -2 stored into it at
|
||||
; fp - 400 - 256 = fp - 656, which is on-entry sp - 48 + 32 - 656 =
|
||||
; on-entry sp - 672. We check this offset in the table later on.
|
||||
|
||||
; CHECK-LABEL: "?func@@YAHXZ":
|
||||
; CHECK: str x28, [sp, #-48]!
|
||||
; CHECK: str x21, [sp, #8]
|
||||
; CHECK: stp x19, x20, [sp, #16]
|
||||
; CHECK: stp x29, x30, [sp, #32]
|
||||
; CHECK: add x29, sp, #32
|
||||
; CHECK: sub sp, sp, #624
|
||||
; CHECK: mov x19, sp
|
||||
; CHECK: orr x1, xzr, #0xfffffffffffffffe
|
||||
; CHECK: stur x1, [x19]
|
||||
|
||||
; Now check that x is stored at fp - 20. We check that this is the same
|
||||
; location accessed from the funclet to retrieve x.
|
||||
; CHECK: orr w8, wzr, #0x1
|
||||
; CHECK: stur w8, [x29, [[X_OFFSET:#-[1-9][0-9]+]]
|
||||
|
||||
; Check the offset off the frame pointer at which B is located.
|
||||
; Check the same offset is used to pass the address of B to init2 in the
|
||||
; funclet.
|
||||
; CHECK: sub x0, x29, [[B_OFFSET:#[1-9][0-9]+]]
|
||||
; CHECK: bl "?init@@YAXPEAH@Z"
|
||||
|
||||
; This is the label for the throw that is encoded in the ip2state.
|
||||
; We are inside the try block, where we make a call to func2
|
||||
; CHECK-LABEL: .Ltmp0:
|
||||
; CHECK: bl "?func2@@YAHXZ
|
||||
|
||||
; CHECK: [[CATCHRETDEST:.LBB0_[0-9]+]]: ; %catchret.dest
|
||||
|
||||
; Check the catch funclet.
|
||||
; CHECK-LABEL: "?catch$2@?0??func@@YAHXZ@4HA":
|
||||
|
||||
; Check that the stack space is allocated only for the callee saved registers.
|
||||
; CHECK: str x28, [sp, #-48]!
|
||||
; CHECK: str x21, [sp, #8]
|
||||
; CHECK: stp x19, x20, [sp, #16]
|
||||
; CHECK: stp x29, x30, [sp, #32]
|
||||
; CHECK: add x20, x19, #12
|
||||
|
||||
; Check that there are no further stack updates.
|
||||
; CHECK-NOT: sub sp, sp
|
||||
|
||||
; Check that the stack address passed to init2 is off the frame pointer, and
|
||||
; that it matches the address of B in the parent function.
|
||||
; CHECK: sub x0, x29, [[B_OFFSET]]
|
||||
; CHECK: bl "?init2@@YAXPEAH@Z"
|
||||
|
||||
; Check that are storing x back to the same location off the frame pointer as in
|
||||
; the parent function.
|
||||
; CHECK: stur w8, [x29, [[X_OFFSET]]]
|
||||
|
||||
; Check that the funclet branches back to the catchret destination
|
||||
; CHECK: adrp x0, .LBB0_3
|
||||
; CHECK-NEXT: add x0, x0, [[CATCHRETDEST]]
|
||||
|
||||
|
||||
; Now check that the offset of the unwind help object from the stack pointer on
|
||||
; entry to func is encoded in cppxdata that is passed to __CxxFrameHandler3. As
|
||||
; computed above, this comes to -672.
|
||||
; CHECK-LABEL: "$cppxdata$?func@@YAHXZ":
|
||||
; CHECK-NEXT: .word 429065506 ; MagicNumber
|
||||
; CHECK-NEXT: .word 2 ; MaxState
|
||||
; CHECK-NEXT: .word ("$stateUnwindMap$?func@@YAHXZ")@IMGREL ; UnwindMap
|
||||
; CHECK-NEXT: .word 1 ; NumTryBlocks
|
||||
; CHECK-NEXT: .word ("$tryMap$?func@@YAHXZ")@IMGREL ; TryBlockMap
|
||||
; CHECK-NEXT: .word 4 ; IPMapEntries
|
||||
; CHECK-NEXT: .word ("$ip2state$?func@@YAHXZ")@IMGREL ; IPToStateXData
|
||||
; CHECK-NEXT: .word -672 ; UnwindHelp
|
||||
|
||||
; UNWIND: Function: ?func@@YAHXZ (0x0)
|
||||
; UNWIND: Prologue [
|
||||
; UNWIND-NEXT: ; nop
|
||||
; UNWIND-NEXT: ; sub sp, #624
|
||||
; UNWIND-NEXT: ; add fp, sp, #32
|
||||
; UNWIND-NEXT: ; stp x29, x30, [sp, #32]
|
||||
; UNWIND-NEXT: ; stp x19, x20, [sp, #16]
|
||||
; UNWIND-NEXT: ; str x21, [sp, #8]
|
||||
; UNWIND-NEXT: ; str x28, [sp, #48]!
|
||||
; UNWIND-NEXT: ; end
|
||||
; UNWIND: Function: ?catch$2@?0??func@@YAHXZ@4HA
|
||||
; UNWIND: Prologue [
|
||||
; UNWIND-NEXT: ; stp x29, x30, [sp, #32]
|
||||
; UNWIND-NEXT: ; stp x19, x20, [sp, #16]
|
||||
; UNWIND-NEXT: ; str x21, [sp, #8]
|
||||
; UNWIND-NEXT: ; str x28, [sp, #48]!
|
||||
; UNWIND-NEXT: ; end
|
||||
|
||||
target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128"
|
||||
target triple = "aarch64-unknown-windows-msvc19.11.0"
|
||||
|
||||
%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
|
||||
%eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 }
|
||||
%eh.CatchableTypeArray.1 = type { i32, [1 x i32] }
|
||||
%eh.ThrowInfo = type { i32, i32, i32, i32 }
|
||||
|
||||
$"??_R0H@8" = comdat any
|
||||
|
||||
$"_CT??_R0H@84" = comdat any
|
||||
|
||||
$_CTA1H = comdat any
|
||||
|
||||
$_TI1H = comdat any
|
||||
|
||||
@"??_7type_info@@6B@" = external constant i8*
|
||||
@"??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
|
||||
@__ImageBase = external dso_local constant i8
|
||||
@"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat
|
||||
@_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat
|
||||
@_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1H to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat
|
||||
|
||||
; Function Attrs: noinline optnone
|
||||
define dso_local i32 @"?func@@YAHXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
|
||||
entry:
|
||||
%B = alloca [50 x i32], align 4
|
||||
%x = alloca i32, align 4
|
||||
%tmp = alloca i32, align 4
|
||||
%i = alloca i32, align 4
|
||||
%C = alloca [100 x i32], align 4
|
||||
store i32 1, i32* %x, align 4
|
||||
%arraydecay = getelementptr inbounds [50 x i32], [50 x i32]* %B, i32 0, i32 0
|
||||
call void @"?init@@YAXPEAH@Z"(i32* %arraydecay)
|
||||
%call = invoke i32 @"?func2@@YAHXZ"()
|
||||
to label %invoke.cont unwind label %catch.dispatch
|
||||
|
||||
invoke.cont: ; preds = %entry
|
||||
store i32 %call, i32* %tmp, align 4
|
||||
%0 = bitcast i32* %tmp to i8*
|
||||
invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* @_TI1H) #2
|
||||
to label %unreachable unwind label %catch.dispatch
|
||||
|
||||
catch.dispatch: ; preds = %invoke.cont, %entry
|
||||
%1 = catchswitch within none [label %catch] unwind to caller
|
||||
|
||||
catch: ; preds = %catch.dispatch
|
||||
%2 = catchpad within %1 [%rtti.TypeDescriptor2* @"??_R0H@8", i32 0, i32* %i]
|
||||
%arraydecay1 = getelementptr inbounds [100 x i32], [100 x i32]* %C, i32 0, i32 0
|
||||
call void @"?init@@YAXPEAH@Z"(i32* %arraydecay1) [ "funclet"(token %2) ]
|
||||
%arraydecay2 = getelementptr inbounds [50 x i32], [50 x i32]* %B, i32 0, i32 0
|
||||
call void @"?init2@@YAXPEAH@Z"(i32* %arraydecay2) [ "funclet"(token %2) ]
|
||||
%3 = load i32, i32* %i, align 4
|
||||
%idxprom = sext i32 %3 to i64
|
||||
%arrayidx = getelementptr inbounds [50 x i32], [50 x i32]* %B, i64 0, i64 %idxprom
|
||||
%4 = load i32, i32* %arrayidx, align 4
|
||||
%5 = load i32, i32* %i, align 4
|
||||
%idxprom3 = sext i32 %5 to i64
|
||||
%arrayidx4 = getelementptr inbounds [100 x i32], [100 x i32]* %C, i64 0, i64 %idxprom3
|
||||
%6 = load i32, i32* %arrayidx4, align 4
|
||||
%add = add nsw i32 %4, %6
|
||||
%7 = load i32, i32* %i, align 4
|
||||
%8 = load i32, i32* %i, align 4
|
||||
%mul = mul nsw i32 %7, %8
|
||||
%add5 = add nsw i32 %add, %mul
|
||||
store i32 %add5, i32* %x, align 4
|
||||
catchret from %2 to label %catchret.dest
|
||||
|
||||
catchret.dest: ; preds = %catch
|
||||
br label %try.cont
|
||||
|
||||
try.cont: ; preds = %catchret.dest
|
||||
%arrayidx6 = getelementptr inbounds [50 x i32], [50 x i32]* %B, i64 0, i64 2
|
||||
%9 = load i32, i32* %arrayidx6, align 4
|
||||
%10 = load i32, i32* %x, align 4
|
||||
%add7 = add nsw i32 %9, %10
|
||||
ret i32 %add7
|
||||
|
||||
unreachable: ; preds = %invoke.cont
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare dso_local void @"?init@@YAXPEAH@Z"(i32*)
|
||||
|
||||
declare dso_local i32 @"?func2@@YAHXZ"()
|
||||
|
||||
declare dso_local i32 @__CxxFrameHandler3(...)
|
||||
|
||||
declare dllimport void @_CxxThrowException(i8*, %eh.ThrowInfo*)
|
||||
|
||||
declare dso_local void @"?init2@@YAXPEAH@Z"(i32*)
|
||||
|
||||
attributes #0 = { noinline optnone }
|
||||
attributes #2 = { noreturn }
|
Loading…
Reference in New Issue
Block a user