Replacing DidCarry with manual calculation and fixing compares.
This commit is contained in:
parent
6b52f6715a
commit
429698c2ec
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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),
|
||||||
|
|
Loading…
Reference in New Issue