Starting compiler work. Adding pass TODOs.
This commit is contained in:
parent
fdb6a5cfa3
commit
c2113c116d
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
#include <alloy/core.h>
|
||||
|
||||
#include <alloy/hir/function_builder.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace compiler {
|
||||
|
@ -21,6 +23,8 @@ class Pass {
|
|||
public:
|
||||
Pass();
|
||||
virtual ~Pass();
|
||||
|
||||
virtual int Run(hir::FunctionBuilder* builder) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -10,6 +10,196 @@
|
|||
#ifndef ALLOY_COMPILER_PASSES_H_
|
||||
#define ALLOY_COMPILER_PASSES_H_
|
||||
|
||||
#include <alloy/compiler/passes/mem2reg_pass.h>
|
||||
//#include <alloy/compiler/passes/constant_propagation_pass.h>
|
||||
//#include <alloy/compiler/passes/context_promotion_pass.h>
|
||||
//#include <alloy/compiler/passes/dead_code_elimination_pass.h>
|
||||
//#include <alloy/compiler/passes/dead_store_elimination_pass.h>
|
||||
#include <alloy/compiler/passes/simplification_pass.h>
|
||||
|
||||
// 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 <c>
|
||||
// - 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:
|
||||
// <block0>:
|
||||
// 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, ...
|
||||
// <block1>:
|
||||
// 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_
|
||||
|
|
|
@ -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 <alloy/compiler/passes/mem2reg_pass.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::compiler;
|
||||
using namespace alloy::compiler::passes;
|
||||
|
||||
|
||||
Mem2RegPass::Mem2RegPass() :
|
||||
Pass() {
|
||||
}
|
||||
|
||||
Mem2RegPass::~Mem2RegPass() {
|
||||
}
|
|
@ -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 <alloy/compiler/passes/simplification_pass.h>
|
||||
#include <alloy/hir/function_builder.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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 <alloy/compiler/pass.h>
|
||||
|
||||
|
@ -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_
|
|
@ -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',
|
||||
],
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -22,6 +22,8 @@ class Label;
|
|||
|
||||
class Block {
|
||||
public:
|
||||
Arena* arena;
|
||||
|
||||
Block* next;
|
||||
Block* prev;
|
||||
|
||||
|
|
|
@ -238,6 +238,7 @@ void FunctionBuilder::InsertLabel(Label* label, Instr* prev_instr) {
|
|||
Block* next_block = prev_instr->block->next;
|
||||
|
||||
Block* new_block = arena_->Alloc<Block>();
|
||||
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>();
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -9,5 +9,41 @@
|
|||
|
||||
#include <alloy/hir/instr.h>
|
||||
|
||||
#include <alloy/hir/block.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,29 @@ using namespace alloy;
|
|||
using namespace alloy::hir;
|
||||
|
||||
|
||||
Value::Use* Value::AddUse(Arena* arena, Instr* instr) {
|
||||
Use* use = arena->Alloc<Use>();
|
||||
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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue