Replacing DidCarry with manual calculation and fixing compares.

This commit is contained in:
Ben Vanik 2015-06-06 15:24:46 -07:00
parent 6b52f6715a
commit 429698c2ec
14 changed files with 156 additions and 428 deletions

View File

@ -2404,14 +2404,14 @@ EMITTER_OPCODE_TABLE(
COMPARE_##op##_I16, \
COMPARE_##op##_I32, \
COMPARE_##op##_I64);
EMITTER_ASSOCIATIVE_COMPARE_XX(SLT, setl, setge);
EMITTER_ASSOCIATIVE_COMPARE_XX(SLE, setle, setg);
EMITTER_ASSOCIATIVE_COMPARE_XX(SGT, setg, setle);
EMITTER_ASSOCIATIVE_COMPARE_XX(SGE, setge, setl);
EMITTER_ASSOCIATIVE_COMPARE_XX(ULT, setb, setae);
EMITTER_ASSOCIATIVE_COMPARE_XX(ULE, setbe, seta);
EMITTER_ASSOCIATIVE_COMPARE_XX(UGT, seta, setbe);
EMITTER_ASSOCIATIVE_COMPARE_XX(UGE, setae, setb);
EMITTER_ASSOCIATIVE_COMPARE_XX(SLT, setl, setg);
EMITTER_ASSOCIATIVE_COMPARE_XX(SLE, setle, setge);
EMITTER_ASSOCIATIVE_COMPARE_XX(SGT, setg, setl);
EMITTER_ASSOCIATIVE_COMPARE_XX(SGE, setge, setle);
EMITTER_ASSOCIATIVE_COMPARE_XX(ULT, setb, seta);
EMITTER_ASSOCIATIVE_COMPARE_XX(ULE, setbe, setae);
EMITTER_ASSOCIATIVE_COMPARE_XX(UGT, seta, setb);
EMITTER_ASSOCIATIVE_COMPARE_XX(UGE, setae, setbe);
// http://x86.renejeschke.de/html/file_module_x86_id_288.html
#define EMITTER_ASSOCIATIVE_COMPARE_FLT_XX(op, instr) \
@ -2449,61 +2449,6 @@ EMITTER_ASSOCIATIVE_COMPARE_FLT_XX(UGT, seta);
EMITTER_ASSOCIATIVE_COMPARE_FLT_XX(UGE, setae);
// ============================================================================
// OPCODE_DID_CARRY
// ============================================================================
// TODO(benvanik): salc/setalc
// https://code.google.com/p/corkami/wiki/x86oddities
EMITTER(DID_CARRY_I8, MATCH(I<OPCODE_DID_CARRY, I8<>, I8<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) {
assert_true(!i.src1.is_constant);
e.LoadEflags();
e.setc(i.dest);
}
};
EMITTER(DID_CARRY_I16, MATCH(I<OPCODE_DID_CARRY, I8<>, I16<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) {
assert_true(!i.src1.is_constant);
e.LoadEflags();
e.setc(i.dest);
}
};
EMITTER(DID_CARRY_I32, MATCH(I<OPCODE_DID_CARRY, I8<>, I32<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) {
assert_true(!i.src1.is_constant);
e.LoadEflags();
e.setc(i.dest);
}
};
EMITTER(DID_CARRY_I64, MATCH(I<OPCODE_DID_CARRY, I8<>, I64<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) {
assert_true(!i.src1.is_constant);
e.LoadEflags();
e.setc(i.dest);
}
};
EMITTER_OPCODE_TABLE(
OPCODE_DID_CARRY,
DID_CARRY_I8,
DID_CARRY_I16,
DID_CARRY_I32,
DID_CARRY_I64);
// ============================================================================
// OPCODE_DID_OVERFLOW
// ============================================================================
EMITTER(DID_OVERFLOW, MATCH(I<OPCODE_DID_OVERFLOW, I8<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) {
e.LoadEflags();
e.seto(i.dest);
}
};
EMITTER_OPCODE_TABLE(
OPCODE_DID_OVERFLOW,
DID_OVERFLOW);
// ============================================================================
// OPCODE_DID_SATURATE
// ============================================================================
@ -2736,10 +2681,6 @@ void EmitAddXX(X64Emitter& e, const ARGS& i) {
e, i,
[](X64Emitter& e, const REG& dest_src, const REG& src) { e.add(dest_src, src); },
[](X64Emitter& e, const REG& dest_src, int32_t constant) { e.add(dest_src, constant); });
if (i.instr->flags & ARITHMETIC_SET_CARRY) {
// CF is set if carried.
e.StoreEflags();
}
}
EMITTER(ADD_I8, MATCH(I<OPCODE_ADD, I8<>, I8<>, I8<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) {
@ -2817,10 +2758,6 @@ void EmitAddCarryXX(X64Emitter& e, const ARGS& i) {
}, [](X64Emitter& e, const REG& dest_src, int32_t constant) {
e.adc(dest_src, constant);
});
if (i.instr->flags & ARITHMETIC_SET_CARRY) {
// CF is set if carried.
e.StoreEflags();
}
}
EMITTER(ADD_CARRY_I8, MATCH(I<OPCODE_ADD_CARRY, I8<>, I8<>, I8<>, I8<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) {
@ -3009,32 +2946,11 @@ EMITTER_OPCODE_TABLE(
// TODO(benvanik): put dest/src1|2 together.
template <typename SEQ, typename REG, typename ARGS>
void EmitSubXX(X64Emitter& e, const ARGS& i) {
if (i.instr->flags & ARITHMETIC_SET_CARRY) {
// TODO(benvanik): faster way of doing sub with CF set?
SEQ::EmitAssociativeBinaryOp(
e, i,
[](X64Emitter& e, const REG& dest_src, const REG& src) {
auto temp = GetTempReg<REG>(e);
e.mov(temp, src);
e.not(temp);
e.stc();
e.adc(dest_src, temp);
},
[](X64Emitter& e, const REG& dest_src, int32_t constant) {
auto temp = GetTempReg<REG>(e);
e.mov(temp, constant);
e.not(temp);
e.stc();
e.adc(dest_src, temp);
});
e.StoreEflags();
} else {
SEQ::EmitAssociativeBinaryOp(
e, i,
[](X64Emitter& e, const REG& dest_src, const REG& src) { e.sub(dest_src, src); },
[](X64Emitter& e, const REG& dest_src, int32_t constant) { e.sub(dest_src, constant); });
}
}
EMITTER(SUB_I8, MATCH(I<OPCODE_SUB, I8<>, I8<>, I8<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) {
EmitSubXX<SUB_I8, Reg8>(e, i);
@ -6576,8 +6492,6 @@ void RegisterSequences() {
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_COMPARE_ULE_FLT);
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_COMPARE_UGT_FLT);
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_COMPARE_UGE_FLT);
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_DID_CARRY);
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_DID_OVERFLOW);
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_DID_SATURATE);
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_VECTOR_COMPARE_EQ);
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_VECTOR_COMPARE_SGT);

