diff options
author | 2025-04-09 22:07:11 +1000 | |
---|---|---|
committer | 2025-04-09 22:07:11 +1000 | |
commit | cff4924beb77418816a72b2dfe7e833eeff93040 (patch) | |
tree | 7b7d84734e60284ae7e852e425c092a2a1f648da | |
parent | 3612c23f9661897b01f1ccba232464446a69379c (diff) |
cpu/uml.cpp: Fixed assertion failures when simplification reduces operand count.
* Also added a few more simplifications.
* cpu/drcbearm64.cpp, cpu/drcbex64.cpp: Removed more speical cases for
things the simplifier deals with.
-rw-r--r-- | src/devices/cpu/drcbearm64.cpp | 54 | ||||
-rw-r--r-- | src/devices/cpu/drcbex64.cpp | 101 | ||||
-rw-r--r-- | src/devices/cpu/uml.cpp | 39 |
3 files changed, 48 insertions, 146 deletions
diff --git a/src/devices/cpu/drcbearm64.cpp b/src/devices/cpu/drcbearm64.cpp index 882f70324a7..ca822f1793c 100644 --- a/src/devices/cpu/drcbearm64.cpp +++ b/src/devices/cpu/drcbearm64.cpp @@ -4167,7 +4167,7 @@ void drcbe_arm64::op_test(a64::Assembler &a, const uml::instruction &inst) const a64::Gp src1 = src1p.select_register(TEMP_REG1, inst.size()); const a64::Gp src2 = src2p.select_register(TEMP_REG2, inst.size()); - if (src1p.is_immediate_value(0) || src2p.is_immediate_value(0)) + if (src2p.is_immediate_value(0)) { const a64::Gp zero = select_register(a64::xzr, inst.size()); @@ -4178,21 +4178,11 @@ void drcbe_arm64::op_test(a64::Assembler &a, const uml::instruction &inst) mov_reg_param(a, inst.size(), src1, src1p); a.tst(src1, src1); } - else if (src1p.is_immediate_value(util::make_bitmask<uint64_t>(inst.size() * 8))) - { - mov_reg_param(a, inst.size(), src2, src2p); - a.tst(src2, src2); - } else if (src2p.is_immediate() && is_valid_immediate_mask(src2p.immediate(), inst.size())) { mov_reg_param(a, inst.size(), src1, src1p); a.tst(src1, src2p.immediate()); } - else if (src1p.is_immediate() && is_valid_immediate_mask(src1p.immediate(), inst.size())) - { - mov_reg_param(a, inst.size(), src2, src2p); - a.tst(src2, src1p.immediate()); - } else { mov_reg_param(a, inst.size(), src1, src1p); @@ -4216,27 +4206,10 @@ void drcbe_arm64::op_or(a64::Assembler &a, const uml::instruction &inst) const a64::Gp dst = dstp.select_register(TEMP_REG3, inst.size()); const a64::Gp src1 = src1p.select_register(dst, inst.size()); - if (src1p.is_immediate() && src2p.is_immediate()) - { - get_imm_relative(a, dst, src1p.immediate() | src2p.immediate()); - } - else if (src2p.is_immediate_value(util::make_bitmask<uint64_t>(inst.size() * 8))) + if (src2p.is_immediate_value(util::make_bitmask<uint64_t>(inst.size() * 8))) { a.mov(dst, src2p.immediate()); } - else if (src2p.is_immediate_value(0) || (src1p == src2p)) - { - if ((dstp == src1p) && !inst.flags()) - { - if ((inst.size() == 8) || (dstp.is_memory() && !dstp.is_cold_register())) - return; - } - - mov_reg_param(a, inst.size(), src1, src1p); - - if ((dst.id() != src1.id()) || ((inst.size() == 4) && (dstp == src1p) && dstp.is_int_register())) - a.mov(dst, src1); - } else if (src2p.is_immediate() && is_valid_immediate_mask(src2p.immediate(), inst.size())) { mov_reg_param(a, inst.size(), src1, src1p); @@ -4274,24 +4247,7 @@ void drcbe_arm64::op_xor(a64::Assembler &a, const uml::instruction &inst) const a64::Gp dst = dstp.select_register(TEMP_REG3, inst.size()); const a64::Gp src1 = src1p.select_register(dst, inst.size()); - if (src1p.is_immediate() && src2p.is_immediate()) - { - get_imm_relative(a, dst, src1p.immediate() ^ src2p.immediate()); - } - else if (src2p.is_immediate_value(0)) - { - if ((dstp == src1p) && !inst.flags()) - { - if ((inst.size() == 8) || (dstp.is_memory() && !dstp.is_cold_register())) - return; - } - - mov_reg_param(a, inst.size(), src1, src1p); - - if ((dst.id() != src1.id()) || ((inst.size() == 4) && (dstp == src1p) && dstp.is_int_register())) - a.mov(dst, src1); - } - else if (src2p.is_immediate_value(util::make_bitmask<uint64_t>(inst.size() * 8))) + if (src2p.is_immediate_value(util::make_bitmask<uint64_t>(inst.size() * 8))) { mov_reg_param(a, inst.size(), src1, src1p); @@ -4303,10 +4259,6 @@ void drcbe_arm64::op_xor(a64::Assembler &a, const uml::instruction &inst) a.eor(dst, src1, src2p.immediate()); } - else if (src1p == src2p) - { - a.mov(dst, select_register(a64::xzr, inst.size())); - } else { const a64::Gp src2 = src2p.select_register(TEMP_REG1, inst.size()); diff --git a/src/devices/cpu/drcbex64.cpp b/src/devices/cpu/drcbex64.cpp index b1147492806..c07d07d158d 100644 --- a/src/devices/cpu/drcbex64.cpp +++ b/src/devices/cpu/drcbex64.cpp @@ -4807,21 +4807,7 @@ void drcbe_x64::op_and(Assembler &a, const instruction &inst) if (dstp.is_memory() && ((inst.size() == 8) || !dstp.is_cold_register()) && (dstp == src1p)) { // dstp == src1p in memory - alu_op_param(a, Inst::kIdAnd, MABS(dstp.memory(), inst.size()), src2p, - [inst](Assembler &a, Operand const &dst, be_parameter const &src) - { - // optimize all-zero and all-one cases - if (!inst.flags() && !src.immediate()) - { - a.mov(dst.as<Mem>(), imm(0)); - return true; - } - else if (!inst.flags() && ones(src.immediate(), inst.size())) - { - return true; - } - return false; - }); + alu_op_param(a, Inst::kIdAnd, MABS(dstp.memory(), inst.size()), src2p); } else if (src2p.is_immediate_value(0xff) && !inst.flags()) { @@ -4870,16 +4856,10 @@ void drcbe_x64::op_and(Assembler &a, const instruction &inst) else if (ones(src.immediate(), inst.size())) { if (inst.size() == 4) - { - if (inst.flags()) - a.and_(dst.as<Gp>(), dst.as<Gp>()); - else - a.mov(dst.as<Gp>(), dst.as<Gp>()); - } - else if (inst.flags()) - { + a.and_(dst.as<Gp>(), dst.as<Gp>()); + else a.test(dst.as<Gp>(), dst.as<Gp>()); - } + return true; } @@ -4918,7 +4898,7 @@ void drcbe_x64::op_test(Assembler &a, const instruction &inst) // general case // pick a target register for the general case - Gp src1reg = (inst.size() == 4) ? src1p.select_register(eax) : src1p.select_register(rax); + const Gp src1reg = src1p.select_register((inst.size() == 4) ? Gp(eax) : Gp(rax)); mov_reg_param(a, src1reg, src1p); alu_op_param(a, Inst::kIdTest, src1reg, src2p, @@ -4966,10 +4946,6 @@ void drcbe_x64::op_or(Assembler &a, const instruction &inst) a.mov(dst.as<Mem>(), imm(-1)); return true; } - else if (!inst.flags() && !src.immediate()) - { - return true; - } return false; }); } @@ -4980,8 +4956,8 @@ void drcbe_x64::op_or(Assembler &a, const instruction &inst) // pick a target register for the general case Gp dstreg = (inst.size() == 4) ? dstp.select_register(eax, src2p) : dstp.select_register(rax, src2p); - mov_reg_param(a, dstreg, src1p); // mov dstreg,src1p - alu_op_param(a, Inst::kIdOr, dstreg, src2p, // or dstreg,src2p + mov_reg_param(a, dstreg, src1p); + alu_op_param(a, Inst::kIdOr, dstreg, src2p, [inst] (Assembler &a, Operand const &dst, be_parameter const &src) { // optimize all-zero and all-one cases @@ -4990,27 +4966,10 @@ void drcbe_x64::op_or(Assembler &a, const instruction &inst) a.mov(dst.as<Gp>(), imm(-1)); return true; } - else if (!src.immediate()) - { - if (inst.size() == 4) - { - if (inst.flags()) - a.or_(dst.as<Gp>(), dst.as<Gp>()); - else - a.mov(dst.as<Gp>(), dst.as<Gp>()); - } - else if (inst.flags()) - { - a.test(dst.as<Gp>(), dst.as<Gp>()); - } - return true; - } - return false; }); - if ((inst.size() == 4) || !src2p.is_immediate_value(0)) - mov_param_reg(a, dstp, dstreg); // mov dstp,dstreg + mov_param_reg(a, dstp, dstreg); } } @@ -5035,17 +4994,15 @@ void drcbe_x64::op_xor(Assembler &a, const instruction &inst) if (dstp.is_memory() && ((inst.size() == 8) || !dstp.is_cold_register()) && (dstp == src1p)) { // dstp == src1p in memory - alu_op_param(a, Inst::kIdXor, MABS(dstp.memory(), inst.size()), src2p, // xor [dstp],src2p + alu_op_param(a, Inst::kIdXor, MABS(dstp.memory(), inst.size()), src2p, [inst] (Assembler &a, Operand const &dst, be_parameter const &src) { - // optimize all-zero and all-one cases + // optimize all-one cases if (!inst.flags() && ones(src.immediate(), inst.size())) { a.not_(dst.as<Mem>()); return true; } - else if (!inst.flags() && !src.immediate()) - return true; return false; }); @@ -5058,27 +5015,12 @@ void drcbe_x64::op_xor(Assembler &a, const instruction &inst) alu_op_param(a, Inst::kIdXor, dst, src2p, [inst] (Assembler &a, Operand const &dst, be_parameter const &src) { - // optimize all-zero and all-one cases + // optimize all-one cases if (!inst.flags() && ones(src.immediate(), inst.size())) { a.not_(dst.as<Gp>()); return true; } - else if (!src.immediate()) - { - if (inst.size() == 4) - { - if (inst.flags()) - a.or_(dst.as<Gp>(), dst.as<Gp>()); - else - a.mov(dst.as<Gp>(), dst.as<Gp>()); - } - else if (inst.flags()) - { - a.test(dst.as<Gp>(), dst.as<Gp>()); - } - return true; - } return false; }); } @@ -5091,33 +5033,16 @@ void drcbe_x64::op_xor(Assembler &a, const instruction &inst) alu_op_param(a, Inst::kIdXor, dstreg, src2p, [inst] (Assembler &a, Operand const &dst, be_parameter const &src) { - // optimize all-zero and all-one cases + // optimize all-one cases if (!inst.flags() && ones(src.immediate(), inst.size())) { a.not_(dst.as<Gp>()); return true; } - else if (!src.immediate()) - { - if (inst.size() == 4) - { - if (inst.flags()) - a.or_(dst.as<Gp>(), dst.as<Gp>()); - else - a.mov(dst.as<Gp>(), dst.as<Gp>()); - } - else if (inst.flags()) - { - a.test(dst.as<Gp>(), dst.as<Gp>()); - } - return true; - } - return false; }); - if ((inst.size() == 4) || !src2p.is_immediate_value(0)) - mov_param_reg(a, dstp, dstreg); + mov_param_reg(a, dstp, dstreg); } } diff --git a/src/devices/cpu/uml.cpp b/src/devices/cpu/uml.cpp index 6670725a18b..d88b30ddcfe 100644 --- a/src/devices/cpu/uml.cpp +++ b/src/devices/cpu/uml.cpp @@ -353,8 +353,8 @@ public: if (inst.param(2).is_immediate_value(mask)) { inst.m_opcode = OP_READ; - inst.m_numparams = 3; inst.m_param[2] = inst.param(3); + inst.m_numparams = 3; } } @@ -381,8 +381,8 @@ public: if (inst.param(2).is_immediate_value(mask)) { inst.m_opcode = OP_WRITE; - inst.m_numparams = 3; inst.m_param[2] = inst.param(3); + inst.m_numparams = 3; } } @@ -450,19 +450,19 @@ public: { // only mask is variable, convert to AND inst.m_opcode = OP_AND; - inst.m_numparams = 3; if (size == 4) inst.m_param[1] = parameter(rotl_32(inst.param(1).immediate(), inst.param(2).immediate())); else inst.m_param[1] = parameter(rotl_64(inst.param(1).immediate(), inst.param(2).immediate())); inst.m_param[2] = inst.param(3); + inst.m_numparams = 3; } else if (inst.param(2).is_immediate_value(0) || inst.param(3).is_immediate_value(0)) { // no shift or zero mask, convert to AND (may be subsequently converted to MOV) inst.m_opcode = OP_AND; - inst.m_numparams = 3; inst.m_param[2] = inst.param(3); + inst.m_numparams = 3; } else if (inst.param(3).is_immediate_value(mask)) { @@ -598,9 +598,9 @@ public: if (inst.param(0) == inst.param(1)) { inst.m_opcode = LoWordOp; - inst.m_numparams = 3; inst.m_param[1] = inst.param(2); inst.m_param[2] = inst.param(3); + inst.m_numparams = 3; return; } @@ -696,7 +696,7 @@ public: // any immediate zero always yields zero convert_to_mov_immediate(inst, 0); } - else if (inst.param(2).is_immediate_value(size_mask(inst))) + else if (inst.param(2).is_immediate_value(size_mask(inst)) || (inst.param(1) == inst.param(2))) { if (!inst.flags()) { @@ -734,6 +734,19 @@ public: using std::swap; swap(inst.m_param[0], inst.m_param[1]); } + + if (inst.param(0).is_immediate() && inst.param(1).is_immediate()) + { + // two immediates, combine values and set second operand to all 0 or all 1 + u64 const val = inst.param(0).immediate() & inst.param(1).immediate(); + inst.m_param[0] = val; + inst.m_param[1] = val ? mask : 0; + } + else if (inst.param(0) == inst.param(1)) + { + // testing a value against itself, turn the second operand into an immediate + inst.m_param[1] = mask; + } } static void _or(instruction &inst) @@ -753,7 +766,7 @@ public: // an immediate with all bits set is unaffected by the other value convert_to_mov_immediate(inst, mask); } - else if (inst.param(2).is_immediate_value(0)) + else if (inst.param(2).is_immediate_value(0) || (inst.param(1) == inst.param(2))) { if (!inst.flags()) { @@ -767,6 +780,12 @@ public: inst.m_opcode = OP_TEST; inst.m_numparams = 2; } + else + { + // convert to AND to simplify code generation + inst.m_opcode = OP_AND; + inst.m_param[2] = mask; + } } } @@ -799,6 +818,12 @@ public: inst.m_opcode = OP_TEST; inst.m_numparams = 2; } + else + { + // convert to AND to simplify code generation + inst.m_opcode = OP_AND; + inst.m_param[2] = size_mask(inst); + } } } |