Skip to content

Commit 713aced

Browse files
committed
[NFCI][MC][DecoderEmitter] Fix BitWidth for fixed length insts encodings
Change `InstructionEncoding` to use `Size` field to derive the BitWidth for fixed length instruction as opposed to the number of bits in the `Inst` field. For some backends, `Inst` has more bits that `Size`, but `Size` is the true size of the instruction. Also add validation that `Inst` has atleast `Size * 8` bits and any bits in `Inst` beyond that are either 0 or unset.
1 parent 4eeeb8a commit 713aced

File tree

2 files changed

+67
-1
lines changed

2 files changed

+67
-1
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: not llvm-tblgen -gen-disassembler -I %p/../../../include %s -DTEST1 2>&1 | FileCheck %s -DFILE=%s --check-prefix=CHECK-TEST1
2+
// RUN: not llvm-tblgen -gen-disassembler -I %p/../../../include %s -DTEST2 2>&1 | FileCheck %s -DFILE=%s --check-prefix=CHECK-TEST2
3+
include "llvm/Target/Target.td"
4+
5+
def archInstrInfo : InstrInfo { }
6+
7+
def arch : Target {
8+
let InstructionSet = archInstrInfo;
9+
}
10+
11+
#ifdef TEST1
12+
// CHECK-TEST1: [[FILE]]:[[@LINE+1]]:5: error: foo: Size is 16 bits, but Inst bits beyond that are not zero/unset
13+
def foo : Instruction {
14+
let OutOperandList = (outs);
15+
let InOperandList = (ins i32imm:$factor);
16+
let Size = 2;
17+
field bits<24> Inst;
18+
field bits<24> SoftFail = 0;
19+
bits<8> factor;
20+
let Inst{15...8} = factor{7...0};
21+
let Inst{20} = 1;
22+
}
23+
#endif
24+
25+
#ifdef TEST2
26+
// CHECK-TEST2: [[FILE]]:[[@LINE+1]]:5: error: bar: Size is 16 bits, but Inst specifies only 8 bits
27+
def bar : Instruction {
28+
let OutOperandList = (outs);
29+
let InOperandList = (ins i32imm:$factor);
30+
let Size = 2;
31+
field bits<8> Inst;
32+
field bits<8> SoftFail = 0;
33+
bits<4> factor;
34+
let Inst{4...1} = factor{3...0};
35+
}
36+
#endif

llvm/utils/TableGen/DecoderEmitter.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2023,6 +2023,7 @@ InstructionEncoding::InstructionEncoding(const Record *EncodingDef,
20232023
HasCompleteDecoder = EncodingDef->getValueAsBit("hasCompleteDecoder");
20242024

20252025
const RecordVal *InstField = EncodingDef->getValue("Inst");
2026+
20262027
if (const auto *DI = dyn_cast<DagInit>(InstField->getValue())) {
20272028
VarLenInst VLI(DI, InstField);
20282029
BitWidth = VLI.size();
@@ -2031,7 +2032,36 @@ InstructionEncoding::InstructionEncoding(const Record *EncodingDef,
20312032
parseVarLenOperands(VLI);
20322033
} else {
20332034
const auto *BI = cast<BitsInit>(InstField->getValue());
2034-
BitWidth = BI->getNumBits();
2035+
unsigned InstNumBits = BI->getNumBits();
2036+
2037+
// For fixed length instructions, sometimes the `Inst` field specifies more
2038+
// bits than the actual size of the instruction. In such cases, derive the
2039+
// BitWidth from the size and do some basic validation.
2040+
BitWidth = EncodingDef->getValueAsInt("Size") * 8;
2041+
if (InstNumBits < BitWidth)
2042+
PrintFatalError(EncodingDef, Twine(Name) + ": Size is " +
2043+
Twine(BitWidth) +
2044+
" bits, but Inst specifies only " +
2045+
Twine(InstNumBits) + " bits");
2046+
2047+
if (InstNumBits > BitWidth) {
2048+
// Ensure that all the bits beyond 'Size' are 0 or unset (i.e., carry no
2049+
// actual encoding).
2050+
ArrayRef<const Init *> UpperBits = BI->getBits().drop_front(BitWidth);
2051+
bool UpperZeroOrUnset = llvm::all_of(UpperBits, [](const Init *Bit) {
2052+
if (const auto *BI = dyn_cast<BitInit>(Bit))
2053+
return !BI->getValue();
2054+
return isa<UnsetInit>(Bit);
2055+
});
2056+
if (!UpperZeroOrUnset) {
2057+
InstField->print(errs());
2058+
PrintFatalError(
2059+
EncodingDef,
2060+
Twine(Name) + ": Size is " + Twine(BitWidth) +
2061+
" bits, but Inst bits beyond that are not zero/unset");
2062+
}
2063+
}
2064+
20352065
// If the encoding has a custom decoder, don't bother parsing the operands.
20362066
if (DecoderMethod.empty())
20372067
parseFixedLenOperands(*BI);

0 commit comments

Comments
 (0)