Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LLVM 19.1.0 clang-cl x86 target, /fp:fast, acosf breaks link #109599

Closed
Nick-Kooij opened this issue Sep 23, 2024 · 16 comments · Fixed by #111218 or #101268
Closed

LLVM 19.1.0 clang-cl x86 target, /fp:fast, acosf breaks link #109599

Nick-Kooij opened this issue Sep 23, 2024 · 16 comments · Fixed by #111218 or #101268

Comments

@Nick-Kooij
Copy link

The following program prints π and exits:

#include <cmath>
#include <cstdio>

int main( int argc, char** argv ) {
    printf( "%f\n", acosf( 0.0f ) * 2 );
    return 0;
}

Compiling the above single-module program with LLVM 19.1.0 through the clang-cl driver, targeting x86, with the fast math (/fp:fast) switch fails to link:

lld-link : error : undefined symbol: _acosf

Steps to reproduce:

  • Obtained LLVM-19.1.0-win64.exe from the official Assests.
  • Install on Windows 11 with Visual Studio 2022 17.11.4
  • Must build a x86 target
    • x64 targets link and run properly
  • Must use the /fp:fast fast math mode compiler switch

This issue was introduced with LLVM 19.1.0, and is not a result of changes to Visual Studio. Prior versions, such as LLVM 18.1.8, link properly, using the aforementioned version Visual Studio.

@Nick-Kooij
Copy link
Author

Attached is a zip archiving, ACosfTest.zip, containing a small Visual Studio 2022 17.11.4 project that show the issue.

Note: attempt to build the a x86 Build

@dtcxzyw dtcxzyw added platform:windows clang-cl `clang-cl` driver. Don't use for other compiler parts floating-point Floating-point math and removed new issue labels Sep 23, 2024
@arsenm
Copy link
Contributor

arsenm commented Sep 23, 2024

x86_32 windows does not have acosf as a library function, at least according to the code:

// Win32 does not support float C89 math functions, in general.

Constant folding is not supposed to occur for library functions which are not recognized, and thus the call should survive compilation. This code should always have failed to link. I'm not sure how you are seeing it ever pass. I see the call is not eliminated in 18 either: https://godbolt.org/z/9dcWPKKsv

@zufuliu
Copy link

zufuliu commented Sep 23, 2024

This code should always have failed to link.

This is not true, msvc acosf is defined as inline function for win32, relevant code from ucrt math.h (corecrt_math.h):

    #if defined _M_X64 || defined _M_ARM || defined _M_ARM64 || defined _M_HYBRID_X86_ARM64 || defined _CORECRT_BUILD_APISET || defined _M_ARM64EC

        _Check_return_ _ACRTIMP float __cdecl acosf(_In_ float _X);
        _Check_return_ _ACRTIMP float __cdecl asinf(_In_ float _X);
        _Check_return_ _ACRTIMP float __cdecl atan2f(_In_ float _Y, _In_ float _X);
        _Check_return_ _ACRTIMP float __cdecl atanf(_In_ float _X);
        _Check_return_ _ACRTIMP float __cdecl ceilf(_In_ float _X);
        _Check_return_ _ACRTIMP float __cdecl cosf(_In_ float _X);
        _Check_return_ _ACRTIMP float __cdecl coshf(_In_ float _X);
        _Check_return_ _ACRTIMP float __cdecl expf(_In_ float _X);

    #else

        _Check_return_ __inline float __CRTDECL acosf(_In_ float _X)
        {
            return (float)acos(_X);
        }

for OP's test file, open "x86 Native Tools Command Prompt for VS 2022":

**********************************************************************
** Visual Studio 2022 Developer Command Prompt v17.11.4
** Copyright (c) 2022 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x86'

D:\Program Files\Microsoft Visual Studio\2022>cd d:\

d:\>cl /fp:fast test.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.41.34120 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

test.cpp
Microsoft (R) Incremental Linker Version 14.41.34120.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:test.exe
test.obj

d:\>clang-cl --target=i686-pc-windows-msvc /fp:fast test.cpp
test-fac079.obj : error LNK2019: unresolved external symbol _acosf referenced in function _main
test.exe : fatal error LNK1120: 1 unresolved externals
clang-cl: error: linker command failed with exit code 1120 (use -v to see invocation)

d:\>clang-cl --target=i686-pc-windows-msvc test.cpp

d:\>

@zufuliu
Copy link

zufuliu commented Sep 23, 2024

