Edwin Steiner
Roland Lezuo
- $Id: codegen.c 5899 2006-11-04 15:46:18Z tbfg $
+ $Id: codegen.c 5928 2006-11-06 16:38:31Z tbfg $
*/
currentline = 0;
for (iptr = bptr->iinstr; len > 0; len--, iptr++) {
+ bool sign_ext = false;
if (iptr->line != currentline) {
dseg_addlinenumber(cd, iptr->line);
currentline = iptr->line;
/* integer operations *************************************************/
case ICMD_INEG: /* ..., value ==> ..., - value */
-
+ sign_ext = true;
+ case ICMD_LNEG:
s1 = emit_load_s1(jd, iptr, REG_ITMP1);
d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
M_NEG(s1, d);
+ if (sign_ext) M_EXTSW(d, d);
emit_store_dst(jd, iptr, d);
break;
- case ICMD_LNEG: /* ..., value ==> ..., - value */
-
- s1 = emit_load_s1(jd, iptr, REG_ITMP1);
- d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
- M_NEG(s1, d); /* XXX */
- emit_store_dst(jd, iptr, d);
- break;
case ICMD_I2L: /* ..., value ==> ..., value */
} else {
ICONST(REG_ITMP2, iptr->sx.val.i);
M_SUB(s1, REG_ITMP2, d);
- M_EXTSW(d, d);
}
+ M_EXTSW(d, d);
emit_store_dst(jd, iptr, d);
break;
break;
case ICMD_IDIV:
+ sign_ext = true;
case ICMD_LDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
s1 = emit_load_s1(jd, iptr, REG_ITMP1);
codegen_add_arithmeticexception_ref(cd);
M_DIV(s1, s2, d);
-
+ /* we need to test if divident was 0x8000000000000, bit OV is set in XER in this case */
+ /* we only need to check this if we did a LDIV, not for IDIV */
+ if (!sign_ext) {
+ M_MFXER(REG_ITMP2);
+ M_ANDIS(REG_ITMP2, 0x4000, REG_ITMP2); /* test OV */
+ M_BLE(1);
+ M_MOV(s1, d); /* java specs says result == dividend */
+ }
+ if (sign_ext) M_EXTSW(d, d);
emit_store_dst(jd, iptr, d);
break;
case ICMD_IREM:
+ sign_ext = true;
case ICMD_LREM: /* ..., val1, val2 ==> ..., val1 % val2 */
s1 = emit_load_s1(jd, iptr, REG_ITMP1);
s2 = emit_load_s2(jd, iptr, REG_ITMP2);
M_BEQ(0);
codegen_add_arithmeticexception_ref(cd);
- /* FIXME s1 == -2^63 && s2 == -1 does not work that way */
M_DIV(s1, s2, REG_ITMP3);
+ /* we need to test if divident was 0x8000000000000, bit OV is set in XER in this case */
+ /* we only need to check this if we did a LDIV, not for IDIV */
+ if (!sign_ext) {
+ M_MFXER(REG_ITMP2);
+ M_ANDIS(REG_ITMP2, 0x4000, REG_ITMP2); /* test OV */
+ M_BLE(2);
+ LCONST(REG_ITMP3, 0); /* result == 0 in this case */
+ M_BR(2);
+ }
M_MUL(REG_ITMP3, s2, REG_ITMP2);
M_SUB(s1, REG_ITMP2, REG_ITMP3);
d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+
M_MOV(REG_ITMP3, d);
emit_store_dst(jd, iptr, REG_ITMP1);
break;
case ICMD_IMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
+ sign_ext = true;
case ICMD_LMUL:
s1 = emit_load_s1(jd, iptr, REG_ITMP1);
s2 = emit_load_s2(jd, iptr, REG_ITMP2);
d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
M_MUL(s1, s2, d);
+ if (sign_ext) M_EXTSW(d, d);
emit_store_dst(jd, iptr, d);
break;
ICONST(REG_ITMP3, iptr->sx.val.i);
M_MUL(s1, REG_ITMP3, d);
}
+ M_EXTSW(d, d);
emit_store_dst(jd, iptr, d);
break;
case ICMD_LMULCONST:
d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
M_AND_IMM(s2, 0x1f, REG_ITMP3);
M_SLL(s1, REG_ITMP3, d);
+ M_EXTSW(d, d);
emit_store_dst(jd, iptr, d);
break;
s1 = emit_load_s1(jd, iptr, REG_ITMP1);
d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
- ICONST(REG_ITMP3, iptr->sx.val.i);
- M_SLL(s1, REG_ITMP3, d);
+ M_SLL_IMM(s1, iptr->sx.val.i & 0x1f, d);
+ M_EXTSW(d,d);
emit_store_dst(jd, iptr, d);
break;
case ICMD_IREMPOW2: /* ..., value ==> ..., value % constant */
/* sx.val.i = constant */
-
s1 = emit_load_s1(jd, iptr, REG_ITMP1);
d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
M_MOV(s1, REG_ITMP2);
M_RLWINM(REG_ITMP2, 0, 0, 30-b, REG_ITMP2);
}
M_SUB(s1, REG_ITMP2, d);
+ M_EXTSW(d, d);
emit_store_dst(jd, iptr, d);
break;
Changes: Christian Thalinger
Christian Ullrich
- $Id: codegen.h 5899 2006-11-04 15:46:18Z tbfg $
+ $Id: codegen.h 5928 2006-11-06 16:38:31Z tbfg $
*/
#define M_MUL(a,b,c) M_OP3(31, 233, 0, 0, c, a, b)
#define M_MUL_IMM(a,b,c) M_OP2_IMM(7, c, a, b)
-#define M_DIV(a,b,c) M_OP3(31, 489, 0, 0, c, a, b)
+#define M_DIV(a,b,c) M_OP3(31, 489, 1, 0, c, a, b)
#define M_NEG(a,b) M_OP3(31, 104, 0, 0, b, a, 0)
#define M_NOT(a,b) M_OP3(31, 124, 0, 0, a, b, a)
#define M_SUBFZE(a,b) M_OP3(31, 200, 0, 0, b, a, 0)
#define M_RLWINM(a,b,c,d,e) M_OP4(21, d, 0, a, e, b, c)
#define M_ADDZE(a,b) M_OP3(31, 202, 0, 0, b, a, 0)
-#define M_SLL_IMM(a,b,c) M_OP3(30, 0, 0, 0, a, c, b) /* RLDICL/ROTLDI FIXME: b is a split field */
+#define M_SLL_IMM(a,b,c) M_OP3(30, ((b)&0x20 ? 1:0), 0, ((((63-(b))&0x1f)<<6) | (((63-(b))&0x20 ? 1:0)<<5) | 0x04), a, c, (b)&0x1f); /* RLDICR is said to be turing complete, this seems right */
#define M_SRL_IMM(a,b,c) M_RLWINM(a,32-(b),b,31,c)
#define M_ADDIS(a,b,c) M_OP2_IMM(15, c, a, b)
#define M_STFIWX(a,b,c) M_OP3(31, 983, 0, 0, a, b, c)