关于反汇编输出的问题

Questions regarding disassembly output

本文关键字:问题 输出 反汇编      更新时间:2023-10-16

考虑C++中的以下代码:

bool foo(int x, int y, int z, int P) {
  return (x < P && y > P && z > P);     
}
int tryout(int iS, int iP) {
  if(foo(iS,iS,iS,iP)) {
       printf("%d", 1000);
  } else {
        printf("%d", 10);
  }
  return 0;
}

当使用英特尔的C++编译器时,代码会产生以下汇编代码:

L__routine_start__Z3fooiiii_0:
foo(int, int, int, int):
        cmpl      %ecx, %edi                                    #5.15
        jge       ..B1.4        # Prob 50%                      #5.15
        cmpl      %ecx, %esi                                    #5.24
        jle       ..B1.4        # Prob 50%                      #5.24
        movl      $1, %esi                                      #5.15
        xorl      %eax, %eax                                    #5.15
        cmpl      %ecx, %edx                                    #5.15
        cmovg     %esi, %eax                                    #5.15
        ret                                                     #5.15
..B1.4:                         # Preds ..B1.2 ..B1.1
        xorl      %eax, %eax                                    #5.15
        ret                                                     #5.15
L__routine_start__Z6tryoutii_1:
tryout(int, int):
        pushq     %rsi                                          #11.28
        cmpl      %esi, %edi                                    #5.15
        jge       ..B2.4        # Prob 50%                      #5.15
        jle       ..B2.4        # Prob 50%                      #5.24
        movl      $.L_2__STRING.0, %edi                         #14.8
        movl      $1000, %esi                                   #14.8
        xorl      %eax, %eax                                    #14.8
        call      printf                                        #14.8
        jmp       ..B2.5        # Prob 100%                     #14.8
..B2.4:                         # Preds ..B2.1 ..B2.2
        movl      $.L_2__STRING.0, %edi                         #16.5
        movl      $10, %esi                                     #16.5
        xorl      %eax, %eax                                    #16.5
        call      printf                                        #16.5
..B2.5:                         # Preds ..B2.4 ..B2.3
        xorl      %eax, %eax                                    #19.10
        popq      %rcx                                          #19.10
        ret                                                     #19.10
.L_2__STRING.0:
    .byte   37
    .byte   100
    .byte   0

我有两个问题:

  1. 为什么tryout方法中有两个跳转到..B2.4,而只有一个if语句
  2. 这个来自方法foo的代码做什么?

    movl      $1, %esi                                      #5.15
    xorl      %eax, %eax                                    #5.15
    cmpl      %ecx, %edx                                    #5.15
    cmovg     %esi, %eax                                    #5.15
    
x < P && y > P && z > P

有三个条件,放在一个if里面并不意味着只需要一个jcc就可以进行评估。(注意,foo()被内联了。没有call指令`。(

编译器通常会测试&如果不能将多个测试组合为一个表达式,则为序列中的每个条件分支。在这种情况下,icc只是内联了它为foo()所做的操作,但它可以省略第二个cmp,因为它正在测试相同的两个变量。请注意,两个分支的分支目标是如何相同的,因为它们都在为相同的if检查条件的不同部分。您没有得到第三个jcc,因为第二个和第三个条件相同,所以编译器将它们组合在一起。

正如评论所指出的,ICC应该注意到的情况根本不需要任何测试。一个或另一个分支总是,所以它本可以像gcc和clang那样做,并将其编译为对printf的简单调用,而不检查任何内容。