自定义SDNode必须在TableGen中用def显式声明并继承SDNode,否则SelectionDAGBuilder会断言失败;需在TargetSelectionDAG.td或目标专属XXXISel.td中正确定义opcode、SDTypeProfile及props(如SDNPHasChain),并在LowerINTRINSIC函数中映射intrinsic,再通过pat规则匹配生成MachineInstr。

自定义 SDNode 必须在 TableGen 中声明
LLVM 不允许运行时动态注册 SDNode,所有自定义节点类型(如 RISCVISD::ADDW 或 M88kISD::RET_FLAG)必须在 .td 文件中用 def 显式定义,并继承自 SDNode 类。否则,SelectionDAGBuilder 遇到对应 ISD:: 节点时会断言失败或静默降级为通用节点。
常见错误现象:Assertion failed: Node->getOpcode() != ISD::DELETED_NODE 或生成的 MachineInstr 完全不匹配预期指令。
- 必须在
TargetSelectionDAG.td或目标专属XXXISel.td中定义,例如:def ADDW : SDNode, SDTCisInt, SDTCisInt]>> -
SDTypeProfile的numresults和numoperands必须与 lowering 函数实际返回的SDValue数量严格一致,否则 DAG 构建阶段会崩溃 - 若节点需 chain 或 glue,必须在
props列表中显式写入SDNPHasChain或SDNPOutGlue,否则后续指令调度和寄存器分配会忽略依赖关系
Lowering 阶段要把 intrinsic 映射成自定义 SDNode
用户代码中调用 __builtin_riscv_custom_addw() 这类 intrinsic,最终要由 LowerINTRINSIC_WO_CHAIN 或 LowerINTRINSIC_W_CHAIN 在 XXXISelLowering.cpp 中捕获,并返回封装了自定义 SDNode 的 SDValue。这一步漏掉,自定义节点就永远不会进入 DAG。
使用场景:RISC-V 自定义指令、DSP 扩展、安全协处理器指令等需要绕过通用 lowering 流程的语义。
- 不能直接 new 一个
SDNode;必须调用CurDAG->getMachineNode()或CurDAG->getNode(),传入你定义好的 opcode(如RISCVISD::ADDW) - 如果 intrinsic 带副作用(如触发硬件状态变更),必须确保返回的节点带
SDNPHasChain属性,并正确连接 input/output chain,否则优化器可能重排或删除该节点 - 对操作数做合法性检查(如立即数范围、寄存器类别)应放在 lowering 里,而不是 pattern matching 阶段——后者只做匹配,不做校验
Pattern matching 需在 .td 文件中覆盖所有合法组合
DAG 到 MachineInstr 的转换靠 pat 规则驱动。自定义 SDNode 若没有对应的 pat,就会卡在 SelectionDAG 阶段,最终 fallback 到 expand 或 abort。
性能影响:一条未命中的 pat 可能导致整个 basic block 降级为 soft-float 或 library call,性能损失一个数量级以上。
-
pat左侧必须是你的自定义 node(如(RISCVISD::ADDW VR128:$rs1, VR128:$rs2)),右侧是(ADDWrr VR128:$rs1, VR128:$rs2)这类 machine operand 形式 - 如果支持立即数变体,必须单独写
pat,例如(RISCVISD::ADDWI VR128:$rs1, i32imm:$imm)→(ADDWIrr VR128:$rs1, i32imm:$imm),不能指望通用 immediate folding 自动处理 - 涉及寄存器类约束(如仅允许
VR128,不允许GPR)必须在PatFrag或Operand定义中显式限定,否则匹配会误选错误指令
调试时优先看 SelectionDAG -view-dag-dags 输出
最容易被忽略的是:自定义节点是否真的出现在 DAG 图中。光看汇编输出没用,因为失败往往发生在 DAG 构建或 lowering 阶段,根本走不到 instruction selection。
运行 llc -view-dag-dags -march=riscv32 test.ll,观察 dot 图里有没有你的 RISCVISD::XXX 节点。没有,说明 lowering 没生效;有但没转成 MachineInstr,说明 pat 匹配失败或条件不满足。
- View 图中节点显示为
0xNNNN RISCVISD::ADDW是正常;若显示为0xNNNN ISD::INTRINSIC_WO_CHAIN,说明 lowering 函数没被调用或返回了空SDValue - 匹配失败常因 operand 类型不匹配:比如你期望
i32,但实际传入的是v4i32,SDTCisInt<1>就会拒斥 -
llc -debug-only=isel会打印每条pat的匹配尝试过程,但输出极冗长,建议先用-view-dag-dags定位节点是否存在

















