summaryrefslogtreecommitdiff
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
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
-rw-r--r--lib/MC/MCAsmStreamer.cpp39
-rw-r--r--lib/MC/MCParser/AsmParser.cpp32
-rw-r--r--test/MC/AsmParser/directive_fill.s43
3 files changed, 99 insertions, 15 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;
}
diff --git a/test/MC/AsmParser/directive_fill.s b/test/MC/AsmParser/directive_fill.s
index bb3ced091c..11da32929f 100644
--- a/test/MC/AsmParser/directive_fill.s
+++ b/test/MC/AsmParser/directive_fill.s
@@ -1,4 +1,5 @@
-# RUN: llvm-mc -triple i386-unknown-unknown %s | FileCheck %s
+# RUN: llvm-mc -triple i386-unknown-unknown %s 2> %t.err | FileCheck %s
+# RUN: FileCheck --check-prefix=CHECK-WARNINGS %s < %t.err
# CHECK: TEST0:
# CHECK: .byte 10
@@ -31,3 +32,43 @@ TEST3:
# CHECK: .short 0
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
+TEST5:
+ .fill 4, 3, 2
+
+# CHECK: TEST6
+# CHECK: .long 2
+# CHECK: .long 0
+# 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-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
+TEST8:
+ .fill -1, 8, 1
+
+# CHECK-WARNINGS: '.fill' directive with negative size has no effect
+TEST9:
+ .fill 1, -1, 1
+
+# CHECK: TEST10
+# CHECK: .short 22136
+# CHECK: .byte 52
+TEST10:
+ .fill 1, 3, 0x12345678