-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Might be an opportunity to improve codegen for ternaries where both the expr-if-true and expr-if-false are constants.
I played a little bit with Compiler Explorer today to get a feeling of how GCC and Clang generate the code for this. Here's what I found from looking at the assembly output, with the accompanying C code for reference.
Method 1: sete/setne
int m1(int a) { return a == 5 ? 2 : 3; }Is generated as, by both Clang and GCC:
xor eax, eax
cmp edi, 5
setne al
add eax, 2
retPlaying a bit with Compiler Explorer, it seems that if both expressions in the ternary are apart by 1, then it can reuse the result of "cmp" as part of the expression. ("sete" is generated if the ternary is inverted, as expected: "a == 5 ? 3 : 2".)
Clang seems to go a bit further with this method before switching to use conditional moves as with "m3" below, by issuing an additional "add" instruction if values are apart by 2, for example.
I suspect a simplified version of this codegen could be used for things like Convert.ToInt32(bool b) too.
Method 2: lea
int m2(int a) { return a == 5 ? 10 : 1; }Is generated as, by GCC:
xor eax, eax
cmp edi, 5
sete al
lea eax, [rax+1+rax*8]
retClang generates similar code but changes the "+1" inside the LEA to an "add
eax, 1" before the "ret".
This is a more generic extension to the previous method, and seems to be preferred to the next method, when the operands would fit the constraints of the LEA instruction arguments.
Method 3: cmov
int m3(int a) { return a == 5 ? 1 : 37; }Is generated as, by both Clang and GCC (order varies a bit):
cmp edi, 5
mov edx, 37
mov eax, 1
cmovne eax, edx
retConditional moves seems to be generated when the above conditions do not hold.
category:cq
theme:optimization
skill-level:expert
cost:medium