@@ -162,30 +162,41 @@ fn (mut c Amd64) neg(reg Amd64Register) {
162162}
163163
164164fn (mut c Amd64) cmp (reg Amd64 Register, size Size, val i64 ) {
165+ // for a register 32bits immediate value compare, CMP is REX.W + 81 /7 id
166+ // REX.W -> 0x48 (0x4a here to enable .r8 to .r15)
167+ // 0x81
168+ // modr/m byte:
169+ // /7 -> the reg/opcode bits are 0b111
170+ // the mod bits 0b11 for register value
171+ // R/M bits depends on the register used in the CMP
172+ // see https://www.sandpile.org/x86/opc_rm.htm for a table for modr/m byte (at the bottom of the second one)
173+
165174 if c.g.pref.arch != .amd64 {
166175 panic ('cmp' )
167176 }
168177 // Second byte depends on the size of the value
169178 match size {
170179 ._8 {
171- c.g.write8 (0x48 )
172- c.g.write8 (0x83 )
180+ c.g.write8 (0x48 ) // REX.W
181+ c.g.write8 (0x83 ) // compares a 64bits register with a 8 bits immediate value
173182 }
174183 ._32 {
175- c.g.write8 (0x4a )
176- c.g.write8 (0x81 )
184+ c.g.write8 (0x4a ) // REX.WX
185+ c.g.write8 (0x81 ) // compares a 64bits register with a 32bits immediate value
177186 }
178187 else {
179- panic ('unhandled cmp' )
188+ panic ('unhandled cmp size ${ size } ' )
180189 }
181190 }
182- // Third byte depends on the register being compared to
191+ // Third byte (modr/m byte) depends on the regiister being compared to
183192 match reg {
184193 .r12 { c.g.write8 (0xfc ) }
185194 .rsi { c.g.write8 (0x3f ) }
186- .eax { c.g.write8 (0xf8 ) }
195+ .rax { c.g.write8 (0xf8 ) }
196+ .rcx { c.g.write8 (0xf9 ) }
197+ .rdx { c.g.write8 (0xfa ) }
187198 .rbx { c.g.write8 (0xfb ) }
188- else { panic ('unhandled cmp' ) }
199+ else { panic ('unhandled cmp reg ${ reg } ' ) }
189200 }
190201 match size {
191202 ._8 {
@@ -195,7 +206,7 @@ fn (mut c Amd64) cmp(reg Amd64Register, size Size, val i64) {
195206 c.g.write32 (i32 (val))
196207 }
197208 else {
198- panic ('unhandled cmp' )
209+ panic ('unhandled cmp size ${ size } ' )
199210 }
200211 }
201212 c.g.println ('cmp ${reg }, ${val }' )
@@ -232,6 +243,9 @@ fn (mut c Amd64) cmp_reg(reg Amd64Register, reg2 Amd64Register) {
232243 .rax {
233244 c.g.write ([u8 (0x48 ), 0x39 , 0xc3 ])
234245 }
246+ .rdx {
247+ c.g.write ([u8 (0x48 ), 0x39 , 0xd3 ])
248+ }
235249 else {
236250 c.g.n_error ('${@LOCATION } Cannot compare ${reg } and ${reg2 }' )
237251 }
@@ -2964,6 +2978,7 @@ fn (mut c Amd64) infix_expr(node ast.InfixExpr) {
29642978
29652979 c.g.expr (node.right)
29662980
2981+ right_type := c.g.unwrap (node.right_type)
29672982 left_type := c.g.unwrap (node.left_type)
29682983
29692984 if left_type.is_pure_float () {
@@ -2999,10 +3014,135 @@ fn (mut c Amd64) infix_expr(node ast.InfixExpr) {
29993014 // left: rax, right: rdx
30003015 match node.op {
30013016 .eq, .ne, .gt, .lt, .ge, .le {
3002- c.cmp_reg (.rax, .rdx)
3003- // TODO: mov_extend_reg
3004- c.mov64 (Amd64 Register.rax, i64 (0 ))
3005- c.cset_op (node.op)
3017+ if left_type.is_unsigned () && right_type.is_unsigned () {
3018+ c.cmp_reg (.rax, .rdx)
3019+ // TODO: mov_extend_reg
3020+ c.mov64 (Amd64 Register.rax, i64 (0 ))
3021+ match node.op {
3022+ .gt { c.cset (.a) }
3023+ .lt { c.cset (.b) }
3024+ .ge { c.cset (.ae) }
3025+ .le { c.cset (.be) }
3026+ else { c.cset_op (node.op) }
3027+ }
3028+ } else if left_type.is_unsigned () && right_type.is_signed () {
3029+ c.mov_reg (Amd64 Register.rbx, Amd64 Register.rax)
3030+ c.mov64 (Amd64 Register.rax, i64 (0 ))
3031+ match node.op {
3032+ .eq {
3033+ c.cmp (.rdx, ._32 , 0 )
3034+ c.cset (.ge) // if right >= 0
3035+ c.mov_reg (Amd64 Register.rcx, Amd64 Register.rax)
3036+ c.cmp_reg (.rbx, .rdx)
3037+ c.cset (.e) // if left (unsigned ==) right
3038+ c.bitand_reg (.rax, .rcx) // only true when right >= 0 and left (unsigned ==) right
3039+ }
3040+ .ne {
3041+ c.cmp (.rdx, ._32 , 0 )
3042+ c.cset (.l) // if right < 0
3043+ c.mov_reg (Amd64 Register.rcx, Amd64 Register.rax)
3044+ c.cmp_reg (.rbx, .rdx)
3045+ c.cset (.ne) // if left (unsigned !=) right
3046+ c.bitor_reg (.rax, .rcx) // true when right < 0 or left (unsigned !=) right
3047+ }
3048+ .gt {
3049+ c.cmp (.rdx, ._32 , 0 )
3050+ c.cset (.l) // if right < 0
3051+ c.mov_reg (Amd64 Register.rcx, Amd64 Register.rax)
3052+ c.cmp_reg (.rbx, .rdx)
3053+ c.cset (.a) // if left (unsigned >) right
3054+ c.bitor_reg (.rax, .rcx) // true when right < 0 or left (unsigned >) right
3055+ }
3056+ .lt {
3057+ c.cmp (.rdx, ._32 , 0 )
3058+ c.cset (.ge) // if right >= 0
3059+ c.mov_reg (Amd64 Register.rcx, Amd64 Register.rax)
3060+ c.cmp_reg (.rbx, .rdx)
3061+ c.cset (.b) // if left (unsigned >) right
3062+ c.bitand_reg (.rax, .rcx) // true when right >= 0 and left (unsigned <) right
3063+ }
3064+ .ge {
3065+ c.cmp (.rdx, ._32 , 0 )
3066+ c.cset (.l) // if right < 0
3067+ c.mov_reg (Amd64 Register.rcx, Amd64 Register.rax)
3068+ c.cmp_reg (.rbx, .rdx)
3069+ c.cset (.ae) // if left (unsigned >=) right
3070+ c.bitor_reg (.rax, .rcx) // true when right < 0 or left (unsigned >=) right
3071+ }
3072+ .le {
3073+ c.cmp (.rdx, ._32 , 0 )
3074+ c.cset (.ge) // if right >= 0
3075+ c.mov_reg (Amd64 Register.rcx, Amd64 Register.rax)
3076+ c.cmp_reg (.rbx, .rdx)
3077+ c.cset (.be) // if left (unsigned <=) right
3078+ c.bitand_reg (.rax, .rcx) // true when right >= 0 and left (unsigned <=) right
3079+ }
3080+ else {
3081+ c.g.n_error ('${@LOCATION } unhandled op ${node .op }' )
3082+ }
3083+ }
3084+ } else if left_type.is_signed () && right_type.is_unsigned () {
3085+ c.mov_reg (Amd64 Register.rbx, Amd64 Register.rax)
3086+ c.mov64 (Amd64 Register.rax, i64 (0 ))
3087+ match node.op {
3088+ .eq {
3089+ c.cmp (.rbx, ._32 , 0 )
3090+ c.cset (.ge) // if left >= 0
3091+ c.mov_reg (Amd64 Register.rcx, Amd64 Register.rax)
3092+ c.cmp_reg (.rbx, .rdx)
3093+ c.cset (.e) // if left (unsigned ==) right
3094+ c.bitand_reg (.rax, .rcx) // only true when left >= 0 and left (unsigned ==) right
3095+ }
3096+ .ne {
3097+ c.cmp (.rbx, ._32 , 0 )
3098+ c.cset (.l) // if left < 0
3099+ c.mov_reg (Amd64 Register.rcx, Amd64 Register.rax)
3100+ c.cmp_reg (.rbx, .rdx)
3101+ c.cset (.ne) // if left (unsigned !=) right
3102+ c.bitor_reg (.rax, .rcx) // true when left < 0 or left (unsigned !=) right
3103+ }
3104+ .gt {
3105+ c.cmp (.rbx, ._32 , 0 )
3106+ c.cset (.ge) // if left >= 0
3107+ c.mov_reg (Amd64 Register.rcx, Amd64 Register.rax)
3108+ c.cmp_reg (.rbx, .rdx)
3109+ c.cset (.a) // if left (unsigned >) right
3110+ c.bitand_reg (.rax, .rcx) // true when left >= 0 and left (unsigned >) right
3111+ }
3112+ .lt {
3113+ c.cmp (.rbx, ._32 , 0 )
3114+ c.cset (.l) // if left < 0
3115+ c.mov_reg (Amd64 Register.rcx, Amd64 Register.rax)
3116+ c.cmp_reg (.rbx, .rdx)
3117+ c.cset (.b) // if left (unsigned >) right
3118+ c.bitor_reg (.rax, .rcx) // true when left < 0 or left (unsigned <) right
3119+ }
3120+ .ge {
3121+ c.cmp (.rbx, ._32 , 0 )
3122+ c.cset (.ge) // if left >= 0
3123+ c.mov_reg (Amd64 Register.rcx, Amd64 Register.rax)
3124+ c.cmp_reg (.rbx, .rdx)
3125+ c.cset (.ae) // if left (unsigned >=) right
3126+ c.bitand_reg (.rax, .rcx) // true when left >= 0 and left (unsigned >=) right
3127+ }
3128+ .le {
3129+ c.cmp (.rbx, ._32 , 0 )
3130+ c.cset (.l) // if left < 0
3131+ c.mov_reg (Amd64 Register.rcx, Amd64 Register.rax)
3132+ c.cmp_reg (.rbx, .rdx)
3133+ c.cset (.be) // if left (unsigned <=) right
3134+ c.bitor_reg (.rax, .rcx) // true when left < 0 or left (unsigned <=) right
3135+ }
3136+ else {
3137+ c.g.n_error ('${@LOCATION } unhandled op ${node .op }' )
3138+ }
3139+ }
3140+ } else {
3141+ c.cmp_reg (.rax, .rdx)
3142+ // TODO: mov_extend_reg
3143+ c.mov64 (Amd64 Register.rax, i64 (0 ))
3144+ c.cset_op (node.op)
3145+ }
30063146 }
30073147 .plus {
30083148 c.add_reg (.rax, .rdx)
0 commit comments