http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58838

            Bug ID: 58838
           Summary: mullw sets condition code incorrectly.
           Product: gcc
           Version: 4.9.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: dougkwan at google dot com

It was observed in 4.7 and trunk that the Power backend generated bad code
involving condition setting mullw.  Below is a test case for the problem:

-----
#include <cassert>
#include <cstdlib>
#include <vector>

struct b88 {
 char data[88];
};

namespace {

inline int int_size(const std::vector<b88>& v) {
 return v.size();
}

}

int __attribute__ ((noinline))
foo(const std::vector<b88>& v) {
 if (int_size(v) > 0) {
   return atoi("1");
 }
 return 0;
}

int main() {
 std::vector<b88> v;
 v.push_back(b88());
 assert(foo(v) != 0);
 return 0;
}
----

The above test failed with gcc 4.7 and trunk for target powerpc64-linux-gnu

We seem to be fine getting out of the middle-end of gcc-4.7:

;; Function int foo(const std::vector<b88>&) (_Z3fooRKSt6vectorI3b88SaIS0_EE,
funcdef_no=473, decl_uid=9136, cgraph_uid=102)

int foo(const std::vector<b88>&) (const struct vector & v)
{
 int _1;
 struct b88 * _4;
 struct b88 * _5;
 long int _6;
 long int _7;
 long int _8;
 long int _9;
 int _10;
 long int _11;
 int _12;

 <bb 2>:
 _4 = MEM[(const struct vector *)v_3(D)];
 _5 = MEM[(const struct vector *)v_3(D) + 8B];
 _6 = (long int) _5;
 _7 = (long int) _4;
 _8 = _6 - _7;
 _9 = _8 /[ex] 88;
 _10 = (int) _9;
 if (_10 > 0)
   goto <bb 3>;
 else
   goto <bb 4>;

 <bb 3>:
 _11 = strtol ("1", 0B, 10);
 _12 = (int) _11;

 <bb 4>:
 # _1 = PHI <_12(3), 0(2)>
 return _1;

}

RTL expansion looks correct, gcc expands "_8 /[ex] 88;" into shift and
multiplication.

(_8 >> 3) * 0x2e8ba2e8ba2e8ba3.

Since we know that the _8 is a multiple of 88, we can do this.
0x2e8ba2e8ba2e8ba3 is the multiplicative-inverse of 11 in Z{2^64}.


But the selected PPC instruction is bad:

  0x10000b80 <._Z3fooRKSt6vectorI3b88SaIS0_EE>:        lis     r9,11915
  0x10000b84 <._Z3fooRKSt6vectorI3b88SaIS0_EE+4>:      ld      r8,8(r3)
  0x10000b88 <._Z3fooRKSt6vectorI3b88SaIS0_EE+8>:      ld      r10,0(r3)
  0x10000b8c <._Z3fooRKSt6vectorI3b88SaIS0_EE+12>:     ori     r9,r9,41704
  0x10000b90 <._Z3fooRKSt6vectorI3b88SaIS0_EE+16>:     rldicr  r9,r9,32,31
  0x10000b94 <._Z3fooRKSt6vectorI3b88SaIS0_EE+20>:     subf    r10,r10,r8
  0x10000b98 <._Z3fooRKSt6vectorI3b88SaIS0_EE+24>:     oris    r9,r9,47662
  0x10000b9c <._Z3fooRKSt6vectorI3b88SaIS0_EE+28>:     sradi   r10,r10,3
  0x10000ba0 <._Z3fooRKSt6vectorI3b88SaIS0_EE+32>:     ori     r9,r9,35747
  0x10000ba4 <._Z3fooRKSt6vectorI3b88SaIS0_EE+36>:     mullw.  r8,r10,r9 
<================ note the "dot"
  0x10000ba8 <._Z3fooRKSt6vectorI3b88SaIS0_EE+40>:     ble     0x10000bf0
<._Z3fooRKSt6vectorI3b88SaIS0_EE+112>

mullw correctly computes the lower 32-bits of  "_9 = _8 /[ex] 88;" but it sets
the condition code incorrectly, since signed-comparison is done in 64 bits. 
Instead there should be sign extension, ie.

mullw  r8,r10,r9
extsw. r8,r8

Reply via email to