| # How To Add A Constrained Floating-Point Intrinsic |
| |
| ```{contents} |
| :local: true |
| ``` |
| |
| :::{warning} |
| This is a work in progress. |
| ::: |
| |
| ## Add the intrinsic |
| |
| Multiple files need to be updated when adding a new constrained intrinsic. |
| |
| Add the new intrinsic to the table of intrinsics: |
| |
| ``` |
| include/llvm/IR/Intrinsics.td |
| ``` |
| |
| ## Add SelectionDAG node types |
| |
| Add the new `STRICT` version of the node type to the `ISD::NodeType` enum: |
| |
| ``` |
| include/llvm/CodeGen/ISDOpcodes.h |
| ``` |
| |
| Strict version name must be a concatenation of prefix `STRICT_` and the name |
| of the corresponding non-strict node name. For instance, strict version of the |
| node `FADD` must be `STRICT_FADD`. |
| |
| ## Update mappings |
| |
| Add new record to the mapping of instructions to constrained intrinsics and |
| DAG nodes: |
| |
| ``` |
| include/llvm/IR/ConstrainedOps.def |
| ``` |
| |
| Follow instructions provided in this file. |
| |
| ## Update IR components |
| |
| Update the IR verifier: |
| |
| ``` |
| lib/IR/Verifier.cpp |
| ``` |
| |
| ## Update Selector components |
| |
| ### Building the SelectionDAG |
| |
| The `SelectionDAGBuilder::visitConstrainedFPIntrinsic` function builds DAG nodes |
| using mappings specified in `ConstrainedOps.def`. If however this default build is |
| not sufficient, the build can be modified, see how it is implemented for |
| `STRICT_FP_ROUND`. The new `STRICT` node will eventually be converted |
| to the matching non-`STRICT` node. For this reason it should have the same |
| operands and values as the non-`STRICT` version but should also use the chain. |
| This makes subsequent sharing of code for `STRICT` and non-`STRICT` code paths |
| easier: |
| |
| ``` |
| lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp |
| ``` |
| |
| Most of the `STRICT` nodes get legalized the same as their matching non-`STRICT` |
| counterparts. A new `STRICT` node with this property must get added to the |
| switch in `SelectionDAGLegalize::LegalizeOp()`: |
| |
| ``` |
| lib/CodeGen/SelectionDAG/LegalizeDAG.cpp |
| ``` |
| |
| Other parts of the legalizer may need to be updated as well. Look for |
| places where the non-`STRICT` counterpart is legalized and update as needed. |
| Be careful of the chain since `STRICT` nodes use it but their counterparts |
| often don't. |
| |
| The conversion or mutation of the `STRICT` node to a non-`STRICT` |
| version of the node happens in `SelectionDAG::mutateStrictFPToFP()`. In most cases |
| the function can do the conversion using information from ConstrainedOps.def. Be |
| careful updating this function since some nodes have the same return type |
| as their input operand, but some are different. Both of these cases must |
| be properly handled: |
| |
| ``` |
| lib/CodeGen/SelectionDAG/SelectionDAG.cpp |
| ``` |
| |
| Whether the mutation happens or not depends on how the new node has been |
| registered in `TargetLoweringBase::initActions()`. By default, all strict nodes are |
| registered with Expand action: |
| |
| ``` |
| lib/CodeGen/TargetLoweringBase.cpp |
| ``` |
| |
| To make debug logs readable, it is helpful to update the SelectionDAG's |
| debug logger: |
| |
| ``` |
| lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp |
| ``` |
| |
| ## Add documentation and tests |
| |
| ``` |
| docs/LangRef.md |
| ``` |