bt64_reg:
mov al, cl
bt rdx, rax
setc al
movzx eax, al
ret
At MMAT_GENERATED:
; USE: ah.1,rax^2.6,rdx.8,cl.1
; DEF: cf.1,rax.8
mov cl.1, al.1 ; u=cl.1 d=al.1
mov call !_bittest64<fast:"const __int64 *" &(rdx.8)<8/0>.8,"unsigned __int64" rax.8>
=> "unsigned __int8" .1, cf.1 ; u=rax.16,(ALLMEM) d=cf.1
At MMAT_LVARS:
; USE: ah.1,rax^2.6,rdx.8,cl.1,(GLBLOW,GLBHIGH)
; DEF: rax.8
mov cl0.1{1}, rax0.1{1} ; u=cl.1 d=al.1
xdu call !_bittest64<fast:"const __int64 *" &(rdx0.8)<8/0>.8,"unsigned __int64" rax0.8>
=> "unsigned __int8" .1, result.8 ; u=rax.16,(GLBLOW,GLBHIGH) d=rax.8
__int64 __fastcall bt64_reg(char a1, __int64 a2)
{
unsigned __int64 v2; // rax
LOBYTE(v2) = a1;
return _bittest64(&a2, v2);
}
For the register form bt rdx, rax, the bit index is RAX & 63, therefore only the low six bits of AL can affect the result after mov al, cl.
The expected recovery is:
return _bittest64(&a2, (unsigned __int8)a1);
// or
return (a2 >> ((unsigned __int8)a1 & 63)) & 1;
For comparison, the explicitly zero extended variant (using movzx eax, cl) is recovered to _bittest64(&a2, (unsigned __int8)a1), which makes me think this is just an issue with the simplification for partial registers in this case. Who knows.
I will also note that the BTS/BTR/BTC C translations are UB, but this is more of a complaint about semantics.