for (uint8_t y_cord = 0; y_cord < height; y_cord++) {
for (uint8_t x_cord = 0; x_cord < width; x_cord++) {
/* Write pixel if not transparent */
// 3503 bytes
*dst_buf = (*src_buf != global_Transparent_Color) ? *src_buf : *dst_buf;
// 3518 bytes
if (*src_buf != global_Transparent_Color) { *dst_buf = *src_buf; }
src_buf++;
dst_buf += x_jump;
}
dst_buf -= y_jump;
}
```I am compiling for the eZ80 with Clang C17 -Oz. I have this code to write some (8bit indexed color) image data to the screen (Copying src to dst). The code checks that the pixel isn't equal to `global_Transparent_Color` before writing it.
Why do the ternary and if-statement versions of the code compile to different things?
#Ternary and if-statement compile to different things
25 messages · Page 1 of 1 (latest)
When your question is answered use !solved to mark the question as resolved.
Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.
Are there any edge cases that are causing them to be different?
;asm -Oz
void foo(int* dest, int* source) {
*dest = (*source != -1) ? *source : *dest;
}
void foo2(int* dest, int* source) {
if (*source != -1) {
*dest = *source;
}
}
Assembly Output
foo:
mov eax, DWORD PTR [rsi]
cmp eax, -1
jne .L2
mov eax, DWORD PTR [rdi]
.L2:
mov DWORD PTR [rdi], eax
ret
foo2:
mov eax, DWORD PTR [rsi]
cmp eax, -1
je .L4
mov DWORD PTR [rdi], eax
.L4:
ret
rosepointer | 82ms | c | x86-64 gcc 14.1 | godbolt.org
IDK, maybe the optimizer just doesn't know how to reason that the false condition of the ternary is a no-op
To clarify, the ternary version compiles to smaller and faster code (saves 15 bytes)
thats werid that its the opposite for x86-64
one moment
Well unless you can show the part of the assembly that is different, it is hard to reason about
I tried a bunch of random compilers and archtectures on godbolt, every one seems to have that one additional instruction for the ternary version. Only one produced the exact same for both versions
https://www.diffchecker.com/exawWGHc/
Here is the difference between the two .src files
The eZ80 is 24bit, so pointers are also 24bit```c
typedef struct gfy_sprite_t {
uint8_t width;
uint8_t height;
uint8_t data[];
} gfy_sprite_t;
void gfy_TransparentSprite_NoClip(const gfy_sprite_t* sprite, uint24_t x, uint8_t y) {
const uint8_t* src_buf = sprite->data;
uint8_t* dst_buf = (uint8_t*)((volatile uint24_t)0xE30014) + y + (x * 240);
const uint24_t dst_jump = (240 * sprite->width) - 1;
for (uint8_t y_cord = 0; y_cord < sprite->height; y_cord++) {
for (uint8_t x_cord = 0; x_cord < sprite->width; x_cord++) {
/* Write pixel if not transparent */
// 3503 bytes
*dst_buf = (*src_buf != global_Transparent_Color) ? *src_buf : *dst_buf;
// 3518 bytes
if (*src_buf != global_Transparent_Color) { *dst_buf = *src_buf; }
src_buf++;
dst_buf += 240;
}
dst_buf -= dst_jump;
}
}
the differences between lines 5-36 seem to do the exact same thing, so they can be ignored
Even adding const and restrict, and compiling them separately, these indeed produce always different outputs. Using -Ofast -march=native gives identical output.
;asm -Oz
void foo(int* restrict const dest, const int* restrict const source) {
*dest = (*source != -1) ? *source : *dest;
}
Assembly Output
foo:
mov eax, DWORD PTR [rsi]
cmp eax, -1
jne .L2
mov eax, DWORD PTR [rdi]
.L2:
mov DWORD PTR [rdi], eax
ret
mynameistrez | 118ms | c | x86-64 gcc 14.1 | godbolt.org
;asm -Oz
void foo2(int* restrict const dest, const int* restrict const source) {
if (*source != -1) {
*dest = *source;
}
}
Assembly Output
foo2:
mov eax, DWORD PTR [rsi]
cmp eax, -1
je .L1
mov DWORD PTR [rdi], eax
.L1:
ret
mynameistrez | 150ms | c | x86-64 gcc 14.1 | godbolt.org
This seems pretty strange, but I guess the difference comes down to the ternary version always assigning to dest? But I'd think that shouldn't matter
I found this intriguing enough to post it as a question to Stack Overflow:
https://stackoverflow.com/questions/78623124/why-does-this-ternary-generate-more-assembly-than-an-equivalent-if
The answers to my question on SO say that it's simply a GCC and Clang skill issue, huh
interesting
@mint flame So since I think your question has been answered, with Stack Overflow experts even weighing in, I think you can mark your question with !solved now :)
!solved