Predicting a static branch on Arm9 with RVCT4.0

I am writing some C registration code for an ARM9 processor. This code will write some data if a dynamic module is present. The module, as a rule, will not be present in the assembly, but the registration code will always be compiled. The idea is that if the client detects an error, we can load this module, and the registration code will delete the debug information.

The registration code should have minimal impact if the module is missing, so each cycle is counted. In general, the registration code looks something like this:

__inline void log_some_stuff(Provider *pProvider, other args go here...)
{
    if (NULL == pProvider)
        return;
    ... logging code goes here ...
}

When optimization is enabled, RVCT 4.0 generates code that looks like this:

ldr     r4,[r0,#0x2C]     ; pProvider,[r0,#44]
cmp     r4,#0x0           ; pProvider,#0
beq     0x23BB4BE (usually taken)
... logging code goes here...
... regular code starts at 0x23BB4BE

, , 2 ( , ).

, , NULL == pProvider, , . RVCT 4.0 ?

__builtin_expect :

if (__builtin_expect(NULL == pProvider, 1))
    return;

, . __builtin_expect ? (, )?

+3
4

, , , , , ? ( , "" , )

__inline void log_some_stuff(Provider *pProvider, other args go here...)
{
    if (pProvider) {
       ... logging code goes here ...
    }
}

"" :

ldr     r4,[r0,#0x2C]     ; pProvider,[r0,#44]
cmp     r4,#0x0           ; pProvider,#0
bneq     logging_code (usually NOT taken)
... regular code here
logging_code: .. well anywhere

, , , , , . , , ? gcc ( VC, , ) . ( ARM ABI, )

+1

:

void log_some_stuff_implementation(Provider *pProvider, int x, int y, char const* str);


__inline void log_some_stuff(Provider *pProvider, int x, int y, char const* str)
{
    if (__builtin_expect( pProvider != NULL, 0)) {
        log_some_stuff_implementation(pProvider, x, y, str);
    }

    return;
}

GCC 4.5.2 -O2 ( , ) log_some_stuff():

// r0 already has the Provider* in it - r2 has a value that indicates whether 
//      r0 was loaded with a valid pointer or not
cmp r2, #0
ldrne   r3, [r1, #0]
addne   r1, r2, #1
ldrneb  r2, [r3, #0]    @ zero_extendqisi2
blne    log_some_stuff_implementation

, ( * NULL), 4 , - , ARM . , , , , , .

, , , , , . , . , , -, , - . ( , ).

, (, , ) , __builtin_expect() , , , , . , , , , , , Linux:

#define likely(x)       __builtin_expect((x),1)
#define unlikely(x)     __builtin_expect((x),0)
+1

. , :

#define log_some_stuff(pProvider, other_arg) \
        do {\
           if(pProvider != NULL) \
              real_log_some_stuff(pProvider, other_arg); \
         } \
        while(0)

, NULL . , , , , r0-r3 lr NULL ( ). , , , , , .

0
source

You can use goto:

__inline void log_some_stuff(Provider *pProvider, other args go here...)
{
    if (pProvider != NULL)
        goto LOGGING;
    return;
LOGGING:
    ... logging code goes here ...
}

Using __ builtin_expect is simpler, but I'm not sure if it has RVCT.

0
source

All Articles