Basic constant propagation.

This commit is contained in:
Ben Vanik 2013-12-07 05:52:51 -08:00
parent 57432d5996
commit 3b268f07ef
10 changed files with 584 additions and 147 deletions

View File

@ -10,7 +10,7 @@
#ifndef ALLOY_COMPILER_PASSES_H_
#define ALLOY_COMPILER_PASSES_H_
//#include <alloy/compiler/passes/constant_propagation_pass.h>
#include <alloy/compiler/passes/constant_propagation_pass.h>
#include <alloy/compiler/passes/context_promotion_pass.h>
#include <alloy/compiler/passes/dead_code_elimination_pass.h>
//#include <alloy/compiler/passes/dead_store_elimination_pass.h>
@ -72,7 +72,7 @@
// instead as it may be faster (at least on the block-level).
//
// - ConstantPropagation
// One ContextPromotion has run there will likely be a whole slew of
// Once ContextPromotion has run there will likely be a whole slew of
// constants that can be pushed through the function.
// Example:
// store_context +100, 1000

View File

@ -0,0 +1,215 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <alloy/compiler/passes/constant_propagation_pass.h>
using namespace alloy;
using namespace alloy::compiler;
using namespace alloy::compiler::passes;
using namespace alloy::hir;
ConstantPropagationPass::ConstantPropagationPass() :
Pass() {
}
ConstantPropagationPass::~ConstantPropagationPass() {
}
int ConstantPropagationPass::Run(FunctionBuilder* builder) {
// Once ContextPromotion has run there will likely be a whole slew of
// constants that can be pushed through the function.
// Example:
// store_context +100, 1000
// v0 = load_context +100
// v1 = add v0, v0
// store_context +200, v1
// after PromoteContext:
// store_context +100, 1000
// v0 = 1000
// v1 = add v0, v0
// store_context +200, v1
// after PropagateConstants:
// store_context +100, 1000
// v0 = 1000
// v1 = add 1000, 1000
// store_context +200, 2000
// A DCE run after this should clean up any of the values no longer needed.
Block* block = builder->first_block();
while (block) {
Instr* i = block->instr_head;
while (i) {
Value* v = i->dest;
switch (i->opcode->num) {
case OPCODE_CAST:
if (i->src1.value->IsConstant()) {
TypeName target_type = v->type;
v->set_from(i->src1.value);
v->Cast(target_type);
i->Remove();
}
break;
case OPCODE_ZERO_EXTEND:
if (i->src1.value->IsConstant()) {
TypeName target_type = v->type;
v->set_from(i->src1.value);
v->ZeroExtend(target_type);
i->Remove();
}
break;
case OPCODE_SIGN_EXTEND:
if (i->src1.value->IsConstant()) {
TypeName target_type = v->type;
v->set_from(i->src1.value);
v->SignExtend(target_type);
i->Remove();
}
break;
case OPCODE_TRUNCATE:
if (i->src1.value->IsConstant()) {
TypeName target_type = v->type;
v->set_from(i->src1.value);
v->Truncate(target_type);
i->Remove();
}
break;
case OPCODE_ADD:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
v->set_from(i->src1.value);
v->Add(i->src2.value);
i->Remove();
}
break;
// TODO(benvanik): ADD_CARRY
case OPCODE_SUB:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
v->set_from(i->src1.value);
v->Sub(i->src2.value);
i->Remove();
}
break;
case OPCODE_MUL:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
v->set_from(i->src1.value);
v->Mul(i->src2.value);
i->Remove();
}
break;
case OPCODE_DIV:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
v->set_from(i->src1.value);
v->Div(i->src2.value);
i->Remove();
}
break;
case OPCODE_REM:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
v->set_from(i->src1.value);
v->Rem(i->src2.value);
i->Remove();
}
break;
// case OPCODE_MULADD:
// case OPCODE_MULSUB
case OPCODE_NEG:
if (i->src1.value->IsConstant()) {
v->set_from(i->src1.value);
v->Neg();
i->Remove();
}
break;
case OPCODE_ABS:
if (i->src1.value->IsConstant()) {
v->set_from(i->src1.value);
v->Abs();
i->Remove();
}
break;
case OPCODE_SQRT:
if (i->src1.value->IsConstant()) {
v->set_from(i->src1.value);
v->Sqrt();
i->Remove();
}
break;
case OPCODE_RSQRT:
if (i->src1.value->IsConstant()) {
v->set_from(i->src1.value);
v->RSqrt();
i->Remove();
}
break;
case OPCODE_AND:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
v->set_from(i->src1.value);
v->And(i->src2.value);
i->Remove();
}
break;
case OPCODE_OR:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
v->set_from(i->src1.value);
v->Or(i->src2.value);
i->Remove();
}
break;
case OPCODE_XOR:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
v->set_from(i->src1.value);
v->Xor(i->src2.value);
i->Remove();
}
break;
case OPCODE_NOT:
if (i->src1.value->IsConstant()) {
v->set_from(i->src1.value);
v->Not();
i->Remove();
}
break;
case OPCODE_SHL:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
v->set_from(i->src1.value);
v->Shl(i->src2.value);
i->Remove();
}
break;
case OPCODE_SHR:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
v->set_from(i->src1.value);
v->Shr(i->src2.value);
i->Remove();
}
break;
case OPCODE_SHA:
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
v->set_from(i->src1.value);
v->Sha(i->src2.value);
i->Remove();
}
break;
case OPCODE_BYTE_SWAP:
if (i->src1.value->IsConstant()) {
v->set_from(i->src1.value);
v->ByteSwap();
i->Remove();
}
break;
}
i = i->next;
}
block = block->next;
}
return 0;
}

