setOperationAction
https://llvm.org/docs/WritingAnLLVMBackend.html#the-selectiondag-legalize-phase
https://blog.csdn.net/jinweifu/article/details/54132939
https://zhuanlan.zhihu.com/p/69406037(Important)
1. 框架中的ISD结点¶
非框架中的自定义的结果,不存在下面说的4种情况,只有一种情况,不需要调用setOperationAction()
1.1 Legal¶
Legal代表默认的情况,所以它很少被使用。默认的ISD都认为是Legal,直接进入到指令选择,没有合适的就报错。
If the new ISD instrucion, you can find one machine instruction for it, you can set it legal, and then, you modify the select() function to select it, or you use the td file to call SelectCode() function.
1.2 Custom(Expand觉得Base提供的方法,不好的时候,用Custom)¶
Or you can't find a machine instruction for it, but you want the compiler create this ISD instruction, you should set it to CUSTOM, and then you should legalize this instruction in the Lowering. 必须有相应的Lowering方法。
PPCISelLowering.cpp¶
SDValue PPCTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
switch (Op.getOpcode()) {
default: llvm_unreachable("Wasn't expecting to be able to lower this!");
case ISD::ConstantPool: return LowerConstantPool(Op, DAG);
case ISD::BlockAddress: return LowerBlockAddress(Op, DAG);
case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG);
case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG);
case ISD::JumpTable: return LowerJumpTable(Op, DAG);
case ISD::SETCC: return LowerSETCC(Op, DAG);
case ISD::INIT_TRAMPOLINE: return LowerINIT_TRAMPOLINE(Op, DAG);
case ISD::ADJUST_TRAMPOLINE: return LowerADJUST_TRAMPOLINE(Op, DAG);
...
}
1.3 Expand¶
You machine instruction can't support this ISD instruction, and you don't want to support this ISD instruction, you can set it Expand, so this ISD instruction will not be created.
对于本地不支持的类型,一个值可能需要被打散。对于一个本地不支持的操作操作,其他操作的合并可能被用来达到相似的效果。在SPARC中,浮点Sine和cosine三角操作通过扩展其他操作来支持,在第三个参数中指定为Expand给setOperationAction,Expand可能由基类提供的ExpandINSERT_VECTOR_ELT()方法完成,也可能由Target Hook自定义的方法完成。通过其它合法的操作序列或库函数模拟该操作。
setOperationAction(ISD::INSERT_VECTOR_ELT, VT, Expand); // 使用Base提供的Expand
setOperationAction(ISD::CTLZ, MVT::i16, Expand), // 使用Target hook
Expand意味着SelectionDAGLegalize::LegalizeOp()方法将调用的ExpandNode()方法:
/// Return a legal replacement for the given operation, with all legal operands.
void SelectionDAGLegalize::LegalizeOp(SDNode *Node) {
...
case TargetLowering::Expand:
if (ExpandNode(Node))
return;
LLVM_FALLTHROUGH;
case TargetLowering::LibCall:
ConvertNodeToLibcall(Node);
return;
case TargetLowering::Promote:
PromoteNode(Node);
return;
}
...
}
bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
LLVM_DEBUG(dbgs() << "Trying to expand node\n");
...
case ISD::CTLZ:
case ISD::CTLZ_ZERO_UNDEF:
if (TLI.expandCTLZ(Node, Tmp1, DAG))
Results.push_back(Tmp1);
break;
case ISD::CTTZ:
case ISD::CTTZ_ZERO_UNDEF:
if (TLI.expandCTTZ(Node, Tmp1, DAG))
Results.push_back(Tmp1);
break;
case ISD::INSERT_VECTOR_ELT:
Results.push_back(ExpandINSERT_VECTOR_ELT(Node->getOperand(0),
Node->getOperand(1),
Node->getOperand(2), dl));
break;
...
}
1.4 Promote¶
For an operation without native support for a given type, the specified type may be promoted to a larger type that is supported.
对于给定一个类型本地并不支持的操作,特定的类型可能要被提升为较大的类型以支持。例如对于Boolean值(i1类型)SPARC不支持符号扩展的load,如此在SparcISelLowering.cpp中第三个参数Promote,在load之前改变i1类型的值为一个较大的值。
提供的具体操作由基类完成。
497
498 if (Subtarget.is64BitELFABI()) {
499 // VAARG always uses double-word chunks, so promote anything smaller.
500 setOperationAction(ISD::VAARG, MVT::i1, Promote);
501 AddPromotedToType(ISD::VAARG, MVT::i1, MVT::i64);
502 setOperationAction(ISD::VAARG, MVT::i8, Promote);
503 AddPromotedToType(ISD::VAARG, MVT::i8, MVT::i64);
504 setOperationAction(ISD::VAARG, MVT::i16, Promote);
505 AddPromotedToType(ISD::VAARG, MVT::i16, MVT::i64);
506 setOperationAction(ISD::VAARG, MVT::i32, Promote);
507 AddPromotedToType(ISD::VAARG, MVT::i32, MVT::i64);
508 setOperationAction(ISD::VAARG, MVT::Other, Expand);
509 }
2 为架构添加原始支持的类型¶
使用addRegisterClass来添加支持的类型,不支持的类型可以使用setOperationAction(promote)。
In the constructor for the XXXTargetLowering class, first use theaddRegisterClass method to specify which types are supported and which register classes are associated with them. The code for the register classes are generated by TableGen from XXXRegisterInfo.td and placed inXXXGenRegisterInfo.h.inc. For example, the implementation of the constructor for the SparcTargetLowering class (in SparcISelLowering.cpp) starts with the following code
以下代码来自于RISCV
RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
const RISCVSubtarget &STI)
: TargetLowering(TM), Subtarget(STI) {
...
MVT XLenVT = Subtarget.getXLenVT();
// Set up the register classes.
addRegisterClass(XLenVT, &RISCV::GPRRegClass);
if (Subtarget.hasStdExtF())
addRegisterClass(MVT::f32, &RISCV::FPR32RegClass);
if (Subtarget.hasStdExtD())
addRegisterClass(MVT::f64, &RISCV::FPR64RegClass)
...
}