| Issue |
161770
|
| Summary |
Clang __builtin_constant_p Inconsistent Behavior Issue Report
|
| Labels |
clang
|
| Assignees |
|
| Reporter |
Moi5t
|
**Problem Description**
In Clang 21.1.0, the `__builtin_constant_p` builtin function exhibits inconsistent behavior when using constant arrays (.rodata) versus stack arrays. The function returns true in recursive contexts with constant arrays, but returns false in recursive contexts with stack arrays.
**Test Case 1: Constant Array**
```
#include <stdio.h>
#include <string.h>
__attribute__((always_inline)) static int o_strlen(const char *string) {
if (! __builtin_constant_p(*string)) {
return strlen(string);
}
return *string ? 1 + o_strlen(string + 1) : 0;
}
void entry() {
char *string = "hello world";
printf("%d", o_strlen(string));
}
```
```clang example.c -S -O3 -ffreestanding```
```
.file "example.c"
.text
.globl entry # -- Begin function entry
.p2align 4
.type entry,@function
entry: # @entry
# %bb.0:
leaq .L.str.1(%rip), %rdi
movl $11, %esi
xorl %eax, %eax
jmp printf@PLT # TAILCALL
.Lfunc_end0:
.size entry, .Lfunc_end0-entry
# -- End function
.type .L.str.1,@object # @.str.1
.section .rodata.str1.1,"aMS",@progbits,1
.L.str.1:
.asciz "%d"
.size .L.str.1, 3
.ident "clang version 21.1.0 (https://github.com/llvm/llvm-project.git 3623fe661ae35c6c80ac221f14d85be76aa870f1)"
.section ".note.GNU-stack","",@progbits
.addrsig
```
***Observation***: o_strlen(string) correctly returns 11, showing the compiler recognizes compile-time constants.
***Test Case 2: Stack Array***
```
#include <stdio.h>
#include <string.h>
__attribute__((always_inline)) static int o_strlen(const char *string) {
if (! __builtin_constant_p(*string)) {
return strlen(string);
}
return *string ? 1 + o_strlen(string + 1) : 0;
}
void entry() {
char string[] = {'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\0'};
printf("%d", o_strlen(string));
}
```
```clang example.c -S -O3 -ffreestanding```
```
.file "example.c"
.text
.globl entry # -- Begin function entry
.p2align 4
.type entry,@function
entry: # @entry
# %bb.0:
subq $24, %rsp
movabsq $8031924123371070824, %rax # imm = 0x6F77206F6C6C6568
movq %rax, 8(%rsp)
movl $6581362, 16(%rsp) # imm = 0x646C72
leaq 8(%rsp), %rdi
callq strlen@PLT
leaq .L.str(%rip), %rdi
movl %eax, %esi
xorl %eax, %eax
callq printf@PLT
addq $24, %rsp
retq
.Lfunc_end0:
.size entry, .Lfunc_end0-entry
# -- End function
.type .L__const.entry.string,@object # @__const.entry.string
.section .rodata.str1.1,"aMS",@progbits,1
.L__const.entry.string:
.asciz "hello world"
.size .L__const.entry.string, 12
.type .L.str,@object # @.str
.L.str:
.asciz "%d"
.size .L.str, 3
.ident "clang version 21.1.0 (https://github.com/llvm/llvm-project.git 3623fe661ae35c6c80ac221f14d85be76aa870f1)"
.section ".note.GNU-stack","",@progbits
.addrsig
```
***Observation***: Optimization fails with stack arrays, and `strlen` is called. This is not because stack arrays cannot return true in `__builtin_constant_p`.
***Test Case 3: Isolated __builtin_constant_p Test***
```
#include <stdio.h>
#include <string.h>
void entry() {
char string[] = {'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\0'};
printf("%d", __builtin_constant_p(*string));
}
```
```clang example.c -S -O3 -ffreestanding```
```
.file "example.c"
.text
.globl entry # -- Begin function entry
.p2align 4
.type entry,@function
entry: # @entry
# %bb.0:
leaq .L.str(%rip), %rdi
movl $1, %esi
xorl %eax, %eax
jmp printf@PLT # TAILCALL
.Lfunc_end0:
.size entry, .Lfunc_end0-entry
# -- End function
.type .L.str,@object # @.str
.section .rodata.str1.1,"aMS",@progbits,1
.L.str:
.asciz "%d"
.size .L.str, 3
.ident "clang version 21.1.0 (https://github.com/llvm/llvm-project.git 3623fe661ae35c6c80ac221f14d85be76aa870f1)"
.section ".note.GNU-stack","",@progbits
.addrsig
```
***Observation***: __builtin_constant_p(*string) correctly returns 1 (true), showing the compiler recognizes compile-time constants.
***Additional Issue: __builtin_strlen with -ffreestanding***
```
#include <stdio.h>
#include <string.h>
void entry() {
char *string = "hello world";
printf("%d", __builtin_strlen(string));
}
```
```clang example.c -S -O3 -ffreestanding```
```
.file "example.c"
.text
.globl entry # -- Begin function entry
.p2align 4
.type entry,@function
entry: # @entry
# %bb.0:
pushq %rax
leaq .L.str(%rip), %rdi
callq strlen@PLT
leaq .L.str.1(%rip), %rdi
movq %rax, %rsi
xorl %eax, %eax
popq %rcx
jmp printf@PLT # TAILCALL
.Lfunc_end0:
.size entry, .Lfunc_end0-entry
# -- End function
.type .L.str,@object # @.str
.section .rodata.str1.1,"aMS",@progbits,1
.L.str:
.asciz "hello world"
.size .L.str, 12
.type .L.str.1,@object # @.str.1
.L.str.1:
.asciz "%d"
.size .L.str.1, 3
.ident "clang version 21.1.0 (https://github.com/llvm/llvm-project.git 3623fe661ae35c6c80ac221f14d85be76aa870f1)"
.section ".note.GNU-stack","",@progbits
.addrsig
```
***Observation***: Even though the string is constant and known at compile time, `__builtin_strlen` calls the library function instead of computing the length at compile time.
***Summary of Issues***
- Inconsistent `__builtin_constant_p` behavior: The function works correctly with constant arrays in recursive contexts but fails with stack arrays in the same recursive contexts, even though isolated tests show stack array elements are recognized as constants.
- Suboptimal `__builtin_strlen` with -ffreestanding: The compiler fails to optimize `__builtin_strlen` for constant strings when using -ffreestanding, always emitting calls to the library strlen function.(This may be related to the main issue.)
These behaviors appear to be compiler bugs or implementation limitations that should be addressed for consistent optimization behavior.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs