[PATCH] [MIPS] fix extension of integer types (function calls)
daniel.sanders at imgtec.com
Mon Apr 27 11:20:23 PDT 2015
In http://reviews.llvm.org/D9198#162000, @petarj wrote:
> In http://reviews.llvm.org/D9198#161802, @dsanders wrote:
> > This shouldn't be a problem but it is an uncomfortable discrepancy with our _documented_ ABI which says that 32-bit integers are always sign-extended to GPR-sized integers. I put the underbars around 'documented' because the available documentation isn't completely reliable as a statement of how things are actually implemented. I discussed it with Matthew Fortune (one of the current GCC maintainers for Mips) at the time and as far as we could tell, the truth of the matter is that unsigned integers are passed zero extended by the caller in all cases. I also ran a few hundred thousand randomized ABI tests and couldn't produce any failures running mixtures of clang-compiled and gcc-compiled code.
> IIRC from a recent discussion, unsigned 32-bit int are represented in a 64-bit register as sign-extended value of the 32-bit value (i.e. bit 31 is copied through the top half). So, the caller has to make sure the value is correctly represented before making a call, right?
That's correct in general, all the 32-bit operations sign-extend their result to 64-bit. The ABI documentation is trying to match this architectural behaviour but that didn't seem to be what was actually implemented in gcc.
In http://reviews.llvm.org/D9198#162018, @spetrovic wrote:
> Yes, I'm trying to resolve bug in dejagnu test suite, this is the shorter version of failed test :
> extern void exit (int);
> extern void abort (void);
> unsigned __attribute__ ((__noinline__)) foo(unsigned a)
> unsigned l;
> l = (a >= (~0u - 512) ? (~0u - 512) : a);
> return l;
> main (void)
> if (foo ((unsigned) -512) != (unsigned) -513)
> abort ();
> exit (0);
Ok, I can see two main differences between gcc and clang in this test. The first is that clang did 'sltiu $1, $4, -513' whereas gcc did 'sltu $3, $4, -512'. When using -mips3, the 'foo' function is otherwise equivalent (just different spellings of the same operations and different delay slot filling) so there's probably something wrong there.
The second may be the one that pointed you in this direction: clang is using 'daddiu $4, $0, -512' while gcc is using 'li $4, -512. These should produce the same register contents though (0xffff ffff ffff ffff fe00) so the off-by-one error above sounds more likely to be the bug causing the test to fail. That said, I'm thinking that there is a bug in the application of zeroext attributes as you say. i16 definitely needs zeroext. i31 and i33 should use zeroext too but it seems that i32 should signext. So maybe the rule should be 'unsigned integers always use zeroext, except i32 which uses signext'.
More information about the cfe-commits