Bug#1031500: numerical differences in x87 fpu code generated by clang-14 and clang-15

Andreas Beckmann anbe at debian.org
Fri Feb 17 09:55:42 GMT 2023


Package: clang-15
Version: 1:15.0.6-4
Severity: important
Control: block 1031414 with -1

While analyzing some autopkgtest regressions when pocl gets built with
llvm-15 instead of llvm-14 (#1030298, #1031414), I finally managed to
extract some parts of the kernel code generated by pocl (parts of the
pocl OpenCL fmod(float, float) implementation, pocl_cl_fmod.ll) and
added a small C wrapper to call the function (main.c, Makefile).
The resulting program produces numeric results that differ in more than
just the last digit depending on whether it was built with clang-14
or clang-15.

$ ./test_pocl_cl_fmod_llvm14
a=0 b=0.1 c=0 d=0 abserr=0 relerr=0
a=0.1 b=0.1221239 c=0.1 d=0.1 abserr=0 relerr=0
a=0.2 b=0.14424779 c=0.055752218 d=0.055752218 abserr=0 relerr=0
a=0.3 b=0.16637169 c=0.13362832 d=0.13362832 abserr=0 relerr=0
a=0.4 b=0.18849558 c=0.023008853 d=0.023008853 abserr=0 relerr=0
a=0.5 b=0.21061946 c=0.078761071 d=0.078761071 abserr=0 relerr=0
a=0.6 b=0.23274337 c=0.13451329 d=0.13451329 abserr=0 relerr=0
a=0.7 b=0.25486726 c=0.19026548 d=0.19026548 abserr=0 relerr=0
a=0.8 b=0.27699116 c=0.24601769 d=0.24601769 abserr=0 relerr=0
a=0.9 b=0.29911503 c=0.0026548803 d=0.0026548803 abserr=0 relerr=0

$ ./test_pocl_cl_fmod_llvm15
a=0 b=0.1 c=0 d=0 abserr=0 relerr=0
a=0.1 b=0.1221239 c=0.1 d=0.1 abserr=0 relerr=0
a=0.2 b=0.14424779 c=0.055752218 d=0.055752218 abserr=0 relerr=0
a=0.3 b=0.16637169 c=0.13362832 d=0.13362832 abserr=0 relerr=0
a=0.4 b=0.18849558 c=0.023008853 d=0.023008853 abserr=0 relerr=0
a=0.5 b=0.21061946 c=0.078761071 d=0.078761071 abserr=0 relerr=0
a=0.6 b=0.23274337 c=0.13451327 d=0.13451329 abserr=1.49012e-08 relerr=6.4024e-08
a=0.7 b=0.25486726 c=0.19026548 d=0.19026548 abserr=0 relerr=0
a=0.8 b=0.27699116 c=0.24601772 d=0.24601769 abserr=-2.98023e-08 relerr=-1.07593e-07 FAIL
a=0.9 b=0.29911503 c=0.0026548505 d=0.0026548803 abserr=2.98023e-08 relerr=9.9635e-08

c = _Z8_cl_fmodff(a, b)  # from pocl
d = fmodf(a, b)          # from libc, as reference

This happens on i386 with -march=i686, i.e. it generates x87 fpu code,
not sse fpu code. The attached Makefile also works for creating 32-bit
binaries on amd64 showing the behavior.

Andreas
-------------- next part --------------
; ModuleID = 'parallel.bc'
source_filename = "parallel_bc"
target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128"
target triple = "i386-unknown-linux-gnu"

; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
declare float @llvm.fma.f32(float, float, float) #7

; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone uwtable willreturn
define float @_Z8_cl_fmodff(float noundef %0, float noundef %1) unnamed_addr #8 {
.r_entry:
  %2 = bitcast float %0 to i32
  %3 = and i32 %2, 2147483647
  %4 = bitcast i32 %3 to float
  %5 = bitcast float %1 to i32
  %6 = and i32 %5, 2147483647
  %7 = bitcast i32 %6 to float
  %8 = fcmp olt float %4, 0x3810000000000000
  %9 = fmul float %4, 0x41D0000000000000
  %10 = select i1 %8, float %9, float %4
  %11 = fcmp ueq float %10, 0.000000e+00
  br i1 %11, label %21, label %12

12:                                               ; preds = %.r_entry
  %13 = select i1 %8, i32 -156, i32 -126
  %14 = bitcast float %10 to i32
  %15 = lshr i32 %14, 23
  %16 = and i32 %15, 255
  %17 = add nsw i32 %16, %13
  %18 = fcmp une float %10, 0x7FF0000000000000
  %19 = fcmp une float %10, 0xFFF0000000000000
  %20 = and i1 %18, %19
  br i1 %20, label %_Z12_cl_expfrexpf.exit, label %21

21:                                               ; preds = %12, %.r_entry
  br label %_Z12_cl_expfrexpf.exit

_Z12_cl_expfrexpf.exit:                           ; preds = %21, %12
  %22 = phi i32 [ 0, %21 ], [ %17, %12 ]
  %23 = fcmp ord float %4, 0.000000e+00
  br i1 %23, label %24, label %_Z11_cl_frfrexpf.exit

24:                                               ; preds = %_Z12_cl_expfrexpf.exit
  %25 = bitcast float %10 to i32
  %26 = and i32 %25, -2139095041
  %27 = or i32 %26, 1056964608
  %28 = fcmp une float %10, 0x7FF0000000000000
  %29 = fcmp une float %10, 0xFFF0000000000000
  %30 = and i1 %28, %29
  %31 = and i32 %25, -2147483648
  %32 = or i32 %31, 2139095040
  %33 = select i1 %30, i32 %27, i32 %32
  %34 = bitcast i32 %33 to float
  %35 = fcmp oeq float %10, 0.000000e+00
  %36 = select i1 %35, float %10, float %34
  br label %_Z11_cl_frfrexpf.exit

_Z11_cl_frfrexpf.exit:                            ; preds = %24, %_Z12_cl_expfrexpf.exit
  %37 = phi float [ %36, %24 ], [ %4, %_Z12_cl_expfrexpf.exit ]
  %38 = fmul float %37, 4.096000e+03
  %39 = fcmp olt float %7, 0x3810000000000000
  %40 = fmul float %7, 0x41D0000000000000
  %41 = select i1 %39, float %40, float %7
  %42 = fcmp ueq float %41, 0.000000e+00
  br i1 %42, label %52, label %43

43:                                               ; preds = %_Z11_cl_frfrexpf.exit
  %44 = select i1 %39, i32 -156, i32 -126
  %45 = bitcast float %41 to i32
  %46 = lshr i32 %45, 23
  %47 = and i32 %46, 255
  %48 = add nsw i32 %47, %44
  %49 = fcmp une float %41, 0x7FF0000000000000
  %50 = fcmp une float %41, 0xFFF0000000000000
  %51 = and i1 %49, %50
  br i1 %51, label %_Z12_cl_expfrexpf.exit1, label %52

52:                                               ; preds = %43, %_Z11_cl_frfrexpf.exit
  br label %_Z12_cl_expfrexpf.exit1

_Z12_cl_expfrexpf.exit1:                          ; preds = %52, %43
  %53 = phi i32 [ 0, %52 ], [ %48, %43 ]
  %54 = fcmp ord float %7, 0.000000e+00
  br i1 %54, label %55, label %_Z11_cl_frfrexpf.exit2

55:                                               ; preds = %_Z12_cl_expfrexpf.exit1
  %56 = bitcast float %41 to i32
  %57 = and i32 %56, -2139095041
  %58 = or i32 %57, 1056964608
  %59 = fcmp une float %41, 0x7FF0000000000000
  %60 = fcmp une float %41, 0xFFF0000000000000
  %61 = and i1 %59, %60
  %62 = and i32 %56, -2147483648
  %63 = or i32 %62, 2139095040
  %64 = select i1 %61, i32 %58, i32 %63
  %65 = bitcast i32 %64 to float
  %66 = fcmp oeq float %41, 0.000000e+00
  %67 = select i1 %66, float %41, float %65
  br label %_Z11_cl_frfrexpf.exit2

_Z11_cl_frfrexpf.exit2:                           ; preds = %55, %_Z12_cl_expfrexpf.exit1
  %68 = phi float [ %67, %55 ], [ %7, %_Z12_cl_expfrexpf.exit1 ]
  %69 = fmul float %68, 2.000000e+00
  %70 = sub nsw i32 %22, %53
  %71 = fdiv float 1.000000e+00, %69, !fpmath !86
  %72 = icmp sgt i32 %70, 12
  br i1 %72, label %.preheader, label %.loopexit

.preheader:                                       ; preds = %_Z11_cl_frfrexpf.exit2
  %73 = bitcast float %69 to i32
  %74 = and i32 %73, -4096
  %75 = bitcast i32 %74 to float
  %76 = fsub float %69, %75
  br label %77

77:                                               ; preds = %_Z8_cl_rintf.exit, %.preheader
  %78 = phi float [ %131, %_Z8_cl_rintf.exit ], [ %38, %.preheader ]
  %79 = phi i32 [ %132, %_Z8_cl_rintf.exit ], [ %70, %.preheader ]
  %80 = fmul float %71, %78
  %81 = fadd float %80, 5.000000e-01
  %82 = fptosi float %81 to i32
  %83 = sitofp i32 %82 to float
  %84 = fsub float %81, %83
  %85 = fcmp olt float %84, 0.000000e+00
  br i1 %85, label %91, label %86

86:                                               ; preds = %77
  %87 = and i32 %82, 1
  %88 = icmp ne i32 %87, 0
  %89 = fcmp oeq float %84, 0.000000e+00
  %90 = select i1 %89, i1 %88, i1 false
  br i1 %90, label %91, label %93

91:                                               ; preds = %86, %77
  %92 = fadd float %84, 1.000000e+00
  br label %93

93:                                               ; preds = %91, %86
  %94 = phi float [ %92, %91 ], [ %84, %86 ]
  %95 = fcmp oeq float %80, 0x3FE0000020000000
  %96 = select i1 %95, float 0.000000e+00, float %81
  %97 = fcmp une float %80, 0x7FF0000000000000
  %98 = fcmp une float %80, 0xFFF0000000000000
  %99 = and i1 %97, %98
  br i1 %99, label %100, label %_Z8_cl_rintf.exit

100:                                              ; preds = %93
  %101 = bitcast float %80 to i32
  %102 = and i32 %101, 2147483647
  %103 = bitcast i32 %102 to float
  %104 = fcmp ult float %103, 0x4160000000000000
  br i1 %104, label %105, label %_Z8_cl_rintf.exit

105:                                              ; preds = %100
  %106 = fsub float %96, %94
  %107 = bitcast float %106 to i32
  %108 = and i32 %107, 2147483647
  %109 = and i32 %101, -2147483648
  %110 = or i32 %108, %109
  %111 = bitcast i32 %110 to float
  br label %_Z8_cl_rintf.exit

_Z8_cl_rintf.exit:                                ; preds = %105, %100, %93
  %112 = phi float [ %111, %105 ], [ %80, %100 ], [ %80, %93 ]
  %113 = bitcast float %112 to i32
  %114 = and i32 %113, -4096
  %115 = bitcast i32 %114 to float
  %116 = fsub float %112, %115
  %117 = fmul float %69, %112
  %118 = fneg float %117
  %119 = tail call float @llvm.fma.f32(float %115, float %75, float %118) #11
  %120 = tail call float @llvm.fma.f32(float %115, float %76, float %119) #11
  %121 = tail call float @llvm.fma.f32(float %116, float %75, float %120) #11
  %122 = tail call float @llvm.fma.f32(float %116, float %76, float %121) #11
  %123 = fsub float %78, %117
  %124 = fsub float %78, %123
  %125 = fsub float %124, %117
  %126 = fsub float %125, %122
  %127 = fadd float %123, %126
  %128 = fcmp olt float %127, 0.000000e+00
  %129 = select i1 %128, float %69, float -0.000000e+00
  %130 = fadd float %127, %129
  %131 = fmul float %130, 4.096000e+03
  %132 = add nsw i32 %79, -12
  %133 = icmp ugt i32 %79, 24
  br i1 %133, label %77, label %.loopexit.loopexit

.loopexit.loopexit:                               ; preds = %_Z8_cl_rintf.exit
  %.lcssa29 = phi float [ %131, %_Z8_cl_rintf.exit ]
  %.lcssa = phi i32 [ %132, %_Z8_cl_rintf.exit ]
  br label %.loopexit

.loopexit:                                        ; preds = %.loopexit.loopexit, %_Z11_cl_frfrexpf.exit2
  %134 = phi i32 [ %70, %_Z11_cl_frfrexpf.exit2 ], [ %.lcssa, %.loopexit.loopexit ]
  %135 = phi float [ %38, %_Z11_cl_frfrexpf.exit2 ], [ %.lcssa29, %.loopexit.loopexit ]
  %136 = add nsw i32 %134, -11
  %137 = ashr i32 %136, 2
  %138 = lshr i32 %136, 31
  %139 = add nsw i32 %137, %138
  %140 = add nsw i32 %134, 38
  %141 = icmp ult i32 %140, 99
  %142 = select i1 %141, i32 0, i32 %139
  %143 = mul nsw i32 %142, -4
  %144 = add nsw i32 %143, %136
  %145 = shl nsw i32 %142, 23
  %146 = add i32 %145, 1065353216
  %147 = bitcast i32 %146 to float
  %148 = shl i32 %144, 23
  %149 = add i32 %148, 1065353216
  %150 = bitcast i32 %149 to float
  %151 = fmul float %135, %150
  %152 = fmul float %151, %147
  %153 = fmul float %152, %147
  %154 = fmul float %153, %147
  %155 = fmul float %154, %147
  %156 = fmul float %71, %155
  %157 = fadd float %156, 5.000000e-01
  %158 = fptosi float %157 to i32
  %159 = sitofp i32 %158 to float
  %160 = fsub float %157, %159
  %161 = fcmp olt float %160, 0.000000e+00
  br i1 %161, label %167, label %162

162:                                              ; preds = %.loopexit
  %163 = and i32 %158, 1
  %164 = icmp ne i32 %163, 0
  %165 = fcmp oeq float %160, 0.000000e+00
  %166 = select i1 %165, i1 %164, i1 false
  br i1 %166, label %167, label %169

167:                                              ; preds = %162, %.loopexit
  %168 = fadd float %160, 1.000000e+00
  br label %169

169:                                              ; preds = %167, %162
  %170 = phi float [ %168, %167 ], [ %160, %162 ]
  %171 = fcmp oeq float %156, 0x3FE0000020000000
  %172 = select i1 %171, float 0.000000e+00, float %157
  %173 = fcmp une float %156, 0x7FF0000000000000
  %174 = fcmp une float %156, 0xFFF0000000000000
  %175 = and i1 %173, %174
  br i1 %175, label %176, label %_Z8_cl_rintf.exit3

176:                                              ; preds = %169
  %177 = bitcast float %156 to i32
  %178 = and i32 %177, 2147483647
  %179 = bitcast i32 %178 to float
  %180 = fcmp ult float %179, 0x4160000000000000
  br i1 %180, label %181, label %_Z8_cl_rintf.exit3

181:                                              ; preds = %176
  %182 = fsub float %172, %170
  %183 = bitcast float %182 to i32
  %184 = and i32 %183, 2147483647
  %185 = and i32 %177, -2147483648
  %186 = or i32 %184, %185
  %187 = bitcast i32 %186 to float
  br label %_Z8_cl_rintf.exit3

_Z8_cl_rintf.exit3:                               ; preds = %181, %176, %169
  %188 = phi float [ %187, %181 ], [ %156, %176 ], [ %156, %169 ]
  %189 = bitcast float %188 to i32
  %190 = and i32 %189, -4096
  %191 = bitcast i32 %190 to float
  %192 = fsub float %188, %191
  %193 = bitcast float %69 to i32
  %194 = and i32 %193, -4096
  %195 = bitcast i32 %194 to float
  %196 = fsub float %69, %195
  %197 = fmul float %69, %188
  %198 = fneg float %197
  %199 = tail call float @llvm.fma.f32(float %191, float %195, float %198) #11
  %200 = tail call float @llvm.fma.f32(float %191, float %196, float %199) #11
  %201 = tail call float @llvm.fma.f32(float %192, float %195, float %200) #11
  %202 = tail call float @llvm.fma.f32(float %192, float %196, float %201) #11
  %203 = fsub float %155, %197
  %204 = fsub float %155, %203
  %205 = fsub float %204, %197
  %206 = fsub float %205, %202
  %207 = fadd float %203, %206
  %208 = add nsw i32 %53, -1
  %209 = ashr i32 %208, 2
  %210 = lshr i32 %208, 31
  %211 = add nsw i32 %209, %210
  %212 = add nsw i32 %53, 48
  %213 = icmp ult i32 %212, 99
  %214 = select i1 %213, i32 0, i32 %211
  %215 = shl nsw i32 %214, 23
  %216 = add i32 %215, 1065353216
  %217 = bitcast i32 %216 to float
  %218 = and i32 %2, -2147483648
  %219 = shl i32 %5, 1
  %220 = icmp ugt i32 %219, -16777216
  %.not = icmp eq i32 %3, 2139095040
  %or.cond = or i1 %.not, %220
  br i1 %or.cond, label %247, label %221

221:                                              ; preds = %_Z8_cl_rintf.exit3
  %222 = fcmp oeq float %4, %7
  %223 = bitcast i32 %218 to float
  %224 = select i1 %222, float %223, float %0
  %225 = fcmp olt float %207, 0.000000e+00
  %226 = select i1 %225, float %69, float -0.000000e+00
  %227 = fadd float %207, %226
  %228 = mul nsw i32 %214, -4
  %229 = add nsw i32 %228, %208
  %230 = shl i32 %229, 23
  %231 = add i32 %230, 1065353216
  %232 = bitcast i32 %231 to float
  %233 = fmul float %227, %232
  %234 = fmul float %233, %217
  %235 = fmul float %234, %217
  %236 = fmul float %235, %217
  %237 = fmul float %236, %217
  %238 = bitcast float %237 to i32
  %239 = xor i32 %218, %238
  %240 = bitcast i32 %239 to float
  %241 = shl i32 %2, 1
  %242 = icmp ugt i32 %241, -16777216
  %243 = fcmp oeq float %1, 0.000000e+00
  %244 = or i1 %243, %242
  %245 = fcmp ogt float %4, %7
  %246 = select i1 %245, float %240, float %224
  br i1 %244, label %247, label %.r_exit

247:                                              ; preds = %221, %_Z8_cl_rintf.exit3
  br label %.r_exit

.r_exit:                                          ; preds = %247, %221
  %248 = phi float [ %246, %221 ], [ 0x7FF8000000000000, %247 ]
  ret float %248
}