It's seems with fp:fast, the inline function is not used.

d:\>clang-cl --target=i686-pc-windows-msvc /fp:fast /c test.cpp

d:\>dumpbin /all test.obj > fast.log

d:\>clang-cl --target=i686-pc-windows-msvc /c test.cpp

d:\>dumpbin /all test.obj > default.log

compare fast.log and default.log, _cos is missing from fast.log's COFF SYMBOL TABLE.
image

@arsenm
Copy link
Contributor

arsenm commented Sep 23, 2024

This is not true, msvc acosf is defined as inline function for win32, relevant code from ucrt math.h (corecrt_math.h):

Is TargetLibraryInfo wrong then, or were these added in a later version of the runtime?

@zufuliu
Copy link

zufuliu commented Sep 23, 2024

or were these added in a later version of the runtime

Seems not, LLVM 18.1.8 and 19.1.0 use same headers, but COFF SYMBOL TABLE created by clang-cl 18.1.8 contains _cos (dumpbin /all test.obj > fast18.log output fast18.log is same as clang-cl 19.1.0's default.log except timestamp).

@zufuliu
Copy link

zufuliu commented Sep 23, 2024

IR for clang-cl --target=i686-pc-windows-msvc /c -Xclang -emit-llvm test.cpp:

; ModuleID = 'test.cpp'
source_filename = "test.cpp"
target datalayout = "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32"
target triple = "i686-pc-windows-msvc19.41.34120"

$printf = comdat any

$acosf = comdat any

$_vfprintf_l = comdat any

$__local_stdio_printf_options = comdat any

$"??_C@_03PPOCCAPH@?$CFf?6?$AA@" = comdat any

$"?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA" = comdat any

@"??_C@_03PPOCCAPH@?$CFf?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [4 x i8] c"%f\0A\00", comdat, align 1
@"?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA" = linkonce_odr dso_local global i64 0, comdat, align 8

; Function Attrs: mustprogress noinline norecurse nounwind optnone sspstrong
define dso_local noundef i32 @main(i32 noundef %0, ptr noundef %1) #0 {
  %3 = alloca i32, align 4
  %4 = alloca ptr, align 4
  %5 = alloca i32, align 4
  store i32 0, ptr %3, align 4
  store ptr %1, ptr %4, align 4
  store i32 %0, ptr %5, align 4
  %6 = call float @acosf(float noundef 0.000000e+00) #5
  %7 = fmul float %6, 2.000000e+00
  %8 = fpext float %7 to double
  %9 = call i32 (ptr, ...) @printf(ptr noundef @"??_C@_03PPOCCAPH@?$CFf?6?$AA@", double noundef %8)
  ret i32 0
}

; Function Attrs: mustprogress noinline nounwind optnone sspstrong
define linkonce_odr dso_local i32 @printf(ptr noundef %0, ...) #1 comdat {
  %2 = alloca ptr, align 4
  %3 = alloca i32, align 4
  %4 = alloca ptr, align 4
  store ptr %0, ptr %2, align 4
  call void @llvm.va_start.p0(ptr %4)
  %5 = load ptr, ptr %4, align 4
  %6 = load ptr, ptr %2, align 4
  %7 = call ptr @__acrt_iob_func(i32 noundef 1)
  %8 = call i32 @_vfprintf_l(ptr noundef %7, ptr noundef %6, ptr noundef null, ptr noundef %5)
  store i32 %8, ptr %3, align 4
  call void @llvm.va_end.p0(ptr %4)
  %9 = load i32, ptr %3, align 4
  ret i32 %9
}

; Function Attrs: mustprogress noinline nounwind optnone sspstrong
define linkonce_odr dso_local float @acosf(float noundef %0) #1 comdat {
  %2 = alloca float, align 4
  store float %0, ptr %2, align 4
  %3 = load float, ptr %2, align 4
  %4 = fpext float %3 to double
  %5 = call double @acos(double noundef %4) #5
  %6 = fptrunc double %5 to float
  ret float %6
}

; Function Attrs: nocallback nofree nosync nounwind willreturn
declare void @llvm.va_start.p0(ptr) #2

