[mips-gnu-discuss] Odd 64 bit multiplication issue on CodeBench Lite 2011.09-75 for MIPS

Andrew Collins bsderandrew at gmail.com
Fri Mar 16 01:30:52 UTC 2012


I'm running into a rather strange issue with CodeBench Lite 2011.09-75
for MIPS.  I first saw an issue after turning on "-mtune=74kc" for my
platform (-march is mips32r2).  I'm using Linux and calls to
timespec_to_jiffies started returning incorrect results, due to bogus
values returned from the first 64 bit multiply in the following code:

unsigned long
timespec_to_jiffies(const struct timespec *value)
{
	unsigned long sec = value->tv_sec;
	long nsec = value->tv_nsec + TICK_NSEC - 1;

	if (sec >= MAX_SEC_IN_JIFFIES){
		sec = MAX_SEC_IN_JIFFIES;
		nsec = 0;
	}
	return (((u64)sec * SEC_CONVERSION) + /* <- This multiplication seems
to return invalid results when using -mtune=74kc */
		(((u64)nsec * NSEC_CONVERSION) >>
		 (NSEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC;

}
EXPORT_SYMBOL(timespec_to_jiffies);

I tried reproducing this with a userspace test case but had no luck,
so I replaced the multiply in timespec_to_jiffies with a small test
function to see what's going on:

static noinline u64 mul64(u32 a)
{
	return (u64)a * 4194304000LLU; /* this constant is what
SEC_CONVERSION works out to */
}

which results in:

0000023c <mul64>:
 23c:	00042823 	negu	a1,a0
 240:	0005182b 	sltu	v1,zero,a1
 244:	00053080 	sll	a2,a1,0x2
 248:	00031823 	negu	v1,v1
 24c:	00c41021 	addu	v0,a2,a0
 250:	00052f82 	srl	a1,a1,0x1e
 254:	00032080 	sll	a0,v1,0x2
 258:	0046182b 	sltu	v1,v0,a2
 25c:	00a42025 	or	a0,a1,a0
 260:	00641821 	addu	v1,v1,a0
 264:	000229c2 	srl	a1,v0,0x7
 268:	00031e40 	sll	v1,v1,0x19
 26c:	00021640 	sll	v0,v0,0x19
 270:	03e00008 	jr	ra
 274:	00a31825 	or	v1,a1,v1

When a == 58 (it's a futex timeout getting converted), the result is
18446744067871080448 (0xFFFFFFFEA4000000) instead of the correct
result of 243269632000 (38A4000000).

Interestingly, although timespec_to_jiffies starts working properly
with mtune=74kc turned off, the function above *still* fails, and
generates:

00000270 <mul64>:
 270:	00042823 	negu	a1,a0
 274:	0005182b 	sltu	v1,zero,a1
 278:	00053080 	sll	a2,a1,0x2
 27c:	00031823 	negu	v1,v1
 280:	00c41021 	addu	v0,a2,a0
 284:	00052f82 	srl	a1,a1,0x1e
 288:	00032080 	sll	a0,v1,0x2
 28c:	00a42025 	or	a0,a1,a0
 290:	0046182b 	sltu	v1,v0,a2
 294:	00641821 	addu	v1,v1,a0
 298:	000229c2 	srl	a1,v0,0x7
 29c:	00031e40 	sll	v1,v1,0x19
 2a0:	00a31825 	or	v1,a1,v1
 2a4:	03e00008 	jr	ra
 2a8:	00021640 	sll	v0,v0,0x19

The ancient gcc-3.4.2 I was using previously generates working code:

00000908 <mul64>:
 908:	3c02fa00 	lui	v0,0xfa00
 90c:	00820019 	multu	a0,v0
 910:	00001012 	mflo	v0
 914:	00001810 	mfhi	v1
 918:	03e00008 	jr	ra
 91c:	00000000 	nop

And finally, the issue seems signedness dependent, changing the
function above to a signed 32 bit argument (which seems wrong):

static noinline u64 mul64(s32 a)
{
	return (u64)a * 4194304000LLU; /* this constant is what
SEC_CONVERSION works out to */
}

Results in working object code even with -mtune=74kc:

0000023c <mul64>:
 23c:	3c05fa00 	lui	a1,0xfa00
 240:	000437c3 	sra	a2,a0,0x1f
 244:	00850019 	multu	a0,a1
 248:	00001810 	mfhi	v1
 24c:	00001012 	mflo	v0
 250:	70c52002 	mul	a0,a2,a1
 254:	00832021 	addu	a0,a0,v1
 258:	03e00008 	jr	ra
 25c:	00801821 	move	v1,a0

I'm not sure whether I'm missing something obvious here with
signedness/casting that's causing my pain, or whether this is a
toolchain issue.  Any ideas?


More information about the mips-gnu-discuss mailing list