This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

using assembly and intrinsics in C code (Arm Compiler 6)

dear arm,

Is there a more detailed document that introduces how to use assembly and intrinsics in C code?

I found a breif introduction in migration_and_compatibility_guide_v6.18. But after reading it, I still don't know how to modify the format to meet Arm Compiler 6' requirements .

The code blow shows the example in migration_and_compatibility_guide_v6.18

// __asm in Arm Compiler 5
int add(int i, int j)
{
    int res;
    __asm
    {
        ADD res, i, j
        SUB res, i, res
    }
    return res;
}

// __asm in Arm Compiler 6
int add(int i, int j)
{
    int res = 0;
    __asm
    (
        "ADD %[result], %[input_i], %[input_j] \t\n"
        "SUB %[result], %[input_i], %[result] \t\n"
        : [result] "=&r" (res)
        : [input_i] "r" (i), [input_j] "r" (j)
        );
    return res;
}

But how should I modify the code below to meet Arm Compiler 6's requirements?

MOV sum, var1, LSL #16
QADD sum, sum, temp
MOV result, sum, ASR #16
MOV zero, #0
RSB var2_inv, var2, #0

many thanks!

Parents
  • Hello, I am unsure exactly what the above code does, it is seemingly part of a larger sequence, but I was able to compile the below:

    int example(int var1, int var2)
    {
    	int result, sum, temp=0, zero, var2_inv;
    	__asm
    	(
    	"MOV	%[sum],		%[input1],	LSL #16		\t\n"
    	"QADD	%[sum],		%[sum],		%[temp]		\t\n"
    	"MOV	%[result],	%[sum],		ASR #16		\t\n"
    	"MOV	%[zero],	#0						\t\n"
    	"RSB	%[var2_inv],%[input2],	#0			\t\n"
    	: [result] "=r" (result), [sum] "=r" (sum), [temp] "=r" (temp), [zero] "=r" (zero), [var2_inv] "=r" (var2_inv)
    	: [input1] "r" (var1), [input2] "r" (var2)
    	);
    	return result;
    }
    

    as:

        example
            0x00000000:    ea4f4100    O..A    LSL      r1,r0,#16
            0x00000004:    fa82f181    ....    QADD     r1,r1,r2
            0x00000008:    ea4f4021    O.!@    ASR      r0,r1,#16
            0x0000000c:    f04f0300    O...    MOV      r3,#0
            0x00000010:    f1c10c00    ....    RSB      r12,r1,#0
            0x00000014:    4770        pG      BX       lr
    

    Command line used:

    armclang -c --target=arm-arm-none-eabi -mcpu=cortex-m7 -O2 example.c
    fromelf -c example.o > example.txt
    

    The below documentation is more thorough than the Migration Guide:
    https://developer.arm.com/documentation/100748/0618/Using-Assembly-and-Intrinsics-in-C-or-C---Code/Writing-inline-assembly-code

Reply
  • Hello, I am unsure exactly what the above code does, it is seemingly part of a larger sequence, but I was able to compile the below:

    int example(int var1, int var2)
    {
    	int result, sum, temp=0, zero, var2_inv;
    	__asm
    	(
    	"MOV	%[sum],		%[input1],	LSL #16		\t\n"
    	"QADD	%[sum],		%[sum],		%[temp]		\t\n"
    	"MOV	%[result],	%[sum],		ASR #16		\t\n"
    	"MOV	%[zero],	#0						\t\n"
    	"RSB	%[var2_inv],%[input2],	#0			\t\n"
    	: [result] "=r" (result), [sum] "=r" (sum), [temp] "=r" (temp), [zero] "=r" (zero), [var2_inv] "=r" (var2_inv)
    	: [input1] "r" (var1), [input2] "r" (var2)
    	);
    	return result;
    }
    

    as:

        example
            0x00000000:    ea4f4100    O..A    LSL      r1,r0,#16
            0x00000004:    fa82f181    ....    QADD     r1,r1,r2
            0x00000008:    ea4f4021    O.!@    ASR      r0,r1,#16
            0x0000000c:    f04f0300    O...    MOV      r3,#0
            0x00000010:    f1c10c00    ....    RSB      r12,r1,#0
            0x00000014:    4770        pG      BX       lr
    

    Command line used:

    armclang -c --target=arm-arm-none-eabi -mcpu=cortex-m7 -O2 example.c
    fromelf -c example.o > example.txt
    

    The below documentation is more thorough than the Migration Guide:
    https://developer.arm.com/documentation/100748/0618/Using-Assembly-and-Intrinsics-in-C-or-C---Code/Writing-inline-assembly-code

