forked from OSchip/llvm-project
[MC] Change AsmParser to leverage Assembler during evaluation
Teach AsmParser to check with Assembler for when evaluating constant expressions. This improves the handing of preprocessor expressions that must be resolved at parse time. This idiom can be found as assembling-time assertion checks in source-level assemblers. Note that this relies on the MCStreamer to keep sufficient tabs on Section / Fragment information which the MCAsmStreamer does not. As a result the textual output may fail where the equivalent object generation would pass. This can most easily be resolved by folding the MCAsmStreamer and MCObjectStreamer together which is planned for in a separate patch. Currently, this feature is only enabled for assembly input, keeping IR compilation consistent between assembly and object generation. Reviewers: echristo, rnk, probinson, espindola, peter.smith Reviewed By: peter.smith Subscribers: eraman, peter.smith, arichardson, jyknight, hiraditya, llvm-commits Differential Revision: https://reviews.llvm.org/D45164 llvm-svn: 331218
This commit is contained in:
parent
8fe04ad3f7
commit
6c0665e221
|
@ -0,0 +1,12 @@
|
|||
// REQUIRES: x86-registered-target
|
||||
// RUN: %clang --target=x86_64-unknown-linux-gnu -c %s -o /dev/null
|
||||
|
||||
// Check that cc1as can use assembler info in object generation.
|
||||
.data
|
||||
|
||||
foo:
|
||||
.if . - foo == 0
|
||||
.byte 0xaa
|
||||
.else
|
||||
.byte 0x00
|
||||
.endif
|
|
@ -435,6 +435,9 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
|
|||
Str.get()->InitSections(Opts.NoExecStack);
|
||||
}
|
||||
|
||||
// Assembly to object compilation should leverage assembly info.
|
||||
Str->setUseAssemblerInfoForParsing(true);
|
||||
|
||||
bool Failed = false;
|
||||
|
||||
std::unique_ptr<MCAsmParser> Parser(
|
||||
|
|
|
@ -96,6 +96,7 @@ public:
|
|||
const SectionAddrMap &Addrs) const;
|
||||
bool evaluateAsAbsolute(int64_t &Res) const;
|
||||
bool evaluateAsAbsolute(int64_t &Res, const MCAssembler &Asm) const;
|
||||
bool evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm) const;
|
||||
bool evaluateAsAbsolute(int64_t &Res, const MCAsmLayout &Layout) const;
|
||||
|
||||
bool evaluateKnownAbsolute(int64_t &Res, const MCAsmLayout &Layout) const;
|
||||
|
|
|
@ -89,7 +89,7 @@ public:
|
|||
void visitUsedSymbol(const MCSymbol &Sym) override;
|
||||
|
||||
MCAssembler &getAssembler() { return *Assembler; }
|
||||
|
||||
MCAssembler *getAssemblerPtr() override;
|
||||
/// \name MCStreamer Interface
|
||||
/// @{
|
||||
|
||||
|
|
|
@ -211,6 +211,8 @@ class MCStreamer {
|
|||
/// requires.
|
||||
unsigned NextWinCFIID = 0;
|
||||
|
||||
bool UseAssemblerInfoForParsing;
|
||||
|
||||
protected:
|
||||
MCStreamer(MCContext &Ctx);
|
||||
|
||||
|
@ -247,6 +249,11 @@ public:
|
|||
|
||||
MCContext &getContext() const { return Context; }
|
||||
|
||||
virtual MCAssembler *getAssemblerPtr() { return nullptr; }
|
||||
|
||||
void setUseAssemblerInfoForParsing(bool v) { UseAssemblerInfoForParsing = v; }
|
||||
bool getUseAssemblerInfoForParsing() { return UseAssemblerInfoForParsing; }
|
||||
|
||||
MCTargetStreamer *getTargetStreamer() {
|
||||
return TargetStreamer.get();
|
||||
}
|
||||
|
|
|
@ -316,6 +316,8 @@ public:
|
|||
Index = Value;
|
||||
}
|
||||
|
||||
bool isUnset() const { return SymbolContents == SymContentsUnset; }
|
||||
|
||||
uint64_t getOffset() const {
|
||||
assert((SymbolContents == SymContentsUnset ||
|
||||
SymbolContents == SymContentsOffset) &&
|
||||
|
|
|
@ -132,6 +132,9 @@ void AsmPrinter::EmitInlineAsm(StringRef Str, const MCSubtargetInfo &STI,
|
|||
std::unique_ptr<MCAsmParser> Parser(
|
||||
createMCAsmParser(SrcMgr, OutContext, *OutStreamer, *MAI, BufNum));
|
||||
|
||||
// Do not use assembler-level information for parsing inline assembly.
|
||||
OutStreamer->setUseAssemblerInfoForParsing(false);
|
||||
|
||||
// We create a new MCInstrInfo here since we might be at the module level
|
||||
// and not have a MachineFunction to initialize the TargetInstrInfo from and
|
||||
// we only need MCInstrInfo for asm parsing. We create one unconditionally
|
||||
|
|
|
@ -78,6 +78,9 @@ public:
|
|||
InstPrinter->setCommentStream(CommentStream);
|
||||
}
|
||||
|
||||
MCAssembler &getAssembler() { return *Assembler; }
|
||||
MCAssembler *getAssemblerPtr() override { return nullptr; }
|
||||
|
||||
inline void EmitEOL() {
|
||||
// Dump Explicit Comments here.
|
||||
emitExplicitComments();
|
||||
|
@ -1656,10 +1659,10 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst,
|
|||
raw_svector_ostream VecOS(Code);
|
||||
|
||||
// If we have no code emitter, don't emit code.
|
||||
if (!Assembler->getEmitterPtr())
|
||||
if (!getAssembler().getEmitterPtr())
|
||||
return;
|
||||
|
||||
Assembler->getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI);
|
||||
getAssembler().getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI);
|
||||
|
||||
// If we are showing fixups, create symbolic markers in the encoded
|
||||
// representation. We do this by making a per-bit map to the fixup item index,
|
||||
|
@ -1672,7 +1675,7 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst,
|
|||
for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
|
||||
MCFixup &F = Fixups[i];
|
||||
const MCFixupKindInfo &Info =
|
||||
Assembler->getBackend().getFixupKindInfo(F.getKind());
|
||||
getAssembler().getBackend().getFixupKindInfo(F.getKind());
|
||||
for (unsigned j = 0; j != Info.TargetSize; ++j) {
|
||||
unsigned Index = F.getOffset() * 8 + Info.TargetOffset + j;
|
||||
assert(Index < Code.size() * 8 && "Invalid offset in fixup!");
|
||||
|
@ -1737,7 +1740,7 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst,
|
|||
for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
|
||||
MCFixup &F = Fixups[i];
|
||||
const MCFixupKindInfo &Info =
|
||||
Assembler->getBackend().getFixupKindInfo(F.getKind());
|
||||
getAssembler().getBackend().getFixupKindInfo(F.getKind());
|
||||
OS << " fixup " << char('A' + i) << " - " << "offset: " << F.getOffset()
|
||||
<< ", value: " << *F.getValue() << ", kind: " << Info.Name << "\n";
|
||||
}
|
||||
|
|
|
@ -441,6 +441,10 @@ bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler &Asm) const {
|
|||
return evaluateAsAbsolute(Res, &Asm, nullptr, nullptr);
|
||||
}
|
||||
|
||||
bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm) const {
|
||||
return evaluateAsAbsolute(Res, Asm, nullptr, nullptr);
|
||||
}
|
||||
|
||||
bool MCExpr::evaluateKnownAbsolute(int64_t &Res,
|
||||
const MCAsmLayout &Layout) const {
|
||||
return evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, nullptr,
|
||||
|
@ -494,7 +498,7 @@ static void AttemptToFoldSymbolOffsetDifference(
|
|||
return;
|
||||
|
||||
if (SA.getFragment() == SB.getFragment() && !SA.isVariable() &&
|
||||
!SB.isVariable()) {
|
||||
!SA.isUnset() && !SB.isVariable() && !SB.isUnset()) {
|
||||
Addend += (SA.getOffset() - SB.getOffset());
|
||||
|
||||
// Pointers to Thumb symbols need to have their low-bit set to allow
|
||||
|
|
|
@ -35,6 +35,15 @@ MCObjectStreamer::MCObjectStreamer(MCContext &Context,
|
|||
|
||||
MCObjectStreamer::~MCObjectStreamer() {}
|
||||
|
||||
// AssemblerPtr is used for evaluation of expressions and causes
|
||||
// difference between asm and object outputs. Return nullptr to in
|
||||
// inline asm mode to limit divergence to assembly inputs.
|
||||
MCAssembler *MCObjectStreamer::getAssemblerPtr() {
|
||||
if (getUseAssemblerInfoForParsing())
|
||||
return Assembler.get();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void MCObjectStreamer::flushPendingLabels(MCFragment *F, uint64_t FOffset) {
|
||||
if (PendingLabels.empty())
|
||||
return;
|
||||
|
@ -155,7 +164,7 @@ void MCObjectStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size,
|
|||
|
||||
// Avoid fixups when possible.
|
||||
int64_t AbsValue;
|
||||
if (Value->evaluateAsAbsolute(AbsValue, getAssembler())) {
|
||||
if (Value->evaluateAsAbsolute(AbsValue, getAssemblerPtr())) {
|
||||
if (!isUIntN(8 * Size, AbsValue) && !isIntN(8 * Size, AbsValue)) {
|
||||
getContext().reportError(
|
||||
Loc, "value evaluated as " + Twine(AbsValue) + " is out of range.");
|
||||
|
@ -217,7 +226,7 @@ void MCObjectStreamer::EmitLabel(MCSymbol *Symbol, SMLoc Loc, MCFragment *F) {
|
|||
|
||||
void MCObjectStreamer::EmitULEB128Value(const MCExpr *Value) {
|
||||
int64_t IntValue;
|
||||
if (Value->evaluateAsAbsolute(IntValue, getAssembler())) {
|
||||
if (Value->evaluateAsAbsolute(IntValue, getAssemblerPtr())) {
|
||||
EmitULEB128IntValue(IntValue);
|
||||
return;
|
||||
}
|
||||
|
@ -226,7 +235,7 @@ void MCObjectStreamer::EmitULEB128Value(const MCExpr *Value) {
|
|||
|
||||
void MCObjectStreamer::EmitSLEB128Value(const MCExpr *Value) {
|
||||
int64_t IntValue;
|
||||
if (Value->evaluateAsAbsolute(IntValue, getAssembler())) {
|
||||
if (Value->evaluateAsAbsolute(IntValue, getAssemblerPtr())) {
|
||||
EmitSLEB128IntValue(IntValue);
|
||||
return;
|
||||
}
|
||||
|
@ -254,7 +263,7 @@ bool MCObjectStreamer::changeSectionImpl(MCSection *Section,
|
|||
|
||||
int64_t IntSubsection = 0;
|
||||
if (Subsection &&
|
||||
!Subsection->evaluateAsAbsolute(IntSubsection, getAssembler()))
|
||||
!Subsection->evaluateAsAbsolute(IntSubsection, getAssemblerPtr()))
|
||||
report_fatal_error("Cannot evaluate subsection number");
|
||||
if (IntSubsection < 0 || IntSubsection > 8192)
|
||||
report_fatal_error("Subsection number out of range");
|
||||
|
@ -400,7 +409,7 @@ void MCObjectStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta,
|
|||
}
|
||||
const MCExpr *AddrDelta = buildSymbolDiff(*this, Label, LastLabel);
|
||||
int64_t Res;
|
||||
if (AddrDelta->evaluateAsAbsolute(Res, getAssembler())) {
|
||||
if (AddrDelta->evaluateAsAbsolute(Res, getAssemblerPtr())) {
|
||||
MCDwarfLineAddr::Emit(this, Assembler->getDWARFLinetableParams(), LineDelta,
|
||||
Res);
|
||||
return;
|
||||
|
@ -412,7 +421,7 @@ void MCObjectStreamer::EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel,
|
|||
const MCSymbol *Label) {
|
||||
const MCExpr *AddrDelta = buildSymbolDiff(*this, Label, LastLabel);
|
||||
int64_t Res;
|
||||
if (AddrDelta->evaluateAsAbsolute(Res, getAssembler())) {
|
||||
if (AddrDelta->evaluateAsAbsolute(Res, getAssemblerPtr())) {
|
||||
MCDwarfFrameEmitter::EmitAdvanceLoc(*this, Res);
|
||||
return;
|
||||
}
|
||||
|
@ -608,7 +617,7 @@ void MCObjectStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue,
|
|||
void MCObjectStreamer::emitFill(const MCExpr &NumValues, int64_t Size,
|
||||
int64_t Expr, SMLoc Loc) {
|
||||
int64_t IntNumValues;
|
||||
if (!NumValues.evaluateAsAbsolute(IntNumValues, getAssembler())) {
|
||||
if (!NumValues.evaluateAsAbsolute(IntNumValues, getAssemblerPtr())) {
|
||||
getContext().reportError(Loc, "expected absolute expression");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -775,7 +775,7 @@ bool AsmParser::processIncbinFile(const std::string &Filename, int64_t Skip,
|
|||
Bytes = Bytes.drop_front(Skip);
|
||||
if (Count) {
|
||||
int64_t Res;
|
||||
if (!Count->evaluateAsAbsolute(Res))
|
||||
if (!Count->evaluateAsAbsolute(Res, getStreamer().getAssemblerPtr()))
|
||||
return Error(Loc, "expected absolute expression");
|
||||
if (Res < 0)
|
||||
return Warning(Loc, "negative count has no effect");
|
||||
|
@ -1378,7 +1378,8 @@ bool AsmParser::parseExpression(const MCExpr *&Res, SMLoc &EndLoc) {
|
|||
Lex();
|
||||
}
|
||||
|
||||
// Try to constant fold it up front, if possible.
|
||||
// Try to constant fold it up front, if possible. Do not exploit
|
||||
// assembler here.
|
||||
int64_t Value;
|
||||
if (Res->evaluateAsAbsolute(Value))
|
||||
Res = MCConstantExpr::create(Value, getContext());
|
||||
|
@ -1419,7 +1420,7 @@ bool AsmParser::parseAbsoluteExpression(int64_t &Res) {
|
|||
if (parseExpression(Expr))
|
||||
return true;
|
||||
|
||||
if (!Expr->evaluateAsAbsolute(Res))
|
||||
if (!Expr->evaluateAsAbsolute(Res, getStreamer().getAssemblerPtr()))
|
||||
return Error(StartLoc, "expected absolute expression");
|
||||
|
||||
return false;
|
||||
|
@ -2616,7 +2617,8 @@ bool AsmParser::parseMacroArguments(const MCAsmMacro *M,
|
|||
Lex();
|
||||
if (parseExpression(AbsoluteExp, EndLoc))
|
||||
return false;
|
||||
if (!AbsoluteExp->evaluateAsAbsolute(Value))
|
||||
if (!AbsoluteExp->evaluateAsAbsolute(Value,
|
||||
getStreamer().getAssemblerPtr()))
|
||||
return Error(StrLoc, "expected absolute expression");
|
||||
const char *StrChar = StrLoc.getPointer();
|
||||
const char *EndChar = EndLoc.getPointer();
|
||||
|
@ -2916,8 +2918,9 @@ bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) {
|
|||
if (parseExpression(Offset))
|
||||
return true;
|
||||
|
||||
if (check(!Offset->evaluateAsAbsolute(OffsetValue), OffsetLoc,
|
||||
"expression is not a constant value") ||
|
||||
if (check(!Offset->evaluateAsAbsolute(OffsetValue,
|
||||
getStreamer().getAssemblerPtr()),
|
||||
OffsetLoc, "expression is not a constant value") ||
|
||||
check(OffsetValue < 0, OffsetLoc, "expression is negative") ||
|
||||
parseToken(AsmToken::Comma, "expected comma") ||
|
||||
check(getTok().isNot(AsmToken::Identifier), "expected relocation name"))
|
||||
|
@ -5344,7 +5347,7 @@ bool AsmParser::parseDirectiveRept(SMLoc DirectiveLoc, StringRef Dir) {
|
|||
return true;
|
||||
|
||||
int64_t Count;
|
||||
if (!CountExpr->evaluateAsAbsolute(Count)) {
|
||||
if (!CountExpr->evaluateAsAbsolute(Count, getStreamer().getAssemblerPtr())) {
|
||||
return Error(CountLoc, "unexpected token in '" + Dir + "' directive");
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,8 @@ void MCTargetStreamer::emitValue(const MCExpr *Value) {
|
|||
void MCTargetStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {}
|
||||
|
||||
MCStreamer::MCStreamer(MCContext &Ctx)
|
||||
: Context(Ctx), CurrentWinFrameInfo(nullptr) {
|
||||
: Context(Ctx), CurrentWinFrameInfo(nullptr),
|
||||
UseAssemblerInfoForParsing(false) {
|
||||
SectionStack.push_back(std::pair<MCSectionSubPair, MCSectionSubPair>());
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# RUN: not llvm-mc -triple x86_64-unknown-unknown %s 2>&1 | FileCheck %s --check-prefix=ERR
|
||||
# RUN: not llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s 2>&1 | FileCheck %s --check-prefix=ERR
|
||||
|
||||
.text
|
||||
|
||||
test2:
|
||||
jmp baz
|
||||
# ERR: [[@LINE+1]]:5: error: expected absolute expression
|
||||
.if . - text2 == 1
|
||||
nop
|
||||
.else
|
||||
ret
|
||||
.endif
|
||||
push fs
|
||||
|
||||
# No additional errors.
|
||||
#
|
||||
# ERR-NOT: {{[0-9]+}}:{{[0-9]+}}: error:
|
|
@ -0,0 +1,14 @@
|
|||
; RUN: not llc -mtriple x86_64-unknown-linux-gnu -o %t.s -filetype=asm %s 2>&1 | FileCheck %s
|
||||
; RUN: not llc -mtriple x86_64-unknown-linux-gnu -o %t.o -filetype=obj %s 2>&1 | FileCheck %s
|
||||
|
||||
; Assembler-aware expression evaluation should be disabled in inline
|
||||
; assembly to prevent differences in behavior between object and
|
||||
; assembly output.
|
||||
|
||||
|
||||
; CHECK: <inline asm>:1:17: error: expected absolute expression
|
||||
|
||||
define i32 @main() local_unnamed_addr {
|
||||
tail call void asm sideeffect "foo: nop; .if . - foo==1; nop;.endif", "~{dirflag},~{fpsr},~{flags}"()
|
||||
ret i32 0
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
# RUN: not llvm-mc -triple x86_64-unknown-unknown %s 2>&1 | FileCheck %s --check-prefix=ASM-ERR
|
||||
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s | llvm-objdump -j .data -s - | FileCheck %s --check-prefix=OBJDATA
|
||||
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s | llvm-objdump -j .text -s - | FileCheck %s --check-prefix=OBJTEXT
|
||||
.data
|
||||
|
||||
# OBJDATA: Contents of section .data
|
||||
# OBJDATA-NEXT: 0000 aa0506ff
|
||||
|
||||
foo2:
|
||||
# ASM-ERR: [[@LINE+1]]:5: error: expected absolute expression
|
||||
.if . - foo2 == 0
|
||||
.byte 0xaa
|
||||
.else
|
||||
.byte 0x00
|
||||
.endif
|
||||
|
||||
foo3:
|
||||
.byte 5
|
||||
# ASM-ERR: [[@LINE+1]]:5: error: expected absolute expression
|
||||
.if . - foo3 == 1
|
||||
.byte 6
|
||||
.else
|
||||
.byte 7
|
||||
.endif
|
||||
|
||||
.byte 0xff
|
||||
|
||||
# nop is a fixed size instruction so this should pass.
|
||||
|
||||
# OBJTEXT: Contents of section .text
|
||||
# OBJTEXT-NEXT: 0000 9090ff34 25
|
||||
|
||||
.text
|
||||
|
||||
text1:
|
||||
nop
|
||||
# ASM-ERR: [[@LINE+1]]:5: error: expected absolute expression
|
||||
.if . - text1 == 1
|
||||
nop
|
||||
.else
|
||||
ret
|
||||
.endif
|
||||
push gs
|
||||
|
||||
# No additional errors.
|
||||
#
|
||||
# ASM-ERR-NOT: {{[0-9]+}}:{{[0-9]+}}: error:
|
|
@ -1,7 +1,7 @@
|
|||
# RUN: llvm-mc -triple i386-unknown-unknown %s 2> %t.err | FileCheck %s
|
||||
# RUN: FileCheck --check-prefix=CHECK-WARNINGS %s < %t.err
|
||||
# RUN: llvm-mc -triple i386-unknown-unknown -filetype=obj -o %t.o %s 2> %t.err
|
||||
# RUN: FileCheck --check-prefix=OBJ-WARNINGS %s < %t.err
|
||||
# RUN: llvm-mc -triple i386-unknown-unknown -filetype=obj -o %t.o %s 2> %t.err2
|
||||
# RUN: FileCheck --check-prefix=OBJ-WARNINGS %s < %t.err2
|
||||
|
||||
# CHECK: TEST0:
|
||||
# CHECK: .fill 1, 1, 0xa
|
||||
|
|
|
@ -475,6 +475,9 @@ int main(int argc, char **argv) {
|
|||
Str->InitSections(true);
|
||||
}
|
||||
|
||||
// Use Assembler information for parsing.
|
||||
Str->setUseAssemblerInfoForParsing(true);
|
||||
|
||||
int Res = 1;
|
||||
bool disassemble = false;
|
||||
switch (Action) {
|
||||
|
|
Loading…
Reference in New Issue