summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2025-04-09 22:07:11 +1000
committer Vas Crabb <vas@vastheman.com>2025-04-09 22:07:11 +1000
commitcff4924beb77418816a72b2dfe7e833eeff93040 (patch)
tree7b7d84734e60284ae7e852e425c092a2a1f648da
parent3612c23f9661897b01f1ccba232464446a69379c (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.cpp54
-rw-r--r--src/devices/cpu/drcbex64.cpp101
-rw-r--r--src/devices/cpu/uml.cpp39
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);
+ }
}
}