; Function Attrs: mustprogress noinline nounwind optnone sspstrong
define linkonce_odr dso_local i32 @_vfprintf_l(ptr noundef %0, ptr noundef %1, ptr noundef %2, ptr noundef %3) #1 comdat {
  %5 = alloca ptr, align 4
  %6 = alloca ptr, align 4
  %7 = alloca ptr, align 4
  %8 = alloca ptr, align 4
  store ptr %3, ptr %5, align 4
  store ptr %2, ptr %6, align 4
  store ptr %1, ptr %7, align 4
  store ptr %0, ptr %8, align 4
  %9 = load ptr, ptr %5, align 4
  %10 = load ptr, ptr %6, align 4
  %11 = load ptr, ptr %7, align 4
  %12 = load ptr, ptr %8, align 4
  %13 = call ptr @__local_stdio_printf_options()
  %14 = load i64, ptr %13, align 8
  %15 = call i32 @__stdio_common_vfprintf(i64 noundef %14, ptr noundef %12, ptr noundef %11, ptr noundef %10, ptr noundef %9)
  ret i32 %15
}

declare dso_local ptr @__acrt_iob_func(i32 noundef) #3

; Function Attrs: nocallback nofree nosync nounwind willreturn
declare void @llvm.va_end.p0(ptr) #2

declare dso_local i32 @__stdio_common_vfprintf(i64 noundef, ptr noundef, ptr noundef, ptr noundef, ptr noundef) #3

; Function Attrs: mustprogress noinline nounwind optnone sspstrong
define linkonce_odr dso_local ptr @__local_stdio_printf_options() #1 comdat {
  ret ptr @"?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA"
}

; Function Attrs: nounwind
declare dso_local double @acos(double noundef) #4

attributes #0 = { mustprogress noinline norecurse nounwind optnone sspstrong "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { mustprogress noinline nounwind optnone sspstrong "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #2 = { nocallback nofree nosync nounwind willreturn }
attributes #3 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #4 = { nounwind "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #5 = { nounwind }

!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.linker.options = !{!4, !5, !6, !7, !8, !9, !10}
!llvm.ident = !{!11}

!0 = !{i32 1, !"NumRegisterParameters", i32 0}
!1 = !{i32 1, !"wchar_size", i32 2}
!2 = !{i32 7, !"frame-pointer", i32 2}
!3 = !{i32 1, !"MaxTLSAlign", i32 65536}
!4 = !{!"/DEFAULTLIB:libcmt.lib"}
!5 = !{!"/DEFAULTLIB:oldnames.lib"}
!6 = !{!"/FAILIFMISMATCH:\22_MSC_VER=1900\22"}
!7 = !{!"/FAILIFMISMATCH:\22_ITERATOR_DEBUG_LEVEL=0\22"}
!8 = !{!"/FAILIFMISMATCH:\22RuntimeLibrary=MT_StaticRelease\22"}
!9 = !{!"/DEFAULTLIB:libcpmt.lib"}
!10 = !{!"/FAILIFMISMATCH:\22_CRT_STDIO_ISO_WIDE_SPECIFIERS=0\22"}
!11 = !{!"clang version 19.1.0"}

IR for clang-cl --target=i686-pc-windows-msvc /c /fp:fast -Xclang -emit-llvm test.cpp:

; ModuleID = 'test.cpp'
source_filename = "test.cpp"
target datalayout = "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32"
target triple = "i686-pc-windows-msvc19.41.34120"

$printf = comdat any

$_vfprintf_l = comdat any

$__local_stdio_printf_options = comdat any

$"??_C@_03PPOCCAPH@?$CFf?6?$AA@" = comdat any

$"?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA" = comdat any

@"??_C@_03PPOCCAPH@?$CFf?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [4 x i8] c"%f\0A\00", comdat, align 1
@"?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA" = linkonce_odr dso_local global i64 0, comdat, align 8

; Function Attrs: mustprogress noinline norecurse nounwind optnone sspstrong
define dso_local noundef i32 @main(i32 noundef %0, ptr noundef %1) #0 {
  %3 = alloca i32, align 4
  %4 = alloca ptr, align 4
  %5 = alloca i32, align 4
  store i32 0, ptr %3, align 4
  store ptr %1, ptr %4, align 4
  store i32 %0, ptr %5, align 4
  %6 = call fast float @llvm.acos.f32(float 0.000000e+00)
  %7 = fmul fast float %6, 2.000000e+00
  %8 = fpext float %7 to double
  %9 = call i32 (ptr, ...) @printf(ptr noundef @"??_C@_03PPOCCAPH@?$CFf?6?$AA@", double noundef nofpclass(nan inf) %8)
  ret i32 0
}

