Code generation and backends
Contract
| Field | Bound contract |
|---|---|
| Trigger | A user asks how LLVM IR becomes machine code for a target, why the legalizer inserted extra operations, why llc and clang emit different assembly, what an llc fatal error at instruction selection means, or what a port to a new architecture involves. |
| Authority | Reversible local: writes only bitcode and assembly files under a scratch directory named in the report; rollback is deleting that directory. No remote mutation. |
| Side effect | Runs clang and llc on the supplied source or bitcode and reads the emitted assembly. Project files are not modified. |
| Done | A codegen report names the stage that produced each observed instruction sequence or failure, the triple and feature set in effect, and the fix or expansion path for every failure. |
Inputs
- Source file, LLVM IR (
.ll), or bitcode (.bc) (required). - Target triple and CPU features (required if not inferrable from the build): for example
aarch64-linux-gnu,riscv64-unknown-elf,thumbv7em-none-eabiwith+neonor+crc. - The observed symptom (required): the assembly region, the
llcerror text, or the question about the pipeline. - Installed LLVM version (
llc --version) (gathered by the skill). Grounded current stable is LLVM 23.1.0; tool flags below are confirmed against that release.
Procedure
Map the question onto the backend pipeline. Per function, LLVM runs: IR legalization of types and operations the target lacks;
SelectionDAGBuilder;LegalizeTypesandLegalizeOps; instruction selection by TableGen pattern match; pre-register-allocation scheduling; register allocation; prolog and epilog insertion;AsmPrinterto assembly or object. Name the stage the symptom belongs to. Done when: one stage is named as the owner of the symptom.Reproduce with
llcin a scratch directory, with the same triple the build uses:clang -c -emit-llvm -O2 -o foo.bc foo.c llc -mtriple=aarch64-linux-gnu -O2 foo.bc -o foo.s llc -mtriple=riscv64-unknown-elf -O2 foo.bc -o foo-rv.s llc -mtriple=thumbv7em-none-eabi -mattr=+dsp foo.bc -o foo-m7.sllc --versionlists registered targets;llc -mattr=help -mtriple=<triple>lists feature names;llc -mcpu=help -mtriple=<triple>lists CPU names. Done when: the assembly or the error reproduces from bitcode with an explicit triple.When
llcoutput andclangoutput differ, compare the triples and feature sets.clang --target=arm-none-eabi -c -O2 foo.cbakes the triple into the bitcode; passing a different-mtripleor-mattrtollcchanges legalization and selection. Done when: both tools run with the same triple, CPU, and attributes, and the difference is either gone or explained by a flag.For extra operations you did not write, read them as legalization. A type the target has no register for (an
i64on a 32-bit core, a vector type without a matching unit) is split, promoted, or expanded into a libcall; an operation without a pattern is expanded into a sequence. The fix is either a target feature that makes the type or operation legal, or an IR change that avoids it. Done when: each unexpected instruction sequence is tied to a type or operation the target cannot represent directly.For a
Cannot selectfatal error, identify the IR operation and type in the message, then decide between marking it legal in the target (a backend change), adding a custom lowering hook inTargetLowering, or rewriting the IR so the operation is not produced. Done when: one of the three paths is chosen and stated with the operation and type.For wrong soft-float or calling-convention behaviour, check the ABI in the triple (
gnueabiversusgnueabihf) and the float ABI flag passed toclang; the target's calling convention lives in TableGen (CC_AArch64,CC_X86_64) and is selected by the triple. Done when: the triple and float ABI match the ABI the linked objects use. For the ABI rules themselves, useabi-and-calling-conventions.For a large stack frame or spill-heavy assembly, treat it as register pressure that survived to allocation, not as a backend defect. Reduce live ranges at the IR or source level. Done when: the spill count changes with the source change, which confirms the diagnosis. For the allocation mechanism, use
compiler-optimizations-deep.For a question about adding a target, give the outline and the effort: define register classes and instruction formats in TableGen
.tdfiles; implement lowering hooks inTargetLowering; implement theAsmPrinterand the MC layer with relocations; implement the calling convention and the object writer for the target format. Patterns such asPat<(add i32 GPR:$a, GPR:$b), (ADD32rr GPR:$a, GPR:$b)>map DAG nodes to machine instructions. Start from the in-tree backend closest to the architecture. A TableGen syntax error is reported byllvm-tblgenwith the.tdline. Done when: the four parts and the closest existing backend are named.
Failure and recovery
| Failure class | Behavior |
|---|---|
Target not registered in the installed llc |
Report the llc --version target list. Stop; a rebuilt LLVM with the target enabled is a prerequisite. |
Bitcode from a different LLVM major than llc |
Report both versions. Regenerate the bitcode with the matching clang; bitcode is not stable across majors. |
| Triple unknown and not inferrable from the build | Report the ambiguity with the evidence examined. Do not guess a triple. |
| Symptom is at the IR level, not the machine level | Hand off to llvm-ir-and-passes and say so; do not narrate a codegen cause for an IR effect. |
No partial result is claimed complete. If a step cannot finish, the report states which steps ran and which are blocked.
Output
A codegen report containing:
- Stage attribution: the pipeline stage that owns each observed instruction sequence or error.
- Effective target: the triple, CPU, and feature set used, and any mismatch found between
clangandllc. - Fix path: for each failure, the chosen path (feature flag, IR change, custom lowering, or backend change) with the operation and type involved.
- Scratch location: the directory holding the generated
.bcand.sfiles.