[llvm] [Analysis] Adding convert_from_arbitrary_fp support in computeKnownFPClass. (PR #208585)

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 28 04:55:50 PDT 2026


================
@@ -0,0 +1,116 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -S < %s | FileCheck %s
+
+define float @test_convert_float8e5m2_to_f32(i8 %bits) {
+; CHECK-LABEL: define nofpclass(sub) float @test_convert_float8e5m2_to_f32(
+; CHECK-SAME: i8 [[BITS:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:    [[FP:%.*]] = call nofpclass(sub) float @llvm.convert.from.arbitrary.fp.f32.i8(i8 [[BITS]], metadata !"Float8E5M2") #[[ATTR2:[0-9]+]]
+; CHECK-NEXT:    ret float [[FP]]
+;
+  %fp = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 %bits, metadata !"Float8E5M2")
+  ret float %fp
+}
+
+define float @test_convert_float8e5m2fnuz_to_f32(i8 %bits) {
+; CHECK-LABEL: define float @test_convert_float8e5m2fnuz_to_f32(
+; CHECK-SAME: i8 [[BITS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[FP:%.*]] = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 [[BITS]], metadata !"Float8E5M2FNUZ") #[[ATTR2]]
+; CHECK-NEXT:    ret float [[FP]]
+;
+  %fp = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 %bits, metadata !"Float8E5M2FNUZ")
+  ret float %fp
+}
+
+define float @test_convert_float8e4m3_to_f32(i8 %bits) {
+; CHECK-LABEL: define float @test_convert_float8e4m3_to_f32(
+; CHECK-SAME: i8 [[BITS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[FP:%.*]] = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 [[BITS]], metadata !"Float8E4M3") #[[ATTR2]]
+; CHECK-NEXT:    ret float [[FP]]
+;
+  %fp = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 %bits, metadata !"Float8E4M3")
+  ret float %fp
+}
+
+define float @test_convert_float8e4m3fn_to_f32(i8 %bits) {
+; CHECK-LABEL: define nofpclass(inf sub) float @test_convert_float8e4m3fn_to_f32(
+; CHECK-SAME: i8 [[BITS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[FP:%.*]] = call nofpclass(inf sub) float @llvm.convert.from.arbitrary.fp.f32.i8(i8 [[BITS]], metadata !"Float8E4M3FN") #[[ATTR2]]
+; CHECK-NEXT:    ret float [[FP]]
+;
+  %fp = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 %bits, metadata !"Float8E4M3FN")
+  ret float %fp
+}
+
+define float @test_convert_float8e4m3fnuz_to_f32(i8 %bits) {
+; CHECK-LABEL: define float @test_convert_float8e4m3fnuz_to_f32(
+; CHECK-SAME: i8 [[BITS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[FP:%.*]] = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 [[BITS]], metadata !"Float8E4M3FNUZ") #[[ATTR2]]
+; CHECK-NEXT:    ret float [[FP]]
+;
+  %fp = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 %bits, metadata !"Float8E4M3FNUZ")
+  ret float %fp
+}
+
+define float @test_convert_float8e4m3b11fnuz_to_f32(i8 %bits) {
+; CHECK-LABEL: define float @test_convert_float8e4m3b11fnuz_to_f32(
+; CHECK-SAME: i8 [[BITS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[FP:%.*]] = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 [[BITS]], metadata !"Float8E4M3B11FNUZ") #[[ATTR2]]
+; CHECK-NEXT:    ret float [[FP]]
+;
+  %fp = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 %bits, metadata !"Float8E4M3B11FNUZ")
+  ret float %fp
+}
+
+define float @test_convert_float8e3m4_to_f32(i8 %bits) {
+; CHECK-LABEL: define float @test_convert_float8e3m4_to_f32(
+; CHECK-SAME: i8 [[BITS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[FP:%.*]] = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 [[BITS]], metadata !"Float8E3M4") #[[ATTR2]]
+; CHECK-NEXT:    ret float [[FP]]
+;
+  %fp = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 %bits, metadata !"Float8E3M4")
+  ret float %fp
+}
+
+define float @test_convert_float8e8m0fnu_to_f32(i8 %bits) {
+; CHECK-LABEL: define float @test_convert_float8e8m0fnu_to_f32(
+; CHECK-SAME: i8 [[BITS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[FP:%.*]] = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 [[BITS]], metadata !"Float8E8M0FNU") #[[ATTR2]]
+; CHECK-NEXT:    ret float [[FP]]
+;
+  %fp = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 %bits, metadata !"Float8E8M0FNU")
+  ret float %fp
+}
+
+define float @test_convert_float6e3m2fn_to_f32(i6 %bits) {
+; CHECK-LABEL: define nofpclass(nan inf sub) float @test_convert_float6e3m2fn_to_f32(
+; CHECK-SAME: i6 [[BITS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[FP:%.*]] = call nofpclass(nan inf sub) float @llvm.convert.from.arbitrary.fp.f32.i6(i6 [[BITS]], metadata !"Float6E3M2FN") #[[ATTR2]]
+; CHECK-NEXT:    ret float [[FP]]
+;
+  %fp = call float @llvm.convert.from.arbitrary.fp.f32.i6(i6 %bits, metadata !"Float6E3M2FN")
+  ret float %fp
+}
+
+define float @test_convert_float6e2m3fn_to_f32(i6 %bits) {
+; CHECK-LABEL: define nofpclass(nan inf sub) float @test_convert_float6e2m3fn_to_f32(
+; CHECK-SAME: i6 [[BITS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[FP:%.*]] = call nofpclass(nan inf sub) float @llvm.convert.from.arbitrary.fp.f32.i6(i6 [[BITS]], metadata !"Float6E2M3FN") #[[ATTR2]]
+; CHECK-NEXT:    ret float [[FP]]
+;
+  %fp = call float @llvm.convert.from.arbitrary.fp.f32.i6(i6 %bits, metadata !"Float6E2M3FN")
+  ret float %fp
+}
+
+define float @test_convert_float4e2m1fn_to_f32(i4 %bits) {
+; CHECK-LABEL: define nofpclass(nan inf sub) float @test_convert_float4e2m1fn_to_f32(
+; CHECK-SAME: i4 [[BITS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[FP:%.*]] = call nofpclass(nan inf sub) float @llvm.convert.from.arbitrary.fp.f32.i4(i4 [[BITS]], metadata !"Float4E2M1FN") #[[ATTR2]]
+; CHECK-NEXT:    ret float [[FP]]
+;
+  %fp = call float @llvm.convert.from.arbitrary.fp.f32.i4(i4 %bits, metadata !"Float4E2M1FN")
+  ret float %fp
+}
+
----------------
arsenm wrote:

> Here, we clear ninf flag but inf is possible. But as format is unsigned anyways, can we keep the ninf cleared in nofpclass ?

Yes, if it's unsigned only then `nofpclass(ninf)` should be fine; this comment has `nofpclass(inf)` on that example, which is a problem since pinf is not known 

https://github.com/llvm/llvm-project/pull/208585


More information about the llvm-commits mailing list