; Function Attrs: mustprogress noinline nounwind optnone sspstrong
define linkonce_odr dso_local i32 @printf(ptr noundef %0, ...) #1 comdat {
  %2 = alloca ptr, align 4
  %3 = alloca i32, align 4
  %4 = alloca ptr, align 4
  store ptr %0, ptr %2, align 4
  call void @llvm.va_start.p0(ptr %4)
  %5 = load ptr, ptr %4, align 4
  %6 = load ptr, ptr %2, align 4
  %7 = call ptr @__acrt_iob_func(i32 noundef 1)
  %8 = call i32 @_vfprintf_l(ptr noundef %7, ptr noundef %6, ptr noundef null, ptr noundef %5)
  store i32 %8, ptr %3, align 4
  call void @llvm.va_end.p0(ptr %4)
  %9 = load i32, ptr %3, align 4
  ret i32 %9
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare float @llvm.acos.f32(float) #2

; Function Attrs: nocallback nofree nosync nounwind willreturn
declare void @llvm.va_start.p0(ptr) #3

; Function Attrs: mustprogress noinline nounwind optnone sspstrong
define linkonce_odr dso_local i32 @_vfprintf_l(ptr noundef %0, ptr noundef %1, ptr noundef %2, ptr noundef %3) #1 comdat {
  %5 = alloca ptr, align 4
  %6 = alloca ptr, align 4
  %7 = alloca ptr, align 4
  %8 = alloca ptr, align 4
  store ptr %3, ptr %5, align 4
  store ptr %2, ptr %6, align 4
  store ptr %1, ptr %7, align 4
  store ptr %0, ptr %8, align 4
  %9 = load ptr, ptr %5, align 4
  %10 = load ptr, ptr %6, align 4
  %11 = load ptr, ptr %7, align 4
  %12 = load ptr, ptr %8, align 4
  %13 = call ptr @__local_stdio_printf_options()
  %14 = load i64, ptr %13, align 8
  %15 = call i32 @__stdio_common_vfprintf(i64 noundef %14, ptr noundef %12, ptr noundef %11, ptr noundef %10, ptr noundef %9)
  ret i32 %15
}

declare dso_local ptr @__acrt_iob_func(i32 noundef) #4

; Function Attrs: nocallback nofree nosync nounwind willreturn
declare void @llvm.va_end.p0(ptr) #3

declare dso_local i32 @__stdio_common_vfprintf(i64 noundef, ptr noundef, ptr noundef, ptr noundef, ptr noundef) #4

; Function Attrs: mustprogress noinline nounwind optnone sspstrong
define linkonce_odr dso_local ptr @__local_stdio_printf_options() #1 comdat {
  ret ptr @"?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA"
}

attributes #0 = { mustprogress noinline norecurse nounwind optnone sspstrong "approx-func-fp-math"="true" "frame-pointer"="all" "min-legal-vector-width"="0" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="true" }
attributes #1 = { mustprogress noinline nounwind optnone sspstrong "approx-func-fp-math"="true" "frame-pointer"="all" "min-legal-vector-width"="0" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="true" }
attributes #2 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
attributes #3 = { nocallback nofree nosync nounwind willreturn }
attributes #4 = { "approx-func-fp-math"="true" "frame-pointer"="all" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="true" }

!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.linker.options = !{!4, !5, !6, !7, !8, !9, !10}
!llvm.ident = !{!11}

!0 = !{i32 1, !"NumRegisterParameters", i32 0}
!1 = !{i32 1, !"wchar_size", i32 2}
!2 = !{i32 7, !"frame-pointer", i32 2}
!3 = !{i32 1, !"MaxTLSAlign", i32 65536}
!4 = !{!"/DEFAULTLIB:libcmt.lib"}
!5 = !{!"/DEFAULTLIB:oldnames.lib"}
!6 = !{!"/FAILIFMISMATCH:\22_MSC_VER=1900\22"}
!7 = !{!"/FAILIFMISMATCH:\22_ITERATOR_DEBUG_LEVEL=0\22"}
!8 = !{!"/FAILIFMISMATCH:\22RuntimeLibrary=MT_StaticRelease\22"}
!9 = !{!"/DEFAULTLIB:libcpmt.lib"}
!10 = !{!"/FAILIFMISMATCH:\22_CRT_STDIO_ISO_WIDE_SPECIFIERS=0\22"}
!11 = !{!"clang version 19.1.0"}

IR for clang-cl --target=i686-pc-windows-msvc /c -Xclang -ffast-math -Xclang -emit-llvm test.cpp:

; ModuleID = 'test.cpp'
source_filename = "test.cpp"
target datalayout = "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32"
target triple = "i686-pc-windows-msvc19.41.34120"

$printf = comdat any

$acosf = comdat any

$_vfprintf_l = comdat any

$__local_stdio_printf_options = comdat any

$"??_C@_03PPOCCAPH@?$CFf?6?$AA@" = comdat any

$"?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA" = comdat any

@"??_C@_03PPOCCAPH@?$CFf?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [4 x i8] c"%f\0A\00", comdat, align 1
@"?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA" = linkonce_odr dso_local global i64 0, comdat, align 8

; Function Attrs: mustprogress noinline norecurse nounwind optnone sspstrong
define dso_local noundef i32 @main(i32 noundef %0, ptr noundef %1) #0 {
  %3 = alloca i32, align 4
  %4 = alloca ptr, align 4
  %5 = alloca i32, align 4
  store i32 0, ptr %3, align 4
  store ptr %1, ptr %4, align 4
  store i32 %0, ptr %5, align 4
  %6 = call reassoc nnan ninf nsz arcp afn nofpclass(nan inf) float @acosf(float noundef nofpclass(nan inf) 0.000000e+00) #5
  %7 = fmul reassoc nnan ninf nsz arcp afn float %6, 2.000000e+00
  %8 = fpext float %7 to double
  %9 = call i32 (ptr, ...) @printf(ptr noundef @"??_C@_03PPOCCAPH@?$CFf?6?$AA@", double noundef nofpclass(nan inf) %8)
  ret i32 0
}

; Function Attrs: mustprogress noinline nounwind optnone sspstrong
define linkonce_odr dso_local i32 @printf(ptr noundef %0, ...) #1 comdat {
  %2 = alloca ptr, align 4
  %3 = alloca i32, align 4
  %4 = alloca ptr, align 4
  store ptr %0, ptr %2, align 4
  call void @llvm.va_start.p0(ptr %4)
  %5 = load ptr, ptr %4, align 4
  %6 = load ptr, ptr %2, align 4
  %7 = call ptr @__acrt_iob_func(i32 noundef 1)
  %8 = call i32 @_vfprintf_l(ptr noundef %7, ptr noundef %6, ptr noundef null, ptr noundef %5)
  store i32 %8, ptr %3, align 4
  call void @llvm.va_end.p0(ptr %4)
  %9 = load i32, ptr %3, align 4
  ret i32 %9
}

; Function Attrs: mustprogress noinline nounwind optnone sspstrong
define linkonce_odr dso_local nofpclass(nan inf) float @acosf(float noundef nofpclass(nan inf) %0) #1 comdat {
  %2 = alloca float, align 4
  store float %0, ptr %2, align 4
  %3 = load float, ptr %2, align 4
  %4 = fpext float %3 to double
  %5 = call reassoc nnan ninf nsz arcp afn nofpclass(nan inf) double @acos(double noundef nofpclass(nan inf) %4) #5
  %6 = fptrunc double %5 to float
  ret float %6
}

; Function Attrs: nocallback nofree nosync nounwind willreturn
declare void @llvm.va_start.p0(ptr) #2

; Function Attrs: mustprogress noinline nounwind optnone sspstrong
define linkonce_odr dso_local i32 @_vfprintf_l(ptr noundef %0, ptr noundef %1, ptr noundef %2, ptr noundef %3) #1 comdat {
  %5 = alloca ptr, align 4
  %6 = alloca ptr, align 4
  %7 = alloca ptr, align 4
  %8 = alloca ptr, align 4
  store ptr %3, ptr %5, align 4
  store ptr %2, ptr %6, align 4
  store ptr %1, ptr %7, align 4
  store ptr %0, ptr %8, align 4
  %9 = load ptr, ptr %5, align 4
  %10 = load ptr, ptr %6, align 4
  %11 = load ptr, ptr %7, align 4
  %12 = load ptr, ptr %8, align 4
  %13 = call ptr @__local_stdio_printf_options()
  %14 = load i64, ptr %13, align 8
  %15 = call i32 @__stdio_common_vfprintf(i64 noundef %14, ptr noundef %12, ptr noundef %11, ptr noundef %10, ptr noundef %9)
  ret i32 %15
}

declare dso_local ptr @__acrt_iob_func(i32 noundef) #3

