forked from OSchip/llvm-project
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. llvm-svn: 200606
This commit is contained in:
parent
ad141abd63
commit
522d3db745
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue