TableGen:指令中嵌套操作数的OperandType
TableGen:指令中嵌套操作数的OperandType
Consider, for example, ARM’s predicate operand:
例如,考虑ARM的谓词操作数:
def pred : PredicateOperand<OtherVT, (ops i32imm, i32imm),
(ops (i32 14), (i32 zero_reg))> {
let PrintMethod = "printPredicateOperand";
let ParserMatchClass = CondCodeOperand;
let DecoderMethod = "DecodePredicateOperand";
}
Or addrmode5
class AddrMode5 : MemOperand,
ComplexPattern<i32, 2, "SelectAddrMode5", []> {
let EncoderMethod = "getAddrMode5OpValue";
let DecoderMethod = "DecodeAddrMode5Operand";
let ParserMatchClass = AddrMode5AsmOperand;
let MIOperandInfo = (ops GPR:$base, i32imm);
}
def addrmode5 : AddrMode5 {
let PrintMethod = "printAddrMode5Operand<false>";
}
例如,考虑ARM的谓词操作数:这些操作数在MIOperandInfo中有多个操作数组成整体。
These operands have multiple operands in MIOperandInfo composing the whole.
- pred (i32imm, i32imm)
- addrmode5 (GPR, i32imm)
“i32imm”被定义为OPERAND_IMMEDIATE类型,但InstrInfoEmitter::GetOperandInfo会为展平操作数列表(–gen instr info)中与i32immm关联的索引发出OPERAND_UNKNOWN类型。
这似乎是预期的行为。考虑上面的“pred” ,‘zero_reg’(寄存器)是默认值,但i32imm(立即数)是操作数类型。
‘i32imm’ is defined as type OPERAND_IMMEDIATE, but InstrInfoEmitter::GetOperandInfo emits the type OPERAND_UNKNOWN for the index associated with the i32imm in the flattened operand list (–gen-instr-info).
本希望机器代码验证器在指令中看到$noreg时标记一个错误,其中需要立即数,但因为操作数类型是UNKNOWN而不是immediate,所以跳过了该错误。
再深入一点,发现InstrInfoEmitter.cpp将每个子操作数的类型分配给包含操作数。
This seems to be expected behavior. Consider ‘pred’ above. ‘zero_reg’, a register, is a default value, but i32imm, an immediate, is the operand type. I would have expected the machine code verifier to flag an error when it saw $noreg in the instruction where an immediate is expected, but because the operand type is UNKNOWN instead of IMMEDIATE, the error is skipped.
Digging a bit deeper, I found that InstrInfoEmitter.cpp assigns the type of each sub-operand to the containing operand.
- Res += "|(1<<MCOI::OptionalDef)";
- // Branch target operands. Check to see if the original unexpanded
- // operand was of type BranchTargetOperand.
- if (Op.Rec->isSubClassOf("BranchTargetOperand"))
- Res += "|(1<<MCOI::BranchTarget)";
- // Fill in operand type.
- Res += ", ";
- assert(!Op.OperandType.empty() && "Invalid operand type.");
- Res += Op.OperandType;
- // Fill in constraint info.
- Res += ", ";
- const CGIOperandList::ConstraintInfo &Constraint =
- Op.Constraints[j];
- if (Constraint.isNone())
- Res += "0";
- else if (Constraint.isEarlyClobber())
- Res += "MCOI_EARLY_CLOBBER";
参考文献链接
Is there an ambiguous situation that is being avoided by such a classification? Assigning ‘correct’ types all the time seems to be a non-starter, as both operands above start break in multiple places during normal machine code verification, such as when addrmode5’s first operand receives a constant pool entry rather than a register for its first operand.
My current experiment replicates some code from CGIOperandList which inspects a record to construct the operand namespace and type.
这种分类是否避免了模棱两可的情况?始终指定“正确”类型似乎不是一个开始,因为在正常的机器代码验证过程中,两个开头以上的操作数都会在多个位置中断,例如addrmode5的第一个操作数收到一个常量池条目,而不是第一个操作数的寄存器。
当前的实验复制了CGIOperandList中的一些代码,该代码检查记录以构造操作数名称空间和类型。
- PrintFatalError(R->getLoc(), "Illegal operand for the '" + R->getName() +
- "' instruction!");
- Record *Rec = Arg->getDef();
- std::string PrintMethod = "printOperand";
- std::string EncoderMethod;
- std::string OperandType = "OPERAND_UNKNOWN";
- std::string OperandNamespace = "MCOI";
- unsigned NumOps = 1;
- DagInit *MIOpInfo = nullptr;
- if (Rec->isSubClassOf("RegisterOperand")) {
- PrintMethod = std::string(Rec->getValueAsString("PrintMethod"));
- OperandType = std::string(Rec->getValueAsString("OperandType"));
- OperandNamespace = std::string(Rec->getValueAsString("OperandNamespace"));
- EncoderMethod = std::string(Rec->getValueAsString("EncoderMethod"));
- } else if (Rec->isSubClassOf("Operand")) {
- PrintMethod = std::string(Rec->getValueAsString("PrintMethod"));
- OperandType = std::string(Rec->getValueAsString("OperandType"));
- OperandNamespace = std::string(Rec->getValueAsString("OperandNamespace"));
- // If there is an explicit encoder method, use it.
- EncoderMethod = std::string(Rec->getValueAsString("EncoderMethod"));
参考文献链接
llvm/llvm-project/blob/4efcea95852abe6ed25ae9a2bf8c3a51a1157675/llvm/utils/TableGen/CodeGenInstruction.cpp#L86
参考文献链接
https://discourse.llvm.org/t/tablegen-operandtype-of-nested-operands-in-instructions/67099/1