This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Unsaved register?


On Tue, May 29, 2001 at 05:11:53PM -0700, Erik Walthinsen wrote:
> On Tue, 29 May 2001, Michael Meissner wrote:
> 
> > However, __asm__ isn't a function call, so rules for what registers are
> > clobbered or not do not apply.  The whole point of extended asm is to tell the
> > compiler, exactly what the inputs are, what the outputs are, what else is
> > clobbered, and whether or not the optimizer can move it.
> 
> So in this case, is listing %ecx as a clobbered register the correct
> solution?  Or should I somehow split the asm into two pieces and put the
> function call in between, in regular C?  It seems that that would be hard,
> since the branching is done explicitely in the asm.  It's just that
> listing %ecx as clobbered seems a hackish solution, since who's to say
> (without looking at the ABI spec) that other registers could cause the
> same problem?

Yes, other registers could also be the problem.

Here is your original code:

	extern inline
	uint32_t bitstream_get_mmx(bitstream_t *bs,uint32_t num_bits) {

	  uint32_t bits,result;
	//fprintf(stderr,"num_bits is %d\n",num_bits);        
	  asm volatile (
		"movq %4, %%mm7\n\t"            // put current bits into mm7          
		"movl %5, %3\n\t"               // put remaining bits into reg3
		"subl %6, %3\n\t"               // subtract num_bits from reg3
		"jnl 1f\n\t"                    // skip if we have enough bits

		"pushl %6\n\t"                  // push num_bits                 
		"pushl %7\n\t"                  // push bs
		"call bitstream_get_bh_mmx\n\t" // call the bottom half
		"movl %%eax, %0\n\t"            // save the result
		"jmp 2f\n\t"
		"1:\n\t"
		"movd %8, %%mm5\n\t"            // put the shift count into mm5

		// we know we have enough bits, they're at the top of mm7
		"movq %%mm7, %%mm6\n\t"         // working copy in mm6
		"movd %6, %%mm4\n\t"            // get the bit count again
		"psrlq %%mm5, %%mm6\n\t"        // shift mm6 right by 64 - numbits
		// mm6 now has the right data
		"movl %3, %2\n\t"               // save back the modified curbits
		"movd %%mm6, %0\n\t"            // write the resulting bits out
		"psllq %%mm4, %%mm7\n\t"        // strip those bits off mm7
		"movq %%mm7, %1\n\t"            // save the remaining bits back
		"2:\n\t"
		:
	    "=r"(result), "=m"(bs->current.u64), "=m"(bs->current_bits), "=r"(bits) :
	    "1"(bs->current.u64), "2"(bs->current_bits), "r"(num_bits), "r"(bs),
	      "rm"(_bitstream_mmx_64_minus[num_bits]) :
	    "memory"
	  );
	  return result;
	}

You need to also provide specific clobbers for all of the floating point
registers, since they are overlaid on top of the mmx registers.  You also
increment the stack with the pushes without decrementing them.  Note, that eax,
ebx, and ecx are clobbered across calls (and esi/dsi seem to be clobbered in
64-bit mode).  I would encode it something like:

	extern __inline__
	uint32_t bitstream_get_mmx(bitstream_t *bs, uint32_t num_bits)
	{
	  int32_t bits;
	  uint32_t result;

	  bits = bs->current_bits - num_bits;
	  if (bits < 0)
	    return bitstream_get_bh_mmx (bs, num_bits);

	  __asm__ volatile ("movq %1, %%mm7\n\t"	// put current bits into mm7
			    "movd %8, %%mm5\n\t"	// put the shift count into mm5
			    "movq %%mm7, %%mm6\n\t"	// working copy in mm6
			    "movd %4, %%mm4\n\t"	// get the bit count again
			    "psrlq %%mm5, %%mm6\n\t"	// shift mm6 right by 64 - numbits
							// mm6 now has the right data
			    "movl %3, %2\n\t"		// save back the modified curbits
			    "movd %%mm6, %0\n\t"	// write the resulting bits out
			    "psllq %%mm4, %%mm7\n\t"	// strip those bits off mm7
			    "movq %%mm7, %1\n\t"	// save the remaining bits back
		: "=r" (result),
		  "+m" (bs->current.u64), 
		  "+m" (bs->current_bits)
		: "r" (bits),
		  "r" (num_bits),
		  "rm" (_bitstream_mmx_64_minus[num_bits])
		// clobber all FPU registers
		: "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
#if (__GNUC__ >= 3) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
		// and also the mmx registers used if we have a new enough compiler
		  , "mm5", "mm6", "mm7"
#endif
	  );

	  return result;
	}

However, since it has been awhile since I supported the x86, I suspect somebody
who has worked with it more recently should look it over.

-- 
Michael Meissner, Red Hat, Inc.  (GCC group)
PMB 198, 174 Littleton Road #3, Westford, Massachusetts 01886, USA
Work:	  meissner@redhat.com		phone: +1 978-486-9304
Non-work: meissner@spectacle-pond.org	fax:   +1 978-692-4482


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]