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:
Bill Wendling 2013-09-09 02:37:14 +00:00
parent 959cd8f49b
commit c3cee57f7d
25 changed files with 454 additions and 363 deletions

View File

@ -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

View File

@ -134,6 +134,8 @@ public:
return *W64UnwindInfos[i];
}
void generateCompactUnwindEncodings(MCAsmBackend &MAB);
/// @name Assembly File Formatting.
/// @{

View File

@ -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);
}
};

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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());
}

View File

@ -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

View File

@ -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()) {

View File

@ -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,

View File

@ -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);

View File

@ -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,

View File

@ -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);

View File

@ -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,

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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));