Basic constant propagation.
This commit is contained in:
parent
57432d5996
commit
3b268f07ef
|
@ -10,7 +10,7 @@
|
||||||
#ifndef ALLOY_COMPILER_PASSES_H_
|
#ifndef ALLOY_COMPILER_PASSES_H_
|
||||||
#define 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/context_promotion_pass.h>
|
||||||
#include <alloy/compiler/passes/dead_code_elimination_pass.h>
|
#include <alloy/compiler/passes/dead_code_elimination_pass.h>
|
||||||
//#include <alloy/compiler/passes/dead_store_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).
|
// instead as it may be faster (at least on the block-level).
|
||||||
//
|
//
|
||||||
// - ConstantPropagation
|
// - 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.
|
// constants that can be pushed through the function.
|
||||||
// Example:
|
// Example:
|
||||||
// store_context +100, 1000
|
// store_context +100, 1000
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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_
|
|
@ -1,8 +1,8 @@
|
||||||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||||
{
|
{
|
||||||
'sources': [
|
'sources': [
|
||||||
#'constant_propagation_pass.cc',
|
'constant_propagation_pass.cc',
|
||||||
#'constant_propagation_pass.h',
|
'constant_propagation_pass.h',
|
||||||
'context_promotion_pass.cc',
|
'context_promotion_pass.cc',
|
||||||
'context_promotion_pass.h',
|
'context_promotion_pass.h',
|
||||||
'dead_code_elimination_pass.cc',
|
'dead_code_elimination_pass.cc',
|
||||||
|
|
|
@ -986,7 +986,7 @@ XEEMITTER(rlwimix, 0x50000000, M )(PPCFunctionBuilder& f, InstrData& i) {
|
||||||
}
|
}
|
||||||
v = f.ZeroExtend(v, INT64_TYPE);
|
v = f.ZeroExtend(v, INT64_TYPE);
|
||||||
Value* ra = f.LoadGPR(i.M.RA);
|
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) {
|
if (i.M.Rc) {
|
||||||
f.UpdateCR(0, v);
|
f.UpdateCR(0, v);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,8 @@ PPCTranslator::PPCTranslator(PPCFrontend* frontend) :
|
||||||
compiler_ = new Compiler(frontend->runtime());
|
compiler_ = new Compiler(frontend->runtime());
|
||||||
|
|
||||||
compiler_->AddPass(new passes::ContextPromotionPass());
|
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::TypePropagationPass());
|
||||||
//compiler_->AddPass(new passes::ByteSwapEliminationPass());
|
//compiler_->AddPass(new passes::ByteSwapEliminationPass());
|
||||||
compiler_->AddPass(new passes::SimplificationPass());
|
compiler_->AddPass(new passes::SimplificationPass());
|
||||||
|
|
|
@ -1024,21 +1024,6 @@ Value* FunctionBuilder::AddWithCarry(
|
||||||
uint32_t arithmetic_flags) {
|
uint32_t arithmetic_flags) {
|
||||||
ASSERT_TYPES_EQUAL(value1, value2);
|
ASSERT_TYPES_EQUAL(value1, value2);
|
||||||
XEASSERT(value3->type == INT8_TYPE);
|
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(
|
Instr* i = AppendInstr(
|
||||||
OPCODE_ADD_CARRY_info, arithmetic_flags,
|
OPCODE_ADD_CARRY_info, arithmetic_flags,
|
||||||
|
@ -1053,19 +1038,6 @@ Value* FunctionBuilder::Sub(
|
||||||
Value* value1, Value* value2, uint32_t arithmetic_flags) {
|
Value* value1, Value* value2, uint32_t arithmetic_flags) {
|
||||||
ASSERT_TYPES_EQUAL(value1, value2);
|
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(
|
Instr* i = AppendInstr(
|
||||||
OPCODE_SUB_info, arithmetic_flags,
|
OPCODE_SUB_info, arithmetic_flags,
|
||||||
AllocValue(value1->type));
|
AllocValue(value1->type));
|
||||||
|
@ -1078,12 +1050,6 @@ Value* FunctionBuilder::Sub(
|
||||||
Value* FunctionBuilder::Mul(Value* value1, Value* value2) {
|
Value* FunctionBuilder::Mul(Value* value1, Value* value2) {
|
||||||
ASSERT_TYPES_EQUAL(value1, value2);
|
ASSERT_TYPES_EQUAL(value1, value2);
|
||||||
|
|
||||||
if (value1->IsConstant() && value2->IsConstant()) {
|
|
||||||
Value* dest = CloneValue(value1);
|
|
||||||
dest->Mul(value2);
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
Instr* i = AppendInstr(
|
Instr* i = AppendInstr(
|
||||||
OPCODE_MUL_info, 0,
|
OPCODE_MUL_info, 0,
|
||||||
AllocValue(value1->type));
|
AllocValue(value1->type));
|
||||||
|
@ -1096,12 +1062,6 @@ Value* FunctionBuilder::Mul(Value* value1, Value* value2) {
|
||||||
Value* FunctionBuilder::Div(Value* value1, Value* value2) {
|
Value* FunctionBuilder::Div(Value* value1, Value* value2) {
|
||||||
ASSERT_TYPES_EQUAL(value1, value2);
|
ASSERT_TYPES_EQUAL(value1, value2);
|
||||||
|
|
||||||
if (value1->IsConstant() && value2->IsConstant()) {
|
|
||||||
Value* dest = CloneValue(value1);
|
|
||||||
dest->Div(value2);
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
Instr* i = AppendInstr(
|
Instr* i = AppendInstr(
|
||||||
OPCODE_DIV_info, 0,
|
OPCODE_DIV_info, 0,
|
||||||
AllocValue(value1->type));
|
AllocValue(value1->type));
|
||||||
|
@ -1114,12 +1074,6 @@ Value* FunctionBuilder::Div(Value* value1, Value* value2) {
|
||||||
Value* FunctionBuilder::Rem(Value* value1, Value* value2) {
|
Value* FunctionBuilder::Rem(Value* value1, Value* value2) {
|
||||||
ASSERT_TYPES_EQUAL(value1, value2);
|
ASSERT_TYPES_EQUAL(value1, value2);
|
||||||
|
|
||||||
if (value1->IsConstant() && value2->IsConstant()) {
|
|
||||||
Value* dest = CloneValue(value1);
|
|
||||||
dest->Rem(value2);
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
Instr* i = AppendInstr(
|
Instr* i = AppendInstr(
|
||||||
OPCODE_REM_info, 0,
|
OPCODE_REM_info, 0,
|
||||||
AllocValue(value1->type));
|
AllocValue(value1->type));
|
||||||
|
@ -1135,12 +1089,7 @@ Value* FunctionBuilder::MulAdd(Value* value1, Value* value2, Value* value3) {
|
||||||
|
|
||||||
bool c1 = value1->IsConstant();
|
bool c1 = value1->IsConstant();
|
||||||
bool c2 = value2->IsConstant();
|
bool c2 = value2->IsConstant();
|
||||||
bool c3 = value3->IsConstant();
|
if (c1 && c2) {
|
||||||
if (c1 && c2 && c3) {
|
|
||||||
Value* dest = AllocValue(value1->type);
|
|
||||||
Value::MulAdd(dest, value1, value2, value3);
|
|
||||||
return dest;
|
|
||||||
} else if (c1 && c2) {
|
|
||||||
Value* dest = CloneValue(value1);
|
Value* dest = CloneValue(value1);
|
||||||
dest->Mul(value2);
|
dest->Mul(value2);
|
||||||
return Add(dest, value3);
|
return Add(dest, value3);
|
||||||
|
@ -1161,12 +1110,7 @@ Value* FunctionBuilder::MulSub(Value* value1, Value* value2, Value* value3) {
|
||||||
|
|
||||||
bool c1 = value1->IsConstant();
|
bool c1 = value1->IsConstant();
|
||||||
bool c2 = value2->IsConstant();
|
bool c2 = value2->IsConstant();
|
||||||
bool c3 = value3->IsConstant();
|
if (c1 && c2) {
|
||||||
if (c1 && c2 && c3) {
|
|
||||||
Value* dest = AllocValue(value1->type);
|
|
||||||
Value::MulSub(dest, value1, value2, value3);
|
|
||||||
return dest;
|
|
||||||
} else if (c1 && c2) {
|
|
||||||
Value* dest = CloneValue(value1);
|
Value* dest = CloneValue(value1);
|
||||||
dest->Mul(value2);
|
dest->Mul(value2);
|
||||||
return Sub(dest, value3);
|
return Sub(dest, value3);
|
||||||
|
@ -1184,12 +1128,6 @@ Value* FunctionBuilder::MulSub(Value* value1, Value* value2, Value* value3) {
|
||||||
Value* FunctionBuilder::Neg(Value* value) {
|
Value* FunctionBuilder::Neg(Value* value) {
|
||||||
ASSERT_NON_VECTOR_TYPE(value);
|
ASSERT_NON_VECTOR_TYPE(value);
|
||||||
|
|
||||||
if (value->IsConstant()) {
|
|
||||||
Value* dest = CloneValue(value);
|
|
||||||
dest->Neg();
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
Instr* i = AppendInstr(
|
Instr* i = AppendInstr(
|
||||||
OPCODE_NEG_info, 0,
|
OPCODE_NEG_info, 0,
|
||||||
AllocValue(value->type));
|
AllocValue(value->type));
|
||||||
|
@ -1201,12 +1139,6 @@ Value* FunctionBuilder::Neg(Value* value) {
|
||||||
Value* FunctionBuilder::Abs(Value* value) {
|
Value* FunctionBuilder::Abs(Value* value) {
|
||||||
ASSERT_NON_VECTOR_TYPE(value);
|
ASSERT_NON_VECTOR_TYPE(value);
|
||||||
|
|
||||||
if (value->IsConstant()) {
|
|
||||||
Value* dest = CloneValue(value);
|
|
||||||
dest->Abs();
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
Instr* i = AppendInstr(
|
Instr* i = AppendInstr(
|
||||||
OPCODE_ABS_info, 0,
|
OPCODE_ABS_info, 0,
|
||||||
AllocValue(value->type));
|
AllocValue(value->type));
|
||||||
|
@ -1218,12 +1150,6 @@ Value* FunctionBuilder::Abs(Value* value) {
|
||||||
Value* FunctionBuilder::Sqrt(Value* value) {
|
Value* FunctionBuilder::Sqrt(Value* value) {
|
||||||
ASSERT_FLOAT_TYPE(value);
|
ASSERT_FLOAT_TYPE(value);
|
||||||
|
|
||||||
if (value->IsConstant()) {
|
|
||||||
Value* dest = CloneValue(value);
|
|
||||||
dest->Sqrt();
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
Instr* i = AppendInstr(
|
Instr* i = AppendInstr(
|
||||||
OPCODE_SQRT_info, 0,
|
OPCODE_SQRT_info, 0,
|
||||||
AllocValue(value->type));
|
AllocValue(value->type));
|
||||||
|
@ -1276,14 +1202,12 @@ Value* FunctionBuilder::And(Value* value1, Value* value2) {
|
||||||
ASSERT_INTEGER_TYPE(value2);
|
ASSERT_INTEGER_TYPE(value2);
|
||||||
ASSERT_TYPES_EQUAL(value1, value2);
|
ASSERT_TYPES_EQUAL(value1, value2);
|
||||||
|
|
||||||
if (value1->IsConstantZero()) {
|
if (value1 == value2) {
|
||||||
|
return value1;
|
||||||
|
} else if (value1->IsConstantZero()) {
|
||||||
return value1;
|
return value1;
|
||||||
} else if (value2->IsConstantZero()) {
|
} else if (value2->IsConstantZero()) {
|
||||||
return value2;
|
return value2;
|
||||||
} else if (value1->IsConstant() && value2->IsConstant()) {
|
|
||||||
Value* dest = CloneValue(value1);
|
|
||||||
dest->And(value2);
|
|
||||||
return dest;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Instr* i = AppendInstr(
|
Instr* i = AppendInstr(
|
||||||
|
@ -1300,14 +1224,12 @@ Value* FunctionBuilder::Or(Value* value1, Value* value2) {
|
||||||
ASSERT_INTEGER_TYPE(value2);
|
ASSERT_INTEGER_TYPE(value2);
|
||||||
ASSERT_TYPES_EQUAL(value1, value2);
|
ASSERT_TYPES_EQUAL(value1, value2);
|
||||||
|
|
||||||
if (value1->IsConstantZero()) {
|
if (value1 == value2) {
|
||||||
|
return value1;
|
||||||
|
} else if (value1->IsConstantZero()) {
|
||||||
return value2;
|
return value2;
|
||||||
} else if (value2->IsConstantZero()) {
|
} else if (value2->IsConstantZero()) {
|
||||||
return value1;
|
return value1;
|
||||||
} else if (value1->IsConstant() && value2->IsConstant()) {
|
|
||||||
Value* dest = CloneValue(value1);
|
|
||||||
dest->Or(value2);
|
|
||||||
return dest;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Instr* i = AppendInstr(
|
Instr* i = AppendInstr(
|
||||||
|
@ -1324,10 +1246,8 @@ Value* FunctionBuilder::Xor(Value* value1, Value* value2) {
|
||||||
ASSERT_INTEGER_TYPE(value2);
|
ASSERT_INTEGER_TYPE(value2);
|
||||||
ASSERT_TYPES_EQUAL(value1, value2);
|
ASSERT_TYPES_EQUAL(value1, value2);
|
||||||
|
|
||||||
if (value1->IsConstant() && value2->IsConstant()) {
|
if (value1 == value2) {
|
||||||
Value* dest = CloneValue(value1);
|
return LoadZero(value1->type);
|
||||||
dest->Xor(value2);
|
|
||||||
return dest;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Instr* i = AppendInstr(
|
Instr* i = AppendInstr(
|
||||||
|
@ -1368,11 +1288,6 @@ Value* FunctionBuilder::Shl(Value* value1, Value* value2) {
|
||||||
if (value2->type != INT8_TYPE) {
|
if (value2->type != INT8_TYPE) {
|
||||||
value2 = Truncate(value2, INT8_TYPE);
|
value2 = Truncate(value2, INT8_TYPE);
|
||||||
}
|
}
|
||||||
if (value1->IsConstant() && value2->IsConstant()) {
|
|
||||||
Value* dest = CloneValue(value1);
|
|
||||||
dest->Shl(value2);
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
Instr* i = AppendInstr(
|
Instr* i = AppendInstr(
|
||||||
OPCODE_SHL_info, 0,
|
OPCODE_SHL_info, 0,
|
||||||
|
@ -1410,11 +1325,6 @@ Value* FunctionBuilder::Shr(Value* value1, Value* value2) {
|
||||||
if (value2->type != INT8_TYPE) {
|
if (value2->type != INT8_TYPE) {
|
||||||
value2 = Truncate(value2, INT8_TYPE);
|
value2 = Truncate(value2, INT8_TYPE);
|
||||||
}
|
}
|
||||||
if (value1->IsConstant() && value2->IsConstant()) {
|
|
||||||
Value* dest = CloneValue(value1);
|
|
||||||
dest->Shr(value2);
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
Instr* i = AppendInstr(
|
Instr* i = AppendInstr(
|
||||||
OPCODE_SHR_info, 0,
|
OPCODE_SHR_info, 0,
|
||||||
|
@ -1438,11 +1348,6 @@ Value* FunctionBuilder::Sha(Value* value1, Value* value2) {
|
||||||
if (value2->type != INT8_TYPE) {
|
if (value2->type != INT8_TYPE) {
|
||||||
value2 = Truncate(value2, INT8_TYPE);
|
value2 = Truncate(value2, INT8_TYPE);
|
||||||
}
|
}
|
||||||
if (value1->IsConstant() && value2->IsConstant()) {
|
|
||||||
Value* dest = CloneValue(value1);
|
|
||||||
dest->Sha(value2);
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
Instr* i = AppendInstr(
|
Instr* i = AppendInstr(
|
||||||
OPCODE_SHA_info, 0,
|
OPCODE_SHA_info, 0,
|
||||||
|
@ -1481,11 +1386,6 @@ Value* FunctionBuilder::ByteSwap(Value* value) {
|
||||||
if (value->type == INT8_TYPE) {
|
if (value->type == INT8_TYPE) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
if (value->IsConstant()) {
|
|
||||||
Value* dest = CloneValue(value);
|
|
||||||
dest->ByteSwap();
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
Instr* i = AppendInstr(
|
Instr* i = AppendInstr(
|
||||||
OPCODE_BYTE_SWAP_info, 0,
|
OPCODE_BYTE_SWAP_info, 0,
|
||||||
|
|
|
@ -50,7 +50,6 @@ void Instr::set_src3(Value* value) {
|
||||||
|
|
||||||
void Instr::Remove() {
|
void Instr::Remove() {
|
||||||
if (dest) {
|
if (dest) {
|
||||||
XEASSERT(!dest->use_head);
|
|
||||||
dest->def = NULL;
|
dest->def = NULL;
|
||||||
}
|
}
|
||||||
if (src1_use) {
|
if (src1_use) {
|
||||||
|
|
|
@ -122,23 +122,111 @@ void Value::Round(RoundMode round_mode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::Add(Value* other) {
|
void Value::Add(Value* other) {
|
||||||
// TODO(benvanik): big matrix.
|
XEASSERT(type == other->type);
|
||||||
XEASSERTALWAYS();
|
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) {
|
void Value::Sub(Value* other) {
|
||||||
// TODO(benvanik): big matrix.
|
XEASSERT(type == other->type);
|
||||||
XEASSERTALWAYS();
|
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) {
|
void Value::Mul(Value* other) {
|
||||||
// TODO(benvanik): big matrix.
|
XEASSERT(type == other->type);
|
||||||
XEASSERTALWAYS();
|
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) {
|
void Value::Div(Value* other) {
|
||||||
// TODO(benvanik): big matrix.
|
XEASSERT(type == other->type);
|
||||||
XEASSERTALWAYS();
|
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) {
|
void Value::Rem(Value* other) {
|
||||||
|
@ -157,58 +245,249 @@ void Value::MulSub(Value* dest, Value* value1, Value* value2, Value* value3) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::Neg() {
|
void Value::Neg() {
|
||||||
// TODO(benvanik): big matrix.
|
switch (type) {
|
||||||
XEASSERTALWAYS();
|
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() {
|
void Value::Abs() {
|
||||||
// TODO(benvanik): big matrix.
|
switch (type) {
|
||||||
XEASSERTALWAYS();
|
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() {
|
void Value::Sqrt() {
|
||||||
// TODO(benvanik): big matrix.
|
switch (type) {
|
||||||
XEASSERTALWAYS();
|
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) {
|
void Value::And(Value* other) {
|
||||||
// TODO(benvanik): big matrix.
|
XEASSERT(type == other->type);
|
||||||
XEASSERTALWAYS();
|
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) {
|
void Value::Or(Value* other) {
|
||||||
// TODO(benvanik): big matrix.
|
XEASSERT(type == other->type);
|
||||||
XEASSERTALWAYS();
|
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) {
|
void Value::Xor(Value* other) {
|
||||||
// TODO(benvanik): big matrix.
|
XEASSERT(type == other->type);
|
||||||
XEASSERTALWAYS();
|
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() {
|
void Value::Not() {
|
||||||
// TODO(benvanik): big matrix.
|
switch (type) {
|
||||||
XEASSERTALWAYS();
|
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) {
|
void Value::Shl(Value* other) {
|
||||||
// TODO(benvanik): big matrix.
|
XEASSERT(type == other->type);
|
||||||
XEASSERTALWAYS();
|
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) {
|
void Value::Shr(Value* other) {
|
||||||
// TODO(benvanik): big matrix.
|
XEASSERT(type == other->type);
|
||||||
XEASSERTALWAYS();
|
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) {
|
void Value::Sha(Value* other) {
|
||||||
// TODO(benvanik): big matrix.
|
XEASSERT(type == other->type);
|
||||||
XEASSERTALWAYS();
|
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() {
|
void Value::ByteSwap() {
|
||||||
// TODO(benvanik): big matrix.
|
switch (type) {
|
||||||
XEASSERTALWAYS();
|
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) {
|
bool Value::Compare(Opcode opcode, Value* other) {
|
||||||
|
|
|
@ -128,6 +128,11 @@ public:
|
||||||
flags |= VALUE_IS_CONSTANT;
|
flags |= VALUE_IS_CONSTANT;
|
||||||
constant.v128 = value;
|
constant.v128 = value;
|
||||||
}
|
}
|
||||||
|
void set_from(const Value* other) {
|
||||||
|
type = other->type;
|
||||||
|
flags = other->flags;
|
||||||
|
constant.v128 = other->constant.v128;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool IsConstant() const {
|
inline bool IsConstant() const {
|
||||||
return !!(flags & VALUE_IS_CONSTANT);
|
return !!(flags & VALUE_IS_CONSTANT);
|
||||||
|
@ -184,6 +189,7 @@ public:
|
||||||
void Neg();
|
void Neg();
|
||||||
void Abs();
|
void Abs();
|
||||||
void Sqrt();
|
void Sqrt();
|
||||||
|
void RSqrt();
|
||||||
void And(Value* other);
|
void And(Value* other);
|
||||||
void Or(Value* other);
|
void Or(Value* other);
|
||||||
void Xor(Value* other);
|
void Xor(Value* other);
|
||||||
|
|
Loading…
Reference in New Issue