Children
  • I change QADD temp, L_var1, 0x00008000 to the code below:

    __inline short AMR_ENCroung_round (long L_var1_
    {
        long temp;
        short result;
        
        __asm
        (
            "QADD %[temp], %[input], 0x00008000\t\n"
            "MOV %[result], %[temp], ASR #16\t\n"
            :[result] "=r" (result), [temp] "=r" (temp)
            :[input] "r" (L_var1)
        );
        
        return result;
    }

    and it goes wrong. The error is:

    pplease help me to solve it, thanks.

  • QADD takes registers as operands, not immediate values (0x8000 above).

    Does this fix your issue?

        __asm
        (
            "MOV %[temp], 0x8000\t\n"
    		"QADD %[temp], %[input], %[temp]\t\n"
            "MOV %[result], %[temp], ASR #16\t\n"
            :[result] "=r" (result), [temp] "=r" (temp)
            :[input] "r" (L_var1)
        );
        

  • YES! 

    I have another question. How should I fix this error when using QSUBLT, RSBLT, SUBNE and so on: predicated instructions must be in IT block.

  • I assume you are using a Cortex-M processor? An IT (if-then) block is needed for such conditional execution:

    https://developer.arm.com/documentation/dui0552/a/BABEHFEF

    So your code would be something like the following (in raw assembler format)

       IT  LT
    ; execute one instruction (iT) if LT
       QSUBLT...

    Or possibly

      ITTE  LT
    ; execute two instructions (iTTe)if LT
      QSUBLT ...
      MOVLT  ...
    ; else
      QSUBGE ...

  • Got it! 

    How should I use CMP and TEQ with ASR/LSL? I wrote the code below and CMP instruction went wrong with: operand must be a register in range[r0, r15]. 

    ....
    "CMP %[input1], %[result], ASR %[input2]\t\n"
    ...
    "IT LT\t\n"
    "MOVLT %[result], #0x80000000\t\n"
    ....

  • That is not a valid instruction. For Cortex-M, such a shift can only be specified with an immediate value.

    I recommend you consult Arm Architecture Reference Manual for such syntax questions:
    https://developer.arm.com/documentation/ddi0403/latest

    Is there a reason you are using the inline assembler? This is typically only used in very special cases. Also using 'true' assembler can give more explicit messaging:

    $ armclang -c -g -O1 --target=arm-arm-none-eabi -mcpu=cortex-m4 foo.S -masm=auto
    "foo.S", line 3: Error: A1872E: Shift by register not allowed
        3 00000000  CMP r0, r1, ASR r2

  • We're using cortex-r processor in thumb mode. "MOV %[result], %[input1], LSL %[input2]\t\n" didn't bring errors. 

  • This is similarly defined in the Arm Architecture for v7A and v7R:
    https://developer.arm.com/documentation/ddi0406/latest/

    CMP only accepts immediate shift in Thumb state (see A8.8.38, T3 encoding).
    MOV can use a register as a shift (see A8.8.106).

    CMP can use a register shift only when in Arm state (A8.8.39).

    From earlier I thought you were using Cortex-M.
    For completeness, IT instruction described at A8.8.55 of this document.

  • I see!

    One last question . The code below gives error message(ARM mode): 

     

    long func()
    {
        long t;
        long result=0;
        __asm
        (
            "MRS %[t], CPSR\t\n"    //MRS t, CPSR
            "BIC %[t], %[t], #0x08000000\t\n"   //BIC t, t, #0x08000000
            "MSR CPSR_f, %[t]\t\n"  //MSR CPSR_f, t
            "AND %[result], %[t], #0x08000000\t\n"  //AND result, t, #0x08000000
            :[t] "=r" (t), [result] "=r" (result)
        );
        return result;
    }

    how should I use CPSR with inline assembler? Why AND instruction occuers unexpected token in operand? 

  • Which compiler version are you using?

    Testing with amclang 6.18, the above compiled without issue for me (both Arm and Thumb, Cortex-R4).

    Arm:
        func
            0x00000000:    e10f1000    ....    MRS      r1,APSR ; formerly CPSR
            0x00000004:    e3c11302    ....    BIC      r1,r1,#0x8000000
            0x00000008:    e128f001    ..(.    MSR      APSR_nzcvq,r1 ; formerly CPSR_f
            0x0000000c:    e2010302    ....    AND      r0,r1,#0x8000000
            0x00000010:    e12fff1e    ../.    BX       lr
            
    Thumb:
        func
            0x00000000:    f3ef8100    ....    MRS      r1,APSR ; formerly CPSR
            0x00000004:    f0216100    !..a    BIC      r1,r1,#0x8000000
            0x00000008:    f3818800    ....    MSR      APSR_nzcvq,r1 ; formerly CPSR_f
            0x0000000c:    f0016000    ...`    AND      r0,r1,#0x8000000
            0x00000010:    4770        pG      BX       lr

  • I'm using armclang6.18, too.

    C:/Program Files/ArmCompilerforEmbedded6.18/bin/armclang --target=arm-arm-none-eabi -mcpu=cortex-r5 -o1 -fno-short-enums -mno-unaligned-access -mlittle-endian -g -marm @build/qogirl6_pubcp_builddir/dep/record_C_MACRO_INC.txt -c -IC:/Program Files/ArmCompilerforEmbedded6.18/include MS_Ref/source/codec/record/src/mp3_encoder/src/mp3_enc_spec_scale.c -MF build/qogirl6_pubcp_builddir/dep/record/mp3_enc_spec_scale.d.tmp -o build/qogirl6_pubcp_builddir/obj/record/mp3_enc_spec_scale.o

  • What options are specified in the file?

    @build/qogirl6_pubcp_builddir/dep/record_C_MACRO_INC.txt
    

  • These are just macro definitions and include paths. They should not affect the compilation. I'm sorry, but I don't understand why it works for me, but not for you. Can you copy the above source exactly and test? Perhaps there is a mistake in your original source?

    The following builds for me without error (both Arm and Thumb):

    armclang --version
    ...
    Arm Compiler for Embedded 6.18
    
    
    armclang -c --target=arm-arm-none-eabi -mcpu=cortex-r5 -o1 -fno-short-enums -mno-unaligned-access -mlittle-endian -g -marm cpsr.c
    armclang -c --target=arm-arm-none-eabi -mcpu=cortex-r5 -o1 -fno-short-enums -mno-unaligned-access -mlittle-endian -g -mthumb cpsr.c