; Function Attrs: nocallback nofree nosync nounwind willreturn
declare void @llvm.va_end.p0(ptr) #2

declare dso_local i32 @__stdio_common_vfprintf(i64 noundef, ptr noundef, ptr noundef, ptr noundef, ptr noundef) #3

; Function Attrs: mustprogress noinline nounwind optnone sspstrong
define linkonce_odr dso_local ptr @__local_stdio_printf_options() #1 comdat {
  ret ptr @"?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA"
}

; Function Attrs: nounwind
declare dso_local nofpclass(nan inf) double @acos(double noundef nofpclass(nan inf)) #4

attributes #0 = { mustprogress noinline norecurse nounwind optnone sspstrong "approx-func-fp-math"="true" "frame-pointer"="all" "min-legal-vector-width"="0" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { mustprogress noinline nounwind optnone sspstrong "approx-func-fp-math"="true" "frame-pointer"="all" "min-legal-vector-width"="0" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #2 = { nocallback nofree nosync nounwind willreturn }
attributes #3 = { "approx-func-fp-math"="true" "frame-pointer"="all" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #4 = { nounwind "approx-func-fp-math"="true" "frame-pointer"="all" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #5 = { nounwind }

!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.linker.options = !{!4, !5, !6, !7, !8, !9, !10}
!llvm.ident = !{!11}

!0 = !{i32 1, !"NumRegisterParameters", i32 0}
!1 = !{i32 1, !"wchar_size", i32 2}
!2 = !{i32 7, !"frame-pointer", i32 2}
!3 = !{i32 1, !"MaxTLSAlign", i32 65536}
!4 = !{!"/DEFAULTLIB:libcmt.lib"}
!5 = !{!"/DEFAULTLIB:oldnames.lib"}
!6 = !{!"/FAILIFMISMATCH:\22_MSC_VER=1900\22"}
!7 = !{!"/FAILIFMISMATCH:\22_ITERATOR_DEBUG_LEVEL=0\22"}
!8 = !{!"/FAILIFMISMATCH:\22RuntimeLibrary=MT_StaticRelease\22"}
!9 = !{!"/DEFAULTLIB:libcpmt.lib"}
!10 = !{!"/FAILIFMISMATCH:\22_CRT_STDIO_ISO_WIDE_SPECIFIERS=0\22"}
!11 = !{!"clang version 19.1.0"}

according to Options.td, /fp:fast is alias for -ffast-math, but clang-cl --target=i686-pc-windows-msvc -Xclang -ffast-math test.cpp links without error.

def _SLASH_fp_fast : CLFlag<"fp:fast">, HelpText<"">, Alias<ffast_math>;

@zufuliu
Copy link

zufuliu commented Sep 23, 2024

IR for 18.1.8 clang-cl --target=i686-pc-windows-msvc /c /fp:fast -Xclang -emit-llvm test.cpp (which is similar to LLVM 19.1.0's clang-cl --target=i686-pc-windows-msvc /c -Xclang -ffast-math -Xclang -emit-llvm test.cpp):

; ModuleID = 'test.cpp'
source_filename = "test.cpp"
target datalayout = "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32"
target triple = "i686-pc-windows-msvc19.41.34120"

$printf = comdat any

$acosf = comdat any

$_vfprintf_l = comdat any

$__local_stdio_printf_options = comdat any

$"??_C@_03PPOCCAPH@?$CFf?6?$AA@" = comdat any

$"?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA" = comdat any

@"??_C@_03PPOCCAPH@?$CFf?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [4 x i8] c"%f\0A\00", comdat, align 1
@"?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA" = linkonce_odr dso_local global i64 0, comdat, align 8

; Function Attrs: mustprogress noinline norecurse nounwind optnone sspstrong
define dso_local noundef i32 @main(i32 noundef %0, ptr noundef %1) #0 {
  %3 = alloca i32, align 4
  %4 = alloca ptr, align 4
  %5 = alloca i32, align 4
  store i32 0, ptr %3, align 4
  store ptr %1, ptr %4, align 4
  store i32 %0, ptr %5, align 4
  %6 = call fast nofpclass(nan inf) float @acosf(float noundef nofpclass(nan inf) 0.000000e+00) #6
  %7 = fmul fast float %6, 2.000000e+00
  %8 = fpext float %7 to double
  %9 = call i32 (ptr, ...) @printf(ptr noundef @"??_C@_03PPOCCAPH@?$CFf?6?$AA@", double noundef nofpclass(nan inf) %8)
  ret i32 0
}

