1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 02:52:53 +02:00

[MC] Support symbolic expressions in assembly directives

This matches the behavior of GNU assembler which supports symbolic
expressions in absolute expressions used in assembly directives.

Differential Revision: http://reviews.llvm.org/D20752

llvm-svn: 271102
This commit is contained in:
Petr Hosek 2016-05-28 05:57:48 +00:00
parent 94e5255730
commit 0178571895
8 changed files with 159 additions and 62 deletions

View File

@ -141,6 +141,11 @@ public:
bool EmitRelocDirective(const MCExpr &Offset, StringRef Name,
const MCExpr *Expr, SMLoc Loc) override;
void EmitFill(uint64_t NumBytes, uint8_t FillValue) override;
void emitFill(const MCExpr &NumBytes, uint64_t FillValue,
SMLoc Loc = SMLoc()) override;
void emitFill(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.

View File

@ -577,6 +577,28 @@ public:
/// This implements directives such as '.space'.
virtual void EmitFill(uint64_t NumBytes, uint8_t FillValue);
/// \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 NumBytes - The number of bytes to emit.
/// \param FillValue - The value to use when filling bytes.
/// \param Loc - The location of the expression for error reporting.
virtual void emitFill(const MCExpr &NumBytes, 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 expression.
///
/// This is used to implement assembler directives such as .fill.
///
/// \param NumValues - The number of copies of \p Size bytes to emit.
/// \param Size - The size (in bytes) of each repeated value.
/// \param Expr - The expression from which \p Size bytes are used.
virtual void emitFill(uint64_t NumValues, int64_t Size, int64_t Expr);
virtual void emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr,
SMLoc Loc = SMLoc());
/// \brief Emit NumBytes worth of zeros.
/// This function properly handles data in virtual sections.
void EmitZeros(uint64_t NumBytes);

View File

@ -31,6 +31,7 @@
#include "llvm/Support/LEB128.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SourceMgr.h"
#include <cctype>
using namespace llvm;
@ -178,6 +179,14 @@ public:
void EmitFill(uint64_t NumBytes, uint8_t FillValue) override;
void emitFill(const MCExpr &NumBytes, uint64_t FillValue,
SMLoc Loc = SMLoc()) override;
void emitFill(uint64_t NumValues, int64_t Size, int64_t Expr) override;
void emitFill(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;
@ -799,16 +808,41 @@ void MCAsmStreamer::EmitGPRel32Value(const MCExpr *Value) {
void MCAsmStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue) {
if (NumBytes == 0) return;
const MCExpr *E = MCConstantExpr::create(NumBytes, getContext());
emitFill(*E, FillValue);
}
void MCAsmStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue,
SMLoc Loc) {
if (const char *ZeroDirective = MAI->getZeroDirective()) {
OS << ZeroDirective << NumBytes;
// FIXME: Emit location directives
OS << ZeroDirective;
NumBytes.print(OS, MAI);
if (FillValue != 0)
OS << ',' << (int)FillValue;
EmitEOL();
return;
}
// Emit a byte at a time.
MCStreamer::EmitFill(NumBytes, FillValue);
MCStreamer::emitFill(NumBytes, FillValue);
}
void MCAsmStreamer::emitFill(uint64_t NumValues, int64_t Size, int64_t Expr) {
if (NumValues == 0)
return;
const MCExpr *E = MCConstantExpr::create(NumValues, getContext());
emitFill(*E, Size, Expr);
}
void MCAsmStreamer::emitFill(const MCExpr &NumValues, int64_t Size,
int64_t Expr, SMLoc Loc) {
// FIXME: Emit location directives
OS << "\t.fill\t";
NumValues.print(OS, MAI);
OS << ", " << Size << ", 0x";
OS.write_hex(truncateToSize(Expr, 4));
EmitEOL();
}
void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value,

View File

@ -20,6 +20,7 @@
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
@ -496,6 +497,43 @@ void MCObjectStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue) {
insert(new MCFillFragment(FillValue, NumBytes));
}
void MCObjectStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue,
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");
return;
}
EmitFill(IntNumBytes, FillValue);
}
void MCObjectStreamer::emitFill(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;
}
if (IntNumValues < 0) {
getContext().getSourceManager()->PrintMessage(
Loc, SourceMgr::DK_Warning,
"'.fill' directive with negative repeat count has no effect");
return;
}
MCStreamer::emitFill(IntNumValues, Size, Expr);
}
void MCObjectStreamer::FinishImpl() {
// If we are generating dwarf for assembly source files dump out the sections.
if (getContext().getGenDwarfForAssembly())

View File

@ -2738,8 +2738,9 @@ bool AsmParser::parseDirectiveRealValue(const fltSemantics &Semantics) {
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;
@ -2754,7 +2755,7 @@ bool AsmParser::parseDirectiveZero() {
Lex();
getStreamer().EmitFill(NumBytes, Val);
getStreamer().emitFill(*NumBytes, Val, NumBytesLoc);
return false;
}
@ -2764,17 +2765,11 @@ bool AsmParser::parseDirectiveZero() {
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 @@ bool AsmParser::parseDirectiveFill() {
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 @@ bool AsmParser::parseDirectiveFill() {
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().emitFill(*NumValues, FillSize, FillExpr, NumValuesLoc);
return false;
}
@ -4057,8 +4044,9 @@ bool AsmParser::parseDirectiveBundleUnlock() {
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;
@ -4076,12 +4064,8 @@ bool AsmParser::parseDirectiveSpace(StringRef IDVal) {
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().emitFill(*NumBytes, FillExpr, NumBytesLoc);
return false;
}

View File

@ -135,9 +135,18 @@ void MCStreamer::EmitGPRel32Value(const MCExpr *Value) {
/// EmitFill - Emit NumBytes bytes worth of the value specified by
/// FillValue. This implements directives such as '.space'.
void MCStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue) {
const MCExpr *E = MCConstantExpr::create(FillValue, getContext());
for (uint64_t i = 0, e = NumBytes; i != e; ++i)
EmitValue(E, 1);
EmitIntValue(FillValue, 1);
}
void MCStreamer::emitFill(uint64_t NumValues, int64_t Size, int64_t Expr) {
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);
}
}
/// The implementation in this class just redirects to EmitFill.
@ -757,6 +766,9 @@ void MCStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) {
}
void MCStreamer::EmitULEB128Value(const MCExpr *Value) {}
void MCStreamer::EmitSLEB128Value(const MCExpr *Value) {}
void MCStreamer::emitFill(const MCExpr &NumBytes, uint64_t Value, SMLoc Loc) {}
void MCStreamer::emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr,
SMLoc Loc) {}
void MCStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value,
unsigned ValueSize,
unsigned MaxBytesToEmit) {}

