diff --git a/clang/test/CodeGen/asm-parser-info.S b/clang/test/CodeGen/asm-parser-info.S new file mode 100644 index 000000000000..62145c0a74d9 --- /dev/null +++ b/clang/test/CodeGen/asm-parser-info.S @@ -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 diff --git a/clang/tools/driver/cc1as_main.cpp b/clang/tools/driver/cc1as_main.cpp index 1c6cc36e6800..05a4d9cf0627 100644 --- a/clang/tools/driver/cc1as_main.cpp +++ b/clang/tools/driver/cc1as_main.cpp @@ -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 Parser( diff --git a/llvm/include/llvm/MC/MCExpr.h b/llvm/include/llvm/MC/MCExpr.h index fcbbe650d26f..01a55bd4054b 100644 --- a/llvm/include/llvm/MC/MCExpr.h +++ b/llvm/include/llvm/MC/MCExpr.h @@ -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; diff --git a/llvm/include/llvm/MC/MCObjectStreamer.h b/llvm/include/llvm/MC/MCObjectStreamer.h index 55556d7ec3cf..124a56c116f4 100644 --- a/llvm/include/llvm/MC/MCObjectStreamer.h +++ b/llvm/include/llvm/MC/MCObjectStreamer.h @@ -89,7 +89,7 @@ public: void visitUsedSymbol(const MCSymbol &Sym) override; MCAssembler &getAssembler() { return *Assembler; } - + MCAssembler *getAssemblerPtr() override; /// \name MCStreamer Interface /// @{ diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h index 582a836023b5..765da35a65e5 100644 --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -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(); } diff --git a/llvm/include/llvm/MC/MCSymbol.h b/llvm/include/llvm/MC/MCSymbol.h index cc8fc02968a5..32586109a528 100644 --- a/llvm/include/llvm/MC/MCSymbol.h +++ b/llvm/include/llvm/MC/MCSymbol.h @@ -316,6 +316,8 @@ public: Index = Value; } + bool isUnset() const { return SymbolContents == SymContentsUnset; } + uint64_t getOffset() const { assert((SymbolContents == SymContentsUnset || SymbolContents == SymContentsOffset) && diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp index 04a72ba3d738..4159eb19423a 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -132,6 +132,9 @@ void AsmPrinter::EmitInlineAsm(StringRef Str, const MCSubtargetInfo &STI, std::unique_ptr 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 diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp index 632a0308f297..d19c8c21dd07 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -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"; } diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp index 4dcfa85d520c..2ad19a793ad6 100644 --- a/llvm/lib/MC/MCExpr.cpp +++ b/llvm/lib/MC/MCExpr.cpp @@ -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 diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp index 19c41df473ce..ebedd9bf815f 100644 --- a/llvm/lib/MC/MCObjectStreamer.cpp +++ b/llvm/lib/MC/MCObjectStreamer.cpp @@ -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; } diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp index 7ee8e1b3e844..c2410413a62e 100644 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -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"); } diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp index 776569894a50..89d418d67436 100644 --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -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()); } diff --git a/llvm/test/MC/AsmParser/assembler-expressions-fail.s b/llvm/test/MC/AsmParser/assembler-expressions-fail.s new file mode 100644 index 000000000000..dd6fe929b68e --- /dev/null +++ b/llvm/test/MC/AsmParser/assembler-expressions-fail.s @@ -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: diff --git a/llvm/test/MC/AsmParser/assembler-expressions-inlineasm.ll b/llvm/test/MC/AsmParser/assembler-expressions-inlineasm.ll new file mode 100644 index 000000000000..35f110f37e2f --- /dev/null +++ b/llvm/test/MC/AsmParser/assembler-expressions-inlineasm.ll @@ -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: :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 +} diff --git a/llvm/test/MC/AsmParser/assembler-expressions.s b/llvm/test/MC/AsmParser/assembler-expressions.s new file mode 100644 index 000000000000..9bc17363ff5a --- /dev/null +++ b/llvm/test/MC/AsmParser/assembler-expressions.s @@ -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: diff --git a/llvm/test/MC/AsmParser/directive_fill.s b/llvm/test/MC/AsmParser/directive_fill.s index 64d0936e5165..8297f9da4269 100644 --- a/llvm/test/MC/AsmParser/directive_fill.s +++ b/llvm/test/MC/AsmParser/directive_fill.s @@ -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 diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp index dd83ac304463..6b0c5a1f15ca 100644 --- a/llvm/tools/llvm-mc/llvm-mc.cpp +++ b/llvm/tools/llvm-mc/llvm-mc.cpp @@ -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) {