blob: bbfb1e93d7a0dc00faf73aa89e8fee39119689a7 [file] [log] [blame]
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef RUNTIME_VM_COMPILER_AOT_WASM_TRANSLATOR_H_
#define RUNTIME_VM_COMPILER_AOT_WASM_TRANSLATOR_H_
#include "vm/compiler/aot/wasm_codegen.h"
#include "vm/compiler/backend/flow_graph.h"
#include "vm/compiler/backend/il.h"
#include "vm/growable_array.h"
namespace dart {
class WasmTranslator : public FlowGraphVisitor {
public:
explicit WasmTranslator(FlowGraph* flow_graph,
WasmCodegen* codegen,
const Function& function,
wasm::Function* wasm_function)
: FlowGraphVisitor(flow_graph->reverse_postorder()),
flow_graph_(flow_graph),
codegen_(codegen),
wasm_scope_(wasm_function->MakeNewBodyAndClearLocals()),
function_(Function::ZoneHandle(function.raw())),
wasm_function_(wasm_function),
irreducible_(false) {
// Add param locals.
intptr_t num_params = wasm_function_->type()->NumParams();
for (intptr_t i = 0; i < num_params; ++i) {
wasm::ValueType* const param_type =
wasm_function_->type()->ParamTypeAt(i);
wasm_function_->AddLocal(
wasm::Local::Kind::kParam, param_type,
String::ZoneHandle(codegen->module_builder()->zone(),
function.ParameterNameAt(i))
.ToCString());
}
}
void Translate() {
PrepareBlocks();
VisitBlocks();
}
bool irreducible() { return irreducible_; }
virtual void VisitFunctionEntry(FunctionEntryInstr* block);
virtual void VisitJoinEntry(JoinEntryInstr* block);
virtual void VisitTargetEntry(TargetEntryInstr* block);
virtual void VisitGoto(GotoInstr* instr);
virtual void VisitBranch(BranchInstr* instr);
virtual void VisitBinaryIntegerOp(BinaryIntegerOpInstr* instr);
virtual void VisitBinaryInt32Op(BinaryInt32OpInstr* instr);
virtual void VisitBinaryInt64Op(BinaryInt64OpInstr* instr);
virtual void VisitBinaryUint32Op(BinaryUint32OpInstr* instr);
virtual void VisitBooleanNegate(BooleanNegateInstr* instr);
virtual void VisitParameter(ParameterInstr* instr);
virtual void VisitStaticCall(StaticCallInstr* instr);
virtual void VisitDispatchTableCall(DispatchTableCallInstr* instr);
virtual void VisitReturn(ReturnInstr* instr);
virtual void VisitAllocateObject(AllocateObjectInstr* instr);
virtual void VisitLoadField(LoadFieldInstr* instr);
virtual void VisitStoreInstanceField(StoreInstanceFieldInstr* instr);
virtual void VisitEqualityCompare(EqualityCompareInstr* instr);
virtual void VisitStrictCompare(StrictCompareInstr* instr);
virtual void VisitRelationalOp(RelationalOpInstr* instr);
private:
// Traverse graph to find start locations of Wasm blocks.
void PrepareBlocks();
intptr_t GetFallthroughPredecessorIndex(BlockEntryInstr* target);
intptr_t GetSourcePredecessorIndex(BlockEntryInstr* target,
BlockEntryInstr* source);
intptr_t GetLabelForTarget(BlockEntryInstr* target);
void PushPhiValues(JoinEntryInstr* join, intptr_t pred_index);
void PopPhiValues(JoinEntryInstr* join);
// The type hint helps in cases where it can not be determined otherwise
// (i.e. for pushing an appropriately-typed Wasm null value). Can be nullptr
// if the caller can guarantee that it is not needed.
void PushValue(Definition* def, const AbstractType& type_hint);
void PopValue(Definition* def);
void EmitWasmBranch(intptr_t label);
void EmitWasmBranchIf(intptr_t label);
// Emit code for computing the result of a comparison IL
// instruction, and negate it if negate is true. Push the
// resulting condition on the stack as an i32.
void PushEvalCondition(ComparisonInstr* comp, bool negated);
void StartWasmBlock(BlockEntryInstr* target);
void EndWasmBlock(bool pop_phi_values);
void StartWasmLoop(bool push_phi_values);
void EndWasmLoop(BlockEntryInstr* source);
void EndWasmScope();
wasm::ValueType* GetWasmType(Definition* def);
wasm::Local* GetWasmLocal(Definition* def);
static Class& GetTypeClass(const AbstractType& type) {
return Class::Handle(type.type_class());
}
static Class& GetTypeClass(CompileType* type) {
return GetTypeClass(*type->ToAbstractType());
}
static Class& GetTypeClass(Value* value) {
return GetTypeClass(value->Type());
}
static bool IsIntegerValue(Value* value) {
return WasmCodegen::IsIntegerClass(GetTypeClass(value));
}
static bool IsBoolValue(Value* value) {
return WasmCodegen::IsBoolClass(GetTypeClass(value));
}
FlowGraph* const flow_graph_;
WasmCodegen* const codegen_;
// The following stacks are used in our implementation of the Stackifier
// Algorithm for recovering structured control flow from arbitrary CFGs:
// - Target blocks of forward and backward edges, sorted (reversed) by the
// order in which the corresponding Wasm block or loop should be started.
GrowableArray<BlockEntryInstr*> edge_stack_;
// - For each backward edge on the edge stack, how many Wasm blocks should be
// started right inside the loop block (because their corresponding targets
// reside inside the loop).
GrowableArray<intptr_t> forward_count_stack_;
// - The target blocks of the current stack of Wasm scopes. The label index
// for a forward jump can be found by searching from the top for the target.
GrowableArray<BlockEntryInstr*> scope_stack_;
// The stack of currently open Wasm scopes (blocks, loops and ifs), other
// than the current one below. This is used to reset the current scope
// pointer when it is closed.
GrowableArray<wasm::InstructionList*> enclosing_wasm_scopes_stack_;
wasm::InstructionList* wasm_scope_;
// Dart function whose body is being generated.
const Function& function_;
// Wasm function whose body is being generated.
wasm::Function* const wasm_function_;
// Mapping from definitions of SSA temps to their assigned Wasm locals.
DirectChainedHashMap<RawPointerKeyValueTrait<Definition, wasm::Local*>>
def_to_wasm_local_;
// Did the transformation fail because the graph is not reducible?
bool irreducible_;
};
} // namespace dart
#endif // RUNTIME_VM_COMPILER_AOT_WASM_TRANSLATOR_H_