/** * Provides fine-tuned implementation for IDIV/IREM operations on IA32-compatible platforms, * in replacement of common arithmetic helper (see arith_rt.h). */ bool CodeGen::gen_a_platf(JavaByteCodes op, jtype jt) { if (jt != i32) return false; if (op != OPCODE_IDIV && op != OPCODE_IREM) { return false; } // // The method is supposed to be platform-depended, and may not have // Encoder support - leaving as-is, without implementing general // support in Encoder // vpark(eax.reg()); vpark(edx.reg()); rlock(eax); rlock(edx); Val& v1 = vstack(1, vis_imm(1)); Val& v2 = vstack(0, true); alu(alu_cmp, v2.as_opnd(), Opnd(-1)); unsigned br_normal = br(ne, 0, 0); alu(alu_cmp, v1.as_opnd(), Opnd(INT_MIN)); unsigned br_exit = NOTHING; if (op == OPCODE_IREM) { do_mov(edx, Opnd(0)); // prepare exit value for the corner case br_exit = br(eq, 0, 0); } else { do_mov(eax, v1); br_exit = br(eq, 0, 0); } patch(br_normal, ip()); do_mov(eax, v1); // // The method is supposed to be platform-depended, and may not have // Encoder support - leaving as-is, without implementing general // support in Encoder // //CDQ EncoderBase::Operands args0(RegName_EDX, RegName_EAX); ip(EncoderBase::encode(ip(), Mnemonic_CDQ, args0)); //IDIV EncoderBase::Operands args(RegName_EDX, RegName_EAX, devirt(v2.reg(), i32)); ip(EncoderBase::encode(ip(), Mnemonic_IDIV, args)); patch(br_exit, ip()); vpop(); vpop(); vpush(op == OPCODE_IREM ? edx : eax); runlock(eax); runlock(edx); return true; }
bool CodeGen::gen_a_generic(JavaByteCodes op, jtype jt) { if (op == OPCODE_INEG) { return false; // later } if (jt == i32) { bool v2_imm = vis_imm(0); if (v2_imm && (op == OPCODE_ISHL || op == OPCODE_ISHL || op == OPCODE_IUSHR)) { // accept it } /*else if (v2_imm && (op == OPCODE_IMUL || op == OPCODE_IDIV)) { // accept it } else if (op == OPCODE_IMUL) { // accept it }*/ else if (op == OPCODE_IADD || op == OPCODE_ISUB) { // accept it } else if (op == OPCODE_IOR || op == OPCODE_IAND || op == OPCODE_IXOR) { // accept it } else if (vis_imm(0) && m_jframe->size()>1 && vis_imm(1)) { // accept it } else { return false; } } else if (is_f(jt)) { if (op != OPCODE_IADD && op != OPCODE_ISUB && op != OPCODE_IMUL && op != OPCODE_IDIV) { return false; } } else { return false; } bool is_dbl = jt == dbl64; unsigned v1_depth = is_dbl?2:1; if (vis_imm(v1_depth) && vis_imm(0)) { const Val& v1 = m_jframe->dip(v1_depth); const Val& v2 = m_jframe->dip(0); Val res; if (jt==dbl64) { double d = rt_h_dbl_a(v1.dval(), v2.dval(), op); res = Val(d); } else if (jt==flt32) { float f = rt_h_flt_a(v1.fval(), v2.fval(), op); res = Val(f); } else { assert(jt==i32); int i = rt_h_i32_a(v1.ival(), v2.ival(), op); res = Val(i); } vpop(); vpop(); vpush(res); return true; } // if v1.is_imm() && v2.is_imm() const Val& v1 = vstack(v1_depth, true); Opnd res = v1.as_opnd(); if (rrefs(v1.reg()) > 1) { rlock(v1); AR ar = valloc(jt); runlock(v1); Opnd reg(jt, ar); mov(reg, v1.as_opnd()); res = reg; } rlock(res); rlock(v1); const Val& v2 = m_jframe->dip(0); /* if (false )v2. #ifdef _IA32_ // on IA32 can use address in a displacement alu(to_alu(op), v1, ar_x, (int)v2.addr()); #else AR addr = valloc(jobj); rlock(addr); movp(addr, v2.addr()); alu_mem(jt, to_alu(op), r1, addr); runlock(addr); #endif } else */ if(v2.is_mem()) { // Everyone can do 'reg, mem' operation alu(to_alu(op), res, v2.as_opnd()); } else if(v2.is_imm() && jt==i32) { // 'reg, imm' is only for i32 operations alu(to_alu(op), res, v2.ival()); } else { Opnd v2 = vstack(0, true).as_opnd(); alu(to_alu(op), res, v2); } vpop(); vpop(); runlock(v1); runlock(res); vpush(res); return true; }