View File

@ -1,66 +1,53 @@
# 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
# CHECK: TEST0:
# CHECK: .byte 10
# CHECK: .fill 1, 1, 0xa
TEST0:
.fill 1, 1, 10
# CHECK: TEST1:
# CHECK: .short 3
# CHECK: .short 3
# CHECK: .fill 2, 2, 0x3
TEST1:
.fill 2, 2, 3
# CHECK: TEST2:
# CHECK: .long 4
# CHECK: .long 0
# CHECK: .fill 1, 8, 0x4
TEST2:
.fill 1, 8, 4
# CHECK: TEST3
# CHECK: .byte 0
# CHECK: .byte 0
# CHECK: .byte 0
# CHECK: .byte 0
# CHECK: .fill 4
TEST3:
.fill 4
# CHECK: TEST4
# CHECK: .short 0
# CHECK: .short 0
# CHECK: .short 0
# CHECK: .short 0
# CHECK: .fill 4, 2
TEST4:
.fill 4, 2
# CHECK: TEST5
# CHECK: .short 2
# CHECK: .byte 0
# CHECK: .short 2
# CHECK: .byte 0
# CHECK: .short 2
# CHECK: .byte 0
# CHECK: .short 2
# CHECK: .byte 0
# CHECK: .fill 4, 3, 0x2
TEST5:
.fill 4, 3, 2
# CHECK: TEST6
# CHECK: .long 2
# CHECK: .long 0
# CHECK: .fill 1, 8, 0x2
# CHECK-WARNINGS: '.fill' directive with size greater than 8 has been truncated to 8
TEST6:
.fill 1, 9, 2
# CHECK: TEST7
# CHECK: .long 0
# CHECK: .long 0
# CHECK: .fill 1, 8, 0x0
# CHECK-WARNINGS: '.fill' directive pattern has been truncated to 32-bits
TEST7:
.fill 1, 8, 1<<32
# CHECK-WARNINGS: '.fill' directive with negative repeat count has no effect
# CHECK: TEST8
# CHECK: .fill -1, 8, 0x1
# OBJ-WARNINGS: '.fill' directive with negative repeat count has no effect
TEST8:
.fill -1, 8, 1
@ -69,7 +56,17 @@ TEST9:
.fill 1, -1, 1
# CHECK: TEST10
# CHECK: .short 22136
# CHECK: .byte 52
# CHECK: .fill 1, 3, 0x12345678
TEST10:
.fill 1, 3, 0x12345678
# CHECK: TEST11
# CHECK: .fill TEST11-TEST10, 1, 0x0
TEST11:
.fill TEST11 - TEST10
# CHECK: TEST12
# CHECK: .fill TEST11-TEST12, 3, 0x12345678
# OBJ-WARNINGS: '.fill' directive with negative repeat count has no effect
TEST12:
.fill TEST11 - TEST12, 3, 0x12345678

View File

@ -14,3 +14,8 @@ TEST1:
# CHECK: .space 1
TEST2:
.skip 1
# CHECK: TEST3
# CHECK: .space TEST0-TEST1
TEST3:
.space TEST0 - TEST1