mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-28 06:00:28 +00:00
Generate compact unwind encoding from CFI directives.
We used to generate the compact unwind encoding from the machine instructions. However, this had the problem that if the user used `-save-temps' or compiled their hand-written `.s' file (with CFI directives), we wouldn't generate the compact unwind encoding. Move the algorithm that generates the compact unwind encoding into the MCAsmBackend. This way we can generate the encoding whether the code is from a `.ll' or `.s' file. <rdar://problem/13623355> git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190290 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
959cd8f49b
commit
c3cee57f7d
@ -10,7 +10,9 @@
|
||||
#ifndef LLVM_MC_MCASMBACKEND_H
|
||||
#define LLVM_MC_MCASMBACKEND_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/MC/MCDirectives.h"
|
||||
#include "llvm/MC/MCDwarf.h"
|
||||
#include "llvm/MC/MCFixup.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
@ -158,6 +160,12 @@ public:
|
||||
/// handleAssemblerFlag - Handle any target-specific assembler flags.
|
||||
/// By default, do nothing.
|
||||
virtual void handleAssemblerFlag(MCAssemblerFlag Flag) {}
|
||||
|
||||
/// \brief Generate the compact unwind encoding for the CFI instructions.
|
||||
virtual unsigned
|
||||
generateCompactUnwindEncoding(ArrayRef<MCCFIInstruction>) const {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
@ -134,6 +134,8 @@ public:
|
||||
return *W64UnwindInfos[i];
|
||||
}
|
||||
|
||||
void generateCompactUnwindEncodings(MCAsmBackend &MAB);
|
||||
|
||||
/// @name Assembly File Formatting.
|
||||
/// @{
|
||||
|
||||
|
@ -104,6 +104,7 @@ namespace llvm {
|
||||
typedef AsmPrinter *(*AsmPrinterCtorTy)(TargetMachine &TM,
|
||||
MCStreamer &Streamer);
|
||||
typedef MCAsmBackend *(*MCAsmBackendCtorTy)(const Target &T,
|
||||
const MCRegisterInfo &MRI,
|
||||
StringRef TT,
|
||||
StringRef CPU);
|
||||
typedef MCTargetAsmParser *(*MCAsmParserCtorTy)(MCSubtargetInfo &STI,
|
||||
@ -373,10 +374,11 @@ namespace llvm {
|
||||
/// createMCAsmBackend - Create a target specific assembly parser.
|
||||
///
|
||||
/// \param Triple The target triple string.
|
||||
MCAsmBackend *createMCAsmBackend(StringRef Triple, StringRef CPU) const {
|
||||
MCAsmBackend *createMCAsmBackend(const MCRegisterInfo &MRI,
|
||||
StringRef Triple, StringRef CPU) const {
|
||||
if (!MCAsmBackendCtorFn)
|
||||
return 0;
|
||||
return MCAsmBackendCtorFn(*this, Triple, CPU);
|
||||
return MCAsmBackendCtorFn(*this, MRI, Triple, CPU);
|
||||
}
|
||||
|
||||
/// createMCAsmParser - Create a target specific assembly parser.
|
||||
@ -1118,9 +1120,10 @@ namespace llvm {
|
||||
}
|
||||
|
||||
private:
|
||||
static MCAsmBackend *Allocator(const Target &T, StringRef Triple,
|
||||
StringRef CPU) {
|
||||
return new MCAsmBackendImpl(T, Triple, CPU);
|
||||
static MCAsmBackend *Allocator(const Target &T,
|
||||
const MCRegisterInfo &MRI,
|
||||
StringRef Triple, StringRef CPU) {
|
||||
return new MCAsmBackendImpl(T, MRI, Triple, CPU);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -178,7 +178,7 @@ bool LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &PM,
|
||||
MCAsmBackend *MAB = 0;
|
||||
if (ShowMCEncoding) {
|
||||
MCE = getTarget().createMCCodeEmitter(MII, MRI, STI, *Context);
|
||||
MAB = getTarget().createMCAsmBackend(getTargetTriple(), TargetCPU);
|
||||
MAB = getTarget().createMCAsmBackend(MRI, getTargetTriple(), TargetCPU);
|
||||
}
|
||||
|
||||
MCStreamer *S = getTarget().createAsmStreamer(*Context, Out,
|
||||
@ -197,7 +197,7 @@ bool LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &PM,
|
||||
// emission fails.
|
||||
MCCodeEmitter *MCE = getTarget().createMCCodeEmitter(MII, MRI, STI,
|
||||
*Context);
|
||||
MCAsmBackend *MAB = getTarget().createMCAsmBackend(getTargetTriple(),
|
||||
MCAsmBackend *MAB = getTarget().createMCAsmBackend(MRI, getTargetTriple(),
|
||||
TargetCPU);
|
||||
if (MCE == 0 || MAB == 0)
|
||||
return true;
|
||||
@ -271,7 +271,8 @@ bool LLVMTargetMachine::addPassesToEmitMC(PassManagerBase &PM,
|
||||
const MCSubtargetInfo &STI = getSubtarget<MCSubtargetInfo>();
|
||||
MCCodeEmitter *MCE = getTarget().createMCCodeEmitter(*getInstrInfo(), MRI,
|
||||
STI, *Ctx);
|
||||
MCAsmBackend *MAB = getTarget().createMCAsmBackend(getTargetTriple(), TargetCPU);
|
||||
MCAsmBackend *MAB = getTarget().createMCAsmBackend(MRI, getTargetTriple(),
|
||||
TargetCPU);
|
||||
if (MCE == 0 || MAB == 0)
|
||||
return true;
|
||||
|
||||
|
@ -396,6 +396,7 @@ void MCMachOStreamer::EmitInstToData(const MCInst &Inst) {
|
||||
}
|
||||
|
||||
void MCMachOStreamer::FinishImpl() {
|
||||
generateCompactUnwindEncodings(getAssembler().getBackend());
|
||||
EmitFrames(true);
|
||||
|
||||
// We have to set the fragment atom associations so we can relax properly for
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/MC/MCAsmBackend.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCExpr.h"
|
||||
@ -72,6 +73,14 @@ raw_ostream &MCStreamer::GetCommentOS() {
|
||||
return nulls();
|
||||
}
|
||||
|
||||
void MCStreamer::generateCompactUnwindEncodings(MCAsmBackend &MAB) {
|
||||
for (std::vector<MCDwarfFrameInfo>::iterator I = FrameInfos.begin(),
|
||||
E = FrameInfos.end(); I != E; ++I)
|
||||
if (!I->CompactUnwindEncoding)
|
||||
I->CompactUnwindEncoding =
|
||||
MAB.generateCompactUnwindEncoding(I->Instructions);
|
||||
}
|
||||
|
||||
void MCStreamer::EmitDwarfSetLineAddr(int64_t LineDelta,
|
||||
const MCSymbol *Label, int PointerSize) {
|
||||
// emit the sequence to set the address
|
||||
|
@ -578,8 +578,8 @@ static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) {
|
||||
}
|
||||
|
||||
MCAsmBackend *
|
||||
llvm::createAArch64AsmBackend(const Target &T, StringRef TT, StringRef CPU) {
|
||||
llvm::createAArch64AsmBackend(const Target &T, const MCRegisterInfo &MRI,
|
||||
StringRef TT, StringRef CPU) {
|
||||
Triple TheTriple(TT);
|
||||
|
||||
return new ELFAArch64AsmBackend(T, TT, TheTriple.getOS());
|
||||
}
|
||||
|
@ -43,8 +43,9 @@ MCCodeEmitter *createAArch64MCCodeEmitter(const MCInstrInfo &MCII,
|
||||
MCObjectWriter *createAArch64ELFObjectWriter(raw_ostream &OS,
|
||||
uint8_t OSABI);
|
||||
|
||||
MCAsmBackend *createAArch64AsmBackend(const Target &T, StringRef TT,
|
||||
StringRef CPU);
|
||||
MCAsmBackend *createAArch64AsmBackend(const Target &T,
|
||||
const MCRegisterInfo &MRI,
|
||||
StringRef TT, StringRef CPU);
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
|
@ -660,7 +660,9 @@ public:
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
MCAsmBackend *llvm::createARMAsmBackend(const Target &T, StringRef TT, StringRef CPU) {
|
||||
MCAsmBackend *llvm::createARMAsmBackend(const Target &T,
|
||||
const MCRegisterInfo &MRI,
|
||||
StringRef TT, StringRef CPU) {
|
||||
Triple TheTriple(TT);
|
||||
|
||||
if (TheTriple.isOSDarwin()) {
|
||||
|
@ -47,7 +47,8 @@ MCCodeEmitter *createARMMCCodeEmitter(const MCInstrInfo &MCII,
|
||||
const MCSubtargetInfo &STI,
|
||||
MCContext &Ctx);
|
||||
|
||||
MCAsmBackend *createARMAsmBackend(const Target &T, StringRef TT, StringRef CPU);
|
||||
MCAsmBackend *createARMAsmBackend(const Target &T, const MCRegisterInfo &MRI,
|
||||
StringRef TT, StringRef CPU);
|
||||
|
||||
/// createARMELFObjectWriter - Construct an ELF Mach-O object writer.
|
||||
MCObjectWriter *createARMELFObjectWriter(raw_ostream &OS,
|
||||
|
@ -253,25 +253,33 @@ public:
|
||||
} // namespace
|
||||
|
||||
// MCAsmBackend
|
||||
MCAsmBackend *llvm::createMipsAsmBackendEL32(const Target &T, StringRef TT,
|
||||
MCAsmBackend *llvm::createMipsAsmBackendEL32(const Target &T,
|
||||
const MCRegisterInfo &MRI,
|
||||
StringRef TT,
|
||||
StringRef CPU) {
|
||||
return new MipsAsmBackend(T, Triple(TT).getOS(),
|
||||
/*IsLittle*/true, /*Is64Bit*/false);
|
||||
}
|
||||
|
||||
MCAsmBackend *llvm::createMipsAsmBackendEB32(const Target &T, StringRef TT,
|
||||
MCAsmBackend *llvm::createMipsAsmBackendEB32(const Target &T,
|
||||
const MCRegisterInfo &MRI,
|
||||
StringRef TT,
|
||||
StringRef CPU) {
|
||||
return new MipsAsmBackend(T, Triple(TT).getOS(),
|
||||
/*IsLittle*/false, /*Is64Bit*/false);
|
||||
}
|
||||
|
||||
MCAsmBackend *llvm::createMipsAsmBackendEL64(const Target &T, StringRef TT,
|
||||
MCAsmBackend *llvm::createMipsAsmBackendEL64(const Target &T,
|
||||
const MCRegisterInfo &MRI,
|
||||
StringRef TT,
|
||||
StringRef CPU) {
|
||||
return new MipsAsmBackend(T, Triple(TT).getOS(),
|
||||
/*IsLittle*/true, /*Is64Bit*/true);
|
||||
}
|
||||
|
||||
MCAsmBackend *llvm::createMipsAsmBackendEB64(const Target &T, StringRef TT,
|
||||
MCAsmBackend *llvm::createMipsAsmBackendEB64(const Target &T,
|
||||
const MCRegisterInfo &MRI,
|
||||
StringRef TT,
|
||||
StringRef CPU) {
|
||||
return new MipsAsmBackend(T, Triple(TT).getOS(),
|
||||
/*IsLittle*/false, /*Is64Bit*/true);
|
||||
|
@ -42,14 +42,14 @@ MCCodeEmitter *createMipsMCCodeEmitterEL(const MCInstrInfo &MCII,
|
||||
const MCSubtargetInfo &STI,
|
||||
MCContext &Ctx);
|
||||
|
||||
MCAsmBackend *createMipsAsmBackendEB32(const Target &T, StringRef TT,
|
||||
StringRef CPU);
|
||||
MCAsmBackend *createMipsAsmBackendEL32(const Target &T, StringRef TT,
|
||||
StringRef CPU);
|
||||
MCAsmBackend *createMipsAsmBackendEB64(const Target &T, StringRef TT,
|
||||
StringRef CPU);
|
||||
MCAsmBackend *createMipsAsmBackendEL64(const Target &T, StringRef TT,
|
||||
StringRef CPU);
|
||||
MCAsmBackend *createMipsAsmBackendEB32(const Target &T, const MCRegisterInfo &MRI,
|
||||
StringRef TT, StringRef CPU);
|
||||
MCAsmBackend *createMipsAsmBackendEL32(const Target &T, const MCRegisterInfo &MRI,
|
||||
StringRef TT, StringRef CPU);
|
||||
MCAsmBackend *createMipsAsmBackendEB64(const Target &T, const MCRegisterInfo &MRI,
|
||||
StringRef TT, StringRef CPU);
|
||||
MCAsmBackend *createMipsAsmBackendEL64(const Target &T, const MCRegisterInfo &MRI,
|
||||
StringRef TT, StringRef CPU);
|
||||
|
||||
MCObjectWriter *createMipsELFObjectWriter(raw_ostream &OS,
|
||||
uint8_t OSABI,
|
||||
|
@ -192,10 +192,9 @@ namespace {
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
|
||||
|
||||
MCAsmBackend *llvm::createPPCAsmBackend(const Target &T, StringRef TT, StringRef CPU) {
|
||||
MCAsmBackend *llvm::createPPCAsmBackend(const Target &T,
|
||||
const MCRegisterInfo &MRI,
|
||||
StringRef TT, StringRef CPU) {
|
||||
if (Triple(TT).isOSDarwin())
|
||||
return new DarwinPPCAsmBackend(T);
|
||||
|
||||
|
@ -40,7 +40,8 @@ MCCodeEmitter *createPPCMCCodeEmitter(const MCInstrInfo &MCII,
|
||||
const MCSubtargetInfo &STI,
|
||||
MCContext &Ctx);
|
||||
|
||||
MCAsmBackend *createPPCAsmBackend(const Target &T, StringRef TT, StringRef CPU);
|
||||
MCAsmBackend *createPPCAsmBackend(const Target &T, const MCRegisterInfo &MRI,
|
||||
StringRef TT, StringRef CPU);
|
||||
|
||||
/// createPPCELFObjectWriter - Construct an PPC ELF object writer.
|
||||
MCObjectWriter *createPPCELFObjectWriter(raw_ostream &OS,
|
||||
|
@ -95,7 +95,9 @@ public:
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
MCAsmBackend *llvm::createAMDGPUAsmBackend(const Target &T, StringRef TT,
|
||||
MCAsmBackend *llvm::createAMDGPUAsmBackend(const Target &T,
|
||||
const MCRegisterInfo &MRI,
|
||||
StringRef TT,
|
||||
StringRef CPU) {
|
||||
return new ELFAMDGPUAsmBackend(T);
|
||||
}
|
||||
|
@ -40,8 +40,8 @@ MCCodeEmitter *createSIMCCodeEmitter(const MCInstrInfo &MCII,
|
||||
const MCSubtargetInfo &STI,
|
||||
MCContext &Ctx);
|
||||
|
||||
MCAsmBackend *createAMDGPUAsmBackend(const Target &T, StringRef TT,
|
||||
StringRef CPU);
|
||||
MCAsmBackend *createAMDGPUAsmBackend(const Target &T, const MCRegisterInfo &MRI,
|
||||
StringRef TT, StringRef CPU);
|
||||
|
||||
MCObjectWriter *createAMDGPUELFObjectWriter(raw_ostream &OS);
|
||||
} // End llvm namespace
|
||||
|
@ -143,8 +143,9 @@ bool SystemZMCAsmBackend::writeNopData(uint64_t Count,
|
||||
return true;
|
||||
}
|
||||
|
||||
MCAsmBackend *llvm::createSystemZMCAsmBackend(const Target &T, StringRef TT,
|
||||
StringRef CPU) {
|
||||
MCAsmBackend *llvm::createSystemZMCAsmBackend(const Target &T,
|
||||
const MCRegisterInfo &MRI,
|
||||
StringRef TT, StringRef CPU) {
|
||||
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(Triple(TT).getOS());
|
||||
return new SystemZMCAsmBackend(OSABI);
|
||||
}
|
||||
|
@ -54,8 +54,9 @@ MCCodeEmitter *createSystemZMCCodeEmitter(const MCInstrInfo &MCII,
|
||||
const MCSubtargetInfo &STI,
|
||||
MCContext &Ctx);
|
||||
|
||||
MCAsmBackend *createSystemZMCAsmBackend(const Target &T, StringRef TT,
|
||||
StringRef CPU);
|
||||
MCAsmBackend *createSystemZMCAsmBackend(const Target &T,
|
||||
const MCRegisterInfo &MRI,
|
||||
StringRef TT, StringRef CPU);
|
||||
|
||||
MCObjectWriter *createSystemZObjectWriter(raw_ostream &OS, uint8_t OSABI);
|
||||
} // end namespace llvm
|
||||
|
@ -27,6 +27,32 @@
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace llvm;
|
||||
|
||||
namespace CU {
|
||||
|
||||
/// Compact unwind encoding values.
|
||||
enum CompactUnwindEncodings {
|
||||
/// [RE]BP based frame where [RE]BP is pused on the stack immediately after
|
||||
/// the return address, then [RE]SP is moved to [RE]BP.
|
||||
UNWIND_MODE_BP_FRAME = 0x01000000,
|
||||
|
||||
/// A frameless function with a small constant stack size.
|
||||
UNWIND_MODE_STACK_IMMD = 0x02000000,
|
||||
|
||||
/// A frameless function with a large constant stack size.
|
||||
UNWIND_MODE_STACK_IND = 0x03000000,
|
||||
|
||||
/// No compact unwind encoding is available.
|
||||
UNWIND_MODE_DWARF = 0x04000000,
|
||||
|
||||
/// Mask for encoding the frame registers.
|
||||
UNWIND_BP_FRAME_REGISTERS = 0x00007FFF,
|
||||
|
||||
/// Mask for encoding the frameless registers.
|
||||
UNWIND_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF
|
||||
};
|
||||
|
||||
} // end CU namespace
|
||||
|
||||
// Option to allow disabling arithmetic relaxation to workaround PR9807, which
|
||||
// is useful when running bitwise comparison experiments on Darwin. We should be
|
||||
// able to remove this once PR9807 is resolved.
|
||||
@ -383,27 +409,330 @@ public:
|
||||
};
|
||||
|
||||
class DarwinX86AsmBackend : public X86AsmBackend {
|
||||
const MCRegisterInfo &MRI;
|
||||
|
||||
/// \brief Number of registers that can be saved in a compact unwind encoding.
|
||||
enum { CU_NUM_SAVED_REGS = 6 };
|
||||
|
||||
mutable unsigned SavedRegs[CU_NUM_SAVED_REGS];
|
||||
bool Is64Bit;
|
||||
|
||||
unsigned OffsetSize; ///< Offset of a "push" instruction.
|
||||
unsigned PushInstrSize; ///< Size of a "push" instruction.
|
||||
unsigned MoveInstrSize; ///< Size of a "move" instruction.
|
||||
unsigned StackDivide; ///< Amount to adjust stack stize by.
|
||||
protected:
|
||||
/// \brief Implementation of algorithm to generate the compact unwind encoding
|
||||
/// for the CFI instructions.
|
||||
uint32_t
|
||||
generateCompactUnwindEncodingImpl(ArrayRef<MCCFIInstruction> Instrs) const {
|
||||
if (Instrs.empty()) return 0;
|
||||
|
||||
// Reset the saved registers.
|
||||
unsigned SavedRegIdx = 0;
|
||||
memset(SavedRegs, 0, sizeof(SavedRegs));
|
||||
|
||||
bool HasFP = false;
|
||||
|
||||
// Encode that we are using EBP/RBP as the frame pointer.
|
||||
uint32_t CompactUnwindEncoding = 0;
|
||||
|
||||
unsigned SubtractInstrIdx = Is64Bit ? 3 : 2;
|
||||
unsigned InstrOffset = 0;
|
||||
unsigned StackAdjust = 0;
|
||||
unsigned StackSize = 0;
|
||||
unsigned PrevStackSize = 0;
|
||||
unsigned NumDefCFAOffsets = 0;
|
||||
|
||||
for (unsigned i = 0, e = Instrs.size(); i != e; ++i) {
|
||||
const MCCFIInstruction &Inst = Instrs[i];
|
||||
|
||||
switch (Inst.getOperation()) {
|
||||
default:
|
||||
llvm_unreachable("cannot handle CFI directive for compact unwind!");
|
||||
case MCCFIInstruction::OpDefCfaRegister: {
|
||||
// Defines a frame pointer. E.g.
|
||||
//
|
||||
// movq %rsp, %rbp
|
||||
// L0:
|
||||
// .cfi_def_cfa_register %rbp
|
||||
//
|
||||
HasFP = true;
|
||||
assert(MRI.getLLVMRegNum(Inst.getRegister(), true) ==
|
||||
(Is64Bit ? X86::RBP : X86::EBP) && "Invalid frame pointer!");
|
||||
|
||||
// Reset the counts.
|
||||
memset(SavedRegs, 0, sizeof(SavedRegs));
|
||||
StackAdjust = 0;
|
||||
SavedRegIdx = 0;
|
||||
InstrOffset += MoveInstrSize;
|
||||
break;
|
||||
}
|
||||
case MCCFIInstruction::OpDefCfaOffset: {
|
||||
// Defines a new offset for the CFA. E.g.
|
||||
//
|
||||
// With frame:
|
||||
//
|
||||
// pushq %rbp
|
||||
// L0:
|
||||
// .cfi_def_cfa_offset 16
|
||||
//
|
||||
// Without frame:
|
||||
//
|
||||
// subq $72, %rsp
|
||||
// L0:
|
||||
// .cfi_def_cfa_offset 80
|
||||
//
|
||||
PrevStackSize = StackSize;
|
||||
StackSize = std::abs(Inst.getOffset()) / StackDivide;
|
||||
++NumDefCFAOffsets;
|
||||
break;
|
||||
}
|
||||
case MCCFIInstruction::OpOffset: {
|
||||
// Defines a "push" of a callee-saved register. E.g.
|
||||
//
|
||||
// pushq %r15
|
||||
// pushq %r14
|
||||
// pushq %rbx
|
||||
// L0:
|
||||
// subq $120, %rsp
|
||||
// L1:
|
||||
// .cfi_offset %rbx, -40
|
||||
// .cfi_offset %r14, -32
|
||||
// .cfi_offset %r15, -24
|
||||
//
|
||||
if (SavedRegIdx == CU_NUM_SAVED_REGS)
|
||||
// If there are too many saved registers, we cannot use a compact
|
||||
// unwind encoding.
|
||||
return CU::UNWIND_MODE_DWARF;
|
||||
|
||||
unsigned Reg = MRI.getLLVMRegNum(Inst.getRegister(), true);
|
||||
SavedRegs[SavedRegIdx++] = Reg;
|
||||
StackAdjust += OffsetSize;
|
||||
InstrOffset += PushInstrSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StackAdjust /= StackDivide;
|
||||
|
||||
if (HasFP) {
|
||||
if ((StackAdjust & 0xFF) != StackAdjust)
|
||||
// Offset was too big for a compact unwind encoding.
|
||||
return CU::UNWIND_MODE_DWARF;
|
||||
|
||||
// Get the encoding of the saved registers when we have a frame pointer.
|
||||
uint32_t RegEnc = encodeCompactUnwindRegistersWithFrame();
|
||||
if (RegEnc == ~0U) return CU::UNWIND_MODE_DWARF;
|
||||
|
||||
CompactUnwindEncoding |= CU::UNWIND_MODE_BP_FRAME;
|
||||
CompactUnwindEncoding |= (StackAdjust & 0xFF) << 16;
|
||||
CompactUnwindEncoding |= RegEnc & CU::UNWIND_BP_FRAME_REGISTERS;
|
||||
} else {
|
||||
// If the amount of the stack allocation is the size of a register, then
|
||||
// we "push" the RAX/EAX register onto the stack instead of adjusting the
|
||||
// stack pointer with a SUB instruction. We don't support the push of the
|
||||
// RAX/EAX register with compact unwind. So we check for that situation
|
||||
// here.
|
||||
if ((NumDefCFAOffsets == SavedRegIdx + 1 &&
|
||||
StackSize - PrevStackSize == 1) ||
|
||||
(Instrs.size() == 1 && NumDefCFAOffsets == 1 && StackSize == 2))
|
||||
return CU::UNWIND_MODE_DWARF;
|
||||
|
||||
SubtractInstrIdx += InstrOffset;
|
||||
++StackAdjust;
|
||||
|
||||
if ((StackSize & 0xFF) == StackSize) {
|
||||
// Frameless stack with a small stack size.
|
||||
CompactUnwindEncoding |= CU::UNWIND_MODE_STACK_IMMD;
|
||||
|
||||
// Encode the stack size.
|
||||
CompactUnwindEncoding |= (StackSize & 0xFF) << 16;
|
||||
} else {
|
||||
if ((StackAdjust & 0x7) != StackAdjust)
|
||||
// The extra stack adjustments are too big for us to handle.
|
||||
return CU::UNWIND_MODE_DWARF;
|
||||
|
||||
// Frameless stack with an offset too large for us to encode compactly.
|
||||
CompactUnwindEncoding |= CU::UNWIND_MODE_STACK_IND;
|
||||
|
||||
// Encode the offset to the nnnnnn value in the 'subl $nnnnnn, ESP'
|
||||
// instruction.
|
||||
CompactUnwindEncoding |= (SubtractInstrIdx & 0xFF) << 16;
|
||||
|
||||
// Encode any extra stack stack adjustments (done via push
|
||||
// instructions).
|
||||
CompactUnwindEncoding |= (StackAdjust & 0x7) << 13;
|
||||
}
|
||||
|
||||
// Encode the number of registers saved. (Reverse the list first.)
|
||||
std::reverse(&SavedRegs[0], &SavedRegs[SavedRegIdx]);
|
||||
CompactUnwindEncoding |= (SavedRegIdx & 0x7) << 10;
|
||||
|
||||
// Get the encoding of the saved registers when we don't have a frame
|
||||
// pointer.
|
||||
uint32_t RegEnc = encodeCompactUnwindRegistersWithoutFrame(SavedRegIdx);
|
||||
if (RegEnc == ~0U) return CU::UNWIND_MODE_DWARF;
|
||||
|
||||
// Encode the register encoding.
|
||||
CompactUnwindEncoding |=
|
||||
RegEnc & CU::UNWIND_FRAMELESS_STACK_REG_PERMUTATION;
|
||||
}
|
||||
|
||||
return CompactUnwindEncoding;
|
||||
}
|
||||
|
||||
private:
|
||||
/// \brief Get the compact unwind number for a given register. The number
|
||||
/// corresponds to the enum lists in compact_unwind_encoding.h.
|
||||
int getCompactUnwindRegNum(unsigned Reg) const {
|
||||
static const uint16_t CU32BitRegs[7] = {
|
||||
X86::EBX, X86::ECX, X86::EDX, X86::EDI, X86::ESI, X86::EBP, 0
|
||||
};
|
||||
static const uint16_t CU64BitRegs[] = {
|
||||
X86::RBX, X86::R12, X86::R13, X86::R14, X86::R15, X86::RBP, 0
|
||||
};
|
||||
const uint16_t *CURegs = Is64Bit ? CU64BitRegs : CU32BitRegs;
|
||||
for (int Idx = 1; *CURegs; ++CURegs, ++Idx)
|
||||
if (*CURegs == Reg)
|
||||
return Idx;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// \brief Return the registers encoded for a compact encoding with a frame
|
||||
/// pointer.
|
||||
uint32_t encodeCompactUnwindRegistersWithFrame() const {
|
||||
// Encode the registers in the order they were saved --- 3-bits per
|
||||
// register. The list of saved registers is assumed to be in reverse
|
||||
// order. The registers are numbered from 1 to CU_NUM_SAVED_REGS.
|
||||
uint32_t RegEnc = 0;
|
||||
for (int i = 0, Idx = 0; i != CU_NUM_SAVED_REGS; ++i) {
|
||||
unsigned Reg = SavedRegs[i];
|
||||
if (Reg == 0) break;
|
||||
|
||||
int CURegNum = getCompactUnwindRegNum(Reg);
|
||||
if (CURegNum == -1) return ~0U;
|
||||
|
||||
// Encode the 3-bit register number in order, skipping over 3-bits for
|
||||
// each register.
|
||||
RegEnc |= (CURegNum & 0x7) << (Idx++ * 3);
|
||||
}
|
||||
|
||||
assert((RegEnc & 0x3FFFF) == RegEnc &&
|
||||
"Invalid compact register encoding!");
|
||||
return RegEnc;
|
||||
}
|
||||
|
||||
/// \brief Create the permutation encoding used with frameless stacks. It is
|
||||
/// passed the number of registers to be saved and an array of the registers
|
||||
/// saved.
|
||||
uint32_t encodeCompactUnwindRegistersWithoutFrame(unsigned RegCount) const {
|
||||
// The saved registers are numbered from 1 to 6. In order to encode the
|
||||
// order in which they were saved, we re-number them according to their
|
||||
// place in the register order. The re-numbering is relative to the last
|
||||
// re-numbered register. E.g., if we have registers {6, 2, 4, 5} saved in
|
||||
// that order:
|
||||
//
|
||||
// Orig Re-Num
|
||||
// ---- ------
|
||||
// 6 6
|
||||
// 2 2
|
||||
// 4 3
|
||||
// 5 3
|
||||
//
|
||||
for (unsigned i = 0; i != CU_NUM_SAVED_REGS; ++i) {
|
||||
int CUReg = getCompactUnwindRegNum(SavedRegs[i]);
|
||||
if (CUReg == -1) return ~0U;
|
||||
SavedRegs[i] = CUReg;
|
||||
}
|
||||
|
||||
// Reverse the list.
|
||||
std::reverse(&SavedRegs[0], &SavedRegs[CU_NUM_SAVED_REGS]);
|
||||
|
||||
uint32_t RenumRegs[CU_NUM_SAVED_REGS];
|
||||
for (unsigned i = CU_NUM_SAVED_REGS - RegCount; i < CU_NUM_SAVED_REGS; ++i){
|
||||
unsigned Countless = 0;
|
||||
for (unsigned j = CU_NUM_SAVED_REGS - RegCount; j < i; ++j)
|
||||
if (SavedRegs[j] < SavedRegs[i])
|
||||
++Countless;
|
||||
|
||||
RenumRegs[i] = SavedRegs[i] - Countless - 1;
|
||||
}
|
||||
|
||||
// Take the renumbered values and encode them into a 10-bit number.
|
||||
uint32_t permutationEncoding = 0;
|
||||
switch (RegCount) {
|
||||
case 6:
|
||||
permutationEncoding |= 120 * RenumRegs[0] + 24 * RenumRegs[1]
|
||||
+ 6 * RenumRegs[2] + 2 * RenumRegs[3]
|
||||
+ RenumRegs[4];
|
||||
break;
|
||||
case 5:
|
||||
permutationEncoding |= 120 * RenumRegs[1] + 24 * RenumRegs[2]
|
||||
+ 6 * RenumRegs[3] + 2 * RenumRegs[4]
|
||||
+ RenumRegs[5];
|
||||
break;
|
||||
case 4:
|
||||
permutationEncoding |= 60 * RenumRegs[2] + 12 * RenumRegs[3]
|
||||
+ 3 * RenumRegs[4] + RenumRegs[5];
|
||||
break;
|
||||
case 3:
|
||||
permutationEncoding |= 20 * RenumRegs[3] + 4 * RenumRegs[4]
|
||||
+ RenumRegs[5];
|
||||
break;
|
||||
case 2:
|
||||
permutationEncoding |= 5 * RenumRegs[4] + RenumRegs[5];
|
||||
break;
|
||||
case 1:
|
||||
permutationEncoding |= RenumRegs[5];
|
||||
break;
|
||||
}
|
||||
|
||||
assert((permutationEncoding & 0x3FF) == permutationEncoding &&
|
||||
"Invalid compact register encoding!");
|
||||
return permutationEncoding;
|
||||
}
|
||||
|
||||
public:
|
||||
DarwinX86AsmBackend(const Target &T, StringRef CPU)
|
||||
: X86AsmBackend(T, CPU) { }
|
||||
DarwinX86AsmBackend(const Target &T, const MCRegisterInfo &MRI, StringRef CPU,
|
||||
bool Is64Bit)
|
||||
: X86AsmBackend(T, CPU), MRI(MRI), Is64Bit(Is64Bit) {
|
||||
memset(SavedRegs, 0, sizeof(SavedRegs));
|
||||
OffsetSize = Is64Bit ? 8 : 4;
|
||||
MoveInstrSize = Is64Bit ? 3 : 2;
|
||||
StackDivide = Is64Bit ? 8 : 4;
|
||||
PushInstrSize = 1;
|
||||
}
|
||||
};
|
||||
|
||||
class DarwinX86_32AsmBackend : public DarwinX86AsmBackend {
|
||||
bool SupportsCU;
|
||||
public:
|
||||
DarwinX86_32AsmBackend(const Target &T, StringRef CPU)
|
||||
: DarwinX86AsmBackend(T, CPU) {}
|
||||
DarwinX86_32AsmBackend(const Target &T, const MCRegisterInfo &MRI,
|
||||
StringRef CPU, bool SupportsCU)
|
||||
: DarwinX86AsmBackend(T, MRI, CPU, false), SupportsCU(SupportsCU) {}
|
||||
|
||||
MCObjectWriter *createObjectWriter(raw_ostream &OS) const {
|
||||
return createX86MachObjectWriter(OS, /*Is64Bit=*/false,
|
||||
MachO::CPU_TYPE_I386,
|
||||
MachO::CPU_SUBTYPE_I386_ALL);
|
||||
}
|
||||
|
||||
/// \brief Generate the compact unwind encoding for the CFI instructions.
|
||||
virtual unsigned
|
||||
generateCompactUnwindEncoding(ArrayRef<MCCFIInstruction> Instrs) const {
|
||||
return SupportsCU ? generateCompactUnwindEncodingImpl(Instrs) : 0;
|
||||
}
|
||||
};
|
||||
|
||||
class DarwinX86_64AsmBackend : public DarwinX86AsmBackend {
|
||||
bool SupportsCU;
|
||||
public:
|
||||
DarwinX86_64AsmBackend(const Target &T, StringRef CPU)
|
||||
: DarwinX86AsmBackend(T, CPU) {
|
||||
DarwinX86_64AsmBackend(const Target &T, const MCRegisterInfo &MRI,
|
||||
StringRef CPU, bool SupportsCU)
|
||||
: DarwinX86AsmBackend(T, MRI, CPU, true), SupportsCU(SupportsCU) {
|
||||
HasReliableSymbolDifference = true;
|
||||
}
|
||||
|
||||
@ -445,15 +774,26 @@ public:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Generate the compact unwind encoding for the CFI instructions.
|
||||
virtual unsigned
|
||||
generateCompactUnwindEncoding(ArrayRef<MCCFIInstruction> Instrs) const {
|
||||
return SupportsCU ? generateCompactUnwindEncodingImpl(Instrs) : 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
MCAsmBackend *llvm::createX86_32AsmBackend(const Target &T, StringRef TT, StringRef CPU) {
|
||||
MCAsmBackend *llvm::createX86_32AsmBackend(const Target &T,
|
||||
const MCRegisterInfo &MRI,
|
||||
StringRef TT,
|
||||
StringRef CPU) {
|
||||
Triple TheTriple(TT);
|
||||
|
||||
if (TheTriple.isOSDarwin() || TheTriple.getEnvironment() == Triple::MachO)
|
||||
return new DarwinX86_32AsmBackend(T, CPU);
|
||||
return new DarwinX86_32AsmBackend(T, MRI, CPU,
|
||||
TheTriple.isMacOSX() &&
|
||||
!TheTriple.isMacOSXVersionLT(10, 7));
|
||||
|
||||
if (TheTriple.isOSWindows() && TheTriple.getEnvironment() != Triple::ELF)
|
||||
return new WindowsX86AsmBackend(T, false, CPU);
|
||||
@ -462,11 +802,16 @@ MCAsmBackend *llvm::createX86_32AsmBackend(const Target &T, StringRef TT, String
|
||||
return new ELFX86_32AsmBackend(T, OSABI, CPU);
|
||||
}
|
||||
|
||||
MCAsmBackend *llvm::createX86_64AsmBackend(const Target &T, StringRef TT, StringRef CPU) {
|
||||
MCAsmBackend *llvm::createX86_64AsmBackend(const Target &T,
|
||||
const MCRegisterInfo &MRI,
|
||||
StringRef TT,
|
||||
StringRef CPU) {
|
||||
Triple TheTriple(TT);
|
||||
|
||||
if (TheTriple.isOSDarwin() || TheTriple.getEnvironment() == Triple::MachO)
|
||||
return new DarwinX86_64AsmBackend(T, CPU);
|
||||
return new DarwinX86_64AsmBackend(T, MRI, CPU,
|
||||
TheTriple.isMacOSX() &&
|
||||
!TheTriple.isMacOSXVersionLT(10, 7));
|
||||
|
||||
if (TheTriple.isOSWindows() && TheTriple.getEnvironment() != Triple::ELF)
|
||||
return new WindowsX86AsmBackend(T, true, CPU);
|
||||
|
@ -79,8 +79,10 @@ MCCodeEmitter *createX86MCCodeEmitter(const MCInstrInfo &MCII,
|
||||
const MCSubtargetInfo &STI,
|
||||
MCContext &Ctx);
|
||||
|
||||
MCAsmBackend *createX86_32AsmBackend(const Target &T, StringRef TT, StringRef CPU);
|
||||
MCAsmBackend *createX86_64AsmBackend(const Target &T, StringRef TT, StringRef CPU);
|
||||
MCAsmBackend *createX86_32AsmBackend(const Target &T, const MCRegisterInfo &MRI,
|
||||
StringRef TT, StringRef CPU);
|
||||
MCAsmBackend *createX86_64AsmBackend(const Target &T, const MCRegisterInfo &MRI,
|
||||
StringRef TT, StringRef CPU);
|
||||
|
||||
/// createX86MachObjectWriter - Construct an X86 Mach-O object writer.
|
||||
MCObjectWriter *createX86MachObjectWriter(raw_ostream &OS,
|
||||
|
@ -365,274 +365,6 @@ void X86FrameLowering::emitCalleeSavedFrameMoves(MachineFunction &MF,
|
||||
}
|
||||
}
|
||||
|
||||
/// getCompactUnwindRegNum - Get the compact unwind number for a given
|
||||
/// register. The number corresponds to the enum lists in
|
||||
/// compact_unwind_encoding.h.
|
||||
static int getCompactUnwindRegNum(unsigned Reg, bool is64Bit) {
|
||||
static const uint16_t CU32BitRegs[] = {
|
||||
X86::EBX, X86::ECX, X86::EDX, X86::EDI, X86::ESI, X86::EBP, 0
|
||||
};
|
||||
static const uint16_t CU64BitRegs[] = {
|
||||
X86::RBX, X86::R12, X86::R13, X86::R14, X86::R15, X86::RBP, 0
|
||||
};
|
||||
const uint16_t *CURegs = is64Bit ? CU64BitRegs : CU32BitRegs;
|
||||
for (int Idx = 1; *CURegs; ++CURegs, ++Idx)
|
||||
if (*CURegs == Reg)
|
||||
return Idx;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Number of registers that can be saved in a compact unwind encoding.
|
||||
#define CU_NUM_SAVED_REGS 6
|
||||
|
||||
/// encodeCompactUnwindRegistersWithoutFrame - Create the permutation encoding
|
||||
/// used with frameless stacks. It is passed the number of registers to be saved
|
||||
/// and an array of the registers saved.
|
||||
static uint32_t
|
||||
encodeCompactUnwindRegistersWithoutFrame(unsigned SavedRegs[CU_NUM_SAVED_REGS],
|
||||
unsigned RegCount, bool Is64Bit) {
|
||||
// The saved registers are numbered from 1 to 6. In order to encode the order
|
||||
// in which they were saved, we re-number them according to their place in the
|
||||
// register order. The re-numbering is relative to the last re-numbered
|
||||
// register. E.g., if we have registers {6, 2, 4, 5} saved in that order:
|
||||
//
|
||||
// Orig Re-Num
|
||||
// ---- ------
|
||||
// 6 6
|
||||
// 2 2
|
||||
// 4 3
|
||||
// 5 3
|
||||
//
|
||||
for (unsigned i = 0; i != CU_NUM_SAVED_REGS; ++i) {
|
||||
int CUReg = getCompactUnwindRegNum(SavedRegs[i], Is64Bit);
|
||||
if (CUReg == -1) return ~0U;
|
||||
SavedRegs[i] = CUReg;
|
||||
}
|
||||
|
||||
// Reverse the list.
|
||||
std::swap(SavedRegs[0], SavedRegs[5]);
|
||||
std::swap(SavedRegs[1], SavedRegs[4]);
|
||||
std::swap(SavedRegs[2], SavedRegs[3]);
|
||||
|
||||
uint32_t RenumRegs[CU_NUM_SAVED_REGS];
|
||||
for (unsigned i = CU_NUM_SAVED_REGS - RegCount; i < CU_NUM_SAVED_REGS; ++i) {
|
||||
unsigned Countless = 0;
|
||||
for (unsigned j = CU_NUM_SAVED_REGS - RegCount; j < i; ++j)
|
||||
if (SavedRegs[j] < SavedRegs[i])
|
||||
++Countless;
|
||||
|
||||
RenumRegs[i] = SavedRegs[i] - Countless - 1;
|
||||
}
|
||||
|
||||
// Take the renumbered values and encode them into a 10-bit number.
|
||||
uint32_t permutationEncoding = 0;
|
||||
switch (RegCount) {
|
||||
case 6:
|
||||
permutationEncoding |= 120 * RenumRegs[0] + 24 * RenumRegs[1]
|
||||
+ 6 * RenumRegs[2] + 2 * RenumRegs[3]
|
||||
+ RenumRegs[4];
|
||||
break;
|
||||
case 5:
|
||||
permutationEncoding |= 120 * RenumRegs[1] + 24 * RenumRegs[2]
|
||||
+ 6 * RenumRegs[3] + 2 * RenumRegs[4]
|
||||
+ RenumRegs[5];
|
||||
break;
|
||||
case 4:
|
||||
permutationEncoding |= 60 * RenumRegs[2] + 12 * RenumRegs[3]
|
||||
+ 3 * RenumRegs[4] + RenumRegs[5];
|
||||
break;
|
||||
case 3:
|
||||
permutationEncoding |= 20 * RenumRegs[3] + 4 * RenumRegs[4]
|
||||
+ RenumRegs[5];
|
||||
break;
|
||||
case 2:
|
||||
permutationEncoding |= 5 * RenumRegs[4] + RenumRegs[5];
|
||||
break;
|
||||
case 1:
|
||||
permutationEncoding |= RenumRegs[5];
|
||||
break;
|
||||
}
|
||||
|
||||
assert((permutationEncoding & 0x3FF) == permutationEncoding &&
|
||||
"Invalid compact register encoding!");
|
||||
return permutationEncoding;
|
||||
}
|
||||
|
||||
/// encodeCompactUnwindRegistersWithFrame - Return the registers encoded for a
|
||||
/// compact encoding with a frame pointer.
|
||||
static uint32_t
|
||||
encodeCompactUnwindRegistersWithFrame(unsigned SavedRegs[CU_NUM_SAVED_REGS],
|
||||
bool Is64Bit) {
|
||||
// Encode the registers in the order they were saved, 3-bits per register. The
|
||||
// registers are numbered from 1 to CU_NUM_SAVED_REGS.
|
||||
uint32_t RegEnc = 0;
|
||||
for (int I = CU_NUM_SAVED_REGS - 1, Idx = 0; I != -1; --I) {
|
||||
unsigned Reg = SavedRegs[I];
|
||||
if (Reg == 0) continue;
|
||||
|
||||
int CURegNum = getCompactUnwindRegNum(Reg, Is64Bit);
|
||||
if (CURegNum == -1) return ~0U;
|
||||
|
||||
// Encode the 3-bit register number in order, skipping over 3-bits for each
|
||||
// register.
|
||||
RegEnc |= (CURegNum & 0x7) << (Idx++ * 3);
|
||||
}
|
||||
|
||||
assert((RegEnc & 0x3FFFF) == RegEnc && "Invalid compact register encoding!");
|
||||
return RegEnc;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
doCompactUnwindEncoding(unsigned SavedRegs[CU_NUM_SAVED_REGS],
|
||||
unsigned StackSize, unsigned StackAdjust,
|
||||
unsigned SubtractInstrIdx, unsigned SavedRegIdx,
|
||||
bool Is64Bit, bool HasFP) {
|
||||
// Encode that we are using EBP/RBP as the frame pointer.
|
||||
unsigned StackDivide = (Is64Bit ? 8 : 4);
|
||||
uint32_t CompactUnwindEncoding = 0;
|
||||
|
||||
StackAdjust /= StackDivide;
|
||||
|
||||
if (HasFP) {
|
||||
if ((StackAdjust & 0xFF) != StackAdjust)
|
||||
// Offset was too big for compact encoding.
|
||||
return CU::UNWIND_MODE_DWARF;
|
||||
|
||||
// Get the encoding of the saved registers when we have a frame pointer.
|
||||
uint32_t RegEnc = encodeCompactUnwindRegistersWithFrame(SavedRegs, Is64Bit);
|
||||
if (RegEnc == ~0U) return CU::UNWIND_MODE_DWARF;
|
||||
|
||||
CompactUnwindEncoding |= CU::UNWIND_MODE_BP_FRAME;
|
||||
CompactUnwindEncoding |= (StackAdjust & 0xFF) << 16;
|
||||
CompactUnwindEncoding |= RegEnc & CU::UNWIND_BP_FRAME_REGISTERS;
|
||||
} else {
|
||||
++StackAdjust;
|
||||
uint32_t TotalStackSize = StackAdjust + StackSize;
|
||||
if ((TotalStackSize & 0xFF) == TotalStackSize) {
|
||||
// Frameless stack with a small stack size.
|
||||
CompactUnwindEncoding |= CU::UNWIND_MODE_STACK_IMMD;
|
||||
|
||||
// Encode the stack size.
|
||||
CompactUnwindEncoding |= (TotalStackSize & 0xFF) << 16;
|
||||
} else {
|
||||
if ((StackAdjust & 0x7) != StackAdjust)
|
||||
// The extra stack adjustments are too big for us to handle.
|
||||
return CU::UNWIND_MODE_DWARF;
|
||||
|
||||
// Frameless stack with an offset too large for us to encode compactly.
|
||||
CompactUnwindEncoding |= CU::UNWIND_MODE_STACK_IND;
|
||||
|
||||
// Encode the offset to the nnnnnn value in the 'subl $nnnnnn, ESP'
|
||||
// instruction.
|
||||
CompactUnwindEncoding |= (SubtractInstrIdx & 0xFF) << 16;
|
||||
|
||||
// Encode any extra stack stack adjustments (done via push instructions).
|
||||
CompactUnwindEncoding |= (StackAdjust & 0x7) << 13;
|
||||
}
|
||||
|
||||
// Encode the number of registers saved.
|
||||
CompactUnwindEncoding |= (SavedRegIdx & 0x7) << 10;
|
||||
|
||||
// Get the encoding of the saved registers when we don't have a frame
|
||||
// pointer.
|
||||
uint32_t RegEnc =
|
||||
encodeCompactUnwindRegistersWithoutFrame(SavedRegs, SavedRegIdx,
|
||||
Is64Bit);
|
||||
if (RegEnc == ~0U) return CU::UNWIND_MODE_DWARF;
|
||||
|
||||
// Encode the register encoding.
|
||||
CompactUnwindEncoding |=
|
||||
RegEnc & CU::UNWIND_FRAMELESS_STACK_REG_PERMUTATION;
|
||||
}
|
||||
|
||||
return CompactUnwindEncoding;
|
||||
}
|
||||
|
||||
uint32_t X86FrameLowering::getCompactUnwindEncoding(MachineFunction &MF) const {
|
||||
const X86RegisterInfo *RegInfo = TM.getRegisterInfo();
|
||||
unsigned FramePtr = RegInfo->getFrameRegister(MF);
|
||||
unsigned StackPtr = RegInfo->getStackRegister();
|
||||
|
||||
bool Is64Bit = STI.is64Bit();
|
||||
|
||||
unsigned SavedRegs[CU_NUM_SAVED_REGS] = { 0, 0, 0, 0, 0, 0 };
|
||||
unsigned SavedRegIdx = 0;
|
||||
|
||||
unsigned OffsetSize = (Is64Bit ? 8 : 4);
|
||||
|
||||
unsigned PushInstr = (Is64Bit ? X86::PUSH64r : X86::PUSH32r);
|
||||
unsigned PushInstrSize = 1;
|
||||
unsigned MoveInstr = (Is64Bit ? X86::MOV64rr : X86::MOV32rr);
|
||||
unsigned MoveInstrSize = (Is64Bit ? 3 : 2);
|
||||
unsigned SubtractInstrIdx = (Is64Bit ? 3 : 2);
|
||||
|
||||
unsigned StackDivide = (Is64Bit ? 8 : 4);
|
||||
|
||||
unsigned InstrOffset = 0;
|
||||
unsigned StackAdjust = 0;
|
||||
unsigned StackSize = 0;
|
||||
|
||||
bool ExpectEnd = false;
|
||||
for (MachineBasicBlock::iterator MBBI = MF.front().begin(),
|
||||
MBBE = MF.front().end(); MBBI != MBBE; ++MBBI) {
|
||||
MachineInstr &MI = *MBBI;
|
||||
unsigned Opc = MI.getOpcode();
|
||||
if (Opc == X86::PROLOG_LABEL) continue;
|
||||
if (!MI.getFlag(MachineInstr::FrameSetup)) break;
|
||||
|
||||
// We don't exect any more prolog instructions.
|
||||
if (ExpectEnd) return CU::UNWIND_MODE_DWARF;
|
||||
|
||||
if (Opc == PushInstr) {
|
||||
// If there are too many saved registers, we cannot use compact encoding.
|
||||
if (SavedRegIdx >= CU_NUM_SAVED_REGS) return CU::UNWIND_MODE_DWARF;
|
||||
|
||||
unsigned Reg = MI.getOperand(0).getReg();
|
||||
if (Reg == (Is64Bit ? X86::RAX : X86::EAX)) {
|
||||
ExpectEnd = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
SavedRegs[SavedRegIdx++] = MI.getOperand(0).getReg();
|
||||
StackAdjust += OffsetSize;
|
||||
InstrOffset += PushInstrSize;
|
||||
} else if (Opc == MoveInstr) {
|
||||
unsigned SrcReg = MI.getOperand(1).getReg();
|
||||
unsigned DstReg = MI.getOperand(0).getReg();
|
||||
|
||||
if (DstReg != FramePtr || SrcReg != StackPtr)
|
||||
return CU::UNWIND_MODE_DWARF;
|
||||
|
||||
StackAdjust = 0;
|
||||
memset(SavedRegs, 0, sizeof(SavedRegs));
|
||||
SavedRegIdx = 0;
|
||||
InstrOffset += MoveInstrSize;
|
||||
} else if (Opc == X86::SUB64ri32 || Opc == X86::SUB64ri8 ||
|
||||
Opc == X86::SUB32ri || Opc == X86::SUB32ri8) {
|
||||
if (StackSize)
|
||||
// We already have a stack size.
|
||||
return CU::UNWIND_MODE_DWARF;
|
||||
|
||||
if (!MI.getOperand(0).isReg() ||
|
||||
MI.getOperand(0).getReg() != MI.getOperand(1).getReg() ||
|
||||
MI.getOperand(0).getReg() != StackPtr || !MI.getOperand(2).isImm())
|
||||
// We need this to be a stack adjustment pointer. Something like:
|
||||
//
|
||||
// %RSP<def> = SUB64ri8 %RSP, 48
|
||||
return CU::UNWIND_MODE_DWARF;
|
||||
|
||||
StackSize = MI.getOperand(2).getImm() / StackDivide;
|
||||
SubtractInstrIdx += InstrOffset;
|
||||
ExpectEnd = true;
|
||||
}
|
||||
}
|
||||
|
||||
return doCompactUnwindEncoding(SavedRegs, StackSize, StackAdjust,
|
||||
SubtractInstrIdx, SavedRegIdx,
|
||||
Is64Bit, hasFP(MF));
|
||||
}
|
||||
|
||||
/// usesTheStack - This function checks if any of the users of EFLAGS
|
||||
/// copies the EFLAGS. We know that the code that lowers COPY of EFLAGS has
|
||||
/// to use the stack, and if we don't adjust the stack we clobber the first
|
||||
@ -975,11 +707,6 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF) const {
|
||||
if (PushedRegs)
|
||||
emitCalleeSavedFrameMoves(MF, Label, HasFP ? FramePtr : StackPtr);
|
||||
}
|
||||
|
||||
// Darwin 10.7 and greater has support for compact unwind encoding.
|
||||
if (STI.getTargetTriple().isMacOSX() &&
|
||||
!STI.getTargetTriple().isMacOSXVersionLT(10, 7))
|
||||
MMI.setCompactUnwindEncoding(getCompactUnwindEncoding(MF));
|
||||
}
|
||||
|
||||
void X86FrameLowering::emitEpilogue(MachineFunction &MF,
|
||||
|
@ -20,32 +20,6 @@
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace CU {
|
||||
|
||||
/// Compact unwind encoding values.
|
||||
enum CompactUnwindEncodings {
|
||||
/// [RE]BP based frame where [RE]BP is pused on the stack immediately after
|
||||
/// the return address, then [RE]SP is moved to [RE]BP.
|
||||
UNWIND_MODE_BP_FRAME = 0x01000000,
|
||||
|
||||
/// A frameless function with a small constant stack size.
|
||||
UNWIND_MODE_STACK_IMMD = 0x02000000,
|
||||
|
||||
/// A frameless function with a large constant stack size.
|
||||
UNWIND_MODE_STACK_IND = 0x03000000,
|
||||
|
||||
/// No compact unwind encoding is available.
|
||||
UNWIND_MODE_DWARF = 0x04000000,
|
||||
|
||||
/// Mask for encoding the frame registers.
|
||||
UNWIND_BP_FRAME_REGISTERS = 0x00007FFF,
|
||||
|
||||
/// Mask for encoding the frameless registers.
|
||||
UNWIND_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF
|
||||
};
|
||||
|
||||
} // end CU namespace
|
||||
|
||||
class MCSymbol;
|
||||
class X86TargetMachine;
|
||||
|
||||
@ -91,7 +65,6 @@ public:
|
||||
int getFrameIndexOffset(const MachineFunction &MF, int FI) const;
|
||||
int getFrameIndexReference(const MachineFunction &MF, int FI,
|
||||
unsigned &FrameReg) const;
|
||||
uint32_t getCompactUnwindEncoding(MachineFunction &MF) const;
|
||||
|
||||
void eliminateCallFramePseudoInstr(MachineFunction &MF,
|
||||
MachineBasicBlock &MBB,
|
||||
|
@ -1,18 +1,21 @@
|
||||
; RUN: llc < %s -disable-cfi -disable-fp-elim -mtriple x86_64-apple-darwin11 | FileCheck %s
|
||||
; RUN: llc < %s -disable-fp-elim -mtriple x86_64-apple-darwin11 | FileCheck -check-prefix=ASM %s
|
||||
; RUN: llc < %s -disable-fp-elim -mtriple x86_64-apple-darwin11 -filetype=obj -o - \
|
||||
; RUN: | llvm-objdump -triple x86_64-apple-darwin11 -s - \
|
||||
; RUN: | FileCheck -check-prefix=CU %s
|
||||
|
||||
%ty = type { i8* }
|
||||
|
||||
@gv = external global i32
|
||||
|
||||
; This is aligning the stack with a push of a random register.
|
||||
; CHECK: pushq %rax
|
||||
; ASM: pushq %rax
|
||||
|
||||
; Even though we can't encode %rax into the compact unwind, We still want to be
|
||||
; able to generate a compact unwind encoding in this particular case.
|
||||
;
|
||||
; CHECK: __LD,__compact_unwind
|
||||
; CHECK: _foo ## Range Start
|
||||
; CHECK: 16842753 ## Compact Unwind Encoding: 0x1010001
|
||||
; CU: Contents of section __compact_unwind:
|
||||
; CU-NEXT: 0020 00000000 00000000 1e000000 01000101
|
||||
; CU-NEXT: 0030 00000000 00000000 00000000 00000000
|
||||
|
||||
define i8* @foo(i64 %size) {
|
||||
%addr = alloca i64, align 8
|
||||
|
@ -1,4 +1,6 @@
|
||||
; RUN: llc < %s -mtriple x86_64-apple-macosx10.8.0 -disable-cfi | FileCheck %s
|
||||
; RUN: llc < %s -mtriple x86_64-apple-macosx10.8.0 -filetype=obj -o - \
|
||||
; RUN: | llvm-objdump -triple x86_64-apple-macosx10.8.0 -s - \
|
||||
; RUN: | FileCheck %s
|
||||
|
||||
%"struct.dyld::MappedRanges" = type { [400 x %struct.anon], %"struct.dyld::MappedRanges"* }
|
||||
%struct.anon = type { %class.ImageLoader*, i64, i64 }
|
||||
@ -13,12 +15,11 @@ declare void @OSMemoryBarrier() optsize
|
||||
; compact unwind encodings for this function. This then defaults to using the
|
||||
; DWARF EH frame.
|
||||
;
|
||||
; CHECK: .section __LD,__compact_unwind,regular,debug
|
||||
; CHECK: .quad _func
|
||||
; CHECK: .long 67108864 ## Compact Unwind Encoding: 0x4000000
|
||||
; CHECK: .quad 0 ## Personality Function
|
||||
; CHECK: .quad 0 ## LSDA
|
||||
; CHECK: Contents of section __compact_unwind:
|
||||
; CHECK-NEXT: 0048 00000000 00000000 42000000 00000004
|
||||
; CHECK-NEXT: 0058 00000000 00000000 00000000 00000000
|
||||
;
|
||||
|
||||
define void @func(%class.ImageLoader* %image) optsize ssp uwtable {
|
||||
entry:
|
||||
br label %for.cond1.preheader
|
||||
|
@ -432,7 +432,7 @@ int main(int argc, char **argv) {
|
||||
MCAsmBackend *MAB = 0;
|
||||
if (ShowEncoding) {
|
||||
CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx);
|
||||
MAB = TheTarget->createMCAsmBackend(TripleName, MCPU);
|
||||
MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU);
|
||||
}
|
||||
bool UseCFI = !DisableCFI;
|
||||
Str.reset(TheTarget->createAsmStreamer(Ctx, FOS, /*asmverbose*/true,
|
||||
@ -446,7 +446,7 @@ int main(int argc, char **argv) {
|
||||
} else {
|
||||
assert(FileType == OFT_ObjectFile && "Invalid file type!");
|
||||
MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx);
|
||||
MCAsmBackend *MAB = TheTarget->createMCAsmBackend(TripleName, MCPU);
|
||||
MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU);
|
||||
Str.reset(TheTarget->createMCObjectStreamer(TripleName, Ctx, *MAB,
|
||||
FOS, CE, RelaxAll,
|
||||
NoExecStack));
|
||||
|
Loading…
Reference in New Issue
Block a user