Index: include/llvm/MC/MCObjectStreamer.h =================================================================== --- include/llvm/MC/MCObjectStreamer.h +++ include/llvm/MC/MCObjectStreamer.h @@ -141,6 +141,13 @@ bool EmitRelocDirective(const MCExpr &Offset, StringRef Name, const MCExpr *Expr, SMLoc Loc) override; void EmitFill(uint64_t NumBytes, uint8_t FillValue) override; + + void emitSpace(const MCExpr *Size, uint64_t FillValue, + SMLoc Loc = SMLoc()) override; + + void emitRepeatedValue(const MCExpr *NumValues, int64_t Size, + int64_t Expr, SMLoc Loc = SMLoc()) override; + void FinishImpl() override; /// Emit the absolute difference between two symbols if possible. Index: include/llvm/MC/MCStreamer.h =================================================================== --- include/llvm/MC/MCStreamer.h +++ include/llvm/MC/MCStreamer.h @@ -581,6 +581,30 @@ /// This function properly handles data in virtual sections. void EmitZeros(uint64_t NumBytes); + /// \brief Emit \p Size bytes worth of the value specified by \p FillValue. + /// + /// This is used to implement assembler directives such as .space or .skip. + /// + /// \param Size - The size of space (in bytes) to emit. + /// \param Value - The value to use when filling bytes. + /// \param Loc - The location of the expression for error reporting. + virtual void emitSpace(const MCExpr *Size, uint64_t FillValue, + SMLoc Loc = SMLoc()); + + /// \brief Emit \p NumValues copies of \p Size bytes. Each \p Size bytes is + /// taken from the lowest order 4 bytes of \p Expr. + /// + /// This is used to implement assembler directives such as .fill. + /// + /// \param Size - The size of space (in bytes) to emit. + /// \param Value - The value to use when filling bytes. + /// \param Loc - The location of the expression for error reporting. + virtual void emitRepeatedValue(const MCExpr *NumValues, int64_t Size, + int64_t Expr, SMLoc Loc = SMLoc()); + + void emitRepeatedValueImpl(int64_t Repeat, int64_t Size, int64_t Value, + SMLoc Loc = SMLoc()); + /// \brief Emit some number of copies of \p Value until the byte alignment \p /// ByteAlignment is reached. /// Index: lib/MC/MCAsmStreamer.cpp =================================================================== --- lib/MC/MCAsmStreamer.cpp +++ lib/MC/MCAsmStreamer.cpp @@ -178,6 +178,12 @@ void EmitFill(uint64_t NumBytes, uint8_t FillValue) override; + void emitSpace(const MCExpr *Size, uint64_t FillValue, + SMLoc Loc = SMLoc()) override; + + void emitRepeatedValue(const MCExpr *NumValues, int64_t Size, + int64_t Expr, SMLoc Loc = SMLoc()) override; + void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, unsigned ValueSize = 1, unsigned MaxBytesToEmit = 0) override; @@ -811,6 +817,34 @@ MCStreamer::EmitFill(NumBytes, FillValue); } +void MCAsmStreamer::emitSpace(const MCExpr *NumBytes, uint64_t Value, + SMLoc Loc) { + int64_t IntNumBytes; + if (NumBytes->evaluateAsAbsolute(IntNumBytes)) { + EmitFill(IntNumBytes, Value); + return; + } + + OS << "\t.space\t"; + NumBytes->print(OS, MAI); + OS << ", " << Value; + EmitEOL(); +} + +void MCAsmStreamer::emitRepeatedValue(const MCExpr *NumValues, int64_t Size, + int64_t Expr, SMLoc Loc) { + int64_t IntNumValues; + if (NumValues->evaluateAsAbsolute(IntNumValues)) { + MCStreamer::emitRepeatedValueImpl(IntNumValues, Size, Expr, Loc); + return; + } + + OS << "\t.fill\t"; + NumValues->print(OS, MAI); + OS << ", " << Size << ", " << Expr; + EmitEOL(); +} + void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned ValueSize, unsigned MaxBytesToEmit) { Index: lib/MC/MCObjectStreamer.cpp =================================================================== --- lib/MC/MCObjectStreamer.cpp +++ lib/MC/MCObjectStreamer.cpp @@ -496,6 +496,34 @@ insert(new MCFillFragment(FillValue, NumBytes)); } +void MCObjectStreamer::emitSpace(const MCExpr *NumBytes, uint64_t FillExpr, + SMLoc Loc) { + MCDataFragment *DF = getOrCreateDataFragment(); + flushPendingLabels(DF, DF->getContents().size()); + + int64_t IntNumBytes; + if (!NumBytes->evaluateAsAbsolute(IntNumBytes, getAssembler())) { + getContext().reportError(Loc, "expected absolute expression"); + return; + } + + if (IntNumBytes <= 0) + getContext().reportError(Loc, "invalid number of bytes"); + + EmitFill(IntNumBytes, FillExpr); +} + +void MCObjectStreamer::emitRepeatedValue(const MCExpr *NumValues, int64_t Size, + int64_t Expr, SMLoc Loc) { + int64_t IntNumValues; + if (!NumValues->evaluateAsAbsolute(IntNumValues, getAssembler())) { + getContext().reportError(Loc, "expected absolute expression"); + return; + } + + MCStreamer::emitRepeatedValueImpl(IntNumValues, Size, Expr, Loc); +} + void MCObjectStreamer::FinishImpl() { // If we are generating dwarf for assembly source files dump out the sections. if (getContext().getGenDwarfForAssembly()) Index: lib/MC/MCParser/AsmParser.cpp =================================================================== --- lib/MC/MCParser/AsmParser.cpp +++ lib/MC/MCParser/AsmParser.cpp @@ -2738,15 +2738,16 @@ bool AsmParser::parseDirectiveZero() { checkForValidSection(); - int64_t NumBytes; - if (parseAbsoluteExpression(NumBytes)) + SMLoc NumBytesLoc = Lexer.getLoc(); + const MCExpr *NumBytes; + if (parseExpression(NumBytes)) return true; int64_t Val = 0; if (getLexer().is(AsmToken::Comma)) { Lex(); if (parseAbsoluteExpression(Val)) - return true; + return false; } if (getLexer().isNot(AsmToken::EndOfStatement)) @@ -2754,7 +2755,7 @@ Lex(); - getStreamer().EmitFill(NumBytes, Val); + getStreamer().emitSpace(NumBytes, Val, NumBytesLoc); return false; } @@ -2764,17 +2765,11 @@ bool AsmParser::parseDirectiveFill() { checkForValidSection(); - SMLoc RepeatLoc = getLexer().getLoc(); - int64_t NumValues; - if (parseAbsoluteExpression(NumValues)) + SMLoc NumValuesLoc = Lexer.getLoc(); + const MCExpr *NumValues; + if (parseExpression(NumValues)) return true; - if (NumValues < 0) { - Warning(RepeatLoc, - "'.fill' directive with negative repeat count has no effect"); - NumValues = 0; - } - int64_t FillSize = 1; int64_t FillExpr = 0; @@ -2806,7 +2801,7 @@ if (FillSize < 0) { Warning(SizeLoc, "'.fill' directive with negative size has no effect"); - NumValues = 0; + NumValues = MCConstantExpr::create(0, getStreamer().getContext()); } if (FillSize > 8) { Warning(SizeLoc, "'.fill' directive with size greater than 8 has been truncated to 8"); @@ -2816,15 +2811,7 @@ if (!isUInt<32>(FillExpr) && FillSize > 4) Warning(ExprLoc, "'.fill' directive pattern has been truncated to 32-bits"); - if (NumValues > 0) { - int64_t NonZeroFillSize = FillSize > 4 ? 4 : FillSize; - FillExpr &= ~0ULL >> (64 - NonZeroFillSize * 8); - for (uint64_t i = 0, e = NumValues; i != e; ++i) { - getStreamer().EmitIntValue(FillExpr, NonZeroFillSize); - if (NonZeroFillSize < FillSize) - getStreamer().EmitIntValue(0, FillSize - NonZeroFillSize); - } - } + getStreamer().emitRepeatedValue(NumValues, FillSize, FillExpr, NumValuesLoc); return false; } @@ -4058,8 +4045,9 @@ bool AsmParser::parseDirectiveSpace(StringRef IDVal) { checkForValidSection(); - int64_t NumBytes; - if (parseAbsoluteExpression(NumBytes)) + SMLoc NumBytesLoc = Lexer.getLoc(); + const MCExpr *NumBytes; + if (parseExpression(NumBytes)) return true; int64_t FillExpr = 0; @@ -4077,12 +4065,8 @@ Lex(); - if (NumBytes <= 0) - return TokError("invalid number of bytes in '" + Twine(IDVal) + - "' directive"); - // FIXME: Sometimes the fill expr is 'nop' if it isn't supplied, instead of 0. - getStreamer().EmitFill(NumBytes, FillExpr); + getStreamer().emitSpace(NumBytes, FillExpr, NumBytesLoc); return false; } Index: lib/MC/MCStreamer.cpp =================================================================== --- lib/MC/MCStreamer.cpp +++ lib/MC/MCStreamer.cpp @@ -26,6 +26,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/SourceMgr.h" #include using namespace llvm; @@ -145,6 +146,29 @@ EmitFill(NumBytes, 0); } +void MCStreamer::emitSpace(const MCExpr *NumBytes, uint64_t Value, SMLoc Loc) {} +void MCStreamer::emitRepeatedValue(const MCExpr *NumValues, int64_t Size, + int64_t Expr, SMLoc Loc) {} + +void MCStreamer::emitRepeatedValueImpl(int64_t NumValues, int64_t Size, + int64_t Expr, SMLoc Loc) { + if (NumValues < 0) { + getContext().getSourceManager()->PrintMessage(Loc, SourceMgr::DK_Warning, + "'.fill' directive with negative repeat count has no effect"); + return; + } + + if (NumValues > 0) { + int64_t NonZeroSize = Size > 4 ? 4 : Size; + Expr &= ~0ULL >> (64 - NonZeroSize * 8); + for (uint64_t i = 0, e = NumValues; i != e; ++i) { + EmitIntValue(Expr, NonZeroSize); + if (NonZeroSize < Size) + EmitIntValue(0, Size - NonZeroSize); + } + } +} + unsigned MCStreamer::EmitDwarfFileDirective(unsigned FileNo, StringRef Directory, StringRef Filename, unsigned CUID) { Index: test/MC/AsmParser/directive_fill.s =================================================================== --- test/MC/AsmParser/directive_fill.s +++ test/MC/AsmParser/directive_fill.s @@ -73,3 +73,11 @@ # CHECK: .byte 52 TEST10: .fill 1, 3, 0x12345678 + +# CHECK: .fill TEST11-TEST10, 1, 0 +TEST11: + .fill TEST11 - TEST10 + +# CHECK: .fill TEST11-TEST12, 3, 305419896 +TEST12: + .fill TEST11 - TEST12, 3, 0x12345678 Index: test/MC/AsmParser/directive_space.s =================================================================== --- test/MC/AsmParser/directive_space.s +++ test/MC/AsmParser/directive_space.s @@ -14,3 +14,8 @@ # CHECK: .space 1 TEST2: .skip 1 + +# CHECK: TEST3 +# CHECK: .space TEST0-TEST1, 0 +TEST3: + .space TEST0 - TEST1 Index: test/MC/AsmParser/symbolic-expression.s =================================================================== --- /dev/null +++ test/MC/AsmParser/symbolic-expression.s @@ -0,0 +1,17 @@ +# RUN: llvm-mc -filetype=obj -triple=i386-unknown-elf %s | llvm-objdump -t - | FileCheck %s + +# CHECK: 00000000 .text 00000000 TEST0 +TEST0: + .fill 0x10 +# CHECK: 00000010 .text 00000000 TEST1 +TEST1: + .fill TEST1 - TEST0 + 0x5 +# CHECK: 00000025 .text 00000000 TEST2 +TEST2: + .zero TEST2 - (TEST1 + 0x5) +# CHECK: 00000035 .text 00000000 TEST3 +TEST3: + .skip (TEST1 - TEST0) * 2 +# CHECK: 00000055 .text 00000000 TEST4 +TEST4: + .space TEST2 - TEST1, 1