From bsderandrew at gmail.com Fri Mar 16 01:30:52 2012 From: bsderandrew at gmail.com (Andrew Collins) Date: Thu, 15 Mar 2012 19:30:52 -0600 Subject: [mips-gnu-discuss] Odd 64 bit multiplication issue on CodeBench Lite 2011.09-75 for MIPS Message-ID: 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 : 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 : 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 : 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 : 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?