Last active
May 15, 2025 16:00
-
-
Save DocBohn/c0e4842e0b93a30306a1076f726e7945 to your computer and use it in GitHub Desktop.
Code demonstrating that early loop termination using `break` is not an optimization
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <string.h> | |
int trim_k_and_r(char s[]) { | |
int n; | |
for (n = strlen(s) - 1; n >= 0; n--) { | |
if (s[n] != ' ' && s[n] != '\t' && s[n] != '\n') { | |
break; | |
} | |
} | |
s[n + 1] = '\0'; | |
return n; | |
} | |
static inline bool is_whitespace(char c) { return (c == ' ' || c == '\t' || c == '\n'); } | |
int trim_cleaner_condition(char s[]) { | |
int n; | |
for (n = strlen(s) - 1; n >= 0; n--) { | |
if (!is_whitespace(s[n])) { | |
break; | |
} | |
} | |
s[n + 1] = '\0'; | |
return n; | |
} | |
int trim_no_break(char s[]) { | |
int n = (int) strlen(s) - 1; | |
while ((n >= 0) && is_whitespace(s[n])) { | |
n--; | |
} | |
s[n + 1] = '\0'; | |
return n; | |
} | |
int trim_whitespace_first(char s[]) { | |
int n = (int) strlen(s) - 1; | |
while (is_whitespace(s[n]) && (n >= 0)) { // extra memory access won't change the outcome | |
n--; | |
} | |
s[n + 1] = '\0'; | |
return n; | |
} | |
int trim_unhappy_path_break(char s[]) { | |
int n = (int) strlen(s) - 1; | |
if (n == -1) return n; | |
while (is_whitespace(s[n])) { | |
n--; | |
if (n < 0) { | |
break; | |
} | |
} | |
s[n + 1] = '\0'; | |
return n; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
trim_k_and_r: | |
stp x29, x30, [sp, -32]! | |
mov x29, sp | |
str x19, [sp, 16] | |
mov x19, x0 | |
bl strlen | |
sub w0, w0, #1 | |
b .L2 | |
.L3: | |
sub w0, w0, #1 | |
.L2: | |
tbnz w0, #31, .L4 | |
ldrb w1, [x19, w0, sxtw] | |
cmp w1, 32 | |
ccmp w1, 9, 4, ne | |
beq .L3 | |
cmp w1, 10 | |
beq .L3 | |
.L4: | |
sxtw x1, w0 | |
add x1, x1, 1 | |
strb wzr, [x19, x1] | |
ldr x19, [sp, 16] | |
ldp x29, x30, [sp], 32 | |
ret | |
trim_cleaner_condition: | |
stp x29, x30, [sp, -32]! | |
mov x29, sp | |
str x19, [sp, 16] | |
mov x19, x0 | |
bl strlen | |
sub w0, w0, #1 | |
b .L8 | |
.L9: | |
sub w0, w0, #1 | |
.L8: | |
tbnz w0, #31, .L10 | |
ldrb w1, [x19, w0, sxtw] | |
cmp w1, 32 | |
cset w3, eq | |
cmp w1, 9 | |
cset w2, eq | |
cmp w3, 0 | |
ccmp w2, 0, 0, eq | |
bne .L9 | |
cmp w1, 10 | |
beq .L9 | |
.L10: | |
sxtw x1, w0 | |
add x1, x1, 1 | |
strb wzr, [x19, x1] | |
ldr x19, [sp, 16] | |
ldp x29, x30, [sp], 32 | |
ret | |
trim_no_break: | |
stp x29, x30, [sp, -32]! | |
mov x29, sp | |
str x19, [sp, 16] | |
mov x19, x0 | |
bl strlen | |
sub w0, w0, #1 | |
b .L14 | |
.L16: | |
sub w0, w0, #1 | |
.L14: | |
tbnz w0, #31, .L15 | |
ldrb w1, [x19, w0, sxtw] | |
cmp w1, 32 | |
cset w3, eq | |
cmp w1, 9 | |
cset w2, eq | |
cmp w3, 0 | |
ccmp w2, 0, 0, eq | |
bne .L16 | |
cmp w1, 10 | |
beq .L16 | |
.L15: | |
sxtw x1, w0 | |
add x1, x1, 1 | |
strb wzr, [x19, x1] | |
ldr x19, [sp, 16] | |
ldp x29, x30, [sp], 32 | |
ret | |
trim_whitespace_first: | |
stp x29, x30, [sp, -32]! | |
mov x29, sp | |
str x19, [sp, 16] | |
mov x19, x0 | |
bl strlen | |
sub w0, w0, #1 | |
b .L19 | |
.L20: | |
tbnz w0, #31, .L21 | |
sub w0, w0, #1 | |
.L19: | |
sxtw x2, w0 | |
ldrb w1, [x19, w0, sxtw] | |
cmp w1, 32 | |
cset w4, eq | |
cmp w1, 9 | |
cset w3, eq | |
cmp w4, 0 | |
ccmp w3, 0, 0, eq | |
bne .L20 | |
cmp w1, 10 | |
beq .L20 | |
.L21: | |
add x2, x2, 1 | |
strb wzr, [x19, x2] | |
ldr x19, [sp, 16] | |
ldp x29, x30, [sp], 32 | |
ret | |
trim_unhappy_path_break: | |
stp x29, x30, [sp, -32]! | |
mov x29, sp | |
str x19, [sp, 16] | |
mov x19, x0 | |
bl strlen | |
sub w1, w0, #1 | |
cbnz w0, .L26 | |
b .L24 | |
.L28: | |
subs w1, w1, #1 | |
bmi .L27 | |
.L26: | |
ldrb w2, [x19, w1, sxtw] | |
cmp w2, 32 | |
cset w3, eq | |
cmp w2, 9 | |
cset w0, eq | |
cmp w3, 0 | |
ccmp w0, 0, 0, eq | |
bne .L28 | |
cmp w2, 10 | |
beq .L28 | |
.L27: | |
sxtw x0, w1 | |
add x0, x0, 1 | |
strb wzr, [x19, x0] | |
.L24: | |
mov w0, w1 | |
ldr x19, [sp, 16] | |
ldp x29, x30, [sp], 32 | |
ret |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
trim_k_and_r: | |
pushq %rbx | |
movq %rdi, %rbx | |
call strlen | |
subl $1, %eax | |
jmp .L2 | |
.L3: | |
subl $1, %eax | |
.L2: | |
testl %eax, %eax | |
js .L4 | |
movslq %eax, %rdx | |
movzbl (%rbx,%rdx), %edx | |
cmpb $32, %dl | |
setne %sil | |
cmpb $9, %dl | |
setne %cl | |
testb %cl, %sil | |
je .L3 | |
cmpb $10, %dl | |
je .L3 | |
.L4: | |
movslq %eax, %rdx | |
movb $0, 1(%rbx,%rdx) | |
popq %rbx | |
ret | |
trim_cleaner_condition: | |
pushq %rbx | |
movq %rdi, %rbx | |
call strlen | |
subl $1, %eax | |
jmp .L8 | |
.L9: | |
subl $1, %eax | |
.L8: | |
testl %eax, %eax | |
js .L10 | |
movslq %eax, %rdx | |
movzbl (%rbx,%rdx), %edx | |
cmpb $32, %dl | |
sete %cl | |
cmpb $9, %dl | |
sete %sil | |
orb %sil, %cl | |
jne .L9 | |
cmpb $10, %dl | |
je .L9 | |
.L10: | |
movslq %eax, %rdx | |
movb $0, 1(%rbx,%rdx) | |
popq %rbx | |
ret | |
trim_no_break: | |
pushq %rbx | |
movq %rdi, %rbx | |
call strlen | |
subl $1, %eax | |
jmp .L14 | |
.L16: | |
subl $1, %eax | |
.L14: | |
testl %eax, %eax | |
js .L15 | |
movslq %eax, %rdx | |
movzbl (%rbx,%rdx), %edx | |
cmpb $32, %dl | |
sete %cl | |
cmpb $9, %dl | |
sete %sil | |
orb %sil, %cl | |
jne .L16 | |
cmpb $10, %dl | |
je .L16 | |
.L15: | |
movslq %eax, %rdx | |
movb $0, 1(%rbx,%rdx) | |
popq %rbx | |
ret | |
trim_whitespace_first: | |
pushq %rbx | |
movq %rdi, %rbx | |
call strlen | |
subl $1, %eax | |
jmp .L19 | |
.L20: | |
testl %eax, %eax | |
js .L21 | |
subl $1, %eax | |
.L19: | |
movslq %eax, %rsi | |
movzbl (%rbx,%rsi), %edx | |
cmpb $32, %dl | |
sete %cl | |
cmpb $9, %dl | |
sete %dil | |
orb %dil, %cl | |
jne .L20 | |
cmpb $10, %dl | |
je .L20 | |
.L21: | |
movb $0, 1(%rbx,%rsi) | |
popq %rbx | |
ret | |
trim_unhappy_path_break: | |
pushq %rbx | |
movq %rdi, %rbx | |
call strlen | |
movq %rax, %rdx | |
leal -1(%rax), %eax | |
testl %edx, %edx | |
jne .L26 | |
jmp .L24 | |
.L28: | |
subl $1, %eax | |
js .L27 | |
.L26: | |
movslq %eax, %rdx | |
movzbl (%rbx,%rdx), %edx | |
cmpb $32, %dl | |
sete %cl | |
cmpb $9, %dl | |
sete %sil | |
orb %sil, %cl | |
jne .L28 | |
cmpb $10, %dl | |
je .L28 | |
.L27: | |
movslq %eax, %rdx | |
movb $0, 1(%rbx,%rdx) | |
.L24: | |
popq %rbx | |
ret |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment