This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] 逻辑否定运算符-寄存器用法(-OFF)

Guru**** 1568615 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/tools/code-composer-studio-group/ccs/f/code-composer-studio-forum/1194722/logical-negation-operator---register-usage--ooff

我参与了安全关键型软件的开发、达到了 RTCA/DO - 178C A 级

编译器:

   TI-CGT-ARM_18.14.LTS

 

选项:

   -mv7R4

   --code_state=32

   -Ooff

   --opt_for_speed=0

   -c99

 

考虑以下 C 源代码:

 

#define true 1.

#define false 0

 

typedef unsigned char BOOL;

 

 

静态 BOOL Test_A (const BOOL 参数 A);

 

 

int main (void){

 

   (空) Test_A (真);

 

   返回(0);

 

 

静态 BOOL 测试_A (常量 BOOL 参数 A)

   bool 结果=!ParamA;

 

   返回(结果);

               

 

使用逻辑否定运算符的源代码行的反汇编如下:

 

 

21           BOOL 结果=!ParamA;

00002894:  E5DD1000           ldrb      R1、[R13]

00002898:  E3A0C000           MOV       R12、#0

0000289c:  E3510000           CMP       R1、#0

000028a0:  E3A00000           mov       r0、#0

000028a4:  0A000000           beq       $C$L1

000028a8:  E3A00001           mov       r0、#1

         $C$L1:

000028ac:  E3500000           CMP       r0、#0

000028b0:  1A000000           bne       $C$L2

000028b4:  E3A0C001           MOV       R12、#1

         $C$L2:

000028b8:  E5CDC001           strb      R12、[R13、#1]

 

 

即使优化已关闭(-Ooff)、上述实现似乎不必要地复杂、尤其是寄存器 r0的使用。

 

问题:

为什么实现使用"附加"寄存器(r0)和两个标签而不是下面示例中详述的单个标签实现、是否有合理的理由?

 

 

00002894:  E5DD0000           ldrb      r0、[R13]

00002898:  E3A0C001           MOV       R12、#1

0000289c:  E3500000           CMP       r0、#0

000028a0:  0A000000           beq       $C$L1

000028a4:  E3A0C000           MOV       R12、#0

         $C$L1:

000028a8:  E5CDC001           strb      R12、[R13、#1]

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    禁用优化后、无需考虑高效代码生成。  除了匹配实际源代码之外、编译器还将生成函数序言和结语块、以控制栈的分配/取消分配。 编译器将为栈分配局部变量。  这可能导致分支数量超过必要数量。  编译器不会优化控制流或寄存器的使用。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Alan、您好、感谢您的回答。

    我非常熟悉如何生成函数 prolog 和 epilog 块来控制分配/取消分配、以及编译器将本地变量分配到栈。

    我在下面的示例函数中包含了完全反汇编。

     

             test_a():

    0000288c:  E24DD008           SUB       R13、R13、#8

    00002890:  E5CD0000           strb      r0、[R13]

    21           BOOL 结果=!ParamA;

    00002894:  E5DD1000           ldrb      R1、[R13]

    00002898:  E3A0C000           MOV       R12、#0

    0000289c:  E3510000           CMP       R1、#0

    000028a0:  E3A00000           mov       r0、#0

    000028a4:  0A000000           beq       $C$L1

    000028a8:  E3A00001           mov       r0、#1

             $C$L1:

    000028ac:  E3500000           CMP       r0、#0

    000028b0:  1A000000           bne       $C$L2

    000028b4:  E3A0C001           MOV       R12、#1

             $C$L2:

    000028b8:  E5CDC001           strb      R12、[R13、#1]

    23           回返(结果);

    000028bc:  E5DD0001           ldrb      r0、[R13、#1]

    24       }

    000028c0:  E28DD008           添加       R13、R13、#8

    000028c4:  E12FFF1E           BX        LR

     

    前两条指令构成序言块:

    • 保留执行所需的所有堆栈空间
    • 将参数从参数寄存器 r0存储到栈。

    在我可以确定的范围内、在执行第二条指令后、寄存器 r0可用于其他用途。

     

    最后三条指令构成结语块:

    • 从堆栈中加载带有本地变量‘Result’的返回寄存器 r0
    • 将堆栈恢复到进入函数之前的状态
    • 分支到链接寄存器中的地址、即函数调用的返回地址

     

    结语块之前的单个指令将逻辑否定的结果存储到栈上的局部变量‘Result’。

     

    鉴于上述情况、我无法看到函数序言和结语块或栈中局部变量的分配与逻辑否定的实现有何关系。

     

    我曾希望你们能够解释我无法确定的执行逻辑否定所需的具体内容,因为 ‘我不会期待最佳解决方案,但即使优化关闭(-Ooff),高效代码生成没有考虑因素’寄存器分配也是出于合理的原因?

     

    我很惊讶、如果使用 if 语句实现逻辑否定、那么编译器生成的指令比使用逻辑否定运算符时少、请参阅下面的 Test_B。

     

    静态 BOOL 测试_B (常量 BOOL 参数 A)

       bool 结果= true;

     

       if (ParamA!= false)

       {

           结果= false;

       }

     

       返回(结果);

     

             TEST_B():

    0000285c:  E24DD008           SUB       R13、R13、#8

    00002860:  E5CD0000           strb      r0、[R13]

    32           BOOL 结果= true;

    00002864:  E3A0C001           MOV       R12、#1

    00002868:  E5CDC001           strb      R12、[R13、#1]

    34           IF (ParamA!= false)

    0000286c:  E5DDC000           ldrb      R12、[R13]

    00002870:  E35C0000           CMP       R12、#0

    00002874:  0A000001           beq       $C$L3

    36               结果= false;

    00002878:  E3A0C000           MOV       R12、#0

    0000287c:  E5CDC001           strb      R12、[R13、#1]

    39           次返回(结果);

             $C$L3:

    00002880:  E5DD0001           ldrb      r0、[R13、#1]

    40       }

    00002884:  E28DD008           添加       R13、R13、#8

    00002888:  E12FFF1E           BX        LR

     

    我怀疑我必须简单地将编译器用于逻辑否定的实现记录为次优、并指出不需要使用两个寄存器和两个标签。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [引用 userid="467206" URL"~/support/tools/code-composer-studio-group/ccs/f/code-composer-studio-forum/1194722/logical-negation-operator---register-usage--ooff/4510955 #4510955"]我曾希望您能够解释实施逻辑否定所需的具体内容,而我无法确定[/引用]

    您正在体验编译器的实际工作方式。  编译器的早期阶段会生成正确但效率低下的代码。  有时效率很低。  编译器的后续阶段(其中有许多阶段)会逐渐将代码更改为更高效的代码。   

    [引用 userid="467206" URL"~/support/tools/code-composer-studio-group/ccs/f/code-composer-studio-forum/1194722/logical-negation-operator---register-usage--ooff/4510955 #4510955"]我怀疑我必须简单地将编译器用于逻辑否定的实现作为次优记录、并声明不需要使用两个寄存器和两个标签。

    这可能是最好的前进方式。

    谢谢、此致、

    乔治