[PATCH 37/59] math: Fix modf{f} build on clang
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Thu Oct 23 14:00:37 GMT 2025
On 22/10/25 18:51, H.J. Lu wrote:
> On Thu, Oct 23, 2025 at 12:26 AM Adhemerval Zanella Netto
> <adhemerval.zanella@linaro.org> wrote:
>>
>>
>>
>> On 20/10/25 19:09, H.J. Lu wrote:
>>> On Tue, Oct 21, 2025 at 1:58 AM Adhemerval Zanella Netto
>>> <adhemerval.zanella@linaro.org> wrote:
>>>>
>>>>
>>>>
>>>> On 18/10/25 03:28, H.J. Lu wrote:
>>>>> On Sat, Oct 18, 2025 at 3:58 AM Adhemerval Zanella
>>>>> <adhemerval.zanella@linaro.org> wrote:
>>>>>>
>>>>>> We need to disable the internal optimize for math builtins
>>>>>> (NO_MATH_REDIRECT) for the USE_TRUNC_BUILTIN case.
>>>>>
>>>>> Does it change GCC codegen?
>>>>
>>>> No, both with clang and gcc either the builtin is issues (on
>>>> aarch64 for instance) or the internal symbol is called.
>>>
>>> Why does NO_MATH_REDIRECT make no difference here?
>>> Why is this macro needed?
>>
>> With clang the internal optimization to avoid PLT usage for symbol
>> that might be inline will make clang to *not* emit the builtin:
>>
>> include/math.h
>>
>> 177 MATH_REDIRECT (trunc, "__", MATH_REDIRECT_UNARY_ARGS)
>>
>> Without NO_MATH_REDIRECT, which disables it; build with clang
>> fails:
>>
>>>>> referenced by s_modf.c:34 ([...]/../sysdeps/ieee754/dbl-64/s_modf.c:34)
>>>>> [...]/aarch64-linux-gnu-clang-21/libc_pic.os.clean:(__modf)
>> clang: error: linker command failed with exit code 1 (use -v to see invocation)
>>
>> gcc is not affected by this, it will emit the 'frintz' regardless
>> of MATH_REDIRECT.
>
> So clang won't inline trunc without NO_MATH_REDIRECT?
> Why isn't gcc impacted?
>
Here is a simplified testcase:
extern float truncf (float __x) __attribute__ ((__nothrow__ )) __attribute__ ((__const__));
extern float __truncf (float __x) __attribute__ ((__nothrow__ )) __attribute__ ((__const__));
#ifdef ALIAS
float (truncf) (float) asm ("__truncf");
#endif
float foo (float x) { return truncf (x); }
If ALIAS is defined clang will always emit a __truncf call. It seems that alias
are applied as early as possible, from -emit-llvm -mllvm -print-after-all
I see that ForceFunctionAttrsPass is the first used and it already issues
a "%call = call float @__truncf(float noundef %0) #2".
Without ALIAS defined, the first IR is already created with a builtin:
%1 = call float @llvm.experimental.constrained.trunc.f32(float %0, metadata !"fpexcept.strict") #2
The gcc does not seems to expand the alias, or have an optimization to
to not consider it. With -fdump-tree-all -fdump-rtl-all I see that the
143t.pre pass have:
---
[...]
ANYTHING = { ANYTHING }
ESCAPED = { ESCAPED NONLOCAL }
NONLOCAL = { ESCAPED NONLOCAL }
STOREDANYTHING = { }
INTEGER = { ANYTHING }
x = { NONLOCAL }
*__truncf = { }
callescape(10) = { NONLOCAL } same as x
CALLUSED(11) = { NONLOCAL } same as x
CALLCLOBBERED(12) = { }
callarg(13) = { NONLOCAL }
_2 = { NONLOCAL } same as callarg(13)
foo = { }
Alias information for foo
Aliased symbols
Call clobber information
[...]
float foo (float x)
{
float _2;
<bb 2> [local count: 1073741824]:
_2 = truncf (x_1(D));
return _2;
}
---
And later on 255r.expand I see that it has selected the expected instruction
since the alias is ignored:
;;
;; Full RTL generated for this function:
;;
(note 1 0 4 NOTE_INSN_DELETED)
(note 4 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
(insn 2 4 3 2 (set (reg/v:SF 93 [ x ])
(reg:SF 32 v0 [ x ])) "t.c":6:21 -1
(nil))
(note 3 2 6 2 NOTE_INSN_FUNCTION_BEG)
(insn 6 3 10 2 (set (reg:SF 92 [ <retval> ])
(unspec:SF [
(reg/v:SF 93 [ x ])
] UNSPEC_FRINTZ)) "t.c":6:30 -1
(nil))
(insn 10 6 11 2 (set (reg/i:SF 32 v0)
(reg:SF 92 [ <retval> ])) "t.c":6:42 -1
(nil))
(insn 11 10 0 2 (use (reg/i:SF 32 v0)) "t.c":6:42 -1
(nil))
More information about the Libc-alpha
mailing list