[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