attributes #7 = { nofree nosync nounwind readnone speculatable willreturn }
attributes #8 = { mustprogress nofree norecurse nosync nounwind readnone uwtable willreturn "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="i686" "target-features"="+cx8,+x87" }
attributes #11 = { nounwind }

!86 = !{float 2.500000e+00}
-------------- next part --------------
#include <stdio.h>
#include <math.h>

float _Z8_cl_fmodff(float, float);

int main()
{
  for (int i = 0; i < 10; ++i) {
    float a = ((float)i) / 10.;
    float b = ((float)i) / 45.2 + 0.1;
    float c = _Z8_cl_fmodff(a, b);
    float d = fmodf(a, b);
    float e = d - c;
    float r = e / b;
    printf("a=%g b=%.8g c=%.8g d=%.8g abserr=%g relerr=%g%s\n",
           a, b, c, d, e, r, fabs(r) >= 1e-7 ? " FAIL" : "");
  }
}
-------------- next part --------------
CFLAGS	 = -O2 --target=i386-unknown-linux-gnu -march=i686

all: test_pocl_cl_fmod_llvm14
all: test_pocl_cl_fmod_llvm15

test_pocl_cl_fmod_llvm%: pocl_cl_fmod.ll main.c
	clang-$* $(CFLAGS) $^ -o $@ -lm

clean:
	$(RM) test_pocl_cl_fmod_llvm??


More information about the Pkg-llvm-team mailing list