[TableGen][CodeEmitterGen] Allow local names for sub-operands in a operand list.
These names can then be matched by name against 'bits' fields in a record, to populate an instruction's encoding. This does _not_ yet change DecoderEmitter to allow by-name matching of sub-operands. Unlike the encoder, the decoder already defaulted to not supporting positional matching, and backends had workarounds in place for the missing decoding support. Additionally, use this new capability to allow the ARM and AArch64 backends not to require any positional operand matching. Differential Revision: https://reviews.llvm.org/D131003
This commit is contained in:
parent
e657acd449
commit
a538d1f13a
|
@ -2238,6 +2238,7 @@ static void ProfileDagInit(FoldingSetNodeID &ID, Init *V, StringInit *VN,
|
||||||
|
|
||||||
DagInit *DagInit::get(Init *V, StringInit *VN, ArrayRef<Init *> ArgRange,
|
DagInit *DagInit::get(Init *V, StringInit *VN, ArrayRef<Init *> ArgRange,
|
||||||
ArrayRef<StringInit *> NameRange) {
|
ArrayRef<StringInit *> NameRange) {
|
||||||
|
assert(ArgRange.size() == NameRange.size());
|
||||||
FoldingSetNodeID ID;
|
FoldingSetNodeID ID;
|
||||||
ProfileDagInit(ID, V, VN, ArgRange, NameRange);
|
ProfileDagInit(ID, V, VN, ArgRange, NameRange);
|
||||||
|
|
||||||
|
|
|
@ -2483,27 +2483,23 @@ class BaseAddSubRegPseudo<RegisterClass regtype,
|
||||||
class BaseAddSubSReg<bit isSub, bit setFlags, RegisterClass regtype,
|
class BaseAddSubSReg<bit isSub, bit setFlags, RegisterClass regtype,
|
||||||
arith_shifted_reg shifted_regtype, string asm,
|
arith_shifted_reg shifted_regtype, string asm,
|
||||||
SDPatternOperator OpNode>
|
SDPatternOperator OpNode>
|
||||||
: I<(outs regtype:$Rd), (ins regtype:$Rn, shifted_regtype:$Rm),
|
: I<(outs regtype:$Rd), (ins regtype:$Rn, (shifted_regtype $Rm, $shift):$Rm_and_shift),
|
||||||
asm, "\t$Rd, $Rn, $Rm", "",
|
asm, "\t$Rd, $Rn, $Rm_and_shift", "",
|
||||||
[(set regtype:$Rd, (OpNode regtype:$Rn, shifted_regtype:$Rm))]>,
|
[(set regtype:$Rd, (OpNode regtype:$Rn, shifted_regtype:$Rm_and_shift))]>,
|
||||||
Sched<[WriteISReg, ReadI, ReadISReg]> {
|
Sched<[WriteISReg, ReadI, ReadISReg]> {
|
||||||
// The operands are in order to match the 'addr' MI operands, so we
|
bits<5> Rd;
|
||||||
// don't need an encoder method and by-name matching. Just use the default
|
bits<5> Rn;
|
||||||
// in-order handling. Since we're using by-order, make sure the names
|
bits<5> Rm;
|
||||||
// do not match.
|
|
||||||
bits<5> dst;
|
|
||||||
bits<5> src1;
|
|
||||||
bits<5> src2;
|
|
||||||
bits<8> shift;
|
bits<8> shift;
|
||||||
let Inst{30} = isSub;
|
let Inst{30} = isSub;
|
||||||
let Inst{29} = setFlags;
|
let Inst{29} = setFlags;
|
||||||
let Inst{28-24} = 0b01011;
|
let Inst{28-24} = 0b01011;
|
||||||
let Inst{23-22} = shift{7-6};
|
let Inst{23-22} = shift{7-6};
|
||||||
let Inst{21} = 0;
|
let Inst{21} = 0;
|
||||||
let Inst{20-16} = src2;
|
let Inst{20-16} = Rm;
|
||||||
let Inst{15-10} = shift{5-0};
|
let Inst{15-10} = shift{5-0};
|
||||||
let Inst{9-5} = src1;
|
let Inst{9-5} = Rn;
|
||||||
let Inst{4-0} = dst;
|
let Inst{4-0} = Rd;
|
||||||
|
|
||||||
let DecoderMethod = "DecodeThreeAddrSRegInstruction";
|
let DecoderMethod = "DecodeThreeAddrSRegInstruction";
|
||||||
}
|
}
|
||||||
|
@ -2511,22 +2507,22 @@ class BaseAddSubSReg<bit isSub, bit setFlags, RegisterClass regtype,
|
||||||
class BaseAddSubEReg<bit isSub, bit setFlags, RegisterClass dstRegtype,
|
class BaseAddSubEReg<bit isSub, bit setFlags, RegisterClass dstRegtype,
|
||||||
RegisterClass src1Regtype, Operand src2Regtype,
|
RegisterClass src1Regtype, Operand src2Regtype,
|
||||||
string asm, SDPatternOperator OpNode>
|
string asm, SDPatternOperator OpNode>
|
||||||
: I<(outs dstRegtype:$R1),
|
: I<(outs dstRegtype:$Rd),
|
||||||
(ins src1Regtype:$R2, src2Regtype:$R3),
|
(ins src1Regtype:$Rn, (src2Regtype $Rm, $extend):$Rm_and_extend),
|
||||||
asm, "\t$R1, $R2, $R3", "",
|
asm, "\t$Rd, $Rn, $Rm_and_extend", "",
|
||||||
[(set dstRegtype:$R1, (OpNode src1Regtype:$R2, src2Regtype:$R3))]>,
|
[(set dstRegtype:$Rd, (OpNode src1Regtype:$Rn, src2Regtype:$Rm_and_extend))]>,
|
||||||
Sched<[WriteIEReg, ReadI, ReadIEReg]> {
|
Sched<[WriteIEReg, ReadI, ReadIEReg]> {
|
||||||
bits<5> Rd;
|
bits<5> Rd;
|
||||||
bits<5> Rn;
|
bits<5> Rn;
|
||||||
bits<5> Rm;
|
bits<5> Rm;
|
||||||
bits<6> ext;
|
bits<6> extend;
|
||||||
let Inst{30} = isSub;
|
let Inst{30} = isSub;
|
||||||
let Inst{29} = setFlags;
|
let Inst{29} = setFlags;
|
||||||
let Inst{28-24} = 0b01011;
|
let Inst{28-24} = 0b01011;
|
||||||
let Inst{23-21} = 0b001;
|
let Inst{23-21} = 0b001;
|
||||||
let Inst{20-16} = Rm;
|
let Inst{20-16} = Rm;
|
||||||
let Inst{15-13} = ext{5-3};
|
let Inst{15-13} = extend{5-3};
|
||||||
let Inst{12-10} = ext{2-0};
|
let Inst{12-10} = extend{2-0};
|
||||||
let Inst{9-5} = Rn;
|
let Inst{9-5} = Rn;
|
||||||
let Inst{4-0} = Rd;
|
let Inst{4-0} = Rd;
|
||||||
|
|
||||||
|
@ -2913,25 +2909,21 @@ class BaseLogicalImm<bits<2> opc, RegisterClass dregtype,
|
||||||
class BaseLogicalSReg<bits<2> opc, bit N, RegisterClass regtype,
|
class BaseLogicalSReg<bits<2> opc, bit N, RegisterClass regtype,
|
||||||
logical_shifted_reg shifted_regtype, string asm,
|
logical_shifted_reg shifted_regtype, string asm,
|
||||||
list<dag> pattern>
|
list<dag> pattern>
|
||||||
: I<(outs regtype:$Rd), (ins regtype:$Rn, shifted_regtype:$Rm),
|
: I<(outs regtype:$Rd), (ins regtype:$Rn, (shifted_regtype $Rm, $shift):$Rm_and_shift),
|
||||||
asm, "\t$Rd, $Rn, $Rm", "", pattern>,
|
asm, "\t$Rd, $Rn, $Rm_and_shift", "", pattern>,
|
||||||
Sched<[WriteISReg, ReadI, ReadISReg]> {
|
Sched<[WriteISReg, ReadI, ReadISReg]> {
|
||||||
// The operands are in order to match the 'addr' MI operands, so we
|
bits<5> Rd;
|
||||||
// don't need an encoder method and by-name matching. Just use the default
|
bits<5> Rn;
|
||||||
// in-order handling. Since we're using by-order, make sure the names
|
bits<5> Rm;
|
||||||
// do not match.
|
|
||||||
bits<5> dst;
|
|
||||||
bits<5> src1;
|
|
||||||
bits<5> src2;
|
|
||||||
bits<8> shift;
|
bits<8> shift;
|
||||||
let Inst{30-29} = opc;
|
let Inst{30-29} = opc;
|
||||||
let Inst{28-24} = 0b01010;
|
let Inst{28-24} = 0b01010;
|
||||||
let Inst{23-22} = shift{7-6};
|
let Inst{23-22} = shift{7-6};
|
||||||
let Inst{21} = N;
|
let Inst{21} = N;
|
||||||
let Inst{20-16} = src2;
|
let Inst{20-16} = Rm;
|
||||||
let Inst{15-10} = shift{5-0};
|
let Inst{15-10} = shift{5-0};
|
||||||
let Inst{9-5} = src1;
|
let Inst{9-5} = Rn;
|
||||||
let Inst{4-0} = dst;
|
let Inst{4-0} = Rd;
|
||||||
|
|
||||||
let DecoderMethod = "DecodeThreeAddrSRegInstruction";
|
let DecoderMethod = "DecodeThreeAddrSRegInstruction";
|
||||||
}
|
}
|
||||||
|
@ -3002,12 +2994,12 @@ multiclass LogicalReg<bits<2> opc, bit N, string mnemonic,
|
||||||
|
|
||||||
def Wrs : BaseLogicalSReg<opc, N, GPR32, logical_shifted_reg32, mnemonic,
|
def Wrs : BaseLogicalSReg<opc, N, GPR32, logical_shifted_reg32, mnemonic,
|
||||||
[(set GPR32:$Rd, (OpNode GPR32:$Rn,
|
[(set GPR32:$Rd, (OpNode GPR32:$Rn,
|
||||||
logical_shifted_reg32:$Rm))]> {
|
logical_shifted_reg32:$Rm_and_shift))]> {
|
||||||
let Inst{31} = 0;
|
let Inst{31} = 0;
|
||||||
}
|
}
|
||||||
def Xrs : BaseLogicalSReg<opc, N, GPR64, logical_shifted_reg64, mnemonic,
|
def Xrs : BaseLogicalSReg<opc, N, GPR64, logical_shifted_reg64, mnemonic,
|
||||||
[(set GPR64:$Rd, (OpNode GPR64:$Rn,
|
[(set GPR64:$Rd, (OpNode GPR64:$Rn,
|
||||||
logical_shifted_reg64:$Rm))]> {
|
logical_shifted_reg64:$Rm_and_shift))]> {
|
||||||
let Inst{31} = 1;
|
let Inst{31} = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3025,11 +3017,11 @@ multiclass LogicalRegS<bits<2> opc, bit N, string mnemonic,
|
||||||
def Xrr : BaseLogicalRegPseudo<GPR64, OpNode>;
|
def Xrr : BaseLogicalRegPseudo<GPR64, OpNode>;
|
||||||
|
|
||||||
def Wrs : BaseLogicalSReg<opc, N, GPR32, logical_shifted_reg32, mnemonic,
|
def Wrs : BaseLogicalSReg<opc, N, GPR32, logical_shifted_reg32, mnemonic,
|
||||||
[(set GPR32:$Rd, (OpNode GPR32:$Rn, logical_shifted_reg32:$Rm))]> {
|
[(set GPR32:$Rd, (OpNode GPR32:$Rn, logical_shifted_reg32:$Rm_and_shift))]> {
|
||||||
let Inst{31} = 0;
|
let Inst{31} = 0;
|
||||||
}
|
}
|
||||||
def Xrs : BaseLogicalSReg<opc, N, GPR64, logical_shifted_reg64, mnemonic,
|
def Xrs : BaseLogicalSReg<opc, N, GPR64, logical_shifted_reg64, mnemonic,
|
||||||
[(set GPR64:$Rd, (OpNode GPR64:$Rn, logical_shifted_reg64:$Rm))]> {
|
[(set GPR64:$Rd, (OpNode GPR64:$Rn, logical_shifted_reg64:$Rm_and_shift))]> {
|
||||||
let Inst{31} = 1;
|
let Inst{31} = 1;
|
||||||
}
|
}
|
||||||
} // Defs = [NZCV]
|
} // Defs = [NZCV]
|
||||||
|
|
|
@ -3896,7 +3896,7 @@ def t2TBH_JT : t2PseudoInst<(outs),
|
||||||
(ins GPR:$base, GPR:$index, i32imm:$jt, i32imm:$pclbl), 0, IIC_Br, []>,
|
(ins GPR:$base, GPR:$index, i32imm:$jt, i32imm:$pclbl), 0, IIC_Br, []>,
|
||||||
Sched<[WriteBr]>;
|
Sched<[WriteBr]>;
|
||||||
|
|
||||||
def t2TBB : T2I<(outs), (ins addrmode_tbb:$addr), IIC_Br,
|
def t2TBB : T2I<(outs), (ins (addrmode_tbb $Rn, $Rm):$addr), IIC_Br,
|
||||||
"tbb", "\t$addr", []>, Sched<[WriteBrTbl]> {
|
"tbb", "\t$addr", []>, Sched<[WriteBrTbl]> {
|
||||||
bits<4> Rn;
|
bits<4> Rn;
|
||||||
bits<4> Rm;
|
bits<4> Rm;
|
||||||
|
@ -3909,7 +3909,7 @@ def t2TBB : T2I<(outs), (ins addrmode_tbb:$addr), IIC_Br,
|
||||||
let DecoderMethod = "DecodeThumbTableBranch";
|
let DecoderMethod = "DecodeThumbTableBranch";
|
||||||
}
|
}
|
||||||
|
|
||||||
def t2TBH : T2I<(outs), (ins addrmode_tbh:$addr), IIC_Br,
|
def t2TBH : T2I<(outs), (ins (addrmode_tbh $Rn, $Rm):$addr), IIC_Br,
|
||||||
"tbh", "\t$addr", []>, Sched<[WriteBrTbl]> {
|
"tbh", "\t$addr", []>, Sched<[WriteBrTbl]> {
|
||||||
bits<4> Rn;
|
bits<4> Rn;
|
||||||
bits<4> Rm;
|
bits<4> Rm;
|
||||||
|
|
|
@ -105,7 +105,10 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,
|
||||||
// operand number. Non-matching operands are assumed to be in
|
// operand number. Non-matching operands are assumed to be in
|
||||||
// order.
|
// order.
|
||||||
unsigned OpIdx;
|
unsigned OpIdx;
|
||||||
if (CGI.Operands.hasOperandNamed(VarName, OpIdx)) {
|
std::pair<unsigned, unsigned> SubOp;
|
||||||
|
if (CGI.Operands.hasSubOperandAlias(VarName, SubOp)) {
|
||||||
|
OpIdx = CGI.Operands[SubOp.first].MIOperandNo + SubOp.second;
|
||||||
|
} else if (CGI.Operands.hasOperandNamed(VarName, OpIdx)) {
|
||||||
// Get the machine operand number for the indicated operand.
|
// Get the machine operand number for the indicated operand.
|
||||||
OpIdx = CGI.Operands[OpIdx].MIOperandNo;
|
OpIdx = CGI.Operands[OpIdx].MIOperandNo;
|
||||||
assert(!CGI.Operands.isFlatOperandNotEmitted(OpIdx) &&
|
assert(!CGI.Operands.isFlatOperandNotEmitted(OpIdx) &&
|
||||||
|
@ -133,7 +136,7 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,
|
||||||
|
|
||||||
OpIdx = NumberedOp++;
|
OpIdx = NumberedOp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<unsigned, unsigned> SO = CGI.Operands.getSubOperandNumber(OpIdx);
|
std::pair<unsigned, unsigned> SO = CGI.Operands.getSubOperandNumber(OpIdx);
|
||||||
std::string &EncoderMethodName = CGI.Operands[SO.first].EncoderMethodName;
|
std::string &EncoderMethodName = CGI.Operands[SO.first].EncoderMethodName;
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,10 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
|
||||||
ArgName = InDI->getArgNameStr(i-NumDefs);
|
ArgName = InDI->getArgNameStr(i-NumDefs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DagInit *SubArgDag = dyn_cast<DagInit>(ArgInit);
|
||||||
|
if (SubArgDag)
|
||||||
|
ArgInit = SubArgDag->getOperator();
|
||||||
|
|
||||||
DefInit *Arg = dyn_cast<DefInit>(ArgInit);
|
DefInit *Arg = dyn_cast<DefInit>(ArgInit);
|
||||||
if (!Arg)
|
if (!Arg)
|
||||||
PrintFatalError(R->getLoc(), "Illegal operand for the '" + R->getName() +
|
PrintFatalError(R->getLoc(), "Illegal operand for the '" + R->getName() +
|
||||||
|
@ -132,6 +136,36 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
|
||||||
Twine(i) +
|
Twine(i) +
|
||||||
" has the same name as a previous operand!");
|
" has the same name as a previous operand!");
|
||||||
|
|
||||||
|
if (SubArgDag) {
|
||||||
|
if (SubArgDag->getNumArgs() != NumOps) {
|
||||||
|
PrintFatalError(R->getLoc(), "In instruction '" + R->getName() +
|
||||||
|
"', operand #" + Twine(i) + " has " +
|
||||||
|
Twine(SubArgDag->getNumArgs()) +
|
||||||
|
" sub-arg names, expected " +
|
||||||
|
Twine(NumOps) + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned j = 0; j < NumOps; ++j) {
|
||||||
|
if (!isa<UnsetInit>(SubArgDag->getArg(j)))
|
||||||
|
PrintFatalError(R->getLoc(),
|
||||||
|
"In instruction '" + R->getName() + "', operand #" +
|
||||||
|
Twine(i) + " sub-arg #" + Twine(j) +
|
||||||
|
" has unexpected operand (expected only $name).");
|
||||||
|
|
||||||
|
StringRef SubArgName = SubArgDag->getArgNameStr(j);
|
||||||
|
if (SubArgName.empty())
|
||||||
|
PrintFatalError(R->getLoc(), "In instruction '" + R->getName() +
|
||||||
|
"', operand #" + Twine(i) +
|
||||||
|
" has no name!");
|
||||||
|
if (!OperandNames.insert(std::string(SubArgName)).second)
|
||||||
|
PrintFatalError(R->getLoc(),
|
||||||
|
"In instruction '" + R->getName() + "', operand #" +
|
||||||
|
Twine(i) + " sub-arg #" + Twine(j) +
|
||||||
|
" has the same name as a previous operand!");
|
||||||
|
SubOpAliases[SubArgName] = std::make_pair(MIOperandNo, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
OperandList.emplace_back(
|
OperandList.emplace_back(
|
||||||
Rec, std::string(ArgName), std::string(PrintMethod),
|
Rec, std::string(ArgName), std::string(PrintMethod),
|
||||||
std::string(EncoderMethod), OperandNamespace + "::" + OperandType,
|
std::string(EncoderMethod), OperandNamespace + "::" + OperandType,
|
||||||
|
@ -175,6 +209,17 @@ bool CGIOperandList::hasOperandNamed(StringRef Name, unsigned &OpIdx) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CGIOperandList::hasSubOperandAlias(
|
||||||
|
StringRef Name, std::pair<unsigned, unsigned> &SubOp) const {
|
||||||
|
assert(!Name.empty() && "Cannot search for operand with no name!");
|
||||||
|
auto SubOpIter = SubOpAliases.find(Name);
|
||||||
|
if (SubOpIter != SubOpAliases.end()) {
|
||||||
|
SubOp = SubOpIter->second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::pair<unsigned,unsigned>
|
std::pair<unsigned,unsigned>
|
||||||
CGIOperandList::ParseOperandName(StringRef Op, bool AllowWholeOp) {
|
CGIOperandList::ParseOperandName(StringRef Op, bool AllowWholeOp) {
|
||||||
if (Op.empty() || Op[0] != '$')
|
if (Op.empty() || Op[0] != '$')
|
||||||
|
@ -195,7 +240,21 @@ CGIOperandList::ParseOperandName(StringRef Op, bool AllowWholeOp) {
|
||||||
OpName = OpName.substr(0, DotIdx);
|
OpName = OpName.substr(0, DotIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned OpIdx = getOperandNamed(OpName);
|
unsigned OpIdx;
|
||||||
|
|
||||||
|
if (std::pair<unsigned, unsigned> SubOp; hasSubOperandAlias(OpName, SubOp)) {
|
||||||
|
// Found a name for a piece of an operand, just return it directly.
|
||||||
|
if (!SubOpName.empty()) {
|
||||||
|
PrintFatalError(
|
||||||
|
TheDef->getLoc(),
|
||||||
|
TheDef->getName() +
|
||||||
|
": Cannot use dotted suboperand name within suboperand '" +
|
||||||
|
OpName + "'");
|
||||||
|
}
|
||||||
|
return SubOp;
|
||||||
|
}
|
||||||
|
|
||||||
|
OpIdx = getOperandNamed(OpName);
|
||||||
|
|
||||||
if (SubOpName.empty()) { // If no suboperand name was specified:
|
if (SubOpName.empty()) { // If no suboperand name was specified:
|
||||||
// If one was needed, throw.
|
// If one was needed, throw.
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#define LLVM_UTILS_TABLEGEN_CODEGENINSTRUCTION_H
|
#define LLVM_UTILS_TABLEGEN_CODEGENINSTRUCTION_H
|
||||||
|
|
||||||
#include "llvm/ADT/BitVector.h"
|
#include "llvm/ADT/BitVector.h"
|
||||||
|
#include "llvm/ADT/StringMap.h"
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
#include "llvm/Support/MachineValueType.h"
|
#include "llvm/Support/MachineValueType.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
@ -149,6 +150,9 @@ template <typename T> class ArrayRef;
|
||||||
/// type (which is a record).
|
/// type (which is a record).
|
||||||
std::vector<OperandInfo> OperandList;
|
std::vector<OperandInfo> OperandList;
|
||||||
|
|
||||||
|
/// SubOpAliases - List of alias names for suboperands.
|
||||||
|
StringMap<std::pair<unsigned, unsigned>> SubOpAliases;
|
||||||
|
|
||||||
// Information gleaned from the operand list.
|
// Information gleaned from the operand list.
|
||||||
bool isPredicable;
|
bool isPredicable;
|
||||||
bool hasOptionalDef;
|
bool hasOptionalDef;
|
||||||
|
@ -179,6 +183,9 @@ template <typename T> class ArrayRef;
|
||||||
/// operand. Otherwise, return false.
|
/// operand. Otherwise, return false.
|
||||||
bool hasOperandNamed(StringRef Name, unsigned &OpIdx) const;
|
bool hasOperandNamed(StringRef Name, unsigned &OpIdx) const;
|
||||||
|
|
||||||
|
bool hasSubOperandAlias(StringRef Name,
|
||||||
|
std::pair<unsigned, unsigned> &SubOp) const;
|
||||||
|
|
||||||
/// ParseOperandName - Parse an operand name like "$foo" or "$foo.bar",
|
/// ParseOperandName - Parse an operand name like "$foo" or "$foo.bar",
|
||||||
/// where $foo is a whole operand and $foo.bar refers to a suboperand.
|
/// where $foo is a whole operand and $foo.bar refers to a suboperand.
|
||||||
/// This aborts if the name is invalid. If AllowWholeOp is true, references
|
/// This aborts if the name is invalid. If AllowWholeOp is true, references
|
||||||
|
|
|
@ -2160,7 +2160,10 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
|
||||||
// to interpret it. As a first step, require the target to provide
|
// to interpret it. As a first step, require the target to provide
|
||||||
// callbacks for decoding register classes.
|
// callbacks for decoding register classes.
|
||||||
|
|
||||||
OperandInfo OpInfo = getOpInfo(cast<DefInit>(Op.first)->getDef());
|
Init *OpInit = Op.first;
|
||||||
|
if (DagInit *Dag = dyn_cast<DagInit>(OpInit))
|
||||||
|
OpInit = Dag->getOperator();
|
||||||
|
OperandInfo OpInfo = getOpInfo(cast<DefInit>(OpInit)->getDef());
|
||||||
|
|
||||||
// Some bits of the operand may be required to be 1 depending on the
|
// Some bits of the operand may be required to be 1 depending on the
|
||||||
// instruction's encoding. Collect those bits.
|
// instruction's encoding. Collect those bits.
|
||||||
|
|
Loading…
Reference in New Issue