Skip to content

Commit d54aeb8

Browse files
s-barannikovgithub-actions[bot]
authored andcommitted
Automerge: [TableGen][DecoderEmitter] Infer encoding's HasCompleteDecoder earlier (NFCI) (#154644)
If an encoding has a custom decoder, the decoder is assumed to be "complete" (always succeed) if hasCompleteDecoder field is true. We determine this when constructing InstructionEncoding. If the decoder for an encoding is *generated*, it always succeeds if none of the operand decoders can fail. The latter is determined based on the value of operands' DecoderMethod/hasCompleteDecoder. This happens late, at table construction time, making the code harder to follow. This change moves this logic to the InstructionEncoding constructor.
2 parents 6d1def9 + 2421929 commit d54aeb8

File tree

1 file changed

+38
-38
lines changed

1 file changed

+38
-38
lines changed

llvm/utils/TableGen/DecoderEmitter.cpp

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,10 @@ class InstructionEncoding {
147147
/// meaning the decoder is generated.
148148
StringRef DecoderMethod;
149149

150-
/// Whether the custom decoding function always succeeds. Should not be used
151-
/// if the decoder is generated.
152-
bool HasCompleteDecoder = true;
150+
/// Whether the custom decoding function always succeeds. If a custom decoder
151+
/// function is specified, the value is taken from the target description,
152+
/// otherwise it is inferred.
153+
bool HasCompleteDecoder;
153154

154155
/// Information about the operands' contribution to this encoding.
155156
SmallVector<OperandInfo, 16> Operands;
@@ -174,11 +175,9 @@ class InstructionEncoding {
174175
/// if the decoder is generated.
175176
StringRef getDecoderMethod() const { return DecoderMethod; }
176177

177-
/// Returns whether the custom decoding function always succeeds.
178-
bool hasCompleteDecoder() const {
179-
assert(!DecoderMethod.empty());
180-
return HasCompleteDecoder;
181-
}
178+
/// Returns whether the decoder (either generated or specified by the user)
179+
/// always succeeds.
180+
bool hasCompleteDecoder() const { return HasCompleteDecoder; }
182181

183182
/// Returns information about the operands' contribution to this encoding.
184183
ArrayRef<OperandInfo> getOperands() const { return Operands; }
@@ -658,12 +657,11 @@ class FilterChooser {
658657
void emitSingletonTableEntry(DecoderTableInfo &TableInfo,
659658
const Filter &Best) const;
660659

661-
bool emitBinaryParser(raw_ostream &OS, indent Indent,
660+
void emitBinaryParser(raw_ostream &OS, indent Indent,
662661
const OperandInfo &OpInfo) const;
663662

664-
bool emitDecoder(raw_ostream &OS, indent Indent, unsigned EncodingID) const;
665-
std::pair<unsigned, bool> getDecoderIndex(DecoderSet &Decoders,
666-
unsigned EncodingID) const;
663+
void emitDecoder(raw_ostream &OS, indent Indent, unsigned EncodingID) const;
664+
unsigned getDecoderIndex(DecoderSet &Decoders, unsigned EncodingID) const;
667665

668666
// Assign a single filter and run with it.
669667
void runSingleFilter(unsigned startBit, unsigned numBit);
@@ -1212,7 +1210,7 @@ FilterChooser::getIslands(const insn_t &Insn) const {
12121210
return Islands;
12131211
}
12141212

1215-
bool FilterChooser::emitBinaryParser(raw_ostream &OS, indent Indent,
1213+
void FilterChooser::emitBinaryParser(raw_ostream &OS, indent Indent,
12161214
const OperandInfo &OpInfo) const {
12171215
const std::string &Decoder = OpInfo.Decoder;
12181216

@@ -1238,65 +1236,56 @@ bool FilterChooser::emitBinaryParser(raw_ostream &OS, indent Indent,
12381236
OS << ";\n";
12391237
}
12401238

1241-
bool OpHasCompleteDecoder;
12421239
if (!Decoder.empty()) {
1243-
OpHasCompleteDecoder = OpInfo.HasCompleteDecoder;
12441240
OS << Indent << "if (!Check(S, " << Decoder
12451241
<< "(MI, tmp, Address, Decoder))) { "
1246-
<< (OpHasCompleteDecoder ? "" : "DecodeComplete = false; ")
1242+
<< (OpInfo.HasCompleteDecoder ? "" : "DecodeComplete = false; ")
12471243
<< "return MCDisassembler::Fail; }\n";
12481244
} else {
1249-
OpHasCompleteDecoder = true;
12501245
OS << Indent << "MI.addOperand(MCOperand::createImm(tmp));\n";
12511246
}
1252-
return OpHasCompleteDecoder;
12531247
}
12541248

1255-
bool FilterChooser::emitDecoder(raw_ostream &OS, indent Indent,
1249+
void FilterChooser::emitDecoder(raw_ostream &OS, indent Indent,
12561250
unsigned EncodingID) const {
12571251
const InstructionEncoding &Encoding = Encodings[EncodingID];
12581252

12591253
// If a custom instruction decoder was specified, use that.
12601254
StringRef DecoderMethod = Encoding.getDecoderMethod();
12611255
if (!DecoderMethod.empty()) {
1262-
bool HasCompleteDecoder = Encoding.hasCompleteDecoder();
12631256
OS << Indent << "if (!Check(S, " << DecoderMethod
12641257
<< "(MI, insn, Address, Decoder))) { "
1265-
<< (HasCompleteDecoder ? "" : "DecodeComplete = false; ")
1258+
<< (Encoding.hasCompleteDecoder() ? "" : "DecodeComplete = false; ")
12661259
<< "return MCDisassembler::Fail; }\n";
1267-
return HasCompleteDecoder;
1260+
return;
12681261
}
12691262

1270-
bool HasCompleteDecoder = true;
12711263
for (const OperandInfo &Op : Encoding.getOperands()) {
12721264
// FIXME: This is broken. If there is an operand that doesn't contribute
12731265
// to the encoding, we generate the same code as if the decoder method
12741266
// was specified on the encoding. And then we stop, ignoring the rest
12751267
// of the operands. M68k disassembler experiences this.
12761268
if (Op.numFields() == 0 && !Op.Decoder.empty()) {
1277-
HasCompleteDecoder = Op.HasCompleteDecoder;
12781269
OS << Indent << "if (!Check(S, " << Op.Decoder
12791270
<< "(MI, insn, Address, Decoder))) { "
1280-
<< (HasCompleteDecoder ? "" : "DecodeComplete = false; ")
1271+
<< (Op.HasCompleteDecoder ? "" : "DecodeComplete = false; ")
12811272
<< "return MCDisassembler::Fail; }\n";
12821273
break;
12831274
}
12841275

1285-
HasCompleteDecoder &= emitBinaryParser(OS, Indent, Op);
1276+
emitBinaryParser(OS, Indent, Op);
12861277
}
1287-
return HasCompleteDecoder;
12881278
}
12891279

1290-
std::pair<unsigned, bool>
1291-
FilterChooser::getDecoderIndex(DecoderSet &Decoders,
1292-
unsigned EncodingID) const {
1280+
unsigned FilterChooser::getDecoderIndex(DecoderSet &Decoders,
1281+
unsigned EncodingID) const {
12931282
// Build up the predicate string.
12941283
SmallString<256> Decoder;
12951284
// FIXME: emitDecoder() function can take a buffer directly rather than
12961285
// a stream.
12971286
raw_svector_ostream S(Decoder);
12981287
indent Indent(UseFnTableInDecodeToMCInst ? 2 : 4);
1299-
bool HasCompleteDecoder = emitDecoder(S, Indent, EncodingID);
1288+
emitDecoder(S, Indent, EncodingID);
13001289

13011290
// Using the full decoder string as the key value here is a bit
13021291
// heavyweight, but is effective. If the string comparisons become a
@@ -1308,7 +1297,7 @@ FilterChooser::getDecoderIndex(DecoderSet &Decoders,
13081297
Decoders.insert(CachedHashString(Decoder));
13091298
// Now figure out the index for when we write out the table.
13101299
DecoderSet::const_iterator P = find(Decoders, Decoder.str());
1311-
return {(unsigned)(P - Decoders.begin()), HasCompleteDecoder};
1300+
return std::distance(Decoders.begin(), P);
13121301
}
13131302

13141303
// If ParenIfBinOp is true, print a surrounding () if Val uses && or ||.
@@ -1508,8 +1497,7 @@ void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo,
15081497
// Check for soft failure of the match.
15091498
emitSoftFailTableEntry(TableInfo, EncodingID);
15101499

1511-
auto [DIdx, HasCompleteDecoder] =
1512-
getDecoderIndex(TableInfo.Decoders, EncodingID);
1500+
unsigned DIdx = getDecoderIndex(TableInfo.Decoders, EncodingID);
15131501

15141502
// Produce OPC_Decode or OPC_TryDecode opcode based on the information
15151503
// whether the instruction decoder is complete or not. If it is complete
@@ -1520,10 +1508,12 @@ void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo,
15201508
// decoder method indicates that additional processing should be done to see
15211509
// if there is any other instruction that also matches the bitpattern and
15221510
// can decode it.
1523-
const uint8_t DecoderOp = HasCompleteDecoder ? MCD::OPC_Decode
1524-
: (TableInfo.isOutermostScope()
1525-
? MCD::OPC_TryDecodeOrFail
1526-
: MCD::OPC_TryDecode);
1511+
const InstructionEncoding &Encoding = Encodings[EncodingID];
1512+
const uint8_t DecoderOp =
1513+
Encoding.hasCompleteDecoder()
1514+
? MCD::OPC_Decode
1515+
: (TableInfo.isOutermostScope() ? MCD::OPC_TryDecodeOrFail
1516+
: MCD::OPC_TryDecode);
15271517
TableInfo.Table.push_back(DecoderOp);
15281518
const Record *InstDef = Encodings[EncodingID].getInstruction()->TheDef;
15291519
TableInfo.Table.insertULEB128(Emitter->getTarget().getInstrIntValue(InstDef));
@@ -2124,6 +2114,16 @@ InstructionEncoding::InstructionEncoding(const Record *EncodingDef,
21242114
if (DecoderMethod.empty())
21252115
parseFixedLenOperands(*BI);
21262116
}
2117+
2118+
if (DecoderMethod.empty()) {
2119+
// A generated decoder is always successful if none of the operand
2120+
// decoders can fail (all are always successful).
2121+
HasCompleteDecoder = all_of(Operands, [](const OperandInfo &Op) {
2122+
// By default, a generated operand decoder is assumed to always succeed.
2123+
// This can be overridden by the user.
2124+
return Op.Decoder.empty() || Op.HasCompleteDecoder;
2125+
});
2126+
}
21272127
}
21282128

21292129
// emitFieldFromInstruction - Emit the templated helper function

0 commit comments

Comments
 (0)