convert c to assembly with predicated instruction [closed]
Asked Answered
C

1

-3

I want to convert this code to assembly using predicated instruction

If (A>B){

    C=A;
    D=B;
    E=0

}

else{

    C=B;
} 

Is it correct or how can i use jump ?

cmp R1,R2; considering B is assigned to R2 and A assigned to R1
movlf R3,R1;R3 assign to C
mov R4,R2;R4 assign to D
mov R5,0; R5 assign to E
movlt R3,R2
Connelley answered 14/5, 2016 at 5:34 Comment(1)
What assembly language are you asking about?Engeddi
N
7

WARNING: Answer for newbies. May bore experienced users to death.


I'm not sure if you misused the terminology or if you really want to use predicated instructions1.

In the latter case, using ARM v6 predication as a study case (and inheriting your premises about register usage), the assembly is simply

;r1 = A    r2 = B    r3 = C    r4 = D    r5 = E
;
;A, B unsigned            | ;A, B signed
                          |
cmp r1, r2                | cmp r1, r2 
                          |
movhi r3, r1              | movgt r3, r1
movhi r4, r2              | movgt r4, r2
movhi r5, #0              | movgt r5, #0
                          |
movls r3, r2              | movle r3, r2

Here I gave two versions based on the sign of the involved variables.

movhi means move if higher. movls means move if lower or same.
movgt means move if greater. movle means move if less or equal.
They mean the same arithmetic comparison, it is just that the latter uses the proper flags for signed numbers.

I grouped the instructions, so it is easy to identify the if-then and the else blocks.
Note how instructions in the same block have the same suffix (e.g. hi and ls).

What really makes this code a if-then-else construct rather than something else is the fact that the conditions hi-ls and gt-le are mutually exclusive (only one of the twos can be true).
So only one block of instructions can be executed.

Using non mutually exclusive conditions give rise to multiple if-then-else statements.


If you misused the terminology and you actually wanted just to implement a conditional statement (or selection), i.e. an if-then-else, then the usual approach is a conditional branch2 as Nutan already shown.
Here a slightly more readable version:

 cmp r1, r2
 bls _A_less_same_B

 mov r3, r1
 mov r4, r2
 eor r5, r5, r5

b _end_if

_A_less_same_B:
 mov r3, r2

_end_if:

Up to you the burden to convert this code to work with signed integers.

The fancy words ending with a colon (:) are called labels, they are an useful way to name points in code (and data)3.
Think about that as flexible line numbers.

b means branch, once it is executed the next instruction is fetched from the label (address) specified as operand (for example from _end_if).
bls is just a predicated b (bls means branch if less or same), commonly known as conditional branch.

Conditional branches are just like normal branches but they can be "ignored" if the conditions specified fails to meet.
A conditional jump is said to be taken if the conditions are met and the CPU execute the jump, thereby fetching the next instructions from the label specified as operand.
It is said to be not taken if the conditions are not met and the CPU continue the execution from the instruction after the branch (the program flow fall through).

The "conditions" usually means flags set and cleared. Some instruction, like cmp, set and clear these flags.
Other instructions, like bls use these flags.

The flags are hold in a dedicated registers (ps in ARM) but there are architectures, most notably MIPS, which don't have a flags register.

You can use your finger to simulate the program flow. For example if A > B the flow is as follow:

                            [Start Here]
                             ¯¯¯¯+¯¯¯¯¯
 cmp r1, r2                      |
 bls _A_less_same_B              + [Branch not taken, fall through]
                                 |
 mov r3, r1                      |
 mov r4, r2                      |
 eor r5, r5, r5                  |
                                 |
b _end_if                        +--[Branch always taken]----+
                                                             |
_A_less_same_B:                                              |
 mov r3, r2                                                  |
                                                             |
_end_if:                         +--[Land here]--------------+
                                 |
                                 V

The bend is mean to picture a "jump over" the code that we want to skip (the else in this case).


I don't recognize the assembly flavor of your question, so I cannot help with writing concrete examples.
I wouldn't do it anyway as I feel that this general explanation is enough and in the hope that such lack of effort on my side will spur you into attempting solving the exercise by yourself.

Which is a mandatory step on the route of learning.


1 Instruction that are fetched, decoded, (probably issued too) but only executed if particular flags are set or cleared.

2 Note that conditional branches are best avoided if possible. Depending on the targeting micro-architecture there can be a more optimal way to achieve the same result. This was just worth noting, don't bother with it right now.

3 Actually offsets that will become addresses.

Naquin answered 14/5, 2016 at 8:40 Comment(6)
This is a really excellent answer to a not so great question. Nice job!Miceli
On ARM, mov r5, #0 is a better and more efficient way to zero a register. It feels weird to not use xor, but that's only good on x86, where the variable-length instruction encoding means that avoiding an immediate byte actually saves space, and is recognized as a zeroing idiom. In ARM Thumb2 machine code, eor r5,r5 is a 4B instruction, but mov r5, #0 is a 2B instruction. Also, eor will have a false dependency on the old value, because there's no reason for an ARM microarchitecture to special-case eor same,same as a zeroing idiom.Lyckman
@PeterCordes My instinct was telling me there was no zero idiom, but I was too lazy to check. Thanks for providing, I'm updating the answer.Naquin
@PeterCordes: It's worse than that: On ARM and POWER, instructions are intentionally kept dependent to preserve memory ordering (this gets into memory_order_consume territory, here be dragons). It's architecturally not a dependency breaking instruction. On x86 with its strong memory model the dependency doesn't need to be tracked through data-processing instructions.Borghese
@EOF: ahh, I hadn't realized that the dep tracking for data dependencies was documented for weakly-ordered architectures (other than Alpha). I assume MIPS documents it, too. Thanks for shedding light on that; I've only ever looked in detail at Intel manuals, which of course don't mention it. I wouldn't be surprised if Intel CPUs do internally track data dependencies for memory-ordering, so they can speculate/OOO in ways that don't affect the globally-visible ordering. Anyway, interesting that ARM is architecturally required not to make xor-zeroing break dependencies.Lyckman
@PeterCordes Some quotes from Instruction set manuals: ARM ARM ARMv7-A and ARMv7-R edition: A3.8.2 Ordering requirements for memory accesses [...] An address dependency exists even if the value read by the first read access does not change the virtual address of the second read or write access. This might be the case if the value returned is masked off before it is used[...], Power ISATM Version 2.06 Revision B: 1.7.1 Storage Access Ordering [...]This applies even if the dependency has no effect on program logic (e.g., the value returned by the first Load is ANDed with zero[...].Borghese

© 2022 - 2024 — McMap. All rights reserved.