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##_I16, \
COMPARE_##op##_I32, \ COMPARE_##op##_I32, \
COMPARE_##op##_I64); COMPARE_##op##_I64);
EMITTER_ASSOCIATIVE_COMPARE_XX(SLT, setl, setge); EMITTER_ASSOCIATIVE_COMPARE_XX(SLT, setl, setg);
EMITTER_ASSOCIATIVE_COMPARE_XX(SLE, setle, setg); EMITTER_ASSOCIATIVE_COMPARE_XX(SLE, setle, setge);
EMITTER_ASSOCIATIVE_COMPARE_XX(SGT, setg, setle); EMITTER_ASSOCIATIVE_COMPARE_XX(SGT, setg, setl);
EMITTER_ASSOCIATIVE_COMPARE_XX(SGE, setge, setl); EMITTER_ASSOCIATIVE_COMPARE_XX(SGE, setge, setle);
EMITTER_ASSOCIATIVE_COMPARE_XX(ULT, setb, setae); EMITTER_ASSOCIATIVE_COMPARE_XX(ULT, setb, seta);
EMITTER_ASSOCIATIVE_COMPARE_XX(ULE, setbe, seta); EMITTER_ASSOCIATIVE_COMPARE_XX(ULE, setbe, setae);
EMITTER_ASSOCIATIVE_COMPARE_XX(UGT, seta, setbe); EMITTER_ASSOCIATIVE_COMPARE_XX(UGT, seta, setb);
EMITTER_ASSOCIATIVE_COMPARE_XX(UGE, setae, setb); EMITTER_ASSOCIATIVE_COMPARE_XX(UGE, setae, setbe);
// http://x86.renejeschke.de/html/file_module_x86_id_288.html // http://x86.renejeschke.de/html/file_module_x86_id_288.html
#define EMITTER_ASSOCIATIVE_COMPARE_FLT_XX(op, instr) \ #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); 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 // OPCODE_DID_SATURATE
// ============================================================================ // ============================================================================
@ -2736,10 +2681,6 @@ void EmitAddXX(X64Emitter& e, const ARGS& i) {
e, i, e, i,
[](X64Emitter& e, const REG& dest_src, const REG& src) { e.add(dest_src, src); }, [](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); }); [](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<>>)) { EMITTER(ADD_I8, MATCH(I<OPCODE_ADD, I8<>, I8<>, I8<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) { 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) { }, [](X64Emitter& e, const REG& dest_src, int32_t constant) {
e.adc(dest_src, 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<>>)) { EMITTER(ADD_CARRY_I8, MATCH(I<OPCODE_ADD_CARRY, I8<>, I8<>, I8<>, I8<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) { static void Emit(X64Emitter& e, const EmitArgType& i) {
@ -3009,31 +2946,10 @@ EMITTER_OPCODE_TABLE(
// TODO(benvanik): put dest/src1|2 together. // TODO(benvanik): put dest/src1|2 together.
template <typename SEQ, typename REG, typename ARGS> template <typename SEQ, typename REG, typename ARGS>
void EmitSubXX(X64Emitter& e, const ARGS& i) { void EmitSubXX(X64Emitter& e, const ARGS& i) {
if (i.instr->flags & ARITHMETIC_SET_CARRY) { SEQ::EmitAssociativeBinaryOp(
// TODO(benvanik): faster way of doing sub with CF set? e, i,
SEQ::EmitAssociativeBinaryOp( [](X64Emitter& e, const REG& dest_src, const REG& src) { e.sub(dest_src, src); },
e, i, [](X64Emitter& e, const REG& dest_src, int32_t constant) { e.sub(dest_src, constant); });
[](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<>>)) { EMITTER(SUB_I8, MATCH(I<OPCODE_SUB, I8<>, I8<>, I8<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) { static void Emit(X64Emitter& e, const EmitArgType& i) {
@ -6576,8 +6492,6 @@ void RegisterSequences() {
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_COMPARE_ULE_FLT); REGISTER_EMITTER_OPCODE_TABLE(OPCODE_COMPARE_ULE_FLT);
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_COMPARE_UGT_FLT); REGISTER_EMITTER_OPCODE_TABLE(OPCODE_COMPARE_UGT_FLT);
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_COMPARE_UGE_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_DID_SATURATE);
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_VECTOR_COMPARE_EQ); REGISTER_EMITTER_OPCODE_TABLE(OPCODE_VECTOR_COMPARE_EQ);
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_VECTOR_COMPARE_SGT); REGISTER_EMITTER_OPCODE_TABLE(OPCODE_VECTOR_COMPARE_SGT);

View File

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

View File

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

View File

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

View File

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

View File

@ -30,6 +30,23 @@ test_addic_2_constant:
#_ REGISTER_OUT r4 0 #_ REGISTER_OUT r4 0
#_ REGISTER_OUT r6 1 #_ 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: test_addic_cr_1:
#_ REGISTER_IN r4 1 #_ REGISTER_IN r4 1
addic. r4, r4, 1 addic. r4, r4, 1

View File

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

View File

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

View File

@ -198,6 +198,11 @@ class TestRunner {
processor->backend()->CommitExecutableRange(START_ADDRESS, processor->backend()->CommitExecutableRange(START_ADDRESS,
START_ADDRESS + 1024 * 1024); START_ADDRESS + 1024 * 1024);
// Add dummy space for memory.
processor->memory()->LookupHeap(0)->AllocFixed(
0x1000, 0xEFFF, 0, kMemoryAllocationReserve | kMemoryAllocationCommit,
kMemoryProtectRead | kMemoryProtectWrite);
// Simulate a thread. // Simulate a thread.
uint32_t stack_size = 64 * 1024; uint32_t stack_size = 64 * 1024;
uint32_t stack_address = START_ADDRESS - stack_size; 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); 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) { Value* HIRBuilder::DidSaturate(Value* value) {
Instr* i = AppendInstr(OPCODE_DID_SATURATE_info, 0, AllocValue(INT8_TYPE)); Instr* i = AppendInstr(OPCODE_DID_SATURATE_info, 0, AllocValue(INT8_TYPE));
i->set_src1(value); i->set_src1(value);

View File

@ -158,8 +158,6 @@ class HIRBuilder {
Value* CompareULE(Value* value1, Value* value2); Value* CompareULE(Value* value1, Value* value2);
Value* CompareUGT(Value* value1, Value* value2); Value* CompareUGT(Value* value1, Value* value2);
Value* CompareUGE(Value* value1, Value* value2); Value* CompareUGE(Value* value1, Value* value2);
Value* DidCarry(Value* value);
Value* DidOverflow(Value* value);
Value* DidSaturate(Value* value); Value* DidSaturate(Value* value);
Value* VectorCompareEQ(Value* value1, Value* value2, TypeName part_type); Value* VectorCompareEQ(Value* value1, Value* value2, TypeName part_type);
Value* VectorCompareSGT(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), PREFETCH_STORE = (1 << 2),
}; };
enum ArithmeticFlags { enum ArithmeticFlags {
ARITHMETIC_SET_CARRY = (1 << 1),
ARITHMETIC_UNSIGNED = (1 << 2), ARITHMETIC_UNSIGNED = (1 << 2),
ARITHMETIC_SATURATE = (1 << 3), ARITHMETIC_SATURATE = (1 << 3),
}; };
@ -163,8 +162,6 @@ enum Opcode {
OPCODE_COMPARE_ULE, OPCODE_COMPARE_ULE,
OPCODE_COMPARE_UGT, OPCODE_COMPARE_UGT,
OPCODE_COMPARE_UGE, OPCODE_COMPARE_UGE,
OPCODE_DID_CARRY,
OPCODE_DID_OVERFLOW,
OPCODE_DID_SATURATE, OPCODE_DID_SATURATE,
OPCODE_VECTOR_COMPARE_EQ, OPCODE_VECTOR_COMPARE_EQ,
OPCODE_VECTOR_COMPARE_SGT, OPCODE_VECTOR_COMPARE_SGT,

View File

@ -341,16 +341,6 @@ DEFINE_OPCODE(
OPCODE_SIG_V_V_V, OPCODE_SIG_V_V_V,
0) 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( DEFINE_OPCODE(
OPCODE_DID_SATURATE, OPCODE_DID_SATURATE,
"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]") { TEST_CASE("ADD_I16", "[instr]") {
TestFunction test([](HIRBuilder& b) { TestFunction test([](HIRBuilder& b) {
StoreGPR(b, 3, b.ZeroExtend(b.Add(b.Truncate(LoadGPR(b, 4), INT16_TYPE), 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]") { TEST_CASE("ADD_I32", "[instr]") {
TestFunction test([](HIRBuilder& b) { TestFunction test([](HIRBuilder& b) {
StoreGPR(b, 3, b.ZeroExtend(b.Add(b.Truncate(LoadGPR(b, 4), INT32_TYPE), 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]") { TEST_CASE("ADD_I64", "[instr]") {
TestFunction test([](HIRBuilder& b) { TestFunction test([](HIRBuilder& b) {
StoreGPR(b, 3, b.Add(LoadGPR(b, 4), LoadGPR(b, 5))); 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]") { TEST_CASE("ADD_F32", "[instr]") {
TestFunction test([](HIRBuilder& b) { TestFunction test([](HIRBuilder& b) {
StoreFPR(b, 3, b.Convert(b.Add(b.Convert(LoadFPR(b, 4), FLOAT32_TYPE), StoreFPR(b, 3, b.Convert(b.Add(b.Convert(LoadFPR(b, 4), FLOAT32_TYPE),