diff --git a/src/alloy/arena.cc b/src/alloy/arena.cc index 4ca1a3cec..c708fecf5 100644 --- a/src/alloy/arena.cc +++ b/src/alloy/arena.cc @@ -40,7 +40,7 @@ void* Arena::Alloc(size_t size) { if (active_chunk_->capacity - active_chunk_->offset < size) { Chunk* next = active_chunk_->next; if (!next) { - XEASSERT(size < size); // need to support larger chunks + XEASSERT(size < chunk_size_); // need to support larger chunks next = new Chunk(chunk_size_); active_chunk_->next = next; } diff --git a/src/alloy/compiler/compiler.cc b/src/alloy/compiler/compiler.cc index 6a1f4d2b9..da1a2e76e 100644 --- a/src/alloy/compiler/compiler.cc +++ b/src/alloy/compiler/compiler.cc @@ -46,7 +46,9 @@ int Compiler::Compile(FunctionBuilder* builder) { // stop changing things, etc. for (PassList::iterator it = passes_.begin(); it != passes_.end(); ++it) { Pass* pass = *it; - // + if (pass->Run(builder)) { + return 1; + } } return 0; diff --git a/src/alloy/compiler/pass.h b/src/alloy/compiler/pass.h index 8cfa96f04..5d020e93c 100644 --- a/src/alloy/compiler/pass.h +++ b/src/alloy/compiler/pass.h @@ -12,6 +12,8 @@ #include +#include + namespace alloy { namespace compiler { @@ -21,6 +23,8 @@ class Pass { public: Pass(); virtual ~Pass(); + + virtual int Run(hir::FunctionBuilder* builder) = 0; }; diff --git a/src/alloy/compiler/passes.h b/src/alloy/compiler/passes.h index 314400f63..e61ca5f2c 100644 --- a/src/alloy/compiler/passes.h +++ b/src/alloy/compiler/passes.h @@ -10,6 +10,196 @@ #ifndef ALLOY_COMPILER_PASSES_H_ #define ALLOY_COMPILER_PASSES_H_ -#include +//#include +//#include +//#include +//#include +#include + +// TODO: +// - mark_use/mark_set +// For now: mark_all_changed on all calls +// For external functions: +// - load_context/mark_use on all arguments +// - mark_set on return argument? +// For internal functions: +// - if liveness analysis already done, use that +// - otherwise, assume everything dirty (ACK!) +// - could use scanner to insert mark_use +// +// Maybe: +// - v0.xx = load_constant +// - v0.xx = load_zero +// Would prevent NULL defs on values, and make constant de-duping possible. +// Not sure if it's worth it, though, as the extra register allocation +// pressure due to de-duped constants seems like it would slow things down +// a lot. +// +// - CFG: +// Blocks need predecessors()/successor() +// phi Instr reference +// +// - block liveness tracking (in/out) +// Block gets: +// AddIncomingValue(Value* value, Block* src_block) ?? + + +// Potentially interesting passes: +// +// Run order: +// ContextPromotion +// ConstantPropagation +// TypePropagation +// ByteSwapElimination +// Simplification +// DeadStoreElimination +// DeadCodeElimination +// +// - ContextPromotion +// Like mem2reg, but because context memory is unaliasable it's easier to +// check and convert LoadContext/StoreContext into value operations. +// Example of load->value promotion: +// v0 = load_context +100 +// store_context +200, v0 +// v1 = load_context +100 <-- replace with v1 = v0 +// store_context +200, v1 +// +// It'd be possible in this stage to also remove redundant context stores: +// Example of dead store elimination: +// store_context +100, v0 <-- removed due to following store +// store_context +100, v1 +// This is more generally done by DSE, however if it could be done here +// 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 +// 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. +// +// - TypePropagation +// There are many extensions/truncations in generated code right now due to +// various load/stores of varying widths. Being able to find and short- +// circuit the conversions early on would make following passes cleaner +// and faster as they'd have to trace through fewer value definitions. +// Example (after ContextPromotion): +// v81.i64 = load_context +88 +// v82.i32 = truncate v81.i64 +// v84.i32 = and v82.i32, 3F +// v85.i64 = zero_extend v84.i32 +// v87.i64 = load_context +248 +// v88.i64 = v85.i64 +// v89.i32 = truncate v88.i64 <-- zero_extend/truncate => v84.i32 +// v90.i32 = byte_swap v89.i32 +// store v87.i64, v90.i32 +// after type propagation / simplification / DCE: +// v81.i64 = load_context +88 +// v82.i32 = truncate v81.i64 +// v84.i32 = and v82.i32, 3F +// v87.i64 = load_context +248 +// v90.i32 = byte_swap v84.i32 +// store v87.i64, v90.i32 +// +// - ByteSwapElimination +// Find chained byte swaps and replace with assignments. This is often found +// in memcpy paths. +// Example: +// v0 = load ... +// v1 = byte_swap v0 +// v2 = byte_swap v1 +// store ..., v2 <-- this could be v0 +// +// It may be tricky to detect, though, as often times there are intervening +// instructions: +// v21.i32 = load v20.i64 +// v22.i32 = byte_swap v21.i32 +// v23.i64 = zero_extend v22.i32 +// v88.i64 = v23.i64 (from ContextPromotion) +// v89.i32 = truncate v88.i64 +// v90.i32 = byte_swap v89.i32 +// store v87.i64, v90.i32 +// After type propagation: +// v21.i32 = load v20.i64 +// v22.i32 = byte_swap v21.i32 +// v89.i32 = v22.i32 +// v90.i32 = byte_swap v89.i32 +// store v87.i64, v90.i32 +// This could ideally become: +// v21.i32 = load v20.i64 +// ... (DCE takes care of this) ... +// store v87.i64, v21.i32 +// +// - Simplification +// Run over the instructions and rename assigned variables: +// v1 = v0 +// v2 = v1 +// v3 = add v0, v2 +// becomes: +// v1 = v0 (will be removed by DCE) +// v2 = v0 (will be removed by DCE) +// v3 = add v0, v0 +// This could be run several times, as it could make other passes faster +// to compute (for example, ConstantPropagation). DCE will take care of +// the useless assigns. +// +// - DeadStoreElimination +// Generic DSE pass, removing all redundant stores. ContextPromotion may be +// able to take care of most of these, as the input assembly is generally +// pretty optimized already. This pass would mainly be looking for introduced +// stores, such as those from comparisons. +// +// Example: +// : +// v0 = compare_ult ... (later removed by DCE) +// v1 = compare_ugt ... (later removed by DCE) +// v2 = compare_eq ... +// store_context +300, v0 <-- removed +// store_context +301, v1 <-- removed +// store_context +302, v2 <-- removed +// branch_true v1, ... +// : +// v3 = compare_ult ... +// v4 = compare_ugt ... +// v5 = compare_eq ... +// store_context +300, v3 <-- these may be required if at end of function +// store_context +301, v4 or before a call +// store_context +302, v5 +// branch_true v5, ... +// +// - DeadCodeElimination +// ContextPromotion/DSE will likely leave around a lot of dead statements. +// Code generated for comparison/testing produces many unused statements and +// with proper use analysis it should be possible to remove most of them: +// After context promotion/simplification: +// v33.i8 = compare_ult v31.i32, 0 +// v34.i8 = compare_ugt v31.i32, 0 +// v35.i8 = compare_eq v31.i32, 0 +// store_context +300, v33.i8 +// store_context +301, v34.i8 +// store_context +302, v35.i8 +// branch_true v35.i8, loc_8201A484 +// After DSE: +// v33.i8 = compare_ult v31.i32, 0 +// v34.i8 = compare_ugt v31.i32, 0 +// v35.i8 = compare_eq v31.i32, 0 +// branch_true v35.i8, loc_8201A484 +// After DCE: +// v35.i8 = compare_eq v31.i32, 0 +// branch_true v35.i8, loc_8201A484 +// #endif // ALLOY_COMPILER_PASSES_H_ diff --git a/src/alloy/compiler/passes/mem2reg_pass.cc b/src/alloy/compiler/passes/mem2reg_pass.cc deleted file mode 100644 index 58dbb205f..000000000 --- a/src/alloy/compiler/passes/mem2reg_pass.cc +++ /dev/null @@ -1,22 +0,0 @@ -/** - ****************************************************************************** - * 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; - - -Mem2RegPass::Mem2RegPass() : - Pass() { -} - -Mem2RegPass::~Mem2RegPass() { -} diff --git a/src/alloy/compiler/passes/simplification_pass.cc b/src/alloy/compiler/passes/simplification_pass.cc new file mode 100644 index 000000000..06323f06e --- /dev/null +++ b/src/alloy/compiler/passes/simplification_pass.cc @@ -0,0 +1,83 @@ +/** + ****************************************************************************** + * 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 +#include + +using namespace alloy; +using namespace alloy::compiler; +using namespace alloy::compiler::passes; +using namespace alloy::hir; + + +SimplificationPass::SimplificationPass() : + Pass() { +} + +SimplificationPass::~SimplificationPass() { +} + +int SimplificationPass::Run(FunctionBuilder* builder) { + // Run over the instructions and rename assigned variables: + // v1 = v0 + // v2 = v1 + // v3 = add v0, v2 + // becomes: + // v1 = v0 + // v2 = v0 + // v3 = add v0, v0 + // This could be run several times, as it could make other passes faster + // to compute (for example, ConstantPropagation). DCE will take care of + // the useless assigns. + // + // We do this by walking each instruction. For each value op we + // look at its def instr to see if it's an assign - if so, we use the src + // of that instr. Because we may have chains, we do this recursively until + // we find a non-assign def. + + Block* block = builder->first_block(); + while (block) { + Instr* i = block->instr_head; + while (i) { + uint32_t signature = i->opcode->signature; + if (GET_OPCODE_SIG_TYPE_SRC1(signature) == OPCODE_SIG_TYPE_V) { + i->set_src1(CheckValue(i->src1.value)); + } + if (GET_OPCODE_SIG_TYPE_SRC2(signature) == OPCODE_SIG_TYPE_V) { + i->set_src2(CheckValue(i->src2.value)); + } + if (GET_OPCODE_SIG_TYPE_SRC3(signature) == OPCODE_SIG_TYPE_V) { + i->set_src3(CheckValue(i->src3.value)); + } + i = i->next; + } + + block = block->next; + } + + return 0; +} + +Value* SimplificationPass::CheckValue(Value* value) { + Instr* def = value->def; + if (def && def->opcode->num == OPCODE_ASSIGN) { + // Value comes from an assignment - recursively find if it comes from + // another assignment. It probably doesn't, if we already replaced it. + Value* replacement = def->src1.value; + while (true) { + def = replacement->def; + if (!def || def->opcode->num != OPCODE_ASSIGN) { + break; + } + replacement = def->src1.value; + } + return replacement; + } + return value; +} diff --git a/src/alloy/compiler/passes/mem2reg_pass.h b/src/alloy/compiler/passes/simplification_pass.h similarity index 64% rename from src/alloy/compiler/passes/mem2reg_pass.h rename to src/alloy/compiler/passes/simplification_pass.h index cafe9b046..44d4e87d8 100644 --- a/src/alloy/compiler/passes/mem2reg_pass.h +++ b/src/alloy/compiler/passes/simplification_pass.h @@ -7,8 +7,8 @@ ****************************************************************************** */ -#ifndef ALLOY_COMPILER_PASSES_MEM2REG_PASS_H_ -#define ALLOY_COMPILER_PASSES_MEM2REG_PASS_H_ +#ifndef ALLOY_COMPILER_PASSES_SIMPLIFICATION_PASS_H_ +#define ALLOY_COMPILER_PASSES_SIMPLIFICATION_PASS_H_ #include @@ -18,10 +18,15 @@ namespace compiler { namespace passes { -class Mem2RegPass : public Pass { +class SimplificationPass : public Pass { public: - Mem2RegPass(); - virtual ~Mem2RegPass(); + SimplificationPass(); + virtual ~SimplificationPass(); + + virtual int Run(hir::FunctionBuilder* builder); + +private: + hir::Value* CheckValue(hir::Value* value); }; @@ -30,4 +35,4 @@ public: } // namespace alloy -#endif // ALLOY_COMPILER_PASSES_MEM2REG_PASS_H_ +#endif // ALLOY_COMPILER_PASSES_SIMPLIFICATION_PASS_H_ diff --git a/src/alloy/compiler/passes/sources.gypi b/src/alloy/compiler/passes/sources.gypi index 3b8cc1e59..275c1ddc5 100644 --- a/src/alloy/compiler/passes/sources.gypi +++ b/src/alloy/compiler/passes/sources.gypi @@ -1,7 +1,15 @@ # Copyright 2013 Ben Vanik. All Rights Reserved. { 'sources': [ - 'mem2reg_pass.cc', - 'mem2reg_pass.h', + #'constant_propagation_pass.cc', + #'constant_propagation_pass.h', + #'context_promotion_pass.cc', + #'context_promotion_pass.h', + #'dead_code_elimination_pass.cc', + #'dead_code_elimination_pass.h', + #'dead_store_elimination_pass.cc', + #'dead_store_elimination_pass.h', + 'simplification_pass.cc', + 'simplification_pass.h', ], } diff --git a/src/alloy/frontend/ppc/ppc_translator.cc b/src/alloy/frontend/ppc/ppc_translator.cc index a847863ad..e72980b23 100644 --- a/src/alloy/frontend/ppc/ppc_translator.cc +++ b/src/alloy/frontend/ppc/ppc_translator.cc @@ -32,8 +32,13 @@ PPCTranslator::PPCTranslator(PPCFrontend* frontend) : compiler_ = new Compiler(); - // TODO(benvanik): passes in a sensible order/etc. - compiler_->AddPass(new passes::Mem2RegPass()); + //compiler_->AddPass(new passes::ContextPromotionPass()); + //compiler_->AddPass(new passes::ConstantPropagationPass()); + //compiler_->AddPass(new passes::TypePropagationPass()); + //compiler_->AddPass(new passes::ByteSwapEliminationPass()); + compiler_->AddPass(new passes::SimplificationPass()); + //compiler_->AddPass(new passes::DeadStoreEliminationPass()); + //compiler_->AddPass(new passes::DeadCodeEliminationPass()); Backend* backend = frontend->runtime()->backend(); assembler_ = backend->CreateAssembler(); diff --git a/src/alloy/hir/block.h b/src/alloy/hir/block.h index 3ff100f03..4756c4fd7 100644 --- a/src/alloy/hir/block.h +++ b/src/alloy/hir/block.h @@ -22,6 +22,8 @@ class Label; class Block { public: + Arena* arena; + Block* next; Block* prev; diff --git a/src/alloy/hir/function_builder.cc b/src/alloy/hir/function_builder.cc index da442b485..9aa145773 100644 --- a/src/alloy/hir/function_builder.cc +++ b/src/alloy/hir/function_builder.cc @@ -238,6 +238,7 @@ void FunctionBuilder::InsertLabel(Label* label, Instr* prev_instr) { Block* next_block = prev_instr->block->next; Block* new_block = arena_->Alloc(); + new_block->arena = arena_; new_block->prev = prev_block; new_block->next = next_block; if (prev_block) { @@ -269,6 +270,7 @@ void FunctionBuilder::InsertLabel(Label* label, Instr* prev_instr) { Block* FunctionBuilder::AppendBlock() { Block* block = arena_->Alloc(); + block->arena = arena_; block->next = NULL; block->prev = block_tail_; if (block_tail_) { @@ -314,6 +316,10 @@ Instr* FunctionBuilder::AppendInstr( instr->opcode = &opcode_info; instr->flags = flags; instr->dest = dest; + instr->src1_use = instr->src2_use = instr->src3_use = NULL; + if (dest) { + dest->def = instr; + } // Rely on callers to set src args. // This prevents redundant stores. return instr; @@ -324,6 +330,8 @@ Value* FunctionBuilder::AllocValue(TypeName type) { value->ordinal = next_value_ordinal_++; value->type = type; value->flags = 0; + value->def = NULL; + value->use_head = NULL; value->tag = NULL; return value; } @@ -334,6 +342,8 @@ Value* FunctionBuilder::CloneValue(Value* source) { value->type = source->type; value->flags = source->flags; value->constant.i64 = source->constant.i64; + value->def = NULL; + value->use_head = NULL; value->tag = NULL; return value; } @@ -400,7 +410,7 @@ void FunctionBuilder::DebugBreakTrue(Value* cond) { } Instr* i = AppendInstr(opcode, 0); - i->src1.value = cond; + i->set_src1(cond); i->src2.value = i->src3.value = NULL; EndBlock(); } @@ -430,7 +440,7 @@ void FunctionBuilder::TrapTrue(Value* cond) { } Instr* i = AppendInstr(opcode, 0); - i->src1.value = cond; + i->set_src1(cond); i->src2.value = i->src3.value = NULL; EndBlock(); } @@ -463,7 +473,7 @@ void FunctionBuilder::CallTrue( } Instr* i = AppendInstr(opcode, call_flags); - i->src1.value = cond; + i->set_src1(cond); i->src2.symbol_info = symbol_info; i->src3.value = NULL; EndBlock(); @@ -479,7 +489,7 @@ void FunctionBuilder::CallIndirect( ASSERT_ADDRESS_TYPE(value); Instr* i = AppendInstr(opcode, call_flags); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; EndBlock(); } @@ -499,8 +509,8 @@ void FunctionBuilder::CallIndirectTrue( ASSERT_ADDRESS_TYPE(value); Instr* i = AppendInstr(opcode, call_flags); - i->src1.value = cond; - i->src2.value = value; + i->set_src1(cond); + i->set_src2(value); i->src3.value = NULL; EndBlock(); } @@ -547,7 +557,7 @@ void FunctionBuilder::BranchIf( } Instr* i = AppendInstr(opcode, branch_flags); - i->src1.value = cond; + i->set_src1(cond); i->src2.label = true_label; i->src3.label = false_label; EndBlock(); @@ -567,7 +577,7 @@ void FunctionBuilder::BranchTrue( } Instr* i = AppendInstr(opcode, branch_flags); - i->src1.value = cond; + i->set_src1(cond); i->src2.label = label; i->src3.value = NULL; EndBlock(); @@ -587,7 +597,7 @@ void FunctionBuilder::BranchFalse( } Instr* i = AppendInstr(opcode, branch_flags); - i->src1.value = cond; + i->set_src1(cond); i->src2.label = label; i->src3.value = NULL; EndBlock(); @@ -609,7 +619,7 @@ Value* FunctionBuilder::Assign(Value* value) { Instr* i = AppendInstr( opcode, 0, AllocValue(value->type)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -632,7 +642,7 @@ Value* FunctionBuilder::Cast(Value* value, TypeName target_type) { Instr* i = AppendInstr( opcode, 0, AllocValue(target_type)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -655,7 +665,7 @@ Value* FunctionBuilder::ZeroExtend(Value* value, TypeName target_type) { Instr* i = AppendInstr( opcode, 0, AllocValue(target_type)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -678,7 +688,7 @@ Value* FunctionBuilder::SignExtend(Value* value, TypeName target_type) { Instr* i = AppendInstr( opcode, 0, AllocValue(target_type)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -704,7 +714,7 @@ Value* FunctionBuilder::Truncate(Value* value, TypeName target_type) { Instr* i = AppendInstr( opcode, 0, AllocValue(target_type)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -728,7 +738,7 @@ Value* FunctionBuilder::Convert(Value* value, TypeName target_type, Instr* i = AppendInstr( opcode, round_mode, AllocValue(target_type)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -751,7 +761,7 @@ Value* FunctionBuilder::Round(Value* value, RoundMode round_mode) { Instr* i = AppendInstr( opcode, round_mode, AllocValue(value->type)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -768,7 +778,7 @@ Value* FunctionBuilder::VectorConvertI2F(Value* value) { Instr* i = AppendInstr( opcode, 0, AllocValue(value->type)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -785,7 +795,7 @@ Value* FunctionBuilder::VectorConvertF2I(Value* value, RoundMode round_mode) { Instr* i = AppendInstr( opcode, round_mode, AllocValue(value->type)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -887,7 +897,7 @@ void FunctionBuilder::StoreContext(size_t offset, Value* value) { Instr* i = AppendInstr(opcode, 0); i->src1.offset = offset; - i->src2.value = value; + i->set_src2(value); i->src3.value = NULL; } @@ -903,7 +913,7 @@ Value* FunctionBuilder::Load( Instr* i = AppendInstr( opcode, load_flags, AllocValue(type)); - i->src1.value = address; + i->set_src1(address); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -920,7 +930,7 @@ Value* FunctionBuilder::LoadAcquire( Instr* i = AppendInstr( opcode, load_flags, AllocValue(type)); - i->src1.value = address; + i->set_src1(address); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -935,8 +945,8 @@ void FunctionBuilder::Store( ASSERT_ADDRESS_TYPE(address); Instr* i = AppendInstr(opcode, store_flags); - i->src1.value = address; - i->src2.value = value; + i->set_src1(address); + i->set_src2(value); i->src3.value = NULL; } @@ -951,8 +961,8 @@ Value* FunctionBuilder::StoreRelease( ASSERT_ADDRESS_TYPE(address); Instr* i = AppendInstr(opcode, store_flags, AllocValue(INT8_TYPE)); - i->src1.value = address; - i->src2.value = value; + i->set_src1(address); + i->set_src2(value); i->src3.value = NULL; return i->dest; } @@ -967,7 +977,7 @@ void FunctionBuilder::Prefetch( ASSERT_ADDRESS_TYPE(address); Instr* i = AppendInstr(opcode, prefetch_flags); - i->src1.value = address; + i->set_src1(address); i->src2.offset = length; i->src3.value = NULL; } @@ -989,8 +999,8 @@ Value* FunctionBuilder::Max(Value* value1, Value* value2) { Instr* i = AppendInstr( opcode, 0, AllocValue(value1->type)); - i->src1.value = value1; - i->src2.value = value2; + i->set_src1(value1); + i->set_src2(value2); i->src3.value = NULL; return i->dest; } @@ -1012,8 +1022,8 @@ Value* FunctionBuilder::Min(Value* value1, Value* value2) { Instr* i = AppendInstr( opcode, 0, AllocValue(value1->type)); - i->src1.value = value1; - i->src2.value = value2; + i->set_src1(value1); + i->set_src2(value2); i->src3.value = NULL; return i->dest; } @@ -1035,9 +1045,9 @@ Value* FunctionBuilder::Select(Value* cond, Value* value1, Value* value2) { Instr* i = AppendInstr( opcode, 0, AllocValue(value1->type)); - i->src1.value = cond; - i->src2.value = value1; - i->src3.value = value2; + i->set_src1(cond); + i->set_src2(value1); + i->set_src3(value2); return i->dest; } @@ -1055,7 +1065,7 @@ Value* FunctionBuilder::IsTrue(Value* value) { Instr* i = AppendInstr( opcode, 0, AllocValue(INT8_TYPE)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -1074,7 +1084,7 @@ Value* FunctionBuilder::IsFalse(Value* value) { Instr* i = AppendInstr( opcode, 0, AllocValue(INT8_TYPE)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -1089,8 +1099,8 @@ Value* FunctionBuilder::CompareXX( Instr* i = AppendInstr( opcode, 0, AllocValue(INT8_TYPE)); - i->src1.value = value1; - i->src2.value = value2; + i->set_src1(value1); + i->set_src2(value2); i->src3.value = NULL; return i->dest; } @@ -1195,7 +1205,7 @@ Value* FunctionBuilder::DidCarry(Value* value) { Instr* i = AppendInstr( opcode, 0, AllocValue(INT8_TYPE)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -1210,7 +1220,7 @@ Value* FunctionBuilder::DidOverflow(Value* value) { Instr* i = AppendInstr( opcode, 0, AllocValue(INT8_TYPE)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -1226,8 +1236,8 @@ Value* FunctionBuilder::VectorCompareXX( Instr* i = AppendInstr( opcode, part_type, AllocValue(value1->type)); - i->src1.value = value1; - i->src2.value = value2; + i->set_src1(value1); + i->set_src2(value2); i->src3.value = NULL; return i->dest; } @@ -1308,8 +1318,8 @@ Value* FunctionBuilder::Add( Instr* i = AppendInstr( opcode, arithmetic_flags, AllocValue(value1->type)); - i->src1.value = value1; - i->src2.value = value2; + i->set_src1(value1); + i->set_src2(value2); i->src3.value = NULL; return i->dest; } @@ -1344,9 +1354,9 @@ Value* FunctionBuilder::AddWithCarry( Instr* i = AppendInstr( opcode, arithmetic_flags, AllocValue(value1->type)); - i->src1.value = value1; - i->src2.value = value2; - i->src3.value = value3; + i->set_src1(value1); + i->set_src2(value2); + i->set_src3(value3); return i->dest; } @@ -1376,8 +1386,8 @@ Value* FunctionBuilder::Sub( Instr* i = AppendInstr( opcode, arithmetic_flags, AllocValue(value1->type)); - i->src1.value = value1; - i->src2.value = value2; + i->set_src1(value1); + i->set_src2(value2); i->src3.value = NULL; return i->dest; } @@ -1400,8 +1410,8 @@ Value* FunctionBuilder::Mul(Value* value1, Value* value2) { Instr* i = AppendInstr( opcode, 0, AllocValue(value1->type)); - i->src1.value = value1; - i->src2.value = value2; + i->set_src1(value1); + i->set_src2(value2); i->src3.value = NULL; return i->dest; } @@ -1424,8 +1434,8 @@ Value* FunctionBuilder::Div(Value* value1, Value* value2) { Instr* i = AppendInstr( opcode, 0, AllocValue(value1->type)); - i->src1.value = value1; - i->src2.value = value2; + i->set_src1(value1); + i->set_src2(value2); i->src3.value = NULL; return i->dest; } @@ -1448,8 +1458,8 @@ Value* FunctionBuilder::Rem(Value* value1, Value* value2) { Instr* i = AppendInstr( opcode, 0, AllocValue(value1->type)); - i->src1.value = value1; - i->src2.value = value2; + i->set_src1(value1); + i->set_src2(value2); i->src3.value = NULL; return i->dest; } @@ -1480,9 +1490,9 @@ Value* FunctionBuilder::MulAdd(Value* value1, Value* value2, Value* value3) { Instr* i = AppendInstr( opcode, 0, AllocValue(value1->type)); - i->src1.value = value1; - i->src2.value = value2; - i->src3.value = value3; + i->set_src1(value1); + i->set_src2(value2); + i->set_src3(value3); return i->dest; } @@ -1512,9 +1522,9 @@ Value* FunctionBuilder::MulSub(Value* value1, Value* value2, Value* value3) { Instr* i = AppendInstr( opcode, 0, AllocValue(value1->type)); - i->src1.value = value1; - i->src2.value = value2; - i->src3.value = value3; + i->set_src1(value1); + i->set_src2(value2); + i->set_src3(value3); return i->dest; } @@ -1536,7 +1546,7 @@ Value* FunctionBuilder::Neg(Value* value) { Instr* i = AppendInstr( opcode, 0, AllocValue(value->type)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -1559,7 +1569,7 @@ Value* FunctionBuilder::Abs(Value* value) { Instr* i = AppendInstr( opcode, 0, AllocValue(value->type)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -1582,7 +1592,7 @@ Value* FunctionBuilder::Sqrt(Value* value) { Instr* i = AppendInstr( opcode, 0, AllocValue(value->type)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -1599,7 +1609,7 @@ Value* FunctionBuilder::RSqrt(Value* value) { Instr* i = AppendInstr( opcode, 0, AllocValue(value->type)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -1618,8 +1628,8 @@ Value* FunctionBuilder::DotProduct3(Value* value1, Value* value2) { Instr* i = AppendInstr( opcode, 0, AllocValue(FLOAT32_TYPE)); - i->src1.value = value1; - i->src2.value = value2; + i->set_src1(value1); + i->set_src2(value2); i->src3.value = NULL; return i->dest; } @@ -1638,8 +1648,8 @@ Value* FunctionBuilder::DotProduct4(Value* value1, Value* value2) { Instr* i = AppendInstr( opcode, 0, AllocValue(FLOAT32_TYPE)); - i->src1.value = value1; - i->src2.value = value2; + i->set_src1(value1); + i->set_src2(value2); i->src3.value = NULL; return i->dest; } @@ -1668,8 +1678,8 @@ Value* FunctionBuilder::And(Value* value1, Value* value2) { Instr* i = AppendInstr( opcode, 0, AllocValue(value1->type)); - i->src1.value = value1; - i->src2.value = value2; + i->set_src1(value1); + i->set_src2(value2); i->src3.value = NULL; return i->dest; } @@ -1698,8 +1708,8 @@ Value* FunctionBuilder::Or(Value* value1, Value* value2) { Instr* i = AppendInstr( opcode, 0, AllocValue(value1->type)); - i->src1.value = value1; - i->src2.value = value2; + i->set_src1(value1); + i->set_src2(value2); i->src3.value = NULL; return i->dest; } @@ -1724,8 +1734,8 @@ Value* FunctionBuilder::Xor(Value* value1, Value* value2) { Instr* i = AppendInstr( opcode, 0, AllocValue(value1->type)); - i->src1.value = value1; - i->src2.value = value2; + i->set_src1(value1); + i->set_src2(value2); i->src3.value = NULL; return i->dest; } @@ -1748,7 +1758,7 @@ Value* FunctionBuilder::Not(Value* value) { Instr* i = AppendInstr( opcode, 0, AllocValue(value->type)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -1780,8 +1790,8 @@ Value* FunctionBuilder::Shl(Value* value1, Value* value2) { Instr* i = AppendInstr( opcode, 0, AllocValue(value1->type)); - i->src1.value = value1; - i->src2.value = value2; + i->set_src1(value1); + i->set_src2(value2); i->src3.value = NULL; return i->dest; } @@ -1803,8 +1813,8 @@ Value* FunctionBuilder::VectorShl(Value* value1, Value* value2, Instr* i = AppendInstr( opcode, part_type, AllocValue(value1->type)); - i->src1.value = value1; - i->src2.value = value2; + i->set_src1(value1); + i->set_src2(value2); i->src3.value = NULL; return i->dest; } @@ -1834,8 +1844,8 @@ Value* FunctionBuilder::Shr(Value* value1, Value* value2) { Instr* i = AppendInstr( opcode, 0, AllocValue(value1->type)); - i->src1.value = value1; - i->src2.value = value2; + i->set_src1(value1); + i->set_src2(value2); i->src3.value = NULL; return i->dest; } @@ -1868,8 +1878,8 @@ Value* FunctionBuilder::Sha(Value* value1, Value* value2) { Instr* i = AppendInstr( opcode, 0, AllocValue(value1->type)); - i->src1.value = value1; - i->src2.value = value2; + i->set_src1(value1); + i->set_src2(value2); i->src3.value = NULL; return i->dest; } @@ -1898,8 +1908,8 @@ Value* FunctionBuilder::RotateLeft(Value* value1, Value* value2) { Instr* i = AppendInstr( opcode, 0, AllocValue(value1->type)); - i->src1.value = value1; - i->src2.value = value2; + i->set_src1(value1); + i->set_src2(value2); i->src3.value = NULL; return i->dest; } @@ -1923,7 +1933,7 @@ Value* FunctionBuilder::ByteSwap(Value* value) { Instr* i = AppendInstr( opcode, 0, AllocValue(value->type)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -1945,7 +1955,7 @@ Value* FunctionBuilder::CountLeadingZeros(Value* value) { Instr* i = AppendInstr( opcode, 0, AllocValue(INT8_TYPE)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -1962,9 +1972,9 @@ Value* FunctionBuilder::Insert(Value* value, uint32_t index, Value* part) { Instr* i = AppendInstr( opcode, 0, AllocValue(value->type)); - i->src1.value = value; + i->set_src1(value); i->src2.offset = index; - i->src3.value = part; + i->set_src3(part); return i->dest; } @@ -1980,7 +1990,7 @@ Value* FunctionBuilder::Extract(Value* value, uint32_t index, TypeName target_ty Instr* i = AppendInstr( opcode, 0, AllocValue(target_type)); - i->src1.value = value; + i->set_src1(value); i->src2.offset = index; i->src3.value = NULL; return i->dest; @@ -1998,7 +2008,7 @@ Value* FunctionBuilder::Splat(Value* value, TypeName target_type) { Instr* i = AppendInstr( opcode, 0, AllocValue(target_type)); - i->src1.value = value; + i->set_src1(value); i->src2.value = i->src3.value = NULL; return i->dest; } @@ -2020,9 +2030,9 @@ Value* FunctionBuilder::Permute( Instr* i = AppendInstr( opcode, 0, AllocValue(value1->type)); - i->src1.value = control; - i->src2.value = value1; - i->src3.value = value2; + i->set_src1(control); + i->set_src2(value1); + i->set_src3(value2); return i->dest; } @@ -2046,7 +2056,7 @@ Value* FunctionBuilder::Swizzle( Instr* i = AppendInstr( opcode, 0, AllocValue(value->type)); - i->src1.value = value; + i->set_src1(value); i->src2.offset = swizzle_mask; i->src3.value = NULL; return i->dest; @@ -2067,9 +2077,9 @@ Value* FunctionBuilder::CompareExchange( Instr* i = AppendInstr( opcode, 0, AllocValue(exchange_value->type)); - i->src1.value = address; - i->src2.value = compare_value; - i->src3.value = exchange_value; + i->set_src1(address); + i->set_src2(compare_value); + i->set_src3(exchange_value); return i->dest; } @@ -2085,8 +2095,8 @@ Value* FunctionBuilder::AtomicAdd(Value* address, Value* value) { Instr* i = AppendInstr( opcode, 0, AllocValue(value->type)); - i->src1.value = address; - i->src2.value = value; + i->set_src1(address); + i->set_src2(value); i->src3.value = NULL; return i->dest; } @@ -2103,8 +2113,8 @@ Value* FunctionBuilder::AtomicSub(Value* address, Value* value) { Instr* i = AppendInstr( opcode, 0, AllocValue(value->type)); - i->src1.value = address; - i->src2.value = value; + i->set_src1(address); + i->set_src2(value); i->src3.value = NULL; return i->dest; } diff --git a/src/alloy/hir/function_builder.h b/src/alloy/hir/function_builder.h index c15d03db2..931c8c2c1 100644 --- a/src/alloy/hir/function_builder.h +++ b/src/alloy/hir/function_builder.h @@ -34,6 +34,8 @@ public: void Dump(StringBuffer* str); + Arena* arena() const { return arena_; } + uint32_t attributes() const { return attributes_; } void set_attributes(uint32_t value) { attributes_ = value; } diff --git a/src/alloy/hir/instr.cc b/src/alloy/hir/instr.cc index eebb0b8db..bfeed371e 100644 --- a/src/alloy/hir/instr.cc +++ b/src/alloy/hir/instr.cc @@ -9,5 +9,41 @@ #include +#include + using namespace alloy; using namespace alloy::hir; + + +void Instr::set_src1(Value* value) { + if (src1.value == value) { + return; + } + if (src1.value) { + src1.value->RemoveUse(src1_use); + } + src1.value = value; + src1_use = value ? value->AddUse(block->arena, this) : NULL; +} + +void Instr::set_src2(Value* value) { + if (src2.value == value) { + return; + } + if (src2.value) { + src2.value->RemoveUse(src2_use); + } + src2.value = value; + src2_use = value ? value->AddUse(block->arena, this) : NULL; +} + +void Instr::set_src3(Value* value) { + if (src3.value == value) { + return; + } + if (src3.value) { + src3.value->RemoveUse(src3_use); + } + src3.value = value; + src3_use = value ? value->AddUse(block->arena, this) : NULL; +} diff --git a/src/alloy/hir/instr.h b/src/alloy/hir/instr.h index 7c6b30326..7a3fc81b6 100644 --- a/src/alloy/hir/instr.h +++ b/src/alloy/hir/instr.h @@ -45,6 +45,14 @@ public: Op src1; Op src2; Op src3; + + Value::Use* src1_use; + Value::Use* src2_use; + Value::Use* src3_use; + + void set_src1(Value* value); + void set_src2(Value* value); + void set_src3(Value* value); }; diff --git a/src/alloy/hir/value.cc b/src/alloy/hir/value.cc index a3da27861..4f29fef31 100644 --- a/src/alloy/hir/value.cc +++ b/src/alloy/hir/value.cc @@ -13,6 +13,29 @@ using namespace alloy; using namespace alloy::hir; +Value::Use* Value::AddUse(Arena* arena, Instr* instr) { + Use* use = arena->Alloc(); + use->instr = instr; + use->prev = NULL; + use->next = use_head; + if (use_head) { + use_head->prev = use; + } + use_head = use; + return use; +} + +void Value::RemoveUse(Use* use) { + if (use == use_head) { + use_head = use->next; + } else { + use->prev->next = use->next; + } + if (use->next) { + use->next->prev = use->prev; + } +} + uint64_t Value::AsUint64() { XEASSERT(IsConstant()); switch (type) { diff --git a/src/alloy/hir/value.h b/src/alloy/hir/value.h index e15cdd3fa..82367c85e 100644 --- a/src/alloy/hir/value.h +++ b/src/alloy/hir/value.h @@ -17,6 +17,8 @@ namespace alloy { namespace hir { +class Instr; + enum TypeName { INT8_TYPE, @@ -36,6 +38,13 @@ enum ValueFlags { class Value { +public: + typedef struct Use_s { + Instr* instr; + Use_s* prev; + Use_s* next; + } Use; + public: uint32_t ordinal; TypeName type; @@ -51,7 +60,13 @@ public: vec128_t v128; } constant; - void* tag; + Instr* def; + Use* use_head; + + void* tag; + + Use* AddUse(Arena* arena, Instr* instr); + void RemoveUse(Use* use); void set_zero(TypeName type) { this->type = type;