Changeset View
Standalone View
llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
Show All 13 Lines | |||||
#include "llvm/MC/MCAsmBackend.h" | #include "llvm/MC/MCAsmBackend.h" | ||||
#include "llvm/MC/MCAssembler.h" | #include "llvm/MC/MCAssembler.h" | ||||
#include "llvm/MC/MCContext.h" | #include "llvm/MC/MCContext.h" | ||||
#include "llvm/MC/MCDwarf.h" | #include "llvm/MC/MCDwarf.h" | ||||
#include "llvm/MC/MCELFObjectWriter.h" | #include "llvm/MC/MCELFObjectWriter.h" | ||||
#include "llvm/MC/MCExpr.h" | #include "llvm/MC/MCExpr.h" | ||||
#include "llvm/MC/MCFixupKindInfo.h" | #include "llvm/MC/MCFixupKindInfo.h" | ||||
#include "llvm/MC/MCInst.h" | #include "llvm/MC/MCInst.h" | ||||
#include "llvm/MC/MCInstrInfo.h" | |||||
#include "llvm/MC/MCMachObjectWriter.h" | #include "llvm/MC/MCMachObjectWriter.h" | ||||
#include "llvm/MC/MCObjectStreamer.h" | |||||
#include "llvm/MC/MCObjectWriter.h" | #include "llvm/MC/MCObjectWriter.h" | ||||
#include "llvm/MC/MCRegisterInfo.h" | #include "llvm/MC/MCRegisterInfo.h" | ||||
#include "llvm/MC/MCSectionMachO.h" | #include "llvm/MC/MCSectionMachO.h" | ||||
#include "llvm/MC/MCSubtargetInfo.h" | #include "llvm/MC/MCSubtargetInfo.h" | ||||
#include "llvm/MC/MCValue.h" | #include "llvm/MC/MCValue.h" | ||||
#include "llvm/Support/CommandLine.h" | |||||
#include "llvm/Support/ErrorHandling.h" | #include "llvm/Support/ErrorHandling.h" | ||||
#include "llvm/Support/raw_ostream.h" | #include "llvm/Support/raw_ostream.h" | ||||
#include "llvm/Support/TargetRegistry.h" | |||||
using namespace llvm; | using namespace llvm; | ||||
static unsigned getFixupKindSize(unsigned Kind) { | static unsigned getFixupKindSize(unsigned Kind) { | ||||
switch (Kind) { | switch (Kind) { | ||||
default: | default: | ||||
llvm_unreachable("invalid fixup kind!"); | llvm_unreachable("invalid fixup kind!"); | ||||
case FK_NONE: | case FK_NONE: | ||||
return 0; | return 0; | ||||
Show All 21 Lines | static unsigned getFixupKindSize(unsigned Kind) { | ||||
case FK_SecRel_8: | case FK_SecRel_8: | ||||
case FK_Data_8: | case FK_Data_8: | ||||
case X86::reloc_global_offset_table8: | case X86::reloc_global_offset_table8: | ||||
return 8; | return 8; | ||||
} | } | ||||
} | } | ||||
namespace { | namespace { | ||||
class X86AlignBranchKind { | |||||
private: | |||||
uint8_t AlignBranchKind = 0; | |||||
public: | |||||
enum Flag : uint8_t { | |||||
AlignBranchNone = 0, | |||||
AlignBranchFused = 1U << 0, | |||||
AlignBranchJcc = 1U << 1, | |||||
AlignBranchJmp = 1U << 2, | |||||
AlignBranchCall = 1U << 3, | |||||
AlignBranchRet = 1U << 4, | |||||
AlignBranchIndirect = 1U << 5 | |||||
}; | |||||
void operator=(const std::string &Val) { | |||||
if (Val.empty()) | |||||
return; | |||||
SmallVector<StringRef, 6> BranchTypes; | |||||
StringRef(Val).split(BranchTypes, '+', -1, false); | |||||
chandlerc: I feel like a comma-separated list would be a bit more clear... | |||||
We can't use comma-separated list because we need pass the option with flto. "-Wl,-plugin-opt=--x86-align-branch-boundary=32,--plugin-opt=-x86-align-branch=fused,jcc,jmp,--plugin-opt=-x86-align-branch-prefix-size=5" would cause a compile fail because "jcc" was recognized as another option rather than a part of option "-x86-align-branch=fused,jcc,jmp" skan: We can't use comma-separated list because we need pass the option with flto. "-Wl,-plugin-opt=… | |||||
Not Done ReplyInline ActionsIsn't there some way to nest quotes into the part of after -plugin-opt= ? craig.topper: Isn't there some way to nest quotes into the part of after -plugin-opt= ? | |||||
I tried to use --plugin-opt=-x86-align-branch="fused,jcc,jmp", it didn't work. skan: I tried to use --plugin-opt=-x86-align-branch="fused,jcc,jmp", it didn't work. | |||||
Not Done ReplyInline ActionsWhat if you put —plugin-opt=“-x86-align-branch=fused,jcc,jmp” craig.topper: What if you put —plugin-opt=“-x86-align-branch=fused,jcc,jmp” | |||||
It doesn't work too. skan: It doesn't work too. | |||||
Not Done ReplyInline ActionsBoth gcc and clang just split the -Wl argument by comma. There is no escape character. For reference, https://sourceware.org/ml/binutils/2019-11/msg00173.html is the GNU as patch on the binutils side. Have you considered + plus? I think it may be more intuitive. MaskRay: Both gcc and clang just split the -Wl argument by comma. There is no escape character. For… | |||||
Yes, I agree with you. Done skan: Yes, I agree with you. Done | |||||
for (auto BranchType : BranchTypes) { | |||||
if (BranchType == "fused") | |||||
addKind(AlignBranchFused); | |||||
else if (BranchType == "jcc") | |||||
addKind(AlignBranchJcc); | |||||
else if (BranchType == "jmp") | |||||
addKind(AlignBranchJmp); | |||||
else if (BranchType == "call") | |||||
addKind(AlignBranchCall); | |||||
else if (BranchType == "ret") | |||||
addKind(AlignBranchRet); | |||||
else if (BranchType == "indirect") | |||||
addKind(AlignBranchIndirect); | |||||
Not Done ReplyInline ActionsAn unknown value is just ignored, e.g. --x86-align-branch=unknown. I think there should be an error, but I haven't looked into the patch detail to confidently suggest how we should surface this error. MaskRay: An unknown value is just ignored, e.g. `--x86-align-branch=unknown`. I think there should be an… | |||||
else { | |||||
report_fatal_error( | |||||
"'-x86-align-branch 'The branches's type is combination of jcc, " | |||||
"fused, jmp, call, ret, indirect.(plus separated)", | |||||
false); | |||||
} | |||||
} | |||||
} | |||||
operator uint8_t() const { return AlignBranchKind; } | |||||
void addKind(Flag Value) { AlignBranchKind |= Value; } | |||||
}; | |||||
X86AlignBranchKind X86AlignBranchKindLoc; | |||||
cl::opt<uint64_t> X86AlignBranchBoundary( | |||||
"x86-align-branch-boundary", cl::init(0), | |||||
cl::desc( | |||||
"Control how the assembler should align branches with NOP. If the " | |||||
"boundary's size is not 0, it should be a power of 2 and no less " | |||||
"than 32. Branches will be aligned within the boundary of specified " | |||||
"size. -x86-align-branch-boundary=0 doesn't align branches.")); | |||||
cl::opt<X86AlignBranchKind, true, cl::parser<std::string>> X86AlignBranch( | |||||
"x86-align-branch", | |||||
cl::desc("Specify types of branches to align (plus separated list of " | |||||
"types). The branches's type is combination of jcc, fused, " | |||||
"jmp, call, ret, indirect."), | |||||
cl::value_desc("jcc(conditional jump), fused(fused conditional jump), " | |||||
"jmp(unconditional jump); call(call); ret(ret), " | |||||
"indirect(indirect jump)."), | |||||
cl::location(X86AlignBranchKindLoc)); | |||||
class X86ELFObjectWriter : public MCELFObjectTargetWriter { | class X86ELFObjectWriter : public MCELFObjectTargetWriter { | ||||
public: | public: | ||||
X86ELFObjectWriter(bool is64Bit, uint8_t OSABI, uint16_t EMachine, | X86ELFObjectWriter(bool is64Bit, uint8_t OSABI, uint16_t EMachine, | ||||
bool HasRelocationAddend, bool foobar) | bool HasRelocationAddend, bool foobar) | ||||
: MCELFObjectTargetWriter(is64Bit, OSABI, EMachine, HasRelocationAddend) {} | : MCELFObjectTargetWriter(is64Bit, OSABI, EMachine, HasRelocationAddend) {} | ||||
}; | }; | ||||
class X86AsmBackend : public MCAsmBackend { | class X86AsmBackend : public MCAsmBackend { | ||||
const MCSubtargetInfo &STI; | const MCSubtargetInfo &STI; | ||||
const MCInstrInfo &MCII; | |||||
X86AlignBranchKind AlignBranchType; | |||||
Align AlignBoundary; | |||||
bool isFirstMacroFusibleInst(const MCInst &Inst) const; | |||||
bool isMacroFused(const MCInst &Cmp, const MCInst &Jcc) const; | |||||
bool isRIPRelative(const MCInst &MI) const; | |||||
bool hasVariantSymbol(const MCInst &MI) const; | |||||
bool needAlign(MCObjectStreamer &OS) const; | |||||
bool needAlignInst(const MCInst &Inst) const; | |||||
MCBoundaryAlignFragment * | |||||
getOrCreateBoundaryAlignFragment(MCObjectStreamer &OS) const; | |||||
MCInst PrevInst; | |||||
public: | public: | ||||
X86AsmBackend(const Target &T, const MCSubtargetInfo &STI) | X86AsmBackend(const Target &T, const MCSubtargetInfo &STI) | ||||
: MCAsmBackend(support::little), STI(STI) {} | : MCAsmBackend(support::little), STI(STI), | ||||
MCII(*(T.createMCInstrInfo())) { | |||||
AlignBoundary = assumeAligned(X86AlignBranchBoundary); | |||||
Not Done ReplyInline ActionsWe can generalize these functions with a function that takes a parameter. MaskRay: We can generalize these functions with a function that takes a parameter. | |||||
We already have a generalized function bool needAlign(const MCInst &Inst) const. needAlignJcc() is only a helper function that makes code more readable. skan: We already have a generalized function `bool needAlign(const MCInst &Inst) const`. | |||||
AlignBranchType = X86AlignBranchKindLoc; | |||||
} | |||||
void alignBranchesBegin(MCObjectStreamer &OS, const MCInst &Inst) override; | |||||
void alignBranchesEnd(MCObjectStreamer &OS, const MCInst &Inst) override; | |||||
Not Done ReplyInline Actions
Should --x86-branches-within-32B-boundaries overwrite --x86-align-branch-boundary and --x86-align-branch and --x86-align-branch-prefix-size? My feeling is that it just provides a default value if either of the three options is not specified. If you are going to remove addKind calls here, you can delete this member function. MaskRay: > } else {
Should --x86-branches-within-32B-boundaries overwrite --x86-align-branch-boundary… | |||||
unsigned getNumFixupKinds() const override { | unsigned getNumFixupKinds() const override { | ||||
return X86::NumTargetFixupKinds; | return X86::NumTargetFixupKinds; | ||||
} | } | ||||
Optional<MCFixupKind> getFixupKind(StringRef Name) const override; | Optional<MCFixupKind> getFixupKind(StringRef Name) const override; | ||||
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override { | const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override { | ||||
const static MCFixupKindInfo Infos[X86::NumTargetFixupKinds] = { | const static MCFixupKindInfo Infos[X86::NumTargetFixupKinds] = { | ||||
{"reloc_riprel_4byte", 0, 32, MCFixupKindInfo::FKF_IsPCRel}, | {"reloc_riprel_4byte", 0, 32, MCFixupKindInfo::FKF_IsPCRel}, | ||||
{"reloc_riprel_4byte_movq_load", 0, 32, MCFixupKindInfo::FKF_IsPCRel}, | {"reloc_riprel_4byte_movq_load", 0, 32, MCFixupKindInfo::FKF_IsPCRel}, | ||||
{"reloc_riprel_4byte_relax", 0, 32, MCFixupKindInfo::FKF_IsPCRel}, | {"reloc_riprel_4byte_relax", 0, 32, MCFixupKindInfo::FKF_IsPCRel}, | ||||
Not Done ReplyInline Actionsspace after if No curly braces around simple statements. MaskRay: space after if
No curly braces around simple statements. | |||||
{"reloc_riprel_4byte_relax_rex", 0, 32, MCFixupKindInfo::FKF_IsPCRel}, | {"reloc_riprel_4byte_relax_rex", 0, 32, MCFixupKindInfo::FKF_IsPCRel}, | ||||
{"reloc_signed_4byte", 0, 32, 0}, | {"reloc_signed_4byte", 0, 32, 0}, | ||||
{"reloc_signed_4byte_relax", 0, 32, 0}, | {"reloc_signed_4byte_relax", 0, 32, 0}, | ||||
{"reloc_global_offset_table", 0, 32, 0}, | {"reloc_global_offset_table", 0, 32, 0}, | ||||
{"reloc_global_offset_table8", 0, 64, 0}, | {"reloc_global_offset_table8", 0, 64, 0}, | ||||
{"reloc_branch_4byte_pcrel", 0, 32, MCFixupKindInfo::FKF_IsPCRel}, | {"reloc_branch_4byte_pcrel", 0, 32, MCFixupKindInfo::FKF_IsPCRel}, | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 153 Lines • ▼ Show 20 Lines | |||||
static unsigned getRelaxedOpcode(const MCInst &Inst, bool is16BitMode) { | static unsigned getRelaxedOpcode(const MCInst &Inst, bool is16BitMode) { | ||||
unsigned R = getRelaxedOpcodeArith(Inst); | unsigned R = getRelaxedOpcodeArith(Inst); | ||||
if (R != Inst.getOpcode()) | if (R != Inst.getOpcode()) | ||||
return R; | return R; | ||||
return getRelaxedOpcodeBranch(Inst, is16BitMode); | return getRelaxedOpcodeBranch(Inst, is16BitMode); | ||||
} | } | ||||
static X86::CondCode getCondFromBranch(const MCInst &MI, | |||||
const MCInstrInfo &MCII) { | |||||
unsigned Opcode = MI.getOpcode(); | |||||
switch (Opcode) { | |||||
default: | |||||
return X86::COND_INVALID; | |||||
case X86::JCC_1: { | |||||
const MCInstrDesc &Desc = MCII.get(Opcode); | |||||
return static_cast<X86::CondCode>( | |||||
MI.getOperand(Desc.getNumOperands() - 1).getImm()); | |||||
} | |||||
} | |||||
} | |||||
static X86::SecondMacroFusionInstKind | |||||
classifySecondInstInMacroFusion(const MCInst &MI, const MCInstrInfo &MCII) { | |||||
X86::CondCode CC = getCondFromBranch(MI, MCII); | |||||
return classifySecondCondCodeInMacroFusion(CC); | |||||
} | |||||
/// Check if the instruction is valid as the first instruction in macro fusion. | |||||
bool X86AsmBackend::isFirstMacroFusibleInst(const MCInst &Inst) const { | |||||
// An Intel instruction with RIP relative addressing is not macro fusible. | |||||
if (isRIPRelative(Inst)) | |||||
return false; | |||||
X86::FirstMacroFusionInstKind FIK = | |||||
X86::classifyFirstOpcodeInMacroFusion(Inst.getOpcode()); | |||||
return FIK != X86::FirstMacroFusionInstKind::Invalid; | |||||
} | |||||
/// Check if the two instructions are macro-fused. | |||||
bool X86AsmBackend::isMacroFused(const MCInst &Cmp, const MCInst &Jcc) const { | |||||
const MCInstrDesc &InstDesc = MCII.get(Jcc.getOpcode()); | |||||
if (!InstDesc.isConditionalBranch()) | |||||
Not Done ReplyInline ActionsCheck 64bit, then use exact comparison with either ___tls_get_addr or __tls_get_addr MaskRay: Check 64bit, then use exact comparison with either `___tls_get_addr` or `__tls_get_addr` | |||||
Why? There exists TLS Call in 32bit mode. Does SymbolName.contains("__tls_get_addr") possibly include more calls rather TLS Call? skan: Why? There exists TLS Call in 32bit mode. Does `SymbolName.contains("__tls_get_addr")`… | |||||
return false; | |||||
if (!isFirstMacroFusibleInst(Cmp)) | |||||
return false; | |||||
const X86::FirstMacroFusionInstKind CmpKind = | |||||
X86::classifyFirstOpcodeInMacroFusion(Cmp.getOpcode()); | |||||
const X86::SecondMacroFusionInstKind BranchKind = | |||||
classifySecondInstInMacroFusion(Jcc, MCII); | |||||
This set of functions down to isIndirectBranch() seems unnecessary. Pushing one line const MCInstrDesc &InstDesc = MCII.get(Inst.getOpcode()); into needAlign(const MCInst &Inst), and then just using InstDesc.isReturn() etc. would be fine. jyknight: This set of functions down to isIndirectBranch() seems unnecessary. Pushing one line
const… | |||||
return X86::isMacroFused(CmpKind, BranchKind); | |||||
} | |||||
/// Check if the instruction is RIP relative addressing. | |||||
bool X86AsmBackend::isRIPRelative(const MCInst &MI) const { | |||||
unsigned Opcode = MI.getOpcode(); | |||||
const MCInstrDesc &Desc = MCII.get(Opcode); | |||||
uint64_t TSFlags = Desc.TSFlags; | |||||
unsigned CurOp = X86II::getOperandBias(Desc); | |||||
int MemoryOperand = X86II::getMemoryOperandNo(TSFlags); | |||||
if (MemoryOperand >= 0) { | |||||
unsigned BaseRegNum = MemoryOperand + CurOp + X86::AddrBaseReg; | |||||
unsigned BaseReg = MI.getOperand(BaseRegNum).getReg(); | |||||
if (BaseReg == X86::RIP) | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
/// Check if the instruction has variant symbol operand. | |||||
bool X86AsmBackend::hasVariantSymbol(const MCInst &MI) const { | |||||
for (auto &Operand : MI) { | |||||
if (Operand.isExpr()) { | |||||
const MCExpr &Expr = *Operand.getExpr(); | |||||
if (Expr.getKind() == MCExpr::SymbolRef && | |||||
cast<MCSymbolRefExpr>(*Operand.getExpr()).getKind() != | |||||
MCSymbolRefExpr::VK_None) | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
bool X86AsmBackend::needAlign(MCObjectStreamer &OS) const { | |||||
if (AlignBoundary == Align::None() || | |||||
AlignBranchType == X86AlignBranchKind::AlignBranchNone) | |||||
return false; | |||||
MCAssembler &Assembler = OS.getAssembler(); | |||||
MCSection *Sec = OS.getCurrentSectionOnly(); | |||||
// To be Done: Currently don't deal with Bundle cases. | |||||
if (Assembler.isBundlingEnabled() && Sec->isBundleLocked()) | |||||
return false; | |||||
please run something like "git clang-format HEAD~1" to re-format your patch. jyknight: please run something like "git clang-format HEAD~1" to re-format your patch. | |||||
// Branches only need to be aligned in 32-bit or 64-bit mode. | |||||
if (!(STI.getFeatureBits()[X86::Mode64Bit] || | |||||
STI.getFeatureBits()[X86::Mode32Bit])) | |||||
return false; | |||||
Comment on why this is doing what it's doing? jyknight: Comment on why this is doing what it's doing? | |||||
return true; | |||||
} | |||||
/// Check if the instruction operand needs to be aligned. Padding is disabled | |||||
/// before intruction which may be rewritten by linker(e.g. TLSCALL). | |||||
bool X86AsmBackend::needAlignInst(const MCInst &Inst) const { | |||||
// Linker may rewrite the instruction with variant symbol operand. | |||||
if (hasVariantSymbol(Inst)) | |||||
return false; | |||||
const MCInstrDesc &InstDesc = MCII.get(Inst.getOpcode()); | |||||
return (InstDesc.isConditionalBranch() && | |||||
(AlignBranchType & X86AlignBranchKind::AlignBranchJcc)) || | |||||
(InstDesc.isUnconditionalBranch() && | |||||
(AlignBranchType & X86AlignBranchKind::AlignBranchJmp)) || | |||||
(InstDesc.isCall() && | |||||
(AlignBranchType & X86AlignBranchKind::AlignBranchCall)) || | |||||
(InstDesc.isReturn() && | |||||
(AlignBranchType & X86AlignBranchKind::AlignBranchRet)) || | |||||
(InstDesc.isIndirectBranch() && | |||||
(AlignBranchType & X86AlignBranchKind::AlignBranchIndirect)); | |||||
} | |||||
static bool canReuseBoundaryAlignFragment(const MCBoundaryAlignFragment &F) { | |||||
// If a MCBoundaryAlignFragment has not been used to emit NOP,we can reuse it. | |||||
return !F.canEmitNops(); | |||||
} | |||||
MCBoundaryAlignFragment * | |||||
X86AsmBackend::getOrCreateBoundaryAlignFragment(MCObjectStreamer &OS) const { | |||||
auto *F = dyn_cast_or_null<MCBoundaryAlignFragment>(OS.getCurrentFragment()); | |||||
if (!F || !canReuseBoundaryAlignFragment(*F)) { | |||||
F = new MCBoundaryAlignFragment(AlignBoundary); | |||||
OS.insert(F); | |||||
} | |||||
return F; | |||||
} | |||||
/// Insert MCBoundaryAlignFragment before instructions to align branches. | |||||
void X86AsmBackend::alignBranchesBegin(MCObjectStreamer &OS, | |||||
const MCInst &Inst) { | |||||
if (!needAlign(OS)) | |||||
return; | |||||
MCFragment *CF = OS.getCurrentFragment(); | |||||
bool NeedAlignFused = AlignBranchType & X86AlignBranchKind::AlignBranchFused; | |||||
if (NeedAlignFused && isMacroFused(PrevInst, Inst) && CF) { | |||||
// Macro fusion actually happens and there is no other fragment inserted | |||||
// after the previous instruction. NOP can be emitted in PF to align fused | |||||
// jcc. | |||||
if (auto *PF = | |||||
dyn_cast_or_null<MCBoundaryAlignFragment>(CF->getPrevNode())) { | |||||
const_cast<MCBoundaryAlignFragment *>(PF)->setEmitNops(true); | |||||
const_cast<MCBoundaryAlignFragment *>(PF)->setFused(true); | |||||
} | |||||
} else if (needAlignInst(Inst)) { | |||||
// Note: When there is at least one fragment, such as MCAlignFragment, | |||||
// inserted after the previous instruction, e.g. | |||||
// | |||||
// \code | |||||
// cmp %rax %rcx | |||||
// .align 16 | |||||
// je .Label0 | |||||
// \ endcode | |||||
Confusing name, and doesn't need to be a separate function than needAlign(const MCAssembler &, MCSection *). Just merge it into that. jyknight: Confusing name, and doesn't need to be a separate function than needAlign(const MCAssembler &… | |||||
// | |||||
// We will treat the JCC as a unfused branch although it may be fused | |||||
// with the CMP. | |||||
auto *F = getOrCreateBoundaryAlignFragment(OS); | |||||
Space after if MaskRay: Space after `if` | |||||
F->setEmitNops(true); | |||||
These functions are only used in one place, and it doesn't make it more readable to split them off. Just merge them into needAlign(const MCInst &Inst) or alignBranchesBegin as appropriate. But also -- AlignBoundarySize shouldn't even need to be checked here, since it's already be checked in needAlign(const MCAssembler &, MCSection *), which is always called first. jyknight: These functions are only used in one place, and it doesn't make it more readable to split them… | |||||
F->setFused(false); | |||||
} else if (NeedAlignFused && isFirstMacroFusibleInst(Inst)) { | |||||
// We don't know if macro fusion happens until the reaching the next | |||||
// instruction, so a place holder is put here if necessary. | |||||
getOrCreateBoundaryAlignFragment(OS); | |||||
} | |||||
PrevInst = Inst; | |||||
} | |||||
/// Insert a MCBoundaryAlignFragment to mark the end of the branch to be aligned | |||||
/// if necessary. | |||||
void X86AsmBackend::alignBranchesEnd(MCObjectStreamer &OS, const MCInst &Inst) { | |||||
if (!needAlign(OS)) | |||||
return; | |||||
// If the branch is emitted into a MCRelaxableFragment, we can determine the | |||||
// size of the branch easily in MCAssembler::relaxBoundaryAlign. When the | |||||
// branch is fused, the fused branch(macro fusion pair) must be emitted into | |||||
// two fragments. Or when the branch is unfused, the branch must be emitted | |||||
// into one fragment. The MCRelaxableFragment naturally marks the end of the | |||||
// fused or unfused branch. | |||||
// Otherwise, we need to insert a MCBoundaryAlignFragment to mark the end of | |||||
// the branch. This MCBoundaryAlignFragment may be reused to emit NOP to align | |||||
// other branch. | |||||
if (needAlignInst(Inst) && !isa<MCRelaxableFragment>(OS.getCurrentFragment())) | |||||
OS.insert(new MCBoundaryAlignFragment(AlignBoundary)); | |||||
// Update the maximum alignment on the current section if necessary. | |||||
MCSection *Sec = OS.getCurrentSectionOnly(); | |||||
if (AlignBoundary.value() > Sec->getAlignment()) | |||||
Doesn't need to have the same name as the next needAlign, clearer if these two overloads are given different names. jyknight: Doesn't need to have the same name as the next needAlign, clearer if these two overloads are… | |||||
Sec->setAlignment(AlignBoundary); | |||||
} | |||||
Optional<MCFixupKind> X86AsmBackend::getFixupKind(StringRef Name) const { | Optional<MCFixupKind> X86AsmBackend::getFixupKind(StringRef Name) const { | ||||
if (STI.getTargetTriple().isOSBinFormatELF()) { | if (STI.getTargetTriple().isOSBinFormatELF()) { | ||||
if (STI.getTargetTriple().getArch() == Triple::x86_64) { | if (STI.getTargetTriple().getArch() == Triple::x86_64) { | ||||
if (Name == "R_X86_64_NONE") | if (Name == "R_X86_64_NONE") | ||||
return FK_NONE; | return FK_NONE; | ||||
} else { | } else { | ||||
if (Name == "R_386_NONE") | if (Name == "R_386_NONE") | ||||
return FK_NONE; | return FK_NONE; | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | void X86AsmBackend::relaxInstruction(const MCInst &Inst, | ||||
} | } | ||||
Res = Inst; | Res = Inst; | ||||
Res.setOpcode(RelaxedOp); | Res.setOpcode(RelaxedOp); | ||||
} | } | ||||
/// Write a sequence of optimal nops to the output, covering \p Count | /// Write a sequence of optimal nops to the output, covering \p Count | ||||
/// bytes. | /// bytes. | ||||
/// \return - true on success, false on failure | /// \return - true on success, false on failure | ||||
bool X86AsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const { | bool X86AsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const { | ||||
Why? jyknight: Why? | |||||
static const char Nops[10][11] = { | static const char Nops[10][11] = { | ||||
// nop | // nop | ||||
"\x90", | "\x90", | ||||
// xchg %ax,%ax | // xchg %ax,%ax | ||||
"\x66\x90", | "\x66\x90", | ||||
// nopl (%[re]ax) | // nopl (%[re]ax) | ||||
"\x0f\x1f\x00", | "\x0f\x1f\x00", | ||||
// nopl 0(%[re]ax) | // nopl 0(%[re]ax) | ||||
"\x0f\x1f\x40\x00", | "\x0f\x1f\x40\x00", | ||||
Not Done ReplyInline Actionsisa<MCMachineDependentFragment>(F) MaskRay: `isa<MCMachineDependentFragment>(F)`
| |||||
// nopl 0(%[re]ax,%[re]ax,1) | // nopl 0(%[re]ax,%[re]ax,1) | ||||
"\x0f\x1f\x44\x00\x00", | "\x0f\x1f\x44\x00\x00", | ||||
// nopw 0(%[re]ax,%[re]ax,1) | // nopw 0(%[re]ax,%[re]ax,1) | ||||
"\x66\x0f\x1f\x44\x00\x00", | "\x66\x0f\x1f\x44\x00\x00", | ||||
// nopl 0L(%[re]ax) | // nopl 0L(%[re]ax) | ||||
"\x0f\x1f\x80\x00\x00\x00\x00", | "\x0f\x1f\x80\x00\x00\x00\x00", | ||||
// nopl 0L(%[re]ax,%[re]ax,1) | // nopl 0L(%[re]ax,%[re]ax,1) | ||||
"\x0f\x1f\x84\x00\x00\x00\x00\x00", | "\x0f\x1f\x84\x00\x00\x00\x00\x00", | ||||
▲ Show 20 Lines • Show All 545 Lines • Show Last 20 Lines |
I feel like a comma-separated list would be a bit more clear...