[mlir][arith] convert-arith-to-llvm silently leaves arith.extf/truncf on fp8 and fp6 types, breaking translation to LLVM IR
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
**Summary**
arith.extf and arith.truncf on the FP8 and FP6 types have no expansion in arith-expand and no conversion in convert-arith-to-llvm. Because convert-arith-to-llvm is a partial conversion, it reports success and leaves the ops in place, so a pipeline that is supposed to produce pure LLVM dialect silently does not, and the failure only appears later in mlir-translate. bf16, f8E8M0FNU and f4E2M1FN are expanded and work correctly; the other eight narrow formats are not.
**Environment**
LLVM 23.0.0git, upstream commit aaa2dbb8d014 (2026-05-20). Reproduced with unmodified mlir-opt and mlir-translate.
**Reproducer**
```mlir
// fp8.mlir
func.func @fp8_roundtrip(%arg0: f32) -> f32 {
%0 = arith.truncf %arg0 : f32 to f8E4M3FN
%1 = arith.extf %0 : f8E4M3FN to f32
return %1 : f32
}
```
Step 1 — arith-expand with every float option enabled is a no-op:
`$ mlir-opt fp8.mlir --arith-expand="include-bf16=true include-f8e8m0=true include-f4e2m1=true"`
```mlir
module {
func.func @fp8_roundtrip(%arg0: f32) -> f32 {
%0 = arith.truncf %arg0 : f32 to f8E4M3FN
%1 = arith.extf %0 : f8E4M3FN to f32
return %1 : f32
}
}
```
Step 2 — arith-emulate-unsupported-floats cannot help either, since it marks these two ops legal by construction:
`$ mlir-opt fp8.mlir --arith-emulate-unsupported-floats="source-types=f8E4M3FN target-type=f32"`
```mlir
%0 = arith.truncf %arg0 : f32 to f8E4M3FN
%1 = arith.extf %0 : f8E4M3FN to f32
```
Step 3 — the actual bug. Lowering to LLVM dialect exits 0, yet arith ops remain:
`$ mlir-opt fp8.mlir --pass-pipeline="builtin.module(convert-arith-to-llvm,convert-func-to-llvm,reconcile-unrealized-casts)"`
```mlir
...
%0 = arith.truncf %arg0 : f32 to f8E4M3FN
%1 = arith.extf %0 : f8E4M3FN to f32
```
```console
$ echo $?
0
```
Step 4 — translation then fails on that output:
```console
$ mlir-translate --mlir-to-llvmir lowered.mlir
error: Dialect `arith' not found for custom op 'arith.truncf'
$ echo $?
1
```
Contrast, same shape with bf16, which upstream does expand:
```console
$ mlir-opt bf16.mlir --arith-expand="include-bf16=true" # no arith.truncf/extf remain
**Scope**
| Type | arith-expand result |
|--------|--------|
| f8E4M3FN, f8E4M3, f8E5M2, f8E3M4 | not expanded |
| f8E5M2FNUZ, f8E4M3FNUZ | not expanded |
| f6E2M3FN, f6E3M2FN | not expanded |
| f8E8M0FNU | expanded |
| f4E2M1FN | expanded |
| bf16 | expanded |
```
**Root cause**
mlir/lib/Dialect/Arith/Transforms/ExpandOps.cpp has three float expansions — populateExpandBFloat16Patterns, populateExpandF8E8M0Patterns, populateExpandF4E2M1Patterns — and the legality predicates name only those types:
```c++
target.addDynamicallyLegalOp(
[=](arith::ExtFOp op) {
...
if (includeBf16) legalTypes &= !(inETy.isBF16() && outETy.isF32());
if (includeF8E8M0) legalTypes &= !llvm::isa(inETy);
if (includeF4E2M1) legalTypes &= !llvm::isa(inETy);
return legalTypes;
});
```
Separately, LLVMTypeConverter::convertFloatType maps every FP8/FP6/FP4 type to a same-width integer, and LLVM::isCompatibleFloatingPointType admits only bf16, f16, f32, f64, f80, f128, ppc_fp128. So the LLVM dialect can carry these values as storage but has no arithmetic for them — the conversion must happen while the format is still in the type system, i.e. at the arith level, which is where the three existing expansions live.
**Expected**
Either an include-f8-style option adding expansions for the remaining formats alongside the existing three, or — at minimum — convert-arith-to-llvm failing loudly instead of reporting success on a module it did not fully convert. The silent success is the more damaging half: a downstream pipeline has no way to detect it short of scanning the output for arith. ops.
Contributor guide
Research direction
Start in mlir/lib/Dialect/Arith/Transforms/ExpandOps.cpp, reviewing the existing float expansion patterns and legality predicates for arith.extf and arith.truncf. Reproduce the f8E4M3FN pipeline with mlir-opt, then verify that the remaining narrow formats are either expanded before LLVM conversion or that conversion fails loudly; confirm the result with mlir-translate.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 56/100