View File

@ -0,0 +1,37 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef ALLOY_COMPILER_PASSES_CONSTANT_PROPAGATION_PASS_H_
#define ALLOY_COMPILER_PASSES_CONSTANT_PROPAGATION_PASS_H_
#include <alloy/compiler/pass.h>
namespace alloy {
namespace compiler {
namespace passes {
class ConstantPropagationPass : public Pass {
public:
ConstantPropagationPass();
virtual ~ConstantPropagationPass();
virtual int Run(hir::FunctionBuilder* builder);
private:
};
} // namespace passes
} // namespace compiler
} // namespace alloy
#endif // ALLOY_COMPILER_PASSES_CONSTANT_PROPAGATION_PASS_H_

View File

@ -1,8 +1,8 @@
# Copyright 2013 Ben Vanik. All Rights Reserved.
{
'sources': [
#'constant_propagation_pass.cc',
#'constant_propagation_pass.h',
'constant_propagation_pass.cc',
'constant_propagation_pass.h',
'context_promotion_pass.cc',
'context_promotion_pass.h',
'dead_code_elimination_pass.cc',

View File

@ -986,7 +986,7 @@ XEEMITTER(rlwimix, 0x50000000, M )(PPCFunctionBuilder& f, InstrData& i) {
}
v = f.ZeroExtend(v, INT64_TYPE);
Value* ra = f.LoadGPR(i.M.RA);
v = f.Or(v, f.And(f.LoadGPR(i.M.RA), f.LoadConstant(~m)));
v = f.Or(v, f.And(f.LoadGPR(i.M.RA), f.LoadConstant((~(uint64_t)m))));
if (i.M.Rc) {
f.UpdateCR(0, v);
}

View File

@ -33,7 +33,8 @@ PPCTranslator::PPCTranslator(PPCFrontend* frontend) :
compiler_ = new Compiler(frontend->runtime());
compiler_->AddPass(new passes::ContextPromotionPass());
//compiler_->AddPass(new passes::ConstantPropagationPass());
compiler_->AddPass(new passes::SimplificationPass());
compiler_->AddPass(new passes::ConstantPropagationPass());
//compiler_->AddPass(new passes::TypePropagationPass());
//compiler_->AddPass(new passes::ByteSwapEliminationPass());
compiler_->AddPass(new passes::SimplificationPass());

View File

@ -1025,21 +1025,6 @@ Value* FunctionBuilder::AddWithCarry(
ASSERT_TYPES_EQUAL(value1, value2);
XEASSERT(value3->type == INT8_TYPE);
// TODO(benvanik): optimize when flags set.
if (!arithmetic_flags) {
if (value3->IsConstantZero()) {
return Add(value1, value2);
} else if (value1->IsConstantZero()) {
return Add(value2, value3);
} else if (value2->IsConstantZero()) {
return Add(value1, value3);
} else if (value1->IsConstant() && value2->IsConstant()) {
Value* dest = CloneValue(value1);
dest->Add(value2);
return Add(dest, value3);
}
}
Instr* i = AppendInstr(
OPCODE_ADD_CARRY_info, arithmetic_flags,
AllocValue(value1->type));
@ -1053,19 +1038,6 @@ Value* FunctionBuilder::Sub(
Value* value1, Value* value2, uint32_t arithmetic_flags) {
ASSERT_TYPES_EQUAL(value1, value2);
// TODO(benvanik): optimize when flags set.
if (!arithmetic_flags) {
if (value1->IsConstantZero()) {
return Neg(value1);
} else if (value2->IsConstantZero()) {
return value1;
} else if (value1->IsConstant() && value2->IsConstant()) {
Value* dest = CloneValue(value1);
dest->Sub(value2);
return dest;
}
}
Instr* i = AppendInstr(
OPCODE_SUB_info, arithmetic_flags,
AllocValue(value1->type));
@ -1078,12 +1050,6 @@ Value* FunctionBuilder::Sub(
Value* FunctionBuilder::Mul(Value* value1, Value* value2) {
ASSERT_TYPES_EQUAL(value1, value2);
if (value1->IsConstant() && value2->IsConstant()) {
Value* dest = CloneValue(value1);
dest->Mul(value2);
return dest;
}
Instr* i = AppendInstr(
OPCODE_MUL_info, 0,
AllocValue(value1->type));
@ -1096,12 +1062,6 @@ Value* FunctionBuilder::Mul(Value* value1, Value* value2) {
Value* FunctionBuilder::Div(Value* value1, Value* value2) {
ASSERT_TYPES_EQUAL(value1, value2);
if (value1->IsConstant() && value2->IsConstant()) {
Value* dest = CloneValue(value1);
dest->Div(value2);
return dest;
}
Instr* i = AppendInstr(
OPCODE_DIV_info, 0,
AllocValue(value1->type));
@ -1114,12 +1074,6 @@ Value* FunctionBuilder::Div(Value* value1, Value* value2) {
Value* FunctionBuilder::Rem(Value* value1, Value* value2) {
ASSERT_TYPES_EQUAL(value1, value2);
if (value1->IsConstant() && value2->IsConstant()) {
Value* dest = CloneValue(value1);
dest->Rem(value2);
return dest;
}
Instr* i = AppendInstr(
OPCODE_REM_info, 0,
AllocValue(value1->type));
@ -1135,12 +1089,7 @@ Value* FunctionBuilder::MulAdd(Value* value1, Value* value2, Value* value3) {
bool c1 = value1->IsConstant();
bool c2 = value2->IsConstant();
bool c3 = value3->IsConstant();
if (c1 && c2 && c3) {
Value* dest = AllocValue(value1->type);
Value::MulAdd(dest, value1, value2, value3);
return dest;
} else if (c1 && c2) {
if (c1 && c2) {
Value* dest = CloneValue(value1);
dest->Mul(value2);
return Add(dest, value3);
@ -1161,12 +1110,7 @@ Value* FunctionBuilder::MulSub(Value* value1, Value* value2, Value* value3) {
bool c1 = value1->IsConstant();
bool c2 = value2->IsConstant();
bool c3 = value3->IsConstant();
if (c1 && c2 && c3) {
Value* dest = AllocValue(value1->type);
Value::MulSub(dest, value1, value2, value3);
return dest;
} else if (c1 && c2) {
if (c1 && c2) {
Value* dest = CloneValue(value1);
dest->Mul(value2);
return Sub(dest, value3);
@ -1184,12 +1128,6 @@ Value* FunctionBuilder::MulSub(Value* value1, Value* value2, Value* value3) {
Value* FunctionBuilder::Neg(Value* value) {
ASSERT_NON_VECTOR_TYPE(value);
if (value->IsConstant()) {
Value* dest = CloneValue(value);
dest->Neg();
return dest;
}
Instr* i = AppendInstr(
OPCODE_NEG_info, 0,
AllocValue(value->type));
@ -1201,12 +1139,6 @@ Value* FunctionBuilder::Neg(Value* value) {
Value* FunctionBuilder::Abs(Value* value) {
ASSERT_NON_VECTOR_TYPE(value);
if (value->IsConstant()) {
Value* dest = CloneValue(value);
dest->Abs();
return dest;
}
Instr* i = AppendInstr(
OPCODE_ABS_info, 0,
AllocValue(value->type));
@ -1218,12 +1150,6 @@ Value* FunctionBuilder::Abs(Value* value) {
Value* FunctionBuilder::Sqrt(Value* value) {
ASSERT_FLOAT_TYPE(value);
if (value->IsConstant()) {
Value* dest = CloneValue(value);
dest->Sqrt();
return dest;
}
Instr* i = AppendInstr(
OPCODE_SQRT_info, 0,
AllocValue(value->type));
@ -1276,14 +1202,12 @@ Value* FunctionBuilder::And(Value* value1, Value* value2) {
ASSERT_INTEGER_TYPE(value2);
ASSERT_TYPES_EQUAL(value1, value2);
if (value1->IsConstantZero()) {
if (value1 == value2) {
return value1;
} else if (value1->IsConstantZero()) {
return value1;
} else if (value2->IsConstantZero()) {
return value2;
} else if (value1->IsConstant() && value2->IsConstant()) {
Value* dest = CloneValue(value1);
dest->And(value2);
return dest;
}
Instr* i = AppendInstr(
@ -1300,14 +1224,12 @@ Value* FunctionBuilder::Or(Value* value1, Value* value2) {
ASSERT_INTEGER_TYPE(value2);
ASSERT_TYPES_EQUAL(value1, value2);
if (value1->IsConstantZero()) {
if (value1 == value2) {
return value1;
} else if (value1->IsConstantZero()) {
return value2;
} else if (value2->IsConstantZero()) {
return value1;
} else if (value1->IsConstant() && value2->IsConstant()) {
Value* dest = CloneValue(value1);
dest->Or(value2);
return dest;
}
Instr* i = AppendInstr(
@ -1324,10 +1246,8 @@ Value* FunctionBuilder::Xor(Value* value1, Value* value2) {
ASSERT_INTEGER_TYPE(value2);
ASSERT_TYPES_EQUAL(value1, value2);
if (value1->IsConstant() && value2->IsConstant()) {
Value* dest = CloneValue(value1);
dest->Xor(value2);
return dest;
if (value1 == value2) {
return LoadZero(value1->type);
}
Instr* i = AppendInstr(
@ -1368,11 +1288,6 @@ Value* FunctionBuilder::Shl(Value* value1, Value* value2) {
if (value2->type != INT8_TYPE) {
value2 = Truncate(value2, INT8_TYPE);
}
if (value1->IsConstant() && value2->IsConstant()) {
Value* dest = CloneValue(value1);
dest->Shl(value2);
return dest;
}
Instr* i = AppendInstr(
OPCODE_SHL_info, 0,
@ -1410,11 +1325,6 @@ Value* FunctionBuilder::Shr(Value* value1, Value* value2) {
if (value2->type != INT8_TYPE) {
value2 = Truncate(value2, INT8_TYPE);
}
if (value1->IsConstant() && value2->IsConstant()) {
Value* dest = CloneValue(value1);
dest->Shr(value2);
return dest;
}
Instr* i = AppendInstr(
OPCODE_SHR_info, 0,
@ -1438,11 +1348,6 @@ Value* FunctionBuilder::Sha(Value* value1, Value* value2) {
if (value2->type != INT8_TYPE) {
value2 = Truncate(value2, INT8_TYPE);
}
if (value1->IsConstant() && value2->IsConstant()) {
Value* dest = CloneValue(value1);
dest->Sha(value2);
return dest;
}
Instr* i = AppendInstr(
OPCODE_SHA_info, 0,
@ -1481,11 +1386,6 @@ Value* FunctionBuilder::ByteSwap(Value* value) {
if (value->type == INT8_TYPE) {
return value;
}
if (value->IsConstant()) {
Value* dest = CloneValue(value);
dest->ByteSwap();
return dest;
}
Instr* i = AppendInstr(
OPCODE_BYTE_SWAP_info, 0,

View File

@ -50,7 +50,6 @@ void Instr::set_src3(Value* value) {
void Instr::Remove() {
if (dest) {
XEASSERT(!dest->use_head);
dest->def = NULL;
}
if (src1_use) {

View File

@ -122,23 +122,111 @@ void Value::Round(RoundMode round_mode) {
}
void Value::Add(Value* other) {
// TODO(benvanik): big matrix.
XEASSERTALWAYS();
XEASSERT(type == other->type);
switch (type) {
case INT8_TYPE:
constant.i8 += other->constant.i8;
break;
case INT16_TYPE:
constant.i16 += other->constant.i16;
break;
case INT32_TYPE:
constant.i32 += other->constant.i32;
break;
case INT64_TYPE:
constant.i64 += other->constant.i64;
break;
case FLOAT32_TYPE:
constant.f32 += other->constant.f32;
break;
case FLOAT64_TYPE:
constant.f64 += other->constant.f64;
break;
default:
XEASSERTALWAYS();
break;
}
}
void Value::Sub(Value* other) {
// TODO(benvanik): big matrix.
XEASSERTALWAYS();
XEASSERT(type == other->type);
switch (type) {
case INT8_TYPE:
constant.i8 -= other->constant.i8;
break;
case INT16_TYPE:
constant.i16 -= other->constant.i16;
break;
case INT32_TYPE:
constant.i32 -= other->constant.i32;
break;
case INT64_TYPE:
constant.i64 -= other->constant.i64;
break;
case FLOAT32_TYPE:
constant.f32 -= other->constant.f32;
break;
case FLOAT64_TYPE:
constant.f64 -= other->constant.f64;
break;
default:
XEASSERTALWAYS();
break;
}
}
void Value::Mul(Value* other) {
// TODO(benvanik): big matrix.
XEASSERTALWAYS();
XEASSERT(type == other->type);
switch (type) {
case INT8_TYPE:
constant.i8 *= other->constant.i8;
break;
case INT16_TYPE:
constant.i16 *= other->constant.i16;
break;
case INT32_TYPE:
constant.i32 *= other->constant.i32;
break;
case INT64_TYPE:
constant.i64 *= other->constant.i64;
break;
case FLOAT32_TYPE:
constant.f32 *= other->constant.f32;
break;
case FLOAT64_TYPE:
constant.f64 *= other->constant.f64;
break;
default:
XEASSERTALWAYS();
break;
}
}
void Value::Div(Value* other) {
// TODO(benvanik): big matrix.
XEASSERTALWAYS();
XEASSERT(type == other->type);
switch (type) {
case INT8_TYPE:
constant.i8 /= other->constant.i8;
break;
case INT16_TYPE:
constant.i16 /= other->constant.i16;
break;
case INT32_TYPE:
constant.i32 /= other->constant.i32;
break;
case INT64_TYPE:
constant.i64 /= other->constant.i64;
break;
case FLOAT32_TYPE:
constant.f32 /= other->constant.f32;
break;
case FLOAT64_TYPE:
constant.f64 /= other->constant.f64;
break;
default:
XEASSERTALWAYS();
break;
}
}
void Value::Rem(Value* other) {
@ -157,58 +245,249 @@ void Value::MulSub(Value* dest, Value* value1, Value* value2, Value* value3) {
}
void Value::Neg() {
// TODO(benvanik): big matrix.
XEASSERTALWAYS();
switch (type) {
case INT8_TYPE:
constant.i8 = -constant.i8;
break;
case INT16_TYPE:
constant.i16 = -constant.i16;
break;
case INT32_TYPE:
constant.i32 = -constant.i32;
break;
case INT64_TYPE:
constant.i64 = -constant.i64;
break;
case FLOAT32_TYPE:
constant.f32 = -constant.f32;
break;
case FLOAT64_TYPE:
constant.f64 = -constant.f64;
break;
default:
XEASSERTALWAYS();
break;
}
}
void Value::Abs() {
// TODO(benvanik): big matrix.
XEASSERTALWAYS();
switch (type) {
case INT8_TYPE:
constant.i8 = abs(constant.i8);
break;
case INT16_TYPE:
constant.i16 = abs(constant.i16);
break;
case INT32_TYPE:
constant.i32 = abs(constant.i32);
break;
case INT64_TYPE:
constant.i64 = abs(constant.i64);
break;
case FLOAT32_TYPE:
constant.f32 = abs(constant.f32);
break;
case FLOAT64_TYPE:
constant.f64 = abs(constant.f64);
break;
default:
XEASSERTALWAYS();
break;
}
}
void Value::Sqrt() {
// TODO(benvanik): big matrix.
XEASSERTALWAYS();
switch (type) {
case FLOAT32_TYPE:
constant.f32 = 1.0f / sqrtf(constant.f32);
break;
case FLOAT64_TYPE:
constant.f64 = 1.0 / sqrt(constant.f64);
break;
default:
XEASSERTALWAYS();
break;
}
}
void Value::RSqrt() {
switch (type) {
case FLOAT32_TYPE:
constant.f32 = sqrt(constant.f32);
break;
case FLOAT64_TYPE:
constant.f64 = sqrt(constant.f64);
break;
default:
XEASSERTALWAYS();
break;
}
}
void Value::And(Value* other) {
// TODO(benvanik): big matrix.
XEASSERTALWAYS();
XEASSERT(type == other->type);
switch (type) {
case INT8_TYPE:
constant.i8 &= other->constant.i8;
break;
case INT16_TYPE:
constant.i16 &= other->constant.i16;
break;
case INT32_TYPE:
constant.i32 &= other->constant.i32;
break;
case INT64_TYPE:
constant.i64 &= other->constant.i64;
break;
default:
XEASSERTALWAYS();
break;
}
}
void Value::Or(Value* other) {
// TODO(benvanik): big matrix.
XEASSERTALWAYS();
XEASSERT(type == other->type);
switch (type) {
case INT8_TYPE:
constant.i8 |= other->constant.i8;
break;
case INT16_TYPE:
constant.i16 |= other->constant.i16;
break;
case INT32_TYPE:
constant.i32 |= other->constant.i32;
break;
case INT64_TYPE:
constant.i64 |= other->constant.i64;
break;
default:
XEASSERTALWAYS();
break;
}
}
void Value::Xor(Value* other) {
// TODO(benvanik): big matrix.
XEASSERTALWAYS();
XEASSERT(type == other->type);
switch (type) {
case INT8_TYPE:
constant.i8 ^= other->constant.i8;
break;
case INT16_TYPE:
constant.i16 ^= other->constant.i16;
break;
case INT32_TYPE:
constant.i32 ^= other->constant.i32;
break;
case INT64_TYPE:
constant.i64 ^= other->constant.i64;
break;
default:
XEASSERTALWAYS();
break;
}
}
void Value::Not() {
// TODO(benvanik): big matrix.
XEASSERTALWAYS();
switch (type) {
case INT8_TYPE:
constant.i8 = ~constant.i8;
break;
case INT16_TYPE:
constant.i16 = ~constant.i16;
break;
case INT32_TYPE:
constant.i32 = ~constant.i32;
break;
case INT64_TYPE:
constant.i64 = ~constant.i64;
break;
default:
XEASSERTALWAYS();
break;
}
}
void Value::Shl(Value* other) {
// TODO(benvanik): big matrix.
XEASSERTALWAYS();
XEASSERT(type == other->type);
switch (type) {
case INT8_TYPE:
constant.i8 <<= other->constant.i8;
break;
case INT16_TYPE:
constant.i16 <<= other->constant.i16;
break;
case INT32_TYPE:
constant.i32 <<= other->constant.i32;
break;
case INT64_TYPE:
constant.i64 <<= other->constant.i64;
break;
default:
XEASSERTALWAYS();
break;
}
}
void Value::Shr(Value* other) {
// TODO(benvanik): big matrix.
XEASSERTALWAYS();
XEASSERT(type == other->type);
switch (type) {
case INT8_TYPE:
constant.i8 = (uint8_t)constant.i8 >> other->constant.i8;
break;
case INT16_TYPE:
constant.i16 = (uint16_t)constant.i16 >> other->constant.i8;
break;
case INT32_TYPE:
constant.i32 = (uint32_t)constant.i32 >> other->constant.i8;
break;
case INT64_TYPE:
constant.i64 = (uint16_t)constant.i64 >> other->constant.i8;
break;
default:
XEASSERTALWAYS();
break;
}
}
void Value::Sha(Value* other) {
// TODO(benvanik): big matrix.
XEASSERTALWAYS();
XEASSERT(type == other->type);
switch (type) {
case INT8_TYPE:
constant.i8 = constant.i8 >> other->constant.i8;
break;
case INT16_TYPE:
constant.i16 = constant.i16 >> other->constant.i8;
break;
case INT32_TYPE:
constant.i32 = constant.i32 >> other->constant.i8;
break;
case INT64_TYPE:
constant.i64 = constant.i64 >> other->constant.i8;
break;
default:
XEASSERTALWAYS();
break;
}
}
void Value::ByteSwap() {
// TODO(benvanik): big matrix.
XEASSERTALWAYS();
switch (type) {
case INT8_TYPE:
constant.i8 = constant.i8;
break;
case INT16_TYPE:
constant.i16 = XESWAP16(constant.i16);
break;
case INT32_TYPE:
constant.i32 = XESWAP32(constant.i32);
break;
case INT64_TYPE:
constant.i64 = XESWAP64(constant.i64);
break;
default:
XEASSERTALWAYS();
break;
}
}
bool Value::Compare(Opcode opcode, Value* other) {

View File

@ -128,6 +128,11 @@ public:
flags |= VALUE_IS_CONSTANT;
constant.v128 = value;
}
void set_from(const Value* other) {
type = other->type;
flags = other->flags;
constant.v128 = other->constant.v128;
}
inline bool IsConstant() const {
return !!(flags & VALUE_IS_CONSTANT);
@ -184,6 +189,7 @@ public:
void Neg();
void Abs();
void Sqrt();
void RSqrt();
void And(Value* other);
void Or(Value* other);
void Xor(Value* other);