CODE
int isHtmlWhitespace(int ch) {
return ch == 0x0009 || ch == 0x000A ||
ch == 0x000C || ch == 0x000D ||
ch == 0x0020;
}
return ch == 0x0009 || ch == 0x000A ||
ch == 0x000C || ch == 0x000D ||
ch == 0x0020;
}
GCC with enabled optimizations is able to produce:
CODE
isHtmlWhitespace(int):
cmp edi, 32; compare ch with 0x0020
ja .L42 ; and return false if ch is larger, since 32 is the largest possible match
movabs rax, 4294981120
mov ecx, edi
shr rax, cl
and eax, 1
ret
.L42:
xor eax, eax
ret
cmp edi, 32; compare ch with 0x0020
ja .L42 ; and return false if ch is larger, since 32 is the largest possible match
movabs rax, 4294981120
mov ecx, edi
shr rax, cl
and eax, 1
ret
.L42:
xor eax, eax
ret
Clang generates different but still very compact and interesting Assembly:
CODE
isHtmlWhitespace(int): # @isHtmlWhitespace(int)
lea eax, [rdi - 9]
cmp eax, 5
jae .LBB2_3
mov ecx, 27
bt ecx, eax
jb .LBB2_2
.LBB2_3:
xor eax, eax
cmp edi, 32
sete al
ret
.LBB2_2:
mov eax, 1
ret
lea eax, [rdi - 9]
cmp eax, 5
jae .LBB2_3
mov ecx, 27
bt ecx, eax
jb .LBB2_2
.LBB2_3:
xor eax, eax
cmp edi, 32
sete al
ret
.LBB2_2:
mov eax, 1
ret
Unfortunately not all compilers are using this clever optimization. Unfortunately Go's compiler is one of such compilers:
CODE
func is_html_whitespace(ch int) bool {
return ch == 0x0009 || ch == 0x000A ||
ch == 0x000C || ch == 0x000D ||
ch == 0x0020
}
return ch == 0x0009 || ch == 0x000A ||
ch == 0x000C || ch == 0x000D ||
ch == 0x0020
}
...is translated into a set of IFs which is very unfortunate:
CODE
v14
00003 (+4) MOVQ "".ch(SP), AX
v30
00004 (4) CMPQ AX, $9
b1
00005 (4) JNE 9
v29
00006 (4) MOVL $1, AX
v28
00007 (+4) MOVB AX, "".~r1+8(SP)
b8
00008 (4) RET
v10
00009 (4) CMPQ AX, $10
b2
00010 (4) JEQ 6
v34
00011 (+5) CMPQ AX, $12
b4
00012 (5) JEQ 6
v31
00013 (5) CMPQ AX, $13
b6
00014 (5) JEQ 6
v7
00015 (+6) CMPQ AX, $32
v24
00016 (6) SETEQ AX
b9
00017 (6) JMP 7
00003 (+4) MOVQ "".ch(SP), AX
v30
00004 (4) CMPQ AX, $9
b1
00005 (4) JNE 9
v29
00006 (4) MOVL $1, AX
v28
00007 (+4) MOVB AX, "".~r1+8(SP)
b8
00008 (4) RET
v10
00009 (4) CMPQ AX, $10
b2
00010 (4) JEQ 6
v34
00011 (+5) CMPQ AX, $12
b4
00012 (5) JEQ 6
v31
00013 (5) CMPQ AX, $13
b6
00014 (5) JEQ 6
v7
00015 (+6) CMPQ AX, $32
v24
00016 (6) SETEQ AX
b9
00017 (6) JMP 7
And what about Rust? Interestingly its Assembly is different from the one generated by Clang compiler for C++ code and impressively contains no branches:
CODE
is_html_whitespace: # @is_html_whitespace
# %bb.0:
# kill: def $edi killed $edi def $rdi
leal -9(%rdi), %eax
cmpl $2, %eax
setb %al
movl %edi, %ecx
andl $-2, %ecx
cmpl $12, %ecx
sete %cl
orb %al, %cl
cmpl $32, %edi
sete %al
orb %cl, %al
retq
# %bb.0:
# kill: def $edi killed $edi def $rdi
leal -9(%rdi), %eax
cmpl $2, %eax
setb %al
movl %edi, %ecx
andl $-2, %ecx
cmpl $12, %ecx
sete %cl
orb %al, %cl
cmpl $32, %edi
sete %al
orb %cl, %al
retq
Source: https://softwarebits.hashnode.dev/bit-testing
Which is the winner? Which is the loser?
This post has been edited by FlierMate: Jun 10 2021, 11:28 PM
Jun 10 2021, 11:26 PM, updated 3y ago
Quote


0.0296sec
0.54
5 queries
GZIP Disabled