summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDavid Majnemer <david.majnemer@gmail.com>2014-02-01 07:19:38 +0000
committerDavid Majnemer <david.majnemer@gmail.com>2014-02-01 07:19:38 +0000
commite18fc7bc2d947abc4ab6c07a0efbb6285ed404d2 (patch)
tree352b153164b57fcbc8d49f917ec2f900ca3aabee /lib
parent69a0d80f55a0994ee857415bcc348d6d54c9ec1a (diff)
downloadllvm-e18fc7bc2d947abc4ab6c07a0efbb6285ed404d2.tar.gz
llvm-e18fc7bc2d947abc4ab6c07a0efbb6285ed404d2.tar.bz2
llvm-e18fc7bc2d947abc4ab6c07a0efbb6285ed404d2.tar.xz
MC: Improve the .fill directive's compatibility with GAS
Per the GAS documentation, .fill should permit pattern widths that aren't a power of two. While I was in the neighborhood, I added some sanity checking. This change was motivated by a use of this construct in the Linux Kernel. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@200606 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/MC/MCAsmStreamer.cpp39
-rw-r--r--lib/MC/MCParser/AsmParser.cpp32
2 files changed, 57 insertions, 14 deletions
diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp
index a8885164a8..1791f73832 100644
--- a/lib/MC/MCAsmStreamer.cpp
+++ b/lib/MC/MCAsmStreamer.cpp
@@ -673,6 +673,7 @@ void MCAsmStreamer::EmitIntValue(uint64_t Value, unsigned Size) {
}
void MCAsmStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size) {
+ assert(Size <= 8 && "Invalid size");
assert(getCurrentSection().first &&
"Cannot emit contents before setting section!");
const char *Directive = 0;
@@ -681,19 +682,37 @@ void MCAsmStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size) {
case 1: Directive = MAI->getData8bitsDirective(); break;
case 2: Directive = MAI->getData16bitsDirective(); break;
case 4: Directive = MAI->getData32bitsDirective(); break;
- case 8:
- Directive = MAI->getData64bitsDirective();
- // If the target doesn't support 64-bit data, emit as two 32-bit halves.
- if (Directive) break;
+ case 8: Directive = MAI->getData64bitsDirective(); break;
+ }
+
+ if (!Directive) {
int64_t IntValue;
if (!Value->EvaluateAsAbsolute(IntValue))
report_fatal_error("Don't know how to emit this value.");
- if (MAI->isLittleEndian()) {
- EmitIntValue((uint32_t)(IntValue >> 0 ), 4);
- EmitIntValue((uint32_t)(IntValue >> 32), 4);
- } else {
- EmitIntValue((uint32_t)(IntValue >> 32), 4);
- EmitIntValue((uint32_t)(IntValue >> 0 ), 4);
+
+ // We couldn't handle the requested integer size so we fallback by breaking
+ // the request down into several, smaller, integers. Since sizes greater
+ // than eight are invalid and size equivalent to eight should have been
+ // handled earlier, we use four bytes as our largest piece of granularity.
+ bool IsLittleEndian = MAI->isLittleEndian();
+ for (unsigned Emitted = 0; Emitted != Size;) {
+ unsigned Remaining = Size - Emitted;
+ // The size of our partial emission must be a power of two less than
+ // eight.
+ unsigned EmissionSize = PowerOf2Floor(Remaining);
+ if (EmissionSize > 4)
+ EmissionSize = 4;
+ // Calculate the byte offset of our partial emission taking into account
+ // the endianness of the target.
+ unsigned ByteOffset =
+ IsLittleEndian ? Emitted : (Remaining - EmissionSize);
+ uint64_t ValueToEmit = IntValue >> (ByteOffset * 8);
+ // We truncate our partial emission to fit within the bounds of the
+ // emission domain. This produces nicer output and silences potential
+ // truncation warnings when round tripping through another assembler.
+ ValueToEmit &= ~0ULL >> (64 - EmissionSize * 8);
+ EmitIntValue(ValueToEmit, EmissionSize);
+ Emitted += EmissionSize;
}
return;
}
diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp
index 3f813a73cc..9157ac4f67 100644
--- a/lib/MC/MCParser/AsmParser.cpp
+++ b/lib/MC/MCParser/AsmParser.cpp
@@ -2397,18 +2397,27 @@ bool AsmParser::parseDirectiveZero() {
bool AsmParser::parseDirectiveFill() {
checkForValidSection();
+ SMLoc RepeatLoc = getLexer().getLoc();
int64_t NumValues;
if (parseAbsoluteExpression(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;
+ SMLoc SizeLoc, ExprLoc;
if (getLexer().isNot(AsmToken::EndOfStatement)) {
if (getLexer().isNot(AsmToken::Comma))
return TokError("unexpected token in '.fill' directive");
Lex();
+ SizeLoc = getLexer().getLoc();
if (parseAbsoluteExpression(FillSize))
return true;
@@ -2417,6 +2426,7 @@ bool AsmParser::parseDirectiveFill() {
return TokError("unexpected token in '.fill' directive");
Lex();
+ ExprLoc = getLexer().getLoc();
if (parseAbsoluteExpression(FillExpr))
return true;
@@ -2427,11 +2437,25 @@ bool AsmParser::parseDirectiveFill() {
}
}
- if (FillSize != 1 && FillSize != 2 && FillSize != 4 && FillSize != 8)
- return TokError("invalid '.fill' size, expected 1, 2, 4, or 8");
+ if (FillSize < 0) {
+ Warning(SizeLoc, "'.fill' directive with negative size has no effect");
+ NumValues = 0;
+ }
+ if (FillSize > 8) {
+ Warning(SizeLoc, "'.fill' directive with size greater than 8 has been truncated to 8");
+ FillSize = 8;
+ }
- for (uint64_t i = 0, e = NumValues; i != e; ++i)
- getStreamer().EmitIntValue(FillExpr, FillSize);
+ if (!isUInt<32>(FillExpr) && FillSize > 4)
+ Warning(ExprLoc, "'.fill' directive pattern has been truncated to 32-bits");
+
+ 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);
+ getStreamer().EmitIntValue(0, FillSize - NonZeroFillSize);
+ }
return false;
}