From 3b268f07ef3cc41c06d1db091f3648c6b2e39386 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Sat, 7 Dec 2013 05:52:51 -0800 Subject: [PATCH] Basic constant propagation. --- src/alloy/compiler/passes.h | 4 +- .../passes/constant_propagation_pass.cc | 215 +++++++++++ .../passes/constant_propagation_pass.h | 37 ++ src/alloy/compiler/passes/sources.gypi | 4 +- src/alloy/frontend/ppc/ppc_emit_alu.cc | 2 +- src/alloy/frontend/ppc/ppc_translator.cc | 3 +- src/alloy/hir/function_builder.cc | 120 +------ src/alloy/hir/instr.cc | 1 - src/alloy/hir/value.cc | 339 ++++++++++++++++-- src/alloy/hir/value.h | 6 + 10 files changed, 584 insertions(+), 147 deletions(-) create mode 100644 src/alloy/compiler/passes/constant_propagation_pass.cc create mode 100644 src/alloy/compiler/passes/constant_propagation_pass.h diff --git a/src/alloy/compiler/passes.h b/src/alloy/compiler/passes.h index 2dd1672d5..39b6463f9 100644 --- a/src/alloy/compiler/passes.h +++ b/src/alloy/compiler/passes.h @@ -10,7 +10,7 @@ #ifndef ALLOY_COMPILER_PASSES_H_ #define ALLOY_COMPILER_PASSES_H_ -//#include +#include #include #include //#include @@ -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 diff --git a/src/alloy/compiler/passes/constant_propagation_pass.cc b/src/alloy/compiler/passes/constant_propagation_pass.cc new file mode 100644 index 000000000..2ddbce90f --- /dev/null +++ b/src/alloy/compiler/passes/constant_propagation_pass.cc @@ -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 + +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; +} diff --git a/src/alloy/compiler/passes/constant_propagation_pass.h b/src/alloy/compiler/passes/constant_propagation_pass.h new file mode 100644 index 000000000..c64a62038 --- /dev/null +++ b/src/alloy/compiler/passes/constant_propagation_pass.h @@ -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 + + +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_ diff --git a/src/alloy/compiler/passes/sources.gypi b/src/alloy/compiler/passes/sources.gypi index 516c90b28..7255c5c84 100644 --- a/src/alloy/compiler/passes/sources.gypi +++ b/src/alloy/compiler/passes/sources.gypi @@ -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', diff --git a/src/alloy/frontend/ppc/ppc_emit_alu.cc b/src/alloy/frontend/ppc/ppc_emit_alu.cc index c207c7d64..23fbac2c7 100644 --- a/src/alloy/frontend/ppc/ppc_emit_alu.cc +++ b/src/alloy/frontend/ppc/ppc_emit_alu.cc @@ -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); } diff --git a/src/alloy/frontend/ppc/ppc_translator.cc b/src/alloy/frontend/ppc/ppc_translator.cc index f109b9bda..ba39f2029 100644 --- a/src/alloy/frontend/ppc/ppc_translator.cc +++ b/src/alloy/frontend/ppc/ppc_translator.cc @@ -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()); diff --git a/src/alloy/hir/function_builder.cc b/src/alloy/hir/function_builder.cc index 118c42e41..f738ae5d6 100644 --- a/src/alloy/hir/function_builder.cc +++ b/src/alloy/hir/function_builder.cc @@ -1024,21 +1024,6 @@ Value* FunctionBuilder::AddWithCarry( uint32_t arithmetic_flags) { 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, @@ -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, diff --git a/src/alloy/hir/instr.cc b/src/alloy/hir/instr.cc index 005f36dd7..0cc38464c 100644 --- a/src/alloy/hir/instr.cc +++ b/src/alloy/hir/instr.cc @@ -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) { diff --git a/src/alloy/hir/value.cc b/src/alloy/hir/value.cc index 4f29fef31..9fc2f2bf3 100644 --- a/src/alloy/hir/value.cc +++ b/src/alloy/hir/value.cc @@ -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) { diff --git a/src/alloy/hir/value.h b/src/alloy/hir/value.h index 82367c85e..9bb55f253 100644 --- a/src/alloy/hir/value.h +++ b/src/alloy/hir/value.h @@ -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);