-4

Can someone show a C-like representation of the uses of cmp/test alongside js/jns/jz/jnz/etc.?

Thanks.

phuclv
  • 37,963
  • 15
  • 156
  • 475
R-Rothrock
  • 303
  • 2
  • 14

1 Answers1

1

Here are some examples:

#include <stdlib.h>
void test_with_self(int A){
    if (A) abort();
}

void test_with_mask(int A, int Mask){
    if (A&Mask) abort();
}

void test_js(int A){
    if (A<0) abort();
}

void test_jns(int A){
    if (A>=0) abort();
}

void cmp_jz(int A){
    if (A==42) abort();
}

void cmp_jnz(int A){
    if (A!=42) abort();
}

and what they could be rendered as (clang output):

test_with_self:                         # @test_with_self
        test    edi, edi
        jne     .LBB0_2
        ret
.LBB0_2:
        push    rax
        call    abort@PLT
test_with_mask:                         # @test_with_mask
        test    esi, edi
        jne     .LBB1_2
        ret
.LBB1_2:
        push    rax
        call    abort@PLT
test_js:                                # @test_js
        test    edi, edi
        js      .LBB2_2
        ret
.LBB2_2:
        push    rax
        call    abort@PLT
test_jns:                               # @test_jns
        test    edi, edi
        jns      .LBB3_2
        ret
.LBB3_2:
        push    rax
        call    abort@PLT
cmp_jz:                                 # @cmp_jz
        cmp     edi, 42
        je      .LBB4_2
        ret
.LBB4_2:
        push    rax
        call    abort@PLT
cmp_jnz:                                # @cmp_jnz
        cmp     edi, 42
        jne     .LBB5_2
        ret
.LBB5_2:
        push    rax
        call    abort@PLT

Note that je == jz and jne == jnz.

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • `jns` is `A>=0`. clang correctly used `jg` for `A>0` to exclude zero: SF==OF and ZF==0. (https://www.felixcloutier.com/x86/jcc (Since FLAGS were set by `test` [like a compare against zero](https://stackoverflow.com/questions/33721204/test-whether-a-register-is-zero-with-cmp-reg-0-vs-or-reg-reg), OF is known to be zero so jns and jge are equivalent in this case, just SF==0) – Peter Cordes Jun 12 '23 at 18:22
  • Interesting that `if() abort();` results in a `jcc` with the if condition not inverted. Since compilers expect not to abort, they do `test/jcc/ret` so the fall-through is the else, not the if body. The ["standard" simple way](https://stackoverflow.com/questions/72061257/how-to-use-jumps-in-assembly-language-to-implement-if-conditions) to turn a C `if` into an asm branch is to `if (!condition) goto after_if_body`, like `test edi,edi` / `jnz` like clang does (https://godbolt.org/z/nj3qW7vrK) when the if body is `sink = 1` storing to a global variable. – Peter Cordes Jun 12 '23 at 18:28
  • 1
    @PeterCordes Thanks. Fixed the brain glitch I was having there with `test_jns`. Yeah, it looks like clang is effectively treating if conditions as unexpected (perhaps only if there's no else branch there). https://godbolt.org/z/3znzYrE1P I like how clang also responds better to the __builtin_expected hints there. gcc seems to always do the `if (!condition) goto after_if_body` thing even if you do `if (unlikely(condition)) something_returning_or_terminating` where I'd rather see the jumps on `condition` rather than on `!condition`. – Petr Skocik Jun 12 '23 at 19:05