Skip to content

Instantly share code, notes, and snippets.

@DocBohn
Last active May 15, 2025 16:00
Show Gist options
  • Save DocBohn/c0e4842e0b93a30306a1076f726e7945 to your computer and use it in GitHub Desktop.
Save DocBohn/c0e4842e0b93a30306a1076f726e7945 to your computer and use it in GitHub Desktop.
Code demonstrating that early loop termination using `break` is not an optimization
#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;
}
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
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