[llvm] [InstCombine] Lower ilogb to bit operations for normal values (PR #218044)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 24 06:02:42 PDT 2026
================
@@ -199,5 +199,253 @@ define i32 @ilogb_poison() {
ret i32 %r
}
-declare i32 @ilogbf(float)
+
+; The following tests are for the ilogb normal optimization where floating-point
+; numbers which are known to be normal can have the exponent extracted using
+; simple bit manipulations.
+
+; copysign is used to create a fp value which won't cause the ilogb call to
+; be immediately constant-folded.
+
+define i32 @ilogb_known_normal_non_pow2(double %sign) {
+; CHECK-LABEL: define i32 @ilogb_known_normal_non_pow2(double %sign) {
+; CHECK-NEXT: ret i32 3
+;
+ %x = call double @llvm.copysign.f64(double 12.5, double %sign)
+ %r = call i32 @ilogb(double %x)
+ ret i32 %r
+}
+
+define i32 @ilogbf_known_normal_non_pow2(float %sign) {
+; CHECK-LABEL: define i32 @ilogbf_known_normal_non_pow2(float %sign) {
+; CHECK-NEXT: ret i32 3
+;
+ %x = call float @llvm.copysign.f32(float 12.5, float %sign)
+ %r = call i32 @ilogbf(float %x)
+ ret i32 %r
+}
+
+define i32 @ilogbl_known_normal_non_pow2(fp128 %sign) {
+; CHECK-LABEL: define i32 @ilogbl_known_normal_non_pow2(fp128 %sign) {
+; CHECK-NEXT: ret i32 3
+;
+ %x = call fp128 @llvm.copysign.f128(fp128 12.5, fp128 %sign)
+ %r = call i32 @ilogbl(fp128 %x)
+ ret i32 %r
+}
+
+
+define i32 @ilogb_known_normal_pow2(double %sign) {
+; CHECK-LABEL: define i32 @ilogb_known_normal_pow2(double %sign) {
+; CHECK-NEXT: ret i32 4
+;
+ %x = call double @llvm.copysign.f64(double 16.0, double %sign)
+ %r = call i32 @ilogb(double %x)
+ ret i32 %r
+}
+
+define i32 @ilogbf_known_normal_pow2(float %sign) {
+; CHECK-LABEL: define i32 @ilogbf_known_normal_pow2(float %sign) {
+; CHECK-NEXT: ret i32 4
+;
+ %x = call float @llvm.copysign.f32(float 16.0, float %sign)
+ %r = call i32 @ilogbf(float %x)
+ ret i32 %r
+}
+
+define i32 @ilogbl_known_normal_pow2(fp128 %sign) {
+; CHECK-LABEL: define i32 @ilogbl_known_normal_pow2(fp128 %sign) {
+; CHECK-NEXT: ret i32 4
+;
+ %x = call fp128 @llvm.copysign.f128(fp128 16.0, fp128 %sign)
+ %r = call i32 @ilogbl(fp128 %x)
+ ret i32 %r
+}
+
+
+define i32 @ilogb_known_normal_smallest_normal(double %sign) {
+; CHECK-LABEL: define i32 @ilogb_known_normal_smallest_normal(double %sign) {
+; CHECK-NEXT: ret i32 -1022
+;
+ %x = call double @llvm.copysign.f64(double 0x1.0p-1022, double %sign)
+ %r = call i32 @ilogb(double %x)
+ ret i32 %r
+}
+
+define i32 @ilogbf_known_normal_smallest_normal(float %sign) {
+; CHECK-LABEL: define i32 @ilogbf_known_normal_smallest_normal(float %sign) {
+; CHECK-NEXT: ret i32 -126
+;
+ %x = call float @llvm.copysign.f32(float 0x1.0p-126, float %sign)
+ %r = call i32 @ilogbf(float %x)
+ ret i32 %r
+}
+
+define i32 @ilogbl_known_normal_smallest_normal(fp128 %sign) {
+; CHECK-LABEL: define i32 @ilogbl_known_normal_smallest_normal(fp128 %sign) {
+; CHECK-NEXT: ret i32 -16382
+;
+ %x = call fp128 @llvm.copysign.f128(fp128 0x1.0p-16382, fp128 %sign)
+ %r = call i32 @ilogbl(fp128 %x)
+ ret i32 %r
+}
+
+
+define i32 @ilogb_known_normal_largest_normal(double %sign) {
+; CHECK-LABEL: define i32 @ilogb_known_normal_largest_normal(double %sign) {
+; CHECK-NEXT: ret i32 1023
+;
+ %x = call double @llvm.copysign.f64(double 0x1.fffffffffffffp+1023, double %sign)
+ %r = call i32 @ilogb(double %x)
+ ret i32 %r
+}
+
+define i32 @ilogbf_known_normal_largest_normal(float %sign) {
+; CHECK-LABEL: define i32 @ilogbf_known_normal_largest_normal(float %sign) {
+; CHECK-NEXT: ret i32 127
+;
+ %x = call float @llvm.copysign.f32(float 0x1.fffffep+127, float %sign)
+ %r = call i32 @ilogbf(float %x)
+ ret i32 %r
+}
+
+define i32 @ilogbl_known_normal_largest_normal(fp128 %sign) {
+; CHECK-LABEL: define i32 @ilogbl_known_normal_largest_normal(fp128 %sign) {
+; CHECK-NEXT: ret i32 16383
+;
+ %x = call fp128 @llvm.copysign.f128(
+ fp128 0x1.ffffffffffffffffffffffffffffp+16383,
+ fp128 %sign)
+ %r = call i32 @ilogbl(fp128 %x)
+ ret i32 %r
+}
+
+define i32 @ilogb_known_normal_operations(double %a) {
+; CHECK-LABEL: @ilogb_known_normal_operations(
+; CHECK-NEXT: [[AND:%.*]] = call i1 @llvm.is.fpclass.f64(double [[A:%.*]], /* (norm) */ i32 264)
+; CHECK-NEXT: call void @llvm.assume(i1 [[AND]])
+; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.fabs.f64(double [[A]])
+; CHECK-NEXT: [[ILOGB_NOSIGN:%.*]] = bitcast double [[TMP1]] to i64
+; CHECK-NEXT: [[ILOGB_EXP:%.*]] = lshr i64 [[ILOGB_NOSIGN]], 52
+; CHECK-NEXT: [[TMP2:%.*]] = trunc nuw nsw i64 [[ILOGB_EXP]] to i32
+; CHECK-NEXT: [[R:%.*]] = add nsw i32 [[TMP2]], -1023
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %and = call i1 @llvm.is.fpclass.f64(double %a, i32 264)
+ call void @llvm.assume(i1 %and)
+ %r = call i32 @ilogb(double %a)
+ ret i32 %r
+}
+
+define i32 @ilogbf_known_normal_operations(float %a) {
+; CHECK-LABEL: @ilogbf_known_normal_operations(
+; CHECK-NEXT: [[AND:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A:%.*]], /* (norm) */ i32 264)
----------------
tadeuszjt wrote:
Please let me know if I should continue with these changes or try again in codegen.
https://github.com/llvm/llvm-project/pull/218044
More information about the llvm-commits
mailing list