View File

@ -232,9 +232,9 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) {
case OPCODE_IS_TRUE:
if (i->src1.value->IsConstant()) {
if (i->src1.value->IsConstantTrue()) {
v->set_constant((int8_t)1);
v->set_constant(uint8_t(1));
} else {
v->set_constant((int8_t)0);
v->set_constant(uint8_t(0));
}
i->Remove();
}
@ -242,9 +242,9 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) {
case OPCODE_IS_FALSE:
if (i->src1.value->IsConstant()) {
if (i->src1.value->IsConstantFalse()) {
v->set_constant((int8_t)1);
v->set_constant(uint8_t(1));
} else {
v->set_constant((int8_t)0);
v->set_constant(uint8_t(0));
}
i->Remove();
}
@ -254,80 +254,74 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) {
case OPCODE_COMPARE_EQ:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
bool value = i->src1.value->IsConstantEQ(i->src2.value);
i->dest->set_constant(value);
i->dest->set_constant(uint8_t(value));
i->Remove();
}
break;
case OPCODE_COMPARE_NE:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
bool value = i->src1.value->IsConstantNE(i->src2.value);
i->dest->set_constant(value);
i->dest->set_constant(uint8_t(value));
i->Remove();
}
break;
case OPCODE_COMPARE_SLT:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
bool value = i->src1.value->IsConstantSLT(i->src2.value);
i->dest->set_constant(value);
i->dest->set_constant(uint8_t(value));
i->Remove();
}
break;
case OPCODE_COMPARE_SLE:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
bool value = i->src1.value->IsConstantSLE(i->src2.value);
i->dest->set_constant(value);
i->dest->set_constant(uint8_t(value));
i->Remove();
}
break;
case OPCODE_COMPARE_SGT:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
bool value = i->src1.value->IsConstantSGT(i->src2.value);
i->dest->set_constant(value);
i->dest->set_constant(uint8_t(value));
i->Remove();
}
break;
case OPCODE_COMPARE_SGE:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
bool value = i->src1.value->IsConstantSGE(i->src2.value);
i->dest->set_constant(value);
i->dest->set_constant(uint8_t(value));
i->Remove();
}
break;
case OPCODE_COMPARE_ULT:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
bool value = i->src1.value->IsConstantULT(i->src2.value);
i->dest->set_constant(value);
i->dest->set_constant(uint8_t(value));
i->Remove();
}
break;
case OPCODE_COMPARE_ULE:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
bool value = i->src1.value->IsConstantULE(i->src2.value);
i->dest->set_constant(value);
i->dest->set_constant(uint8_t(value));
i->Remove();
}
break;
case OPCODE_COMPARE_UGT:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
bool value = i->src1.value->IsConstantUGT(i->src2.value);
i->dest->set_constant(value);
i->dest->set_constant(uint8_t(value));
i->Remove();
}
break;
case OPCODE_COMPARE_UGE:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
bool value = i->src1.value->IsConstantUGE(i->src2.value);
i->dest->set_constant(value);
i->dest->set_constant(uint8_t(value));
i->Remove();
}
break;
case OPCODE_DID_CARRY:
assert_true(!i->src1.value->IsConstant());
break;
case OPCODE_DID_OVERFLOW:
assert_true(!i->src1.value->IsConstant());
break;
case OPCODE_DID_SATURATE:
assert_true(!i->src1.value->IsConstant());
break;
@ -336,33 +330,13 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) {
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
v->set_from(i->src1.value);
bool did_carry = v->Add(i->src2.value);
bool propagate_carry = !!(i->flags & ARITHMETIC_SET_CARRY);
i->Remove();
// If carry is set find the DID_CARRY and fix it.
if (propagate_carry) {
PropagateCarry(v, did_carry);
}
}
break;
// TODO(benvanik): ADD_CARRY (w/ ARITHMETIC_SET_CARRY)
case OPCODE_ADD_CARRY:
if (i->src1.value->IsConstantZero() &&
i->src2.value->IsConstantZero()) {
Value* ca = i->src3.value;
// If carry is set find the DID_CARRY and fix it.
if (!!(i->flags & ARITHMETIC_SET_CARRY)) {
auto next = i->dest->use_head;
while (next) {
auto use = next;
next = use->next;
if (use->instr->opcode == &OPCODE_DID_CARRY_info) {
// Replace carry value.
use->instr->Replace(&OPCODE_ASSIGN_info, 0);
use->instr->set_src1(builder->LoadZero(INT8_TYPE));
}
}
}
if (ca->IsConstant()) {
TypeName target_type = v->type;
v->set_from(ca);
@ -383,13 +357,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) {
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
v->set_from(i->src1.value);
bool did_carry = v->Sub(i->src2.value);
bool propagate_carry = !!(i->flags & ARITHMETIC_SET_CARRY);
i->Remove();
// If carry is set find the DID_CARRY and fix it.
if (propagate_carry) {
PropagateCarry(v, did_carry);
}
}
break;
case OPCODE_MUL:
@ -535,19 +503,6 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) {
return true;
}
void ConstantPropagationPass::PropagateCarry(Value* v, bool did_carry) {
auto next = v->use_head;
while (next) {
auto use = next;
next = use->next;
if (use->instr->opcode == &OPCODE_DID_CARRY_info) {
// Replace carry value.
use->instr->dest->set_constant(int8_t(did_carry ? 1 : 0));
use->instr->Remove();
}
}
}
} // namespace passes
} // namespace compiler
} // namespace cpu

View File

@ -25,7 +25,6 @@ class ConstantPropagationPass : public CompilerPass {
bool Run(hir::HIRBuilder* builder) override;
private:
void PropagateCarry(hir::Value* v, bool did_carry);
};
} // namespace passes

View File

@ -24,6 +24,27 @@ using xe::cpu::hir::Value;
// Integer arithmetic (A-3)
Value* AddDidCarry(PPCHIRBuilder& f, Value* v1, Value* v2) {
return f.CompareUGT(f.Truncate(v2, INT32_TYPE),
f.Not(f.Truncate(v1, INT32_TYPE)));
}
Value* SubDidCarry(PPCHIRBuilder& f, Value* v1, Value* v2) {
return f.Or(f.CompareUGT(f.Truncate(v1, INT32_TYPE),
f.Not(f.Neg(f.Truncate(v2, INT32_TYPE)))),
f.IsFalse(f.Truncate(v2, INT32_TYPE)));
}
// https://github.com/sebastianbiallas/pearpc/blob/0b3c823f61456faa677f6209545a7b906e797421/src/cpu/cpu_generic/ppc_tools.h#L26
Value* AddWithCarryDidCarry(PPCHIRBuilder& f, Value* v1, Value* v2, Value* v3) {
v1 = f.Truncate(v1, INT32_TYPE);
v2 = f.Truncate(v2, INT32_TYPE);
assert_true(v3->type == INT8_TYPE);
v3 = f.ZeroExtend(v3, INT32_TYPE);
return f.Or(f.CompareULT(f.Add(f.Add(v1, v2), v3), v3),
f.CompareULT(f.Add(v1, v2), v1));
}
XEEMITTER(addx, 0x7C000214, XO)(PPCHIRBuilder& f, InstrData& i) {
// RD <- (RA) + (RB)
Value* v = f.Add(f.LoadGPR(i.XO.RA), f.LoadGPR(i.XO.RB));
@ -41,13 +62,15 @@ XEEMITTER(addx, 0x7C000214, XO)(PPCHIRBuilder& f, InstrData& i) {
XEEMITTER(addcx, 0x7C000014, XO)(PPCHIRBuilder& f, InstrData& i) {
// RD <- (RA) + (RB)
// CA <- carry bit
Value* v =
f.Add(f.LoadGPR(i.XO.RA), f.LoadGPR(i.XO.RB), ARITHMETIC_SET_CARRY);
f.StoreCA(f.DidCarry(v));
Value* ra = f.LoadGPR(i.XO.RA);
Value* rb = f.LoadGPR(i.XO.RB);
Value* v = f.Add(ra, rb);
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
assert_always();
// e.update_xer_with_overflow(EFLAGS OF?);
} else {
f.StoreCA(AddDidCarry(f, ra, rb));
}
if (i.XO.Rc) {
f.UpdateCR(0, v);
@ -58,13 +81,15 @@ XEEMITTER(addcx, 0x7C000014, XO)(PPCHIRBuilder& f, InstrData& i) {
XEEMITTER(addex, 0x7C000114, XO)(PPCHIRBuilder& f, InstrData& i) {
// RD <- (RA) + (RB) + XER[CA]
// CA <- carry bit
Value* v = f.AddWithCarry(f.LoadGPR(i.XO.RA), f.LoadGPR(i.XO.RB), f.LoadCA(),
ARITHMETIC_SET_CARRY);
f.StoreCA(f.DidCarry(v));
Value* ra = f.LoadGPR(i.XO.RA);
Value* rb = f.LoadGPR(i.XO.RB);
Value* v = f.AddWithCarry(ra, rb, f.LoadCA());
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
assert_always();
// e.update_xer_with_overflow(EFLAGS OF?);
} else {
f.StoreCA(AddWithCarryDidCarry(f, ra, rb, f.LoadCA()));
}
if (i.XO.Rc) {
f.UpdateCR(0, v);
@ -89,20 +114,20 @@ XEEMITTER(addi, 0x38000000, D)(PPCHIRBuilder& f, InstrData& i) {
XEEMITTER(addic, 0x30000000, D)(PPCHIRBuilder& f, InstrData& i) {
// RT <- (RA) + EXTS(SI)
// CA <- carry bit
Value* v = f.Add(f.LoadGPR(i.D.RA), f.LoadConstant(XEEXTS16(i.D.DS)),
ARITHMETIC_SET_CARRY);
f.StoreCA(f.DidCarry(v));
Value* ra = f.LoadGPR(i.D.RA);
Value* v = f.Add(ra, f.LoadConstant(XEEXTS16(i.D.DS)));
f.StoreGPR(i.D.RT, v);
f.StoreCA(AddDidCarry(f, ra, f.LoadConstant(XEEXTS16(i.D.DS))));
return 0;
}
XEEMITTER(addicx, 0x34000000, D)(PPCHIRBuilder& f, InstrData& i) {
// RT <- (RA) + EXTS(SI)
// CA <- carry bit
Value* v = f.Add(f.LoadGPR(i.D.RA), f.LoadConstant(XEEXTS16(i.D.DS)),
ARITHMETIC_SET_CARRY);
f.StoreCA(f.DidCarry(v));
Value* ra = f.LoadGPR(i.D.RA);
Value* v = f.Add(f.LoadGPR(i.D.RA), f.LoadConstant(XEEXTS16(i.D.DS)));
f.StoreGPR(i.D.RT, v);
f.StoreCA(AddDidCarry(f, ra, f.LoadConstant(XEEXTS16(i.D.DS))));
f.UpdateCR(0, v);
return 0;
}
@ -124,17 +149,18 @@ XEEMITTER(addis, 0x3C000000, D)(PPCHIRBuilder& f, InstrData& i) {
XEEMITTER(addmex, 0x7C0001D4, XO)(PPCHIRBuilder& f, InstrData& i) {
// RT <- (RA) + CA - 1
// CA <- carry bit
Value* v = f.AddWithCarry(f.LoadGPR(i.XO.RA), f.LoadConstant((int64_t)-1),
f.LoadCA(), ARITHMETIC_SET_CARRY);
Value* ra = f.LoadGPR(i.XO.RA);
Value* v = f.AddWithCarry(ra, f.LoadConstant((int64_t)-1), f.LoadCA());
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
// With XER[SO] update too.
// e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1));
assert_always();
} else {
// Just CA update.
f.StoreCA(f.DidCarry(v));
f.StoreCA(
AddWithCarryDidCarry(f, ra, f.LoadConstant((int64_t)-1), f.LoadCA()));
}
f.StoreGPR(i.XO.RT, v);
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
@ -144,17 +170,17 @@ XEEMITTER(addmex, 0x7C0001D4, XO)(PPCHIRBuilder& f, InstrData& i) {
XEEMITTER(addzex, 0x7C000194, XO)(PPCHIRBuilder& f, InstrData& i) {
// RT <- (RA) + CA
// CA <- carry bit
Value* v = f.AddWithCarry(f.LoadGPR(i.XO.RA), f.LoadZero(INT64_TYPE),
f.LoadCA(), ARITHMETIC_SET_CARRY);
Value* ra = f.LoadGPR(i.XO.RA);
Value* v = f.AddWithCarry(ra, f.LoadZero(INT64_TYPE), f.LoadCA());
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
// With XER[SO] update too.
// e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1));
assert_always();
} else {
// Just CA update.
f.StoreCA(f.DidCarry(v));
f.StoreCA(AddWithCarryDidCarry(f, ra, f.LoadZero(INT64_TYPE), f.LoadCA()));
}
f.StoreGPR(i.XO.RT, v);
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
@ -425,13 +451,15 @@ XEEMITTER(subfx, 0x7C000050, XO)(PPCHIRBuilder& f, InstrData& i) {
XEEMITTER(subfcx, 0x7C000010, XO)(PPCHIRBuilder& f, InstrData& i) {
// RT <- ¬(RA) + (RB) + 1
Value* v =
f.Sub(f.LoadGPR(i.XO.RB), f.LoadGPR(i.XO.RA), ARITHMETIC_SET_CARRY);
f.StoreCA(f.DidCarry(v));
Value* ra = f.LoadGPR(i.XO.RA);
Value* rb = f.LoadGPR(i.XO.RB);
Value* v = f.Sub(rb, ra);
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
assert_always();
// e.update_xer_with_overflow(EFLAGS??);
} else {
f.StoreCA(SubDidCarry(f, rb, ra));
}
if (i.XO.Rc) {
f.UpdateCR(0, v);
@ -441,22 +469,24 @@ XEEMITTER(subfcx, 0x7C000010, XO)(PPCHIRBuilder& f, InstrData& i) {
XEEMITTER(subficx, 0x20000000, D)(PPCHIRBuilder& f, InstrData& i) {
// RT <- ¬(RA) + EXTS(SI) + 1
Value* v = f.Sub(f.LoadConstant(XEEXTS16(i.D.DS)), f.LoadGPR(i.D.RA),
ARITHMETIC_SET_CARRY);
f.StoreCA(f.DidCarry(v));
Value* ra = f.LoadGPR(i.D.RA);
Value* v = f.Sub(f.LoadConstant(XEEXTS16(i.D.DS)), ra);
f.StoreGPR(i.D.RT, v);
f.StoreCA(SubDidCarry(f, f.LoadConstant(XEEXTS16(i.D.DS)), ra));
return 0;
}
XEEMITTER(subfex, 0x7C000110, XO)(PPCHIRBuilder& f, InstrData& i) {
// RT <- ¬(RA) + (RB) + CA
Value* v = f.AddWithCarry(f.Not(f.LoadGPR(i.XO.RA)), f.LoadGPR(i.XO.RB),
f.LoadCA(), ARITHMETIC_SET_CARRY);
f.StoreCA(f.DidCarry(v));
Value* not_ra = f.Not(f.LoadGPR(i.XO.RA));
Value* rb = f.LoadGPR(i.XO.RB);
Value* v = f.AddWithCarry(not_ra, rb, f.LoadCA());
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
assert_always();
// e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1));
} else {
f.StoreCA(AddWithCarryDidCarry(f, not_ra, rb, f.LoadCA()));
}
if (i.XO.Rc) {
f.UpdateCR(0, v);
@ -466,16 +496,16 @@ XEEMITTER(subfex, 0x7C000110, XO)(PPCHIRBuilder& f, InstrData& i) {
XEEMITTER(subfmex, 0x7C0001D0, XO)(PPCHIRBuilder& f, InstrData& i) {
// RT <- ¬(RA) + CA - 1
Value* v =
f.AddWithCarry(f.Not(f.LoadGPR(i.XO.RA)), f.LoadConstant((int64_t)-1),
f.LoadCA(), ARITHMETIC_SET_CARRY);
Value* not_ra = f.Not(f.LoadGPR(i.XO.RA));
Value* v = f.AddWithCarry(not_ra, f.LoadConstant((int64_t)-1), f.LoadCA());
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
assert_always();
// e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1));
} else {
f.StoreCA(f.DidCarry(v));
f.StoreCA(AddWithCarryDidCarry(f, not_ra, f.LoadConstant((int64_t)-1),
f.LoadCA()));
}
f.StoreGPR(i.XO.RT, v);
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
@ -484,15 +514,16 @@ XEEMITTER(subfmex, 0x7C0001D0, XO)(PPCHIRBuilder& f, InstrData& i) {
XEEMITTER(subfzex, 0x7C000190, XO)(PPCHIRBuilder& f, InstrData& i) {
// RT <- ¬(RA) + CA
Value* v = f.AddWithCarry(f.Not(f.LoadGPR(i.XO.RA)), f.LoadZero(INT64_TYPE),
f.LoadCA(), ARITHMETIC_SET_CARRY);
Value* not_ra = f.Not(f.LoadGPR(i.XO.RA));
Value* v = f.AddWithCarry(not_ra, f.LoadZero(INT64_TYPE), f.LoadCA());
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
assert_always();
// e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1));
} else {
f.StoreCA(f.DidCarry(v));
f.StoreCA(
AddWithCarryDidCarry(f, not_ra, f.LoadZero(INT64_TYPE), f.LoadCA()));
}
f.StoreGPR(i.XO.RT, v);
if (i.XO.Rc) {
f.UpdateCR(0, v);
}

View File

@ -248,7 +248,7 @@ test_addc_cr_6:
#_ REGISTER_OUT r3 0x8000000000000001
#_ REGISTER_OUT r4 0x7FFFFFFFFFFFFFFF
#_ REGISTER_OUT r5 2
#_ REGISTER_OUT r6 0
#_ REGISTER_OUT r6 1
#_ REGISTER_OUT r12 0x40000000
test_addc_cr_6_constant:
@ -262,5 +262,5 @@ test_addc_cr_6_constant:
#_ REGISTER_OUT r3 0x8000000000000001
#_ REGISTER_OUT r4 0x7FFFFFFFFFFFFFFF
#_ REGISTER_OUT r5 2
#_ REGISTER_OUT r6 0
#_ REGISTER_OUT r6 1
#_ REGISTER_OUT r12 0x40000000

View File

@ -30,6 +30,23 @@ test_addic_2_constant:
#_ REGISTER_OUT r4 0
#_ REGISTER_OUT r6 1
test_addic_3:
#_ REGISTER_IN r4 0xFFFFFFFF
addic r4, r4, 1
adde r6, r0, r0
blr
#_ REGISTER_OUT r4 0x0000000100000000
#_ REGISTER_OUT r6 1
test_addic_3_constant:
li r4, 0xFFFFFFFF
srw r4, r4, 0
addic r4, r4, 1
adde r6, r0, r0
blr
#_ REGISTER_OUT r4 0x0000000100000000
#_ REGISTER_OUT r6 1
test_addic_cr_1:
#_ REGISTER_IN r4 1
addic. r4, r4, 1

View File

@ -1,95 +1,95 @@
test_lvebx_1:
#_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
#_ REGISTER_IN r4 0
#_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
#_ REGISTER_IN r4 0x00001000
lvebx v3, r0, r4
blr
#_ REGISTER_OUT r4 0
#_ REGISTER_OUT r4 0x00001000
#_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F]
test_lvebx_1_constant:
#_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
li r4, 0
#_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
li r4, 0x00001000
lvebx v3, r0, r4
blr
#_ REGISTER_OUT r4 0
#_ REGISTER_OUT r4 0x00001000
#_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F]
test_lvebx_2:
#_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
#_ REGISTER_IN r4 4
#_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
#_ REGISTER_IN r4 0x00001004
lvebx v3, r0, r4
blr
#_ REGISTER_OUT r4 4
#_ REGISTER_OUT r4 0x00001004
#_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F]
test_lvebx_2_constant:
#_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
li r4, 4
#_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
li r4, 0x00001004
lvebx v3, r0, r4
blr
#_ REGISTER_OUT r4 4
#_ REGISTER_OUT r4 0x00001004
#_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F]
test_lvehx_1:
#_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
#_ REGISTER_IN r4 0
#_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
#_ REGISTER_IN r4 0x00001000
lvehx v3, r0, r4
blr
#_ REGISTER_OUT r4 0
#_ REGISTER_OUT r4 0x00001000
#_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F]
test_lvehx_1_constant:
#_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
li r4, 0
#_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
li r4, 0x00001000
lvehx v3, r0, r4
blr
#_ REGISTER_OUT r4 0
#_ REGISTER_OUT r4 0x00001000
#_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F]
test_lvehx_2:
#_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
#_ REGISTER_IN r4 4
#_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
#_ REGISTER_IN r4 0x00001004
lvehx v3, r0, r4
blr
#_ REGISTER_OUT r4 4
#_ REGISTER_OUT r4 0x00001004
#_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F]
test_lvehx_2_constant:
#_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
li r4, 4
#_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
li r4, 0x00001004
lvehx v3, r0, r4
blr
#_ REGISTER_OUT r4 4
#_ REGISTER_OUT r4 0x00001004
#_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F]
test_lvewx_1:
#_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
#_ REGISTER_IN r4 0
#_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
#_ REGISTER_IN r4 0x00001000
lvewx v3, r0, r4
blr
#_ REGISTER_OUT r4 0
#_ REGISTER_OUT r4 0x00001000
#_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F]
test_lvewx_1_constant:
#_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
li r4, 0
#_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
li r4, 0x00001000
lvewx v3, r0, r4
blr
#_ REGISTER_OUT r4 0
#_ REGISTER_OUT r4 0x00001000
#_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F]
test_lvewx_2:
#_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
#_ REGISTER_IN r4 4
#_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
#_ REGISTER_IN r4 0x00001004
lvewx v3, r0, r4
blr
#_ REGISTER_OUT r4 4
#_ REGISTER_OUT r4 0x00001004
#_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F]
test_lvewx_2_constant:
#_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
li r4, 4
#_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
li r4, 0x00001004
lvewx v3, r0, r4
blr
#_ REGISTER_OUT r4 4
#_ REGISTER_OUT r4 0x00001004
#_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F]

View File

@ -33,7 +33,7 @@ test_equiv_2:
li r12, 1
blr
#_ REGISTER_OUT r7 0xffffffffffffffff
#_ REGISTER_OUT r8 0xffffffff00000000
#_ REGISTER_OUT r8 0
#_ REGISTER_OUT r9 0xffffffff9e2a0000
#_ REGISTER_OUT r30 0xffffffff9e2a83c1
#_ REGISTER_OUT r31 0

View File

@ -198,6 +198,11 @@ class TestRunner {
processor->backend()->CommitExecutableRange(START_ADDRESS,
START_ADDRESS + 1024 * 1024);
// Add dummy space for memory.
processor->memory()->LookupHeap(0)->AllocFixed(
0x1000, 0xEFFF, 0, kMemoryAllocationReserve | kMemoryAllocationCommit,
kMemoryProtectRead | kMemoryProtectWrite);
// Simulate a thread.
uint32_t stack_size = 64 * 1024;
uint32_t stack_address = START_ADDRESS - stack_size;

View File

@ -1287,20 +1287,6 @@ Value* HIRBuilder::CompareUGE(Value* value1, Value* value2) {
return CompareXX(OPCODE_COMPARE_UGE_info, value1, value2);
}
Value* HIRBuilder::DidCarry(Value* value) {
Instr* i = AppendInstr(OPCODE_DID_CARRY_info, 0, AllocValue(INT8_TYPE));
i->set_src1(value);
i->src2.value = i->src3.value = NULL;
return i->dest;
}
Value* HIRBuilder::DidOverflow(Value* value) {
Instr* i = AppendInstr(OPCODE_DID_OVERFLOW_info, 0, AllocValue(INT8_TYPE));
i->set_src1(value);
i->src2.value = i->src3.value = NULL;
return i->dest;
}
Value* HIRBuilder::DidSaturate(Value* value) {
Instr* i = AppendInstr(OPCODE_DID_SATURATE_info, 0, AllocValue(INT8_TYPE));
i->set_src1(value);

View File

@ -158,8 +158,6 @@ class HIRBuilder {
Value* CompareULE(Value* value1, Value* value2);
Value* CompareUGT(Value* value1, Value* value2);
Value* CompareUGE(Value* value1, Value* value2);
Value* DidCarry(Value* value);
Value* DidOverflow(Value* value);
Value* DidSaturate(Value* value);
Value* VectorCompareEQ(Value* value1, Value* value2, TypeName part_type);
Value* VectorCompareSGT(Value* value1, Value* value2, TypeName part_type);

View File

@ -48,7 +48,6 @@ enum PrefetchFlags {
PREFETCH_STORE = (1 << 2),
};
enum ArithmeticFlags {
ARITHMETIC_SET_CARRY = (1 << 1),
ARITHMETIC_UNSIGNED = (1 << 2),
ARITHMETIC_SATURATE = (1 << 3),
};
@ -163,8 +162,6 @@ enum Opcode {
OPCODE_COMPARE_ULE,
OPCODE_COMPARE_UGT,
OPCODE_COMPARE_UGE,
OPCODE_DID_CARRY,
OPCODE_DID_OVERFLOW,
OPCODE_DID_SATURATE,
OPCODE_VECTOR_COMPARE_EQ,
OPCODE_VECTOR_COMPARE_SGT,

View File

@ -341,16 +341,6 @@ DEFINE_OPCODE(
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_DID_CARRY,
"did_carry",
OPCODE_SIG_V_V,
OPCODE_FLAG_PAIRED_PREV)
DEFINE_OPCODE(
OPCODE_DID_OVERFLOW,
"did_overflow",
OPCODE_SIG_V_V,
OPCODE_FLAG_PAIRED_PREV)
DEFINE_OPCODE(
OPCODE_DID_SATURATE,
"did_saturate",

View File

@ -81,47 +81,6 @@ TEST_CASE("ADD_I8", "[instr]") {
});
}
TEST_CASE("ADD_I8_CARRY", "[instr]") {
TestFunction test([](HIRBuilder& b) {
auto v = b.Add(b.Truncate(LoadGPR(b, 4), INT8_TYPE),
b.Truncate(LoadGPR(b, 5), INT8_TYPE), ARITHMETIC_SET_CARRY);
StoreGPR(b, 3, b.ZeroExtend(b.DidCarry(v), INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 0);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT8_MAX;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT8_MAX;
ctx->r[5] = UINT8_MAX;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = INT8_MIN;
ctx->r[5] = -1;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
}
TEST_CASE("ADD_I16", "[instr]") {
TestFunction test([](HIRBuilder& b) {
StoreGPR(b, 3, b.ZeroExtend(b.Add(b.Truncate(LoadGPR(b, 4), INT16_TYPE),
@ -187,47 +146,6 @@ TEST_CASE("ADD_I16", "[instr]") {
});
}
TEST_CASE("ADD_I16_CARRY", "[instr]") {
TestFunction test([](HIRBuilder& b) {
auto v = b.Add(b.Truncate(LoadGPR(b, 4), INT16_TYPE),
b.Truncate(LoadGPR(b, 5), INT16_TYPE), ARITHMETIC_SET_CARRY);
StoreGPR(b, 3, b.ZeroExtend(b.DidCarry(v), INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 0);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT16_MAX;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT16_MAX;
ctx->r[5] = UINT16_MAX;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = INT16_MIN;
ctx->r[5] = -1;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
}
TEST_CASE("ADD_I32", "[instr]") {
TestFunction test([](HIRBuilder& b) {
StoreGPR(b, 3, b.ZeroExtend(b.Add(b.Truncate(LoadGPR(b, 4), INT32_TYPE),
@ -293,47 +211,6 @@ TEST_CASE("ADD_I32", "[instr]") {
});
}
TEST_CASE("ADD_I32_CARRY", "[instr]") {
TestFunction test([](HIRBuilder& b) {
auto v = b.Add(b.Truncate(LoadGPR(b, 4), INT32_TYPE),
b.Truncate(LoadGPR(b, 5), INT32_TYPE), ARITHMETIC_SET_CARRY);
StoreGPR(b, 3, b.ZeroExtend(b.DidCarry(v), INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 0);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT32_MAX;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT32_MAX;
ctx->r[5] = UINT32_MAX;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = INT32_MIN;
ctx->r[5] = -1;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
}
TEST_CASE("ADD_I64", "[instr]") {
TestFunction test([](HIRBuilder& b) {
StoreGPR(b, 3, b.Add(LoadGPR(b, 4), LoadGPR(b, 5)));
@ -397,47 +274,6 @@ TEST_CASE("ADD_I64", "[instr]") {
});
}
TEST_CASE("ADD_I64_CARRY", "[instr]") {
TestFunction test([](HIRBuilder& b) {
auto v = b.Add(b.Truncate(LoadGPR(b, 4), INT64_TYPE),
b.Truncate(LoadGPR(b, 5), INT64_TYPE), ARITHMETIC_SET_CARRY);
StoreGPR(b, 3, b.ZeroExtend(b.DidCarry(v), INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 0);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT64_MAX;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT64_MAX;
ctx->r[5] = UINT64_MAX;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = INT64_MIN;
ctx->r[5] = -1;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
}
TEST_CASE("ADD_F32", "[instr]") {
TestFunction test([](HIRBuilder& b) {
StoreFPR(b, 3, b.Convert(b.Add(b.Convert(LoadFPR(b, 4), FLOAT32_TYPE),