Skip to content
  • Bill Wendling's avatar
    There seems to be a (potential) hardware bug with the CMN instruction and · a9a0599b
    Bill Wendling authored
    comparison with 0. These two pieces of code should give identical results:
    
      rsbs r1, r1, 0
      cmp  r0, r1
      mov  r0, #0
      it   ls
      mov  r0, #1
    
    and:
    
      cmn  r0, r1
      mov  r0, #0
      it   ls
      mov  r0, #1
    
    However, the CMN gives the *opposite* result when r1 is 0. This is because the
    carry flag is set in the CMP case but not in the CMN case. In short, the CMP
    instruction doesn't perform a truncate of the (logical) NOT of 0 plus the value
    of r0 and the carry bit (because the "carry bit" parameter to AddWithCarry is
    defined as 1 in this case, the carry flag will always be set when r0 >= 0). The
    CMN instruction doesn't perform a NOT of 0 so there is never a "carry" when this
    AddWithCarry is performed (because the "carry bit" parameter to AddWithCarry is
    defined as 0).
    
    The AddWithCarry in the CMP case seems to be relying upon the identity:
    
      ~x + 1 = -x
    
    However when x is 0 and unsigned, this doesn't hold:
    
       x = 0
      ~x = 0xFFFF FFFF
      ~x + 1 = 0x1 0000 0000
      (-x = 0) != (0x1 0000 0000 = ~x + 1)
    
    Therefore, we should disable *all* versions of CMN, especially when comparing
    against zero, until we can limit when the CMN instruction is used (when we know
    that the RHS is not 0) or when we have a hardware fix for this.
    
    (See the ARM docs for the "AddWithCarry" pseudo-code.)
    
    This is related to <rdar://problem/7569620>.
    
    llvm-svn: 112176
    a9a0599b
Loading