; Function Attrs: mustprogress noinline nounwind optnone sspstrong
define linkonce_odr dso_local i32 @printf(ptr noundef %0, ...) #1 comdat {
  %2 = alloca ptr, align 4
  %3 = alloca i32, align 4
  %4 = alloca ptr, align 4
  store ptr %0, ptr %2, align 4
  call void @llvm.va_start(ptr %4)
  %5 = load ptr, ptr %4, align 4
  %6 = load ptr, ptr %2, align 4
  %7 = call ptr @__acrt_iob_func(i32 noundef 1)
  %8 = call i32 @_vfprintf_l(ptr noundef %7, ptr noundef %6, ptr noundef null, ptr noundef %5)
  store i32 %8, ptr %3, align 4
  call void @llvm.va_end(ptr %4)
  %9 = load i32, ptr %3, align 4
  ret i32 %9
}

; Function Attrs: mustprogress noinline nounwind optnone sspstrong willreturn memory(none)
define linkonce_odr dso_local nofpclass(nan inf) float @acosf(float noundef nofpclass(nan inf) %0) #2 comdat {
  %2 = alloca float, align 4
  store float %0, ptr %2, align 4
  %3 = load float, ptr %2, align 4
  %4 = fpext float %3 to double
  %5 = call fast nofpclass(nan inf) double @acos(double noundef nofpclass(nan inf) %4) #6
  %6 = fptrunc double %5 to float
  ret float %6
}

; Function Attrs: nocallback nofree nosync nounwind willreturn
declare void @llvm.va_start(ptr) #3

; Function Attrs: mustprogress noinline nounwind optnone sspstrong
define linkonce_odr dso_local i32 @_vfprintf_l(ptr noundef %0, ptr noundef %1, ptr noundef %2, ptr noundef %3) #1 comdat {
  %5 = alloca ptr, align 4
  %6 = alloca ptr, align 4
  %7 = alloca ptr, align 4
  %8 = alloca ptr, align 4
  store ptr %3, ptr %5, align 4
  store ptr %2, ptr %6, align 4
  store ptr %1, ptr %7, align 4
  store ptr %0, ptr %8, align 4
  %9 = load ptr, ptr %5, align 4
  %10 = load ptr, ptr %6, align 4
  %11 = load ptr, ptr %7, align 4
  %12 = load ptr, ptr %8, align 4
  %13 = call ptr @__local_stdio_printf_options()
  %14 = load i64, ptr %13, align 8
  %15 = call i32 @__stdio_common_vfprintf(i64 noundef %14, ptr noundef %12, ptr noundef %11, ptr noundef %10, ptr noundef %9)
  ret i32 %15
}

declare dso_local ptr @__acrt_iob_func(i32 noundef) #4

; Function Attrs: nocallback nofree nosync nounwind willreturn
declare void @llvm.va_end(ptr) #3

declare dso_local i32 @__stdio_common_vfprintf(i64 noundef, ptr noundef, ptr noundef, ptr noundef, ptr noundef) #4

; Function Attrs: mustprogress noinline nounwind optnone sspstrong
define linkonce_odr dso_local ptr @__local_stdio_printf_options() #1 comdat {
  ret ptr @"?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA"
}

; Function Attrs: nounwind willreturn memory(none)
declare dso_local nofpclass(nan inf) double @acos(double noundef nofpclass(nan inf)) #5

attributes #0 = { mustprogress noinline norecurse nounwind optnone sspstrong "approx-func-fp-math"="true" "frame-pointer"="all" "min-legal-vector-width"="0" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="true" }
attributes #1 = { mustprogress noinline nounwind optnone sspstrong "approx-func-fp-math"="true" "frame-pointer"="all" "min-legal-vector-width"="0" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="true" }
attributes #2 = { mustprogress noinline nounwind optnone sspstrong willreturn memory(none) "approx-func-fp-math"="true" "frame-pointer"="all" "min-legal-vector-width"="0" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="true" }
attributes #3 = { nocallback nofree nosync nounwind willreturn }
attributes #4 = { "approx-func-fp-math"="true" "frame-pointer"="all" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="true" }
attributes #5 = { nounwind willreturn memory(none) "approx-func-fp-math"="true" "frame-pointer"="all" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="true" }
attributes #6 = { nounwind willreturn memory(none) }

!llvm.linker.options = !{!0, !1, !2, !3, !4, !5, !6}
!llvm.module.flags = !{!7, !8, !9, !10}
!llvm.ident = !{!11}

!0 = !{!"/DEFAULTLIB:libcmt.lib"}
!1 = !{!"/DEFAULTLIB:oldnames.lib"}
!2 = !{!"/FAILIFMISMATCH:\22_MSC_VER=1900\22"}
!3 = !{!"/FAILIFMISMATCH:\22_ITERATOR_DEBUG_LEVEL=0\22"}
!4 = !{!"/FAILIFMISMATCH:\22RuntimeLibrary=MT_StaticRelease\22"}
!5 = !{!"/DEFAULTLIB:libcpmt.lib"}
!6 = !{!"/FAILIFMISMATCH:\22_CRT_STDIO_ISO_WIDE_SPECIFIERS=0\22"}
!7 = !{i32 1, !"NumRegisterParameters", i32 0}
!8 = !{i32 1, !"wchar_size", i32 2}
!9 = !{i32 7, !"frame-pointer", i32 2}
!10 = !{i32 1, !"MaxTLSAlign", i32 65536}
!11 = !{!"clang version 18.1.8"}

@efriedma-quic
Copy link
Collaborator

See #101268 (which was merged to main, but not 19).

@zufuliu
Copy link

zufuliu commented Oct 3, 2024

Still not fixed in 19.1.1.

**********************************************************************
** Visual Studio 2022 Developer Command Prompt v17.11.4
** Copyright (c) 2022 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x86'

D:\Program Files\Microsoft Visual Studio\2022>cd d:\

d:\>clang-cl --target=i686-pc-windows-msvc --version
clang version 19.1.1
Target: i686-pc-windows-msvc
Thread model: posix
InstalledDir: D:\Dev\LLVM\bin

d:\>clang-cl --target=i686-pc-windows-msvc /fp:fast test.cpp
test-92ddf8.obj : error LNK2019: unresolved external symbol _acosf referenced in function _main
test.exe : fatal error LNK1120: 1 unresolved externals
clang-cl: error: linker command failed with exit code 1120 (use -v to see invocation)

@arsenm arsenm added this to the LLVM 19.X Release milestone Oct 4, 2024
@farzonl
Copy link
Member

farzonl commented Oct 4, 2024

@arsenm What am I expected to do here from @tycho comment #101268 (comment) I thought the cherry-pick was already applied 2 weeks ago?

@arsenm
Copy link
Contributor

arsenm commented Oct 4, 2024

#101268 (comment)

I don't see that referenced in this issue, and I don't see the change in the release branch. I guess the auto cherry-pick failed, and the manually merged version didn't materialize?

@farzonl
Copy link
Member

farzonl commented Oct 4, 2024

@arsenm

If that's the case, what do you need me to do to resolve this issue? This is my first time trying to put a patch in a release, so I need some guidance on the process. Do you just want a PR targeting the 19.x branch? How do I keep the merge commit the same or does that not matter?

@efriedma-quic
Copy link
Collaborator

Yes, just a PR against the 19.x branch. The branch is configured to squash-then-merge, so it doesn't matter whether there are any merge commits.

@h-vetinari
Copy link
Contributor

The backport #111218 was now released with LLVM 19.1.2

@arsenm arsenm closed this as completed Oct 16, 2024
@EugeneZelenko EugeneZelenko added backend:X86 and removed clang-cl `clang-cl` driver. Don't use for other compiler parts labels Oct 16, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Oct 16, 2024

@llvm/issue-subscribers-backend-x86

Author: None (Nick-Kooij)

The following program prints π and exits:
#include &lt;cmath&gt;
#include &lt;cstdio&gt;

int main( int argc, char** argv ) {
    printf( "%f\n", acosf( 0.0f ) * 2 );
    return 0;
}

Compiling the above single-module program with LLVM 19.1.0 through the clang-cl driver, targeting x86, with the fast math (/fp:fast) switch fails to link:

lld-link : error : undefined symbol: _acosf

Steps to reproduce:

  • Obtained LLVM-19.1.0-win64.exe from the official Assests.
  • Install on Windows 11 with Visual Studio 2022 17.11.4
  • Must build a x86 target
    • x64 targets link and run properly
  • Must use the /fp:fast fast math mode compiler switch

This issue was introduced with LLVM 19.1.0, and is not a result of changes to Visual Studio. Prior versions, such as LLVM 18.1.8, link properly, using the aforementioned version Visual Studio.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment