mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-02-08 07:55:10 +00:00
14288f59b0
Implement 2-level Multi-tier JIT engine: tier-up from Fast JIT to LLVM JIT to get quick cold startup by Fast JIT and better performance by gradually switching to LLVM JIT when the LLVM JIT functions are compiled by the backend threads. Refer to: https://github.com/bytecodealliance/wasm-micro-runtime/issues/1302
498 lines
11 KiB
C
498 lines
11 KiB
C
/*
|
|
* Copyright (C) 2021 Intel Corporation. All rights reserved.
|
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
*/
|
|
|
|
#ifndef _JIT_FRONTEND_H_
|
|
#define _JIT_FRONTEND_H_
|
|
|
|
#include "jit_utils.h"
|
|
#include "jit_ir.h"
|
|
#include "../interpreter/wasm_interp.h"
|
|
#if WASM_ENABLE_AOT != 0
|
|
#include "../aot/aot_runtime.h"
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT == 0
|
|
typedef enum IntCond {
|
|
INT_EQZ = 0,
|
|
INT_EQ,
|
|
INT_NE,
|
|
INT_LT_S,
|
|
INT_LT_U,
|
|
INT_GT_S,
|
|
INT_GT_U,
|
|
INT_LE_S,
|
|
INT_LE_U,
|
|
INT_GE_S,
|
|
INT_GE_U
|
|
} IntCond;
|
|
|
|
typedef enum FloatCond {
|
|
FLOAT_EQ = 0,
|
|
FLOAT_NE,
|
|
FLOAT_LT,
|
|
FLOAT_GT,
|
|
FLOAT_LE,
|
|
FLOAT_GE,
|
|
FLOAT_UNO
|
|
} FloatCond;
|
|
#else
|
|
#define IntCond AOTIntCond
|
|
#define FloatCond AOTFloatCond
|
|
#endif
|
|
|
|
typedef enum IntArithmetic {
|
|
INT_ADD = 0,
|
|
INT_SUB,
|
|
INT_MUL,
|
|
INT_DIV_S,
|
|
INT_DIV_U,
|
|
INT_REM_S,
|
|
INT_REM_U
|
|
} IntArithmetic;
|
|
|
|
typedef enum V128Arithmetic {
|
|
V128_ADD = 0,
|
|
V128_SUB,
|
|
V128_MUL,
|
|
V128_DIV,
|
|
V128_NEG,
|
|
V128_MIN,
|
|
V128_MAX,
|
|
} V128Arithmetic;
|
|
|
|
typedef enum IntBitwise {
|
|
INT_AND = 0,
|
|
INT_OR,
|
|
INT_XOR,
|
|
} IntBitwise;
|
|
|
|
typedef enum V128Bitwise {
|
|
V128_NOT,
|
|
V128_AND,
|
|
V128_ANDNOT,
|
|
V128_OR,
|
|
V128_XOR,
|
|
V128_BITSELECT,
|
|
} V128Bitwise;
|
|
|
|
typedef enum IntShift {
|
|
INT_SHL = 0,
|
|
INT_SHR_S,
|
|
INT_SHR_U,
|
|
INT_ROTL,
|
|
INT_ROTR
|
|
} IntShift;
|
|
|
|
typedef enum FloatMath {
|
|
FLOAT_ABS = 0,
|
|
FLOAT_NEG,
|
|
FLOAT_CEIL,
|
|
FLOAT_FLOOR,
|
|
FLOAT_TRUNC,
|
|
FLOAT_NEAREST,
|
|
FLOAT_SQRT
|
|
} FloatMath;
|
|
|
|
typedef enum FloatArithmetic {
|
|
FLOAT_ADD = 0,
|
|
FLOAT_SUB,
|
|
FLOAT_MUL,
|
|
FLOAT_DIV,
|
|
FLOAT_MIN,
|
|
FLOAT_MAX,
|
|
} FloatArithmetic;
|
|
|
|
/**
|
|
* Translate instructions in a function. The translated block must
|
|
* end with a branch instruction whose targets are offsets relating to
|
|
* the end bcip of the translated block, which are integral constants.
|
|
* If a target of a branch is really a constant value (which should be
|
|
* rare), put it into a register and then jump to the register instead
|
|
* of using the constant value directly in the target. In the
|
|
* translation process, don't create any new labels. The code bcip of
|
|
* the begin and end of the translated block is stored in the
|
|
* jit_annl_begin_bcip and jit_annl_end_bcip annotations of the label
|
|
* of the block, which must be the same as the bcips used in
|
|
* profiling.
|
|
*
|
|
* NOTE: the function must explicitly set SP to correct value when the
|
|
* entry's bcip is the function's entry address.
|
|
*
|
|
* @param cc containing compilation context of generated IR
|
|
* @param entry entry of the basic block to be translated. If its
|
|
* value is NULL, the function will clean up any pass local data that
|
|
* might be created previously.
|
|
* @param is_reached a bitmap recording which bytecode has been
|
|
* reached as a block entry
|
|
*
|
|
* @return IR block containing translated instructions if succeeds,
|
|
* NULL otherwise
|
|
*/
|
|
JitBasicBlock *
|
|
jit_frontend_translate_func(JitCompContext *cc);
|
|
|
|
/**
|
|
* Lower the IR of the given compilation context.
|
|
*
|
|
* @param cc the compilation context
|
|
*
|
|
* @return true if succeeds, false otherwise
|
|
*/
|
|
bool
|
|
jit_frontend_lower(JitCompContext *cc);
|
|
|
|
uint32
|
|
jit_frontend_get_jitted_return_addr_offset();
|
|
|
|
uint32
|
|
jit_frontend_get_global_data_offset(const WASMModule *module,
|
|
uint32 global_idx);
|
|
|
|
uint32
|
|
jit_frontend_get_table_inst_offset(const WASMModule *module, uint32 tbl_idx);
|
|
|
|
uint32
|
|
jit_frontend_get_module_inst_extra_offset(const WASMModule *module);
|
|
|
|
JitReg
|
|
get_module_inst_reg(JitFrame *frame);
|
|
|
|
JitReg
|
|
get_module_reg(JitFrame *frame);
|
|
|
|
JitReg
|
|
get_import_func_ptrs_reg(JitFrame *frame);
|
|
|
|
JitReg
|
|
get_fast_jit_func_ptrs_reg(JitFrame *frame);
|
|
|
|
JitReg
|
|
get_func_type_indexes_reg(JitFrame *frame);
|
|
|
|
JitReg
|
|
get_aux_stack_bound_reg(JitFrame *frame);
|
|
|
|
JitReg
|
|
get_aux_stack_bottom_reg(JitFrame *frame);
|
|
|
|
JitReg
|
|
get_memory_data_reg(JitFrame *frame, uint32 mem_idx);
|
|
|
|
JitReg
|
|
get_memory_data_end_reg(JitFrame *frame, uint32 mem_idx);
|
|
|
|
JitReg
|
|
get_mem_bound_check_1byte_reg(JitFrame *frame, uint32 mem_idx);
|
|
|
|
JitReg
|
|
get_mem_bound_check_2bytes_reg(JitFrame *frame, uint32 mem_idx);
|
|
|
|
JitReg
|
|
get_mem_bound_check_4bytes_reg(JitFrame *frame, uint32 mem_idx);
|
|
|
|
JitReg
|
|
get_mem_bound_check_8bytes_reg(JitFrame *frame, uint32 mem_idx);
|
|
|
|
JitReg
|
|
get_mem_bound_check_16bytes_reg(JitFrame *frame, uint32 mem_idx);
|
|
|
|
JitReg
|
|
get_table_elems_reg(JitFrame *frame, uint32 table_idx);
|
|
|
|
JitReg
|
|
get_table_cur_size_reg(JitFrame *frame, uint32 table_idx);
|
|
|
|
void
|
|
clear_fixed_virtual_regs(JitFrame *frame);
|
|
|
|
void
|
|
clear_memory_regs(JitFrame *frame);
|
|
|
|
void
|
|
clear_table_regs(JitFrame *frame);
|
|
|
|
/**
|
|
* Get the offset from frame pointer to the n-th local variable slot.
|
|
*
|
|
* @param n the index to the local variable array
|
|
*
|
|
* @return the offset from frame pointer to the local variable slot
|
|
*/
|
|
static inline unsigned
|
|
offset_of_local(unsigned n)
|
|
{
|
|
return offsetof(WASMInterpFrame, lp) + n * 4;
|
|
}
|
|
|
|
/**
|
|
* Generate instruction to load an integer from the frame.
|
|
*
|
|
* This and the below gen_load_X functions generate instructions to
|
|
* load values from the frame into registers if the values have not
|
|
* been loaded yet.
|
|
*
|
|
* @param frame the frame information
|
|
* @param n slot index to the local variable array
|
|
*
|
|
* @return register holding the loaded value
|
|
*/
|
|
JitReg
|
|
gen_load_i32(JitFrame *frame, unsigned n);
|
|
|
|
/**
|
|
* Generate instruction to load a i64 integer from the frame.
|
|
*
|
|
* @param frame the frame information
|
|
* @param n slot index to the local variable array
|
|
*
|
|
* @return register holding the loaded value
|
|
*/
|
|
JitReg
|
|
gen_load_i64(JitFrame *frame, unsigned n);
|
|
|
|
/**
|
|
* Generate instruction to load a floating point value from the frame.
|
|
*
|
|
* @param frame the frame information
|
|
* @param n slot index to the local variable array
|
|
*
|
|
* @return register holding the loaded value
|
|
*/
|
|
JitReg
|
|
gen_load_f32(JitFrame *frame, unsigned n);
|
|
|
|
/**
|
|
* Generate instruction to load a double value from the frame.
|
|
*
|
|
* @param frame the frame information
|
|
* @param n slot index to the local variable array
|
|
*
|
|
* @return register holding the loaded value
|
|
*/
|
|
JitReg
|
|
gen_load_f64(JitFrame *frame, unsigned n);
|
|
|
|
/**
|
|
* Generate instructions to commit computation result to the frame.
|
|
* The general principle is to only commit values that will be used
|
|
* through the frame.
|
|
*
|
|
* @param frame the frame information
|
|
* @param begin the begin value slot to commit
|
|
* @param end the end value slot to commit
|
|
*/
|
|
void
|
|
gen_commit_values(JitFrame *frame, JitValueSlot *begin, JitValueSlot *end);
|
|
|
|
/**
|
|
* Generate instructions to commit SP and IP pointers to the frame.
|
|
*
|
|
* @param frame the frame information
|
|
*/
|
|
void
|
|
gen_commit_sp_ip(JitFrame *frame);
|
|
|
|
/**
|
|
* Generate commit instructions for the block end.
|
|
*
|
|
* @param frame the frame information
|
|
*/
|
|
static inline void
|
|
gen_commit_for_branch(JitFrame *frame)
|
|
{
|
|
gen_commit_values(frame, frame->lp, frame->sp);
|
|
}
|
|
|
|
/**
|
|
* Generate commit instructions for exception checks.
|
|
*
|
|
* @param frame the frame information
|
|
*/
|
|
static inline void
|
|
gen_commit_for_exception(JitFrame *frame)
|
|
{
|
|
gen_commit_values(frame, frame->lp, frame->lp + frame->max_locals);
|
|
gen_commit_sp_ip(frame);
|
|
}
|
|
|
|
/**
|
|
* Generate commit instructions to commit all status.
|
|
*
|
|
* @param frame the frame information
|
|
*/
|
|
static inline void
|
|
gen_commit_for_all(JitFrame *frame)
|
|
{
|
|
gen_commit_values(frame, frame->lp, frame->sp);
|
|
gen_commit_sp_ip(frame);
|
|
}
|
|
|
|
static inline void
|
|
clear_values(JitFrame *frame)
|
|
{
|
|
size_t total_size =
|
|
sizeof(JitValueSlot) * (frame->max_locals + frame->max_stacks);
|
|
memset(frame->lp, 0, total_size);
|
|
frame->committed_sp = NULL;
|
|
frame->committed_ip = NULL;
|
|
clear_fixed_virtual_regs(frame);
|
|
}
|
|
|
|
static inline void
|
|
push_i32(JitFrame *frame, JitReg value)
|
|
{
|
|
frame->sp->reg = value;
|
|
frame->sp->dirty = 1;
|
|
frame->sp++;
|
|
}
|
|
|
|
static inline void
|
|
push_i64(JitFrame *frame, JitReg value)
|
|
{
|
|
frame->sp->reg = value;
|
|
frame->sp->dirty = 1;
|
|
frame->sp++;
|
|
frame->sp->reg = value;
|
|
frame->sp->dirty = 1;
|
|
frame->sp++;
|
|
}
|
|
|
|
static inline void
|
|
push_f32(JitFrame *frame, JitReg value)
|
|
{
|
|
push_i32(frame, value);
|
|
}
|
|
|
|
static inline void
|
|
push_f64(JitFrame *frame, JitReg value)
|
|
{
|
|
push_i64(frame, value);
|
|
}
|
|
|
|
static inline JitReg
|
|
pop_i32(JitFrame *frame)
|
|
{
|
|
frame->sp--;
|
|
return gen_load_i32(frame, frame->sp - frame->lp);
|
|
}
|
|
|
|
static inline JitReg
|
|
pop_i64(JitFrame *frame)
|
|
{
|
|
frame->sp -= 2;
|
|
return gen_load_i64(frame, frame->sp - frame->lp);
|
|
}
|
|
|
|
static inline JitReg
|
|
pop_f32(JitFrame *frame)
|
|
{
|
|
frame->sp--;
|
|
return gen_load_f32(frame, frame->sp - frame->lp);
|
|
}
|
|
|
|
static inline JitReg
|
|
pop_f64(JitFrame *frame)
|
|
{
|
|
frame->sp -= 2;
|
|
return gen_load_f64(frame, frame->sp - frame->lp);
|
|
}
|
|
|
|
static inline void
|
|
pop(JitFrame *frame, int n)
|
|
{
|
|
frame->sp -= n;
|
|
memset(frame->sp, 0, n * sizeof(*frame->sp));
|
|
}
|
|
|
|
static inline JitReg
|
|
local_i32(JitFrame *frame, int n)
|
|
{
|
|
return gen_load_i32(frame, n);
|
|
}
|
|
|
|
static inline JitReg
|
|
local_i64(JitFrame *frame, int n)
|
|
{
|
|
return gen_load_i64(frame, n);
|
|
}
|
|
|
|
static inline JitReg
|
|
local_f32(JitFrame *frame, int n)
|
|
{
|
|
return gen_load_f32(frame, n);
|
|
}
|
|
|
|
static inline JitReg
|
|
local_f64(JitFrame *frame, int n)
|
|
{
|
|
return gen_load_f64(frame, n);
|
|
}
|
|
|
|
static void
|
|
set_local_i32(JitFrame *frame, int n, JitReg val)
|
|
{
|
|
frame->lp[n].reg = val;
|
|
frame->lp[n].dirty = 1;
|
|
}
|
|
|
|
static void
|
|
set_local_i64(JitFrame *frame, int n, JitReg val)
|
|
{
|
|
frame->lp[n].reg = val;
|
|
frame->lp[n].dirty = 1;
|
|
frame->lp[n + 1].reg = val;
|
|
frame->lp[n + 1].dirty = 1;
|
|
}
|
|
|
|
static inline void
|
|
set_local_f32(JitFrame *frame, int n, JitReg val)
|
|
{
|
|
set_local_i32(frame, n, val);
|
|
}
|
|
|
|
static inline void
|
|
set_local_f64(JitFrame *frame, int n, JitReg val)
|
|
{
|
|
set_local_i64(frame, n, val);
|
|
}
|
|
|
|
#define POP(jit_value, value_type) \
|
|
do { \
|
|
if (!jit_cc_pop_value(cc, value_type, &jit_value)) \
|
|
goto fail; \
|
|
} while (0)
|
|
|
|
#define POP_I32(v) POP(v, VALUE_TYPE_I32)
|
|
#define POP_I64(v) POP(v, VALUE_TYPE_I64)
|
|
#define POP_F32(v) POP(v, VALUE_TYPE_F32)
|
|
#define POP_F64(v) POP(v, VALUE_TYPE_F64)
|
|
#define POP_FUNCREF(v) POP(v, VALUE_TYPE_FUNCREF)
|
|
#define POP_EXTERNREF(v) POP(v, VALUE_TYPE_EXTERNREF)
|
|
|
|
#define PUSH(jit_value, value_type) \
|
|
do { \
|
|
if (!jit_value) \
|
|
goto fail; \
|
|
if (!jit_cc_push_value(cc, value_type, jit_value)) \
|
|
goto fail; \
|
|
} while (0)
|
|
|
|
#define PUSH_I32(v) PUSH(v, VALUE_TYPE_I32)
|
|
#define PUSH_I64(v) PUSH(v, VALUE_TYPE_I64)
|
|
#define PUSH_F32(v) PUSH(v, VALUE_TYPE_F32)
|
|
#define PUSH_F64(v) PUSH(v, VALUE_TYPE_F64)
|
|
#define PUSH_FUNCREF(v) PUSH(v, VALUE_TYPE_FUNCREF)
|
|
#define PUSH_EXTERNREF(v) PUSH(v, VALUE_TYPE_EXTERNREF)
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|