diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h index cf37a984da93f..cc6f377f51741 100644 --- a/bolt/include/bolt/Core/MCPlusBuilder.h +++ b/bolt/include/bolt/Core/MCPlusBuilder.h @@ -1086,7 +1086,7 @@ class MCPlusBuilder { return false; } - /// Use \p Input1 or Input2 as the current value for the input + /// Use \p Input1 or \p Input2 as the current value for the input /// register and put in \p Output the changes incurred by executing /// \p Inst. Return false if it was not possible to perform the /// evaluation. evaluateStackOffsetExpr is restricted to operations diff --git a/bolt/lib/Utils/CommandLineOpts.cpp b/bolt/lib/Utils/CommandLineOpts.cpp index ad714371436e0..e27606078b633 100644 --- a/bolt/lib/Utils/CommandLineOpts.cpp +++ b/bolt/lib/Utils/CommandLineOpts.cpp @@ -146,7 +146,7 @@ cl::opt Lite("lite", cl::desc("skip processing of cold functions"), cl::cat(BoltCategory)); cl::opt -OutputFilename("o", +OutputFilename("ooo", cl::desc(""), cl::Optional, cl::cat(BoltOutputCategory)); diff --git a/llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s b/llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s new file mode 100644 index 0000000000000..eb55ff6b378e8 --- /dev/null +++ b/llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s @@ -0,0 +1,33 @@ +# RUN: not llvm-mc %s --validate-cfi --filetype=null 2>&1 \ +# RUN: | FileCheck %s + .text + .globl f + .type f,@function +f: + .cfi_startproc + + .cfi_undefined %rax + + pushq %rbp + # CHECK: error: Expected CFA [reg: 61, offset: 16] but got [reg: 61, offset: 17] + .cfi_def_cfa_offset 17 + .cfi_offset %rbp, -16 + + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + + movl %edi, -4(%rbp) + + movl -4(%rbp), %eax + + addl $10, %eax + + popq %rbp + .cfi_def_cfa %rsp, 8 + + retq + +.Lfunc_end0: + .size f, .Lfunc_end0-f + + .cfi_endproc diff --git a/llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s b/llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s new file mode 100644 index 0000000000000..044c0bbf88eb6 --- /dev/null +++ b/llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s @@ -0,0 +1,32 @@ +# RUN: not llvm-mc %s --validate-cfi --filetype=null 2>&1 \ +# RUN: | FileCheck %s + .text + .globl f + .type f,@function +f: + .cfi_startproc + + .cfi_undefined %rax + + pushq %rbp + .cfi_def_cfa_offset 16 + + movq %rsp, %rbp + # CHECK: error: Reg#52 caller's value is in reg#52 which is changed by this instruction, but not changed in CFI directives + .cfi_def_cfa_register %rbp + + movl %edi, -4(%rbp) + + movl -4(%rbp), %eax + + addl $10, %eax + + popq %rbp + .cfi_def_cfa %rsp, 8 + + retq + +.Lfunc_end0: + .size f, .Lfunc_end0-f + + .cfi_endproc diff --git a/llvm/test/tools/llvm-mc/cfi-validation/single-func.s b/llvm/test/tools/llvm-mc/cfi-validation/single-func.s new file mode 100644 index 0000000000000..b2615eafce1d5 --- /dev/null +++ b/llvm/test/tools/llvm-mc/cfi-validation/single-func.s @@ -0,0 +1,31 @@ +# RUN: llvm-mc %s --validate-cfi --filetype=null + .text + .globl f + .type f,@function +f: + .cfi_startproc + + .cfi_undefined %rax + + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + + movl %edi, -4(%rbp) + + movl -4(%rbp), %eax + + addl $10, %eax + + popq %rbp + .cfi_def_cfa %rsp, 8 + + retq + +.Lfunc_end0: + .size f, .Lfunc_end0-f + + .cfi_endproc diff --git a/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s b/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s new file mode 100644 index 0000000000000..d7baf3e871e87 --- /dev/null +++ b/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s @@ -0,0 +1,47 @@ +# RUN: not llvm-mc %s --validate-cfi --filetype=null 2>&1 \ +# RUN: | FileCheck %s + .text + .type _start,@function + .globl _start + .hidden _start +_start: + .cfi_startproc + + .cfi_same_value %rdi + .cfi_same_value %rsi + + pushq %rbp + .cfi_adjust_cfa_offset 8 + .cfi_offset %rbp, -16 + + movq %rsp, %rbp + + pushq %rdi + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset %rdi, 0 + + pushq %rsi + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset %rsi, 0 + + popq %rsi + # CHECK: warning: The reg#55 CFI state is changed + .cfi_adjust_cfa_offset -8 + .cfi_same_value %rdi + + popq %rdi + # CHECK: warning: The reg#60 CFI state is changed + # CHECK: Reg#55 caller's value is in reg#55 which is changed by this instruction, but not changed in CFI directives + .cfi_adjust_cfa_offset -8 + .cfi_same_value %rsi + + popq %rbp + .cfi_adjust_cfa_offset -8 + .cfi_same_value %rbp + + retq + + .cfi_endproc +.Ltmp0: + .size _start, .Ltmp0-_start + .text diff --git a/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg.s b/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg.s new file mode 100644 index 0000000000000..70ea3b49d8c75 --- /dev/null +++ b/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg.s @@ -0,0 +1,43 @@ +# RUN: llvm-mc %s --validate-cfi --filetype=null + .text + .type _start,@function + .globl _start + .hidden _start +_start: + .cfi_startproc + + .cfi_same_value %rdi + .cfi_same_value %rsi + + pushq %rbp + .cfi_adjust_cfa_offset 8 + .cfi_offset %rbp, -16 + + movq %rsp, %rbp + + pushq %rdi + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset %rdi, 0 + + pushq %rsi + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset %rsi, 0 + + popq %rsi + .cfi_adjust_cfa_offset -8 + .cfi_same_value %rsi + + popq %rdi + .cfi_adjust_cfa_offset -8 + .cfi_same_value %rdi + + popq %rbp + .cfi_adjust_cfa_offset -8 + .cfi_same_value %rbp + + retq + + .cfi_endproc +.Ltmp0: + .size _start, .Ltmp0-_start + .text diff --git a/llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s b/llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s new file mode 100644 index 0000000000000..1384d8a864608 --- /dev/null +++ b/llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s @@ -0,0 +1,31 @@ +# RUN: not llvm-mc %s --validate-cfi --filetype=null 2>&1 \ +# RUN: | FileCheck %s + .text + .globl f + .type f,@function +f: + .cfi_startproc + + .cfi_same_value %rax + .cfi_same_value %rbx + .cfi_same_value %rcx + .cfi_same_value %rdx + + movq $10, %rax + # CHECK: error: Reg#51 caller's value is in reg#51 which is changed by this instruction, but not changed in CFI directives + + movq $10, %rbx + # CHECK: error: Reg#53 caller's value is in reg#53 which is changed by this instruction, but not changed in CFI directives + + movq $10, %rcx + # CHECK: error: Reg#54 caller's value is in reg#54 which is changed by this instruction, but not changed in CFI directives + + movq $10, %rdx + # CHECK: error: Reg#56 caller's value is in reg#56 which is changed by this instruction, but not changed in CFI directives + + retq + +.Lfunc_end0: + .size f, .Lfunc_end0-f + + .cfi_endproc diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h new file mode 100644 index 0000000000000..57e2b7247b45f --- /dev/null +++ b/llvm/tools/llvm-mc/CFIAnalysis.h @@ -0,0 +1,444 @@ +#ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H +#define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H + +#include "CFIState.h" +#include "ExtendedMCInstrAnalysis.h" +#include "bolt/Core/MCPlusBuilder.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDwarf.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegister.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormatVariadic.h" +#include +#include +#include +#include + +namespace llvm { + +// TODO remove it, it's just for debug purposes. +void printUntilNextLine(const char *Str) { + for (int I = 0; Str[I] != '\0' && Str[I] != '\n'; I++) + dbgs() << Str[I]; +} + +class CFIAnalysis { + MCContext &Context; + MCInstrInfo const &MCII; + MCRegisterInfo const *MCRI; + std::unique_ptr EMCIA; + CFIState State; + +private: + // The CFI analysis only keeps track and cares about super registers, not the + // subregisters. All reads to/writes from subregisters and considered the same + // operation to super registers. Other operations like loading and stores are + // considered only if they are exactly doing the operation to or from a super + // register. + // As en example, if you spill a sub register to stack, the CFI analysis does + // not consider that a register spilling. + bool isSuperReg(MCPhysReg Reg) { return MCRI->superregs(Reg).empty(); } + + std::set getAllSuperRegs() { + std::set SuperRegs; + for (auto &&RegClass : MCRI->regclasses()) { + for (unsigned I = 0; I < RegClass.getNumRegs(); I++) { + MCPhysReg Reg = RegClass.getRegister(I); + if (!isSuperReg(Reg)) + continue; + SuperRegs.insert(Reg); + } + } + + return SuperRegs; + } + + MCPhysReg getSuperReg(MCPhysReg Reg) { + if (isSuperReg(Reg)) + return Reg; + for (auto SuperReg : MCRI->superregs(Reg)) { + if (isSuperReg(SuperReg)) + return SuperReg; + } + + llvm_unreachable("Should either be a super reg, or have a super reg"); + } + +public: + CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII, + MCInstrAnalysis *MCIA, + ArrayRef PrologueCFIDirectives) + : Context(Context), MCII(MCII), MCRI(Context.getRegisterInfo()) { + EMCIA.reset(new ExtendedMCInstrAnalysis(Context, MCII, MCIA)); + + // TODO CFA offset should be the slot size, but for now I don't have any + // access to it, maybe can be read from the prologue + // TODO check what should be passed as EH? + State = CFIState(MCRI->getDwarfRegNum(EMCIA->getStackPointer(), false), 8); + for (MCPhysReg I : getAllSuperRegs()) { + DWARFRegType DwarfI = MCRI->getDwarfRegNum(I, false); + State.RegisterCFIStates[DwarfI] = RegisterCFIState::createSameValue(); + } + + // TODO these are temporay added to make things work. + // Setup the basic information: + State.RegisterCFIStates[MCRI->getDwarfRegNum(MCRI->getProgramCounter(), + false)] = + RegisterCFIState::createUndefined(); // For now, we don't care about the + // PC + State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getStackPointer(), + false)] = + RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA + + State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getFlagsReg(), false)] = + RegisterCFIState::createUndefined(); // Flags cannot be caller-saved + + // Applying the prologue after default assumptions to overwrite them. + for (auto &&PrologueCFIDirective : PrologueCFIDirectives) { + State.apply(PrologueCFIDirective); + } + } + + void update(MCInst &Inst, ArrayRef CFIDirectives) { + const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode()); + CFIState AfterState(State); + for (auto &&CFIDirective : CFIDirectives) + if (!AfterState.apply(CFIDirective)) + Context.reportWarning( + CFIDirective.getLoc(), + "I don't support this CFI directive, I assume this does nothing " + "(which will probably break other things)"); + + std::set Writes, Reads; + for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++) + Reads.insert(MCRI->getDwarfRegNum( + getSuperReg(MCInstInfo.implicit_uses()[I]), false)); + for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++) + Writes.insert(MCRI->getDwarfRegNum( + getSuperReg(MCInstInfo.implicit_defs()[I]), false)); + + for (unsigned I = 0; I < Inst.getNumOperands(); I++) { + auto &&Operand = Inst.getOperand(I); + if (Operand.isReg()) { + if (I < MCInstInfo.getNumDefs()) + Writes.insert( + MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false)); + else if (Operand.getReg()) + Reads.insert( + MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false)); + } + } + + checkCFADiff(Inst, State, AfterState, Reads, Writes); + + for (auto &&[Reg, RegState] : State.RegisterCFIStates) { + assert(AfterState.RegisterCFIStates.count(Reg) && + "Registers' state should not be deleted by CFI instruction."); + checkRegDiff(Inst, Reg, State, AfterState, RegState, + AfterState.RegisterCFIStates[Reg], Reads, Writes); + } + + State = AfterState; + } + +private: + void checkRegDiff(const MCInst &Inst, DWARFRegType Reg, + const CFIState &PrevState, const CFIState &NextState, + const RegisterCFIState &PrevRegState, + const RegisterCFIState &NextRegState, + const std::set &Reads, + const std::set &Writes) { + auto RegLLVMOpt = MCRI->getLLVMRegNum(Reg, false); + if (RegLLVMOpt == std::nullopt) { + assert(PrevRegState == NextRegState); + return; + } + MCPhysReg RegLLVM = RegLLVMOpt.value(); + + auto &&PrevRefReg = + PrevState.getReferenceRegisterForCallerValueOfRegister(Reg); + auto &&NextRefReg = + NextState.getReferenceRegisterForCallerValueOfRegister(Reg); + + std::optional PrevRefRegLLVM = + (PrevRefReg != std::nullopt + ? std::make_optional( + MCRI->getLLVMRegNum(PrevRefReg.value(), false).value()) + : std::nullopt); + std::optional NextRefRegLLVM = + (PrevRefReg != std::nullopt + ? std::make_optional( + MCRI->getLLVMRegNum(PrevRefReg.value(), false).value()) + : std::nullopt); + + MCPhysReg PrevStateCFARegLLVM = + MCRI->getLLVMRegNum(PrevState.CFARegister, false).value(); + + { // try generate + // Widen + std::vector PossibleNextRegStates; + { // storing to offset from CFA + if (PrevRegState.RetrieveApproach == RegisterCFIState::SameValue || + PrevRegState.RetrieveApproach == + RegisterCFIState::AnotherRegister) { + int64_t OffsetFromCFAReg; + if (EMCIA->doStoreFromReg(Inst, PrevRefRegLLVM.value(), + PrevStateCFARegLLVM, OffsetFromCFAReg)) { + PossibleNextRegStates.push_back( + RegisterCFIState::createOffsetFromCFAAddr(OffsetFromCFAReg - + PrevState.CFAOffset)); + } + } + } + + { // loading from an offset from CFA + if (PrevRegState.RetrieveApproach == + RegisterCFIState::OffsetFromCFAAddr) { + int64_t OffsetFromCFAReg; + MCPhysReg ToRegLLVM; + if (EMCIA->doLoadFromReg(Inst, PrevStateCFARegLLVM, OffsetFromCFAReg, + ToRegLLVM) && + OffsetFromCFAReg - PrevState.CFAOffset == + PrevRegState.Info.OffsetFromCFA) { + DWARFRegType ToReg = MCRI->getDwarfRegNum(ToRegLLVM, false); + if (ToReg == Reg) { + PossibleNextRegStates.push_back( + RegisterCFIState::createSameValue()); + } else { + PossibleNextRegStates.push_back( + RegisterCFIState::createAnotherRegister(ToReg)); + } + } + } + } + + { // moved from reg to other reg + if (PrevRegState.RetrieveApproach == RegisterCFIState::SameValue || + PrevRegState.RetrieveApproach == + RegisterCFIState::AnotherRegister) { + + int Diff; + MCPhysReg PossibleRegLLVM; + if (EMCIA->isInConstantDistanceOfEachOther( + Inst, PossibleRegLLVM, PrevRefRegLLVM.value(), Diff)) { + DWARFRegType PossibleReg = + MCRI->getDwarfRegNum(PossibleRegLLVM, false); + if (Diff == 0) { + if (PossibleReg == Reg) { + PossibleNextRegStates.push_back( + RegisterCFIState::createSameValue()); + } else { + PossibleNextRegStates.push_back( + RegisterCFIState::createAnotherRegister(PossibleReg)); + } + } + } + } + } + + { // stay the same + bool CanStayTheSame = false; + + switch (PrevRegState.RetrieveApproach) { + case RegisterCFIState::Undefined: + case RegisterCFIState::OffsetFromCFAVal: + CanStayTheSame = true; + break; + case RegisterCFIState::SameValue: + case RegisterCFIState::AnotherRegister: + CanStayTheSame = !Writes.count(PrevRefReg.value()); + break; + case RegisterCFIState::OffsetFromCFAAddr: + case RegisterCFIState::Other: + // cannot be sure + break; + } + + if (CanStayTheSame) + PossibleNextRegStates.push_back(PrevRegState); + } + + for (auto &&PossibleNextRegState : PossibleNextRegStates) { + if (PossibleNextRegState == NextRegState) { + // Everything is ok + return; + } + } + + for (auto &&PossibleNextRegState : PossibleNextRegStates) { + if (PossibleNextRegState.RetrieveApproach != + NextRegState.RetrieveApproach) + continue; + + if (PossibleNextRegState.RetrieveApproach == + RegisterCFIState::OffsetFromCFAAddr) { + Context.reportError( + Inst.getLoc(), + formatv( + "Expected caller's value of reg#{0} should be at offset {1} " + "of CFA but the CFI directives say it's in {2}", + RegLLVM, PossibleNextRegState.Info.OffsetFromCFA, + NextRegState.Info.OffsetFromCFA)); + } + } + } + // Either couldn't generate, or the programmer changed the state to + // something that couldn't be matched to any of the generated states. So + // it falls back into read/write checks. + + if (PrevRegState == NextRegState) { + switch (PrevRegState.RetrieveApproach) { + case RegisterCFIState::SameValue: + case RegisterCFIState::AnotherRegister: + if (Writes.count(PrevRefReg.value())) { + Context.reportError( + Inst.getLoc(), + formatv("Reg#{0} caller's value is in reg#{1} which is changed " + "by this instruction, but not changed in CFI directives", + RegLLVM, PrevRefRegLLVM.value())); + return; + } + break; + default: + // Everything may be ok + break; + } + return; + } + + if (PrevRegState.RetrieveApproach == NextRegState.RetrieveApproach) { + // Everything may be ok + return; + } + + if (PrevRegState.RetrieveApproach == RegisterCFIState::Undefined) { + Context.reportError(Inst.getLoc(), + "Cannot change a register CFI information from " + "undefined to something else."); + return; + } + + Context.reportWarning(Inst.getLoc(), + formatv("The reg#{0} CFI state is changed, but I " + "don't have any idea how.", + RegLLVM)); + // Everything may be ok + return; + } + + void checkCFADiff(const MCInst &Inst, const CFIState &PrevState, + const CFIState &NextState, + const std::set &Reads, + const std::set &Writes) { + MCPhysReg PrevCFAPhysReg = + MCRI->getLLVMRegNum(PrevState.CFARegister, false).value(); + MCPhysReg NextCFAPhysReg = + MCRI->getLLVMRegNum(NextState.CFARegister, false).value(); + + { // try generate + // Widen + std::vector> PossibleNextCFAStates; + { // no change + if (!Writes.count(PrevState.CFARegister)) { + PossibleNextCFAStates.emplace_back(PrevState.CFARegister, + PrevState.CFAOffset); + } + } + + { // const change + int64_t HowMuch; + if (EMCIA->doesConstantChange(Inst, PrevCFAPhysReg, HowMuch)) { + PossibleNextCFAStates.emplace_back(PrevState.CFARegister, + PrevState.CFAOffset - HowMuch); + } + } + + { // constant distance with each other + int Diff; + MCPhysReg PossibleNewCFAReg; + if (EMCIA->isInConstantDistanceOfEachOther(Inst, PossibleNewCFAReg, + PrevCFAPhysReg, Diff)) { + PossibleNextCFAStates.emplace_back( + MCRI->getDwarfRegNum(PossibleNewCFAReg, false), + PrevState.CFAOffset - Diff); + } + } + + for (auto &&[PossibleNextCFAReg, PossibleNextCFAOffset] : + PossibleNextCFAStates) { + if (PossibleNextCFAReg != NextState.CFARegister) + continue; + + if (PossibleNextCFAOffset == NextState.CFAOffset) { + // Everything is ok! + return; + } + + Context.reportError(Inst.getLoc(), + formatv("Expected CFA [reg: {0}, offset: {1}] but " + "got [reg: {2}, offset: {3}].", + NextCFAPhysReg, PossibleNextCFAOffset, + NextCFAPhysReg, NextState.CFAOffset)); + return; + } + } + + // Either couldn't generate, or did, but the programmer wants to change + // the source of register for CFA to something not expected by the + // generator. So it falls back into read/write checks. + + if (PrevState.CFARegister == NextState.CFARegister) { + if (PrevState.CFAOffset == NextState.CFAOffset) { + if (Writes.count(PrevState.CFARegister)) { + Context.reportError( + Inst.getLoc(), + formatv("This instruction changes reg#{0}, which is " + "the CFA register, but the CFI directives do not.", + PrevCFAPhysReg)); + return; + } + + // Everything is ok! + return; + } + // The offset is changed. + + if (!Writes.count(PrevState.CFARegister)) { + Context.reportError( + Inst.getLoc(), + formatv( + "You changed the CFA offset, but there is no modification to " + "the CFA register happening in this instruction.")); + } + + Context.reportWarning( + Inst.getLoc(), + "I don't know what the instruction did, but it changed the CFA " + "reg's " + "value, and the offset is changed as well by the CFI directives."); + // Everything may be ok! + return; + } + // The CFA register is changed + Context.reportWarning( + Inst.getLoc(), "The CFA register is changed to something, and I don't " + "have any idea on the new register relevance to CFA. I " + "assume CFA is preserved."); + // Everything may be ok! + } +}; + +} // namespace llvm +#endif \ No newline at end of file diff --git a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h new file mode 100644 index 0000000000000..7f79653004e5e --- /dev/null +++ b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h @@ -0,0 +1,149 @@ +#ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_MC_STREAMER_H +#define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_MC_STREAMER_H + +#include "CFIAnalysis.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDwarf.h" +#include "llvm/MC/MCInstrAnalysis.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCStreamer.h" +#include +#include +#include + +namespace llvm { + +class CFIAnalysisMCStreamer : public MCStreamer { + MCInstrInfo const &MCII; + std::unique_ptr MCIA; + + struct CFIDirectivesState { + int DirectiveIndex; + + CFIDirectivesState() : DirectiveIndex(0) {} + + CFIDirectivesState(int FrameIndex, int InstructionIndex) + : DirectiveIndex(InstructionIndex) {} + } LastCFIDirectivesState; + std::vector FrameIndices; + std::vector CFIAs; + + struct ICFI { + MCInst Instruction; + std::pair CFIDirectivesRange; + + ICFI(MCInst Instruction, std::pair CFIDirectives) + : Instruction(Instruction), CFIDirectivesRange(CFIDirectives) {} + }; + + std::optional LastInstruction; + + std::pair getCFIDirectivesRange() { + auto DwarfFrameInfos = getDwarfFrameInfos(); + int FrameIndex = FrameIndices.back(); + auto CurrentCFIDirectiveState = + hasUnfinishedDwarfFrameInfo() + ? CFIDirectivesState( + FrameIndex, DwarfFrameInfos[FrameIndex].Instructions.size()) + : CFIDirectivesState(); + assert(CurrentCFIDirectiveState.DirectiveIndex >= + LastCFIDirectivesState.DirectiveIndex); + + std::pair CFIDirectivesRange( + LastCFIDirectivesState.DirectiveIndex, + CurrentCFIDirectiveState.DirectiveIndex); + LastCFIDirectivesState = CurrentCFIDirectiveState; + return CFIDirectivesRange; + } + + void feedCFIA() { + auto FrameIndex = FrameIndices.back(); + if (FrameIndex < 0) { + // TODO Maybe this corner case causes bugs, when the programmer did a + // mistake in the startproc, endprocs and also made a mistake in not + // adding cfi directives for a instruction. Then this would cause to + // ignore the instruction. + auto CFIDirectivesRange = getCFIDirectivesRange(); + assert(!LastInstruction || + CFIDirectivesRange.first == CFIDirectivesRange.second); + return; + } + + // TODO get this from emit yourself, instead of getting it in this way + const auto *LastDwarfFrameInfo = &getDwarfFrameInfos()[FrameIndex]; + + auto CFIDirectivesRange = getCFIDirectivesRange(); + ArrayRef CFIDirectives; + if (CFIDirectivesRange.first < CFIDirectivesRange.second) { + CFIDirectives = + ArrayRef(LastDwarfFrameInfo->Instructions); + CFIDirectives = CFIDirectives.drop_front(CFIDirectivesRange.first) + .drop_back(LastDwarfFrameInfo->Instructions.size() - + CFIDirectivesRange.second); + } + + if (LastInstruction != std::nullopt) { + assert(!CFIAs.empty()); + + CFIAs.back().update(LastInstruction.value(), CFIDirectives); + } else { + CFIAs.emplace_back(getContext(), MCII, MCIA.get(), CFIDirectives); + } + } + +public: + CFIAnalysisMCStreamer(MCContext &Context, const MCInstrInfo &MCII, + std::unique_ptr MCIA) + : MCStreamer(Context), MCII(MCII), MCIA(std::move(MCIA)), + LastCFIDirectivesState(), LastInstruction(std::nullopt) { + FrameIndices.push_back(-1); + } + + bool hasRawTextSupport() const override { return true; } + void emitRawTextImpl(StringRef String) override {} + + bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { + return true; + } + + void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + Align ByteAlignment) override {} + void beginCOFFSymbolDef(const MCSymbol *Symbol) override {} + void emitCOFFSymbolStorageClass(int StorageClass) override {} + void emitCOFFSymbolType(int Type) override {} + void endCOFFSymbolDef() override {} + void emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol, + MCSymbolAttr Linkage, + MCSymbolAttr Visibility) override {} + + void emitInstruction(const MCInst &Inst, + const MCSubtargetInfo &STI) override { + feedCFIA(); + LastInstruction = Inst; + } + + void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override { + feedCFIA(); + FrameIndices.push_back(getNumFrameInfos()); + LastInstruction = std::nullopt; + LastCFIDirectivesState.DirectiveIndex = 0; + MCStreamer::emitCFIStartProcImpl(Frame); + } + + void emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) override { + feedCFIA(); + // TODO this will break if the input frame are malformed. + FrameIndices.pop_back(); + CFIAs.pop_back(); + LastInstruction = std::nullopt; + auto FrameIndex = FrameIndices.back(); + LastCFIDirectivesState.DirectiveIndex = + FrameIndex >= 0 ? getDwarfFrameInfos()[FrameIndex].Instructions.size() + : 0; + MCStreamer::emitCFIEndProcImpl(CurFrame); + } +}; + +} // namespace llvm +#endif \ No newline at end of file diff --git a/llvm/tools/llvm-mc/CFIState.h b/llvm/tools/llvm-mc/CFIState.h new file mode 100644 index 0000000000000..4ffcda3c5063a --- /dev/null +++ b/llvm/tools/llvm-mc/CFIState.h @@ -0,0 +1,220 @@ +#ifndef LLVM_TOOLS_LLVM_MC_CFI_STATE_H +#define LLVM_TOOLS_LLVM_MC_CFI_STATE_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/MC/MCDwarf.h" +#include "llvm/Support/FormatVariadic.h" +#include +#include +#include +#include +namespace llvm { + +using DWARFRegType = int64_t; + +struct RegisterCFIState { + enum Approach { + Undefined, + SameValue, + AnotherRegister, + OffsetFromCFAAddr, + OffsetFromCFAVal, + Other, + } RetrieveApproach; + + // TODO use a correct type for this. + union { + int OffsetFromCFA; + DWARFRegType Register; + } Info; + + std::string dump() { + switch (RetrieveApproach) { + case Undefined: + return "undefined"; + case SameValue: + return "same value"; + case AnotherRegister: + return formatv("stored in another register, which is reg#{0}", + Info.Register); + case OffsetFromCFAAddr: + return formatv("offset {0} from CFA", Info.OffsetFromCFA); + case OffsetFromCFAVal: + return formatv("CFA value + {0}", Info.OffsetFromCFA); + case Other: + return "other"; + } + } + + bool operator==(const RegisterCFIState &OtherState) const { + if (RetrieveApproach != OtherState.RetrieveApproach) + return false; + + switch (RetrieveApproach) { + case Undefined: + case SameValue: + case Other: + return true; + case AnotherRegister: + return Info.Register == OtherState.Info.Register; + case OffsetFromCFAAddr: + case OffsetFromCFAVal: + return Info.OffsetFromCFA == OtherState.Info.OffsetFromCFA; + } + } + + bool operator!=(const RegisterCFIState &OtherState) const { + return !(*this == OtherState); + } + + static RegisterCFIState createUndefined() { + RegisterCFIState State; + State.RetrieveApproach = Undefined; + + return State; + } + + static RegisterCFIState createSameValue() { + RegisterCFIState State; + State.RetrieveApproach = SameValue; + + return State; + } + + static RegisterCFIState createAnotherRegister(DWARFRegType Register) { + RegisterCFIState State; + State.RetrieveApproach = AnotherRegister; + State.Info.Register = Register; + + return State; + } + + static RegisterCFIState createOffsetFromCFAAddr(int OffsetFromCFA) { + RegisterCFIState State; + State.RetrieveApproach = OffsetFromCFAAddr; + State.Info.OffsetFromCFA = OffsetFromCFA; + + return State; + } + + static RegisterCFIState createOffsetFromCFAVal(int OffsetFromCFA) { + RegisterCFIState State; + State.RetrieveApproach = OffsetFromCFAVal; + State.Info.OffsetFromCFA = OffsetFromCFA; + + return State; + } + + static RegisterCFIState createOther() { + RegisterCFIState State; + State.RetrieveApproach = Other; + + return State; + } +}; +struct CFIState { + DenseMap RegisterCFIStates; + DWARFRegType CFARegister; + int CFAOffset; + + CFIState() : CFARegister(-1), CFAOffset(-1) {} + + CFIState(const CFIState &Other) { + CFARegister = Other.CFARegister; + CFAOffset = Other.CFAOffset; + RegisterCFIStates = Other.RegisterCFIStates; + } + + CFIState &operator=(const CFIState &Other) { + if (this != &Other) { + CFARegister = Other.CFARegister; + CFAOffset = Other.CFAOffset; + RegisterCFIStates = Other.RegisterCFIStates; + } + + return *this; + } + + CFIState(DWARFRegType CFARegister, int CFIOffset) + : CFARegister(CFARegister), CFAOffset(CFIOffset) {} + + std::optional + getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const { + assert(RegisterCFIStates.count(Reg) && + "The register should be tracked inside the register states"); + auto &&RegState = RegisterCFIStates.at(Reg); + switch (RegState.RetrieveApproach) { + case RegisterCFIState::Undefined: + case RegisterCFIState::Other: + return std::nullopt; + case RegisterCFIState::SameValue: + return Reg; + case RegisterCFIState::AnotherRegister: + return RegState.Info.Register; + case RegisterCFIState::OffsetFromCFAAddr: + case RegisterCFIState::OffsetFromCFAVal: + return CFARegister; + } + } + + bool apply(const MCCFIInstruction &CFIDirective) { + switch (CFIDirective.getOperation()) { + case MCCFIInstruction::OpDefCfaRegister: + CFARegister = CFIDirective.getRegister(); + break; + case MCCFIInstruction::OpDefCfaOffset: + CFAOffset = CFIDirective.getOffset(); + break; + case MCCFIInstruction::OpAdjustCfaOffset: + CFAOffset += CFIDirective.getOffset(); + break; + case MCCFIInstruction::OpDefCfa: + CFARegister = CFIDirective.getRegister(); + CFAOffset = CFIDirective.getOffset(); + break; + case MCCFIInstruction::OpOffset: + RegisterCFIStates[CFIDirective.getRegister()] = + RegisterCFIState::createOffsetFromCFAAddr(CFIDirective.getOffset()); + break; + case MCCFIInstruction::OpRegister: + RegisterCFIStates[CFIDirective.getRegister()] = + RegisterCFIState::createAnotherRegister(CFIDirective.getRegister2()); + break; + case MCCFIInstruction::OpRelOffset: + RegisterCFIStates[CFIDirective.getRegister()] = + RegisterCFIState::createOffsetFromCFAAddr(CFIDirective.getOffset() - + CFAOffset); + break; + case MCCFIInstruction::OpUndefined: + RegisterCFIStates[CFIDirective.getRegister()] = + RegisterCFIState::createUndefined(); + break; + case MCCFIInstruction::OpSameValue: + RegisterCFIStates[CFIDirective.getRegister()] = + RegisterCFIState::createSameValue(); + break; + case MCCFIInstruction::OpValOffset: + RegisterCFIStates[CFIDirective.getRegister()] = + RegisterCFIState::createOffsetFromCFAVal(CFIDirective.getOffset()); + break; + case MCCFIInstruction::OpRestoreState: + case MCCFIInstruction::OpRememberState: + case MCCFIInstruction::OpLLVMDefAspaceCfa: + case MCCFIInstruction::OpRestore: + case MCCFIInstruction::OpEscape: + case MCCFIInstruction::OpWindowSave: + case MCCFIInstruction::OpNegateRAState: + case MCCFIInstruction::OpNegateRAStateWithPC: + case MCCFIInstruction::OpGnuArgsSize: + case MCCFIInstruction::OpLabel: + // These instructions are not supported. + return false; + break; + } + + return true; + } +}; +} // namespace llvm + +#endif \ No newline at end of file diff --git a/llvm/tools/llvm-mc/CMakeLists.txt b/llvm/tools/llvm-mc/CMakeLists.txt index f57356f9ee0c0..368f29c62201f 100644 --- a/llvm/tools/llvm-mc/CMakeLists.txt +++ b/llvm/tools/llvm-mc/CMakeLists.txt @@ -13,3 +13,6 @@ add_llvm_tool(llvm-mc llvm-mc.cpp Disassembler.cpp ) + +target_link_libraries(llvm-mc PRIVATE LLVMBOLTCore LLVMBOLTTargetX86) +target_include_directories(llvm-mc PRIVATE "${LLVM_MAIN_SRC_DIR}/../bolt/include") diff --git a/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h new file mode 100644 index 0000000000000..dd23063555053 --- /dev/null +++ b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h @@ -0,0 +1,206 @@ +#ifndef LLVM_TOOLS_LLVM_MC_EXTENDED_MC_INSTR_ANALYSIS_H +#define LLVM_TOOLS_LLVM_MC_EXTENDED_MC_INSTR_ANALYSIS_H + +#include "bolt/Core/MCPlusBuilder.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDwarf.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegister.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/TargetRegistry.h" +#include +#include +#include + +namespace llvm { + +class ExtendedMCInstrAnalysis { +private: + std::unique_ptr MCPB; + + static bolt::MCPlusBuilder * + createMCPlusBuilder(const Triple::ArchType Arch, + const MCInstrAnalysis *Analysis, const MCInstrInfo *Info, + const MCRegisterInfo *RegInfo, + const MCSubtargetInfo *STI) { + if (Arch == Triple::x86_64) + return bolt::createX86MCPlusBuilder(Analysis, Info, RegInfo, STI); + + llvm_unreachable("architecture unsupported by ExtendedMCInstrAnalysis"); + } + +public: + ExtendedMCInstrAnalysis(MCContext &Context, MCInstrInfo const &MCII, + MCInstrAnalysis *MCIA) { + MCPB.reset(createMCPlusBuilder(Context.getTargetTriple().getArch(), MCIA, + &MCII, Context.getRegisterInfo(), + Context.getSubtargetInfo())); + } + + /// Extra semantic information needed from MC layer: + + MCPhysReg getStackPointer() const { return MCPB->getStackPointer(); } + MCPhysReg getFlagsReg() const { return MCPB->getFlagsReg(); } + + bool doesConstantChange(const MCInst &Inst, MCPhysReg Reg, int64_t &HowMuch) { + if (isPush(Inst) && Reg == getStackPointer()) { + // TODO should get the stack direction here, now it assumes that it goes + // down. + HowMuch = -getPushSize(Inst); + return true; + } + + if (isPop(Inst) && Reg == getStackPointer()) { + // TODO should get the stack direction here, now it assumes that it goes + // down. + HowMuch = getPopSize(Inst); + return true; + } + + return false; + } + + // Tries to guess Reg1's value in a form of Reg2 (before Inst's execution) + + // Diff. + bool isInConstantDistanceOfEachOther(const MCInst &Inst, MCPhysReg &Reg1, + MCPhysReg Reg2, int &Diff) { + { + MCPhysReg From; + MCPhysReg To; + if (isRegToRegMove(Inst, From, To) && From == Reg2) { + Reg1 = To; + Diff = 0; + return true; + } + } + + return false; + } + + bool doStoreFromReg(const MCInst &Inst, MCPhysReg StoringReg, + MCPhysReg FromReg, int64_t &Offset) { + if (isPush(Inst) && FromReg == getStackPointer()) { + // TODO should get the stack direction here, now it assumes that it goes + // down. + Offset = -getPushSize(Inst); + return true; + } + + { + bool IsLoad; + bool IsStore; + bool IsStoreFromReg; + MCPhysReg SrcReg; + int32_t SrcImm; + uint16_t StackPtrReg; + int64_t StackOffset; + uint8_t Size; + bool IsSimple; + bool IsIndexed; + if (isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, SrcReg, SrcImm, + StackPtrReg, StackOffset, Size, IsSimple, IsIndexed)) { + // TODO make sure that simple means that it's store and does nothing + // more. + if (IsStore && IsSimple && StackPtrReg == FromReg && IsStoreFromReg && + SrcReg == StoringReg) { + Offset = StackOffset; + return true; + } + } + } + + return false; + } + + bool doLoadFromReg(const MCInst &Inst, MCPhysReg FromReg, int64_t &Offset, + MCPhysReg &LoadingReg) { + if (isPop(Inst) && FromReg == getStackPointer()) { + // TODO should get the stack direction here, now it assumes that it goes + // down. + Offset = 0; + LoadingReg = Inst.getOperand(0).getReg(); + return true; + } + + { + bool IsLoad; + bool IsStore; + bool IsStoreFromReg; + MCPhysReg SrcReg; + int32_t SrcImm; + uint16_t StackPtrReg; + int64_t StackOffset; + uint8_t Size; + bool IsSimple; + bool IsIndexed; + if (isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, SrcReg, SrcImm, + StackPtrReg, StackOffset, Size, IsSimple, IsIndexed)) { + // TODO make sure that simple means that it's store and does nothing + // more. + if (IsLoad && IsSimple && StackPtrReg == FromReg) { + Offset = StackOffset; + LoadingReg = SrcReg; + return true; + } + } + } + + { + if (isMoveMem2Reg(Inst)) { + auto X86MemAccess = evaluateX86MemoryOperand(Inst).value(); + if (X86MemAccess.BaseRegNum == FromReg && + (X86MemAccess.ScaleImm == 0 || X86MemAccess.IndexRegNum == 0) && + !X86MemAccess.DispExpr) { + LoadingReg = Inst.getOperand(0).getReg(); + Offset = X86MemAccess.DispImm; + return true; + } + } + } + + return false; + } + +private: + bool isPush(const MCInst &Inst) const { return MCPB->isPush(Inst); } + int getPushSize(const MCInst &Inst) const { return MCPB->getPushSize(Inst); } + + bool isPop(const MCInst &Inst) const { return MCPB->isPop(Inst); } + int getPopSize(const MCInst &Inst) const { return MCPB->getPopSize(Inst); } + + bool isRegToRegMove(const MCInst &Inst, MCPhysReg &From, + MCPhysReg &To) const { + return MCPB->isRegToRegMove(Inst, From, To); + } + bool isConditionalMove(const MCInst &Inst) const { + return MCPB->isConditionalMove(Inst); + } + bool isMoveMem2Reg(const MCInst &Inst) const { + return MCPB->isMoveMem2Reg(Inst); + } + bool isSUB(const MCInst &Inst) const { return MCPB->isSUB(Inst); } + + int getMemoryOperandNo(const MCInst &Inst) const { + return MCPB->getMemoryOperandNo(Inst); + } + std::optional + evaluateX86MemoryOperand(const MCInst &Inst) const { + return MCPB->evaluateX86MemoryOperand(Inst); + } + bool isStackAccess(const MCInst &Inst, bool &IsLoad, bool &IsStore, + bool &IsStoreFromReg, MCPhysReg &Reg, int32_t &SrcImm, + uint16_t &StackPtrReg, int64_t &StackOffset, uint8_t &Size, + bool &IsSimple, bool &IsIndexed) const { + return MCPB->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg, + SrcImm, StackPtrReg, StackOffset, Size, IsSimple, + IsIndexed); + } +}; + +} // namespace llvm + +#endif \ No newline at end of file diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp index b59a54d8fbc8a..ca4f71cb9cabd 100644 --- a/llvm/tools/llvm-mc/llvm-mc.cpp +++ b/llvm/tools/llvm-mc/llvm-mc.cpp @@ -11,12 +11,14 @@ // //===----------------------------------------------------------------------===// +#include "CFIAnalysisMCStreamer.h" #include "Disassembler.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCInstrAnalysis.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCObjectWriter.h" @@ -25,6 +27,7 @@ #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetOptions.h" #include "llvm/MC/MCTargetOptionsCommandFlags.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/CommandLine.h" @@ -37,7 +40,11 @@ #include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/WithColor.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" #include "llvm/TargetParser/Host.h" +#include +#include using namespace llvm; @@ -114,11 +121,7 @@ static cl::opt CommentColumn("comment-column", cl::desc("Asm comments indentation"), cl::init(40)); -enum OutputFileType { - OFT_Null, - OFT_AssemblyFile, - OFT_ObjectFile -}; +enum OutputFileType { OFT_Null, OFT_AssemblyFile, OFT_ObjectFile }; static cl::opt FileType("filetype", cl::init(OFT_AssemblyFile), cl::desc("Choose an output file type:"), @@ -212,6 +215,10 @@ static cl::opt NoExecStack("no-exec-stack", cl::desc("File doesn't need an exec stack"), cl::cat(MCCategory)); +static cl::opt ValidateCFI("validate-cfi", + cl::desc("Validate the CFI directives"), + cl::cat(MCCategory)); + enum ActionType { AC_AsLex, AC_Assemble, @@ -241,8 +248,8 @@ static const Target *GetTarget(const char *ProgName) { // Get the target specific parser. std::string Error; - const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple, - Error); + const Target *TheTarget = + TargetRegistry::lookupTarget(ArchName, TheTriple, Error); if (!TheTarget) { WithColor::error(errs(), ProgName) << Error; return nullptr; @@ -253,8 +260,8 @@ static const Target *GetTarget(const char *ProgName) { return TheTarget; } -static std::unique_ptr GetOutputStream(StringRef Path, - sys::fs::OpenFlags Flags) { +static std::unique_ptr +GetOutputStream(StringRef Path, sys::fs::OpenFlags Flags) { std::error_code EC; auto Out = std::make_unique(Path, EC, Flags); if (EC) { @@ -278,13 +285,12 @@ static void setDwarfDebugFlags(int argc, char **argv) { static std::string DwarfDebugProducer; static void setDwarfDebugProducer() { - if(!getenv("DEBUG_PRODUCER")) + if (!getenv("DEBUG_PRODUCER")) return; DwarfDebugProducer += getenv("DEBUG_PRODUCER"); } -static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, - raw_ostream &OS) { +static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, raw_ostream &OS) { AsmLexer Lexer(MAI); Lexer.setBuffer(SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())->getBuffer()); @@ -301,7 +307,7 @@ static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, } static int fillCommandLineSymbols(MCAsmParser &Parser) { - for (auto &I: DefineSymbol) { + for (auto &I : DefineSymbol) { auto Pair = StringRef(I).split('='); auto Sym = Pair.first; auto Val = Pair.second; @@ -325,8 +331,7 @@ static int AssembleInput(const char *ProgName, const Target *TheTarget, SourceMgr &SrcMgr, MCContext &Ctx, MCStreamer &Str, MCAsmInfo &MAI, MCSubtargetInfo &STI, MCInstrInfo &MCII, MCTargetOptions const &MCOptions) { - std::unique_ptr Parser( - createMCAsmParser(SrcMgr, Ctx, Str, MAI)); + std::unique_ptr Parser(createMCAsmParser(SrcMgr, Ctx, Str, MAI)); std::unique_ptr TAP( TheTarget->createMCAsmParser(STI, *Parser, MCII, MCOptions)); @@ -337,7 +342,7 @@ static int AssembleInput(const char *ProgName, const Target *TheTarget, } int SymbolResult = fillCommandLineSymbols(*Parser); - if(SymbolResult) + if (SymbolResult) return SymbolResult; Parser->setShowParsedOperands(ShowInstOperands); Parser->setTargetParser(*TAP); @@ -519,8 +524,17 @@ int main(int argc, char **argv) { std::unique_ptr MCII(TheTarget->createMCInstrInfo()); assert(MCII && "Unable to create instruction info!"); + std::unique_ptr MCIA( + TheTarget->createMCInstrAnalysis(MCII.get())); + assert(MCIA && "Unable to create instruction analysis!"); + std::unique_ptr IP; - if (FileType == OFT_AssemblyFile) { + if (ValidateCFI) { + assert(FileType == OFT_Null); + auto *CFIAMCS = new CFIAnalysisMCStreamer(Ctx, *MCII, std::move(MCIA)); + TheTarget->createNullTargetStreamer(*CFIAMCS); + Str.reset(CFIAMCS); + } else if (FileType == OFT_AssemblyFile) { IP.reset(TheTarget->createMCInstPrinter( Triple(TripleName), OutputAsmVariant, *MAI, *MCII, *MRI));