Refactor LLVM JIT (#1613)

Refactor LLVM JIT for some purposes:
- To simplify the source code of JIT compilation
- To simplify the JIT modes
- To align with LLVM latest changes
- To prepare for the Multi-tier JIT compilation, refer to #1302

The changes mainly include:
- Remove the MCJIT mode, replace it with ORC JIT eager mode
- Remove the LLVM legacy pass manager (only keep the LLVM new pass manager)
- Change the lazy mode's LLVM module/function binding:
  change each function in an individual LLVM module into all functions in a single LLVM module
- Upgraded ORC JIT to ORCv2 JIT to enable lazy compilation

Refer to #1468
This commit is contained in:
Wenyong Huang 2022-10-18 20:17:34 +08:00 committed by GitHub
parent 84b1a6c10e
commit e87a554616
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 1058 additions and 1104 deletions

View File

@ -34,8 +34,8 @@ env:
AOT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" AOT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
CLASSIC_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" CLASSIC_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" LLVM_EAGER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0"
MC_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0" LLVM_LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1"
# LLVM # LLVM
LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex" LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex"
# For Spec Test # For Spec Test
@ -184,8 +184,8 @@ jobs:
$AOT_BUILD_OPTIONS, $AOT_BUILD_OPTIONS,
$CLASSIC_INTERP_BUILD_OPTIONS, $CLASSIC_INTERP_BUILD_OPTIONS,
$FAST_INTERP_BUILD_OPTIONS, $FAST_INTERP_BUILD_OPTIONS,
$LAZY_JIT_BUILD_OPTIONS, $LLVM_EAGER_JIT_BUILD_OPTIONS,
$MC_JIT_BUILD_OPTIONS, $LLVM_LAZY_JIT_BUILD_OPTIONS,
] ]
make_options_feature: [ make_options_feature: [
# Features # Features
@ -210,12 +210,12 @@ jobs:
# uncompatiable feature and platform # uncompatiable feature and platform
# uncompatiable mode and feature # uncompatiable mode and feature
# MULTI_MODULE only on INTERP mode # MULTI_MODULE only on INTERP mode
- make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
- make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
- make_options_run_mode: $AOT_BUILD_OPTIONS - make_options_run_mode: $AOT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
- make_options_run_mode: $MC_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
# SIMD only on JIT/AOT mode # SIMD only on JIT/AOT mode
- make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS - make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_SIMD=1" make_options_feature: "-DWAMR_BUILD_SIMD=1"
@ -224,9 +224,9 @@ jobs:
# DEBUG_INTERP only on CLASSIC INTERP mode # DEBUG_INTERP only on CLASSIC INTERP mode
- make_options_run_mode: $AOT_BUILD_OPTIONS - make_options_run_mode: $AOT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
- make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
- make_options_run_mode: $MC_JIT_BUILD_OPTIONS - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
- make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
@ -236,16 +236,16 @@ jobs:
- make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
# TODO: DEBUG_AOT on JIT # TODO: DEBUG_AOT on JIT
- make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
- make_options_run_mode: $MC_JIT_BUILD_OPTIONS - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
# MINI_LOADER only on INTERP mode # MINI_LOADER only on INTERP mode
- make_options_run_mode: $AOT_BUILD_OPTIONS - make_options_run_mode: $AOT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
- make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
- make_options_run_mode: $MC_JIT_BUILD_OPTIONS - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
include: include:
- os: ubuntu-20.04 - os: ubuntu-20.04
@ -293,11 +293,11 @@ jobs:
matrix: matrix:
make_options: [ make_options: [
# Running mode # Running mode
$AOT_BUILD_OPTIONS,
$CLASSIC_INTERP_BUILD_OPTIONS, $CLASSIC_INTERP_BUILD_OPTIONS,
$FAST_INTERP_BUILD_OPTIONS, $FAST_INTERP_BUILD_OPTIONS,
$LAZY_JIT_BUILD_OPTIONS, $LLVM_EAGER_JIT_BUILD_OPTIONS,
$MC_JIT_BUILD_OPTIONS, $LLVM_LAZY_JIT_BUILD_OPTIONS,
$AOT_BUILD_OPTIONS,
] ]
os: [ubuntu-20.04, ubuntu-22.04] os: [ubuntu-20.04, ubuntu-22.04]
include: include:

View File

@ -30,11 +30,13 @@ concurrency:
cancel-in-progress: true cancel-in-progress: true
env: env:
# For BUILD
AOT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" AOT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
CLASSIC_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" CLASSIC_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" LLVM_EAGER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0"
MC_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0" LLVM_LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1"
# LLVM
LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex" LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex"
jobs: jobs:
@ -160,8 +162,8 @@ jobs:
$AOT_BUILD_OPTIONS, $AOT_BUILD_OPTIONS,
$CLASSIC_INTERP_BUILD_OPTIONS, $CLASSIC_INTERP_BUILD_OPTIONS,
$FAST_INTERP_BUILD_OPTIONS, $FAST_INTERP_BUILD_OPTIONS,
$LAZY_JIT_BUILD_OPTIONS, $LLVM_EAGER_JIT_BUILD_OPTIONS,
$MC_JIT_BUILD_OPTIONS, $LLVM_LAZY_JIT_BUILD_OPTIONS,
] ]
make_options_feature: [ make_options_feature: [
# Features # Features
@ -187,12 +189,12 @@ jobs:
# uncompatiable feature and platform # uncompatiable feature and platform
# uncompatiable mode and feature # uncompatiable mode and feature
# MULTI_MODULE only on INTERP mode # MULTI_MODULE only on INTERP mode
- make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
- make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
- make_options_run_mode: $AOT_BUILD_OPTIONS - make_options_run_mode: $AOT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
- make_options_run_mode: $MC_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
# SIMD only on JIT/AOT mode # SIMD only on JIT/AOT mode
- make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS - make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_SIMD=1" make_options_feature: "-DWAMR_BUILD_SIMD=1"
@ -201,9 +203,9 @@ jobs:
# DEBUG_INTERP only on CLASSIC INTERP mode # DEBUG_INTERP only on CLASSIC INTERP mode
- make_options_run_mode: $AOT_BUILD_OPTIONS - make_options_run_mode: $AOT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
- make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
- make_options_run_mode: $MC_JIT_BUILD_OPTIONS - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
- make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
@ -213,16 +215,16 @@ jobs:
- make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
# TODO: DEBUG_AOT on JIT # TODO: DEBUG_AOT on JIT
- make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
- make_options_run_mode: $MC_JIT_BUILD_OPTIONS - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
# MINI_LOADER only on INTERP mode # MINI_LOADER only on INTERP mode
- make_options_run_mode: $AOT_BUILD_OPTIONS - make_options_run_mode: $AOT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
- make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
- make_options_run_mode: $MC_JIT_BUILD_OPTIONS - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
include: include:
- os: macos-latest - os: macos-latest
@ -271,9 +273,9 @@ jobs:
$CLASSIC_INTERP_BUILD_OPTIONS, $CLASSIC_INTERP_BUILD_OPTIONS,
$FAST_INTERP_BUILD_OPTIONS, $FAST_INTERP_BUILD_OPTIONS,
# doesn't support # doesn't support
#$LAZY_JIT_BUILD_OPTIONS,
#$MC_JIT_BUILD_OPTIONS,
#$AOT_BUILD_OPTIONS, #$AOT_BUILD_OPTIONS,
#$LLVM_EAGER_JIT_BUILD_OPTIONS,
#$LLVM_LAZY_JIT_BUILD_OPTIONS,
] ]
os: [macos-latest] os: [macos-latest]
include: include:

View File

@ -30,11 +30,13 @@ concurrency:
cancel-in-progress: true cancel-in-progress: true
env: env:
# For BUILD
AOT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" AOT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
CLASSIC_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" CLASSIC_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" LLVM_EAGER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0"
MC_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0" LLVM_LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1"
# LLVM
LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex" LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex"
jobs: jobs:
@ -119,8 +121,8 @@ jobs:
$CLASSIC_INTERP_BUILD_OPTIONS, $CLASSIC_INTERP_BUILD_OPTIONS,
$FAST_INTERP_BUILD_OPTIONS, $FAST_INTERP_BUILD_OPTIONS,
# doesn't support # doesn't support
# $LAZY_JIT_BUILD_OPTIONS, #$LLVM_EAGER_JIT_BUILD_OPTIONS,
# $MC_JIT_BUILD_OPTIONS, #$LLVM_LAZY_JIT_BUILD_OPTIONS,
] ]
make_options_feature: [ make_options_feature: [
# Features # Features
@ -251,9 +253,9 @@ jobs:
$CLASSIC_INTERP_BUILD_OPTIONS, $CLASSIC_INTERP_BUILD_OPTIONS,
$FAST_INTERP_BUILD_OPTIONS, $FAST_INTERP_BUILD_OPTIONS,
# doesn't support # doesn't support
#$LAZY_JIT_BUILD_OPTIONS,
#$MC_JIT_BUILD_OPTIONS,
#$AOT_BUILD_OPTIONS, #$AOT_BUILD_OPTIONS,
#$LLVM_EAGER_JIT_BUILD_OPTIONS,
#$LLVM_LAZY_JIT_BUILD_OPTIONS,
] ]
os: [ubuntu-20.04] os: [ubuntu-20.04]
include: include:

1
.gitignore vendored
View File

@ -30,5 +30,4 @@ samples/socket-api/wasm-src/inc/pthread.h
**/__pycache__ **/__pycache__
# ignore benchmarks generated
tests/benchmarks/coremark/coremark* tests/benchmarks/coremark/coremark*

View File

@ -84,11 +84,9 @@ endif ()
endif () endif ()
if (WAMR_BUILD_JIT EQUAL 1) if (WAMR_BUILD_JIT EQUAL 1)
add_definitions("-DWASM_ENABLE_JIT=1")
if (NOT WAMR_BUILD_LAZY_JIT EQUAL 0) if (NOT WAMR_BUILD_LAZY_JIT EQUAL 0)
# Enable Lazy JIT by default # Enable Lazy JIT by default
set (WAMR_BUILD_LAZY_JIT 1) set (WAMR_BUILD_LAZY_JIT 1)
add_definitions("-DWASM_ENABLE_LAZY_JIT=1")
endif () endif ()
if (NOT DEFINED LLVM_DIR) if (NOT DEFINED LLVM_DIR)
set (LLVM_SRC_ROOT "${WAMR_ROOT_DIR}/core/deps/llvm") set (LLVM_SRC_ROOT "${WAMR_ROOT_DIR}/core/deps/llvm")
@ -148,13 +146,15 @@ else ()
message (" WAMR Fast JIT disabled") message (" WAMR Fast JIT disabled")
endif () endif ()
if (WAMR_BUILD_JIT EQUAL 1) if (WAMR_BUILD_JIT EQUAL 1)
add_definitions("-DWASM_ENABLE_JIT=1")
if (WAMR_BUILD_LAZY_JIT EQUAL 1) if (WAMR_BUILD_LAZY_JIT EQUAL 1)
message (" WAMR LLVM Orc Lazy JIT enabled") add_definitions("-DWASM_ENABLE_LAZY_JIT=1")
message (" WAMR LLVM ORC JIT enabled with Lazy Compilation")
else () else ()
message (" WAMR LLVM MC JIT enabled") message (" WAMR LLVM ORC JIT enabled with Eager Compilation")
endif () endif ()
else () else ()
message (" WAMR LLVM JIT disabled") message (" WAMR LLVM ORC JIT disabled")
endif () endif ()
if (WAMR_BUILD_LIBC_BUILTIN EQUAL 1) if (WAMR_BUILD_LIBC_BUILTIN EQUAL 1)
message (" Libc builtin enabled") message (" Libc builtin enabled")

View File

@ -81,12 +81,26 @@
#define WASM_ENABLE_LAZY_JIT 0 #define WASM_ENABLE_LAZY_JIT 0
#endif #endif
#ifndef WASM_LAZY_JIT_COMPILE_THREAD_NUM #ifndef WASM_ORC_JIT_BACKEND_THREAD_NUM
#define WASM_LAZY_JIT_COMPILE_THREAD_NUM 4 /* The number of backend threads created by runtime */
#define WASM_ORC_JIT_BACKEND_THREAD_NUM 4
#endif
#if WASM_ORC_JIT_BACKEND_THREAD_NUM < 1
#error "WASM_ORC_JIT_BACKEND_THREAD_NUM must be greater than 0"
#endif
#ifndef WASM_ORC_JIT_COMPILE_THREAD_NUM
/* The number of compilation threads created by LLVM JIT */
#define WASM_ORC_JIT_COMPILE_THREAD_NUM 4
#endif
#if WASM_ORC_JIT_COMPILE_THREAD_NUM < 1
#error "WASM_ORC_JIT_COMPILE_THREAD_NUM must be greater than 0"
#endif #endif
#if (WASM_ENABLE_AOT == 0) && (WASM_ENABLE_JIT != 0) #if (WASM_ENABLE_AOT == 0) && (WASM_ENABLE_JIT != 0)
/* LazyJIT or MCJIT can only be enabled when AOT is enabled */ /* LLVM JIT can only be enabled when AOT is enabled */
#undef WASM_ENABLE_JIT #undef WASM_ENABLE_JIT
#define WASM_ENABLE_JIT 0 #define WASM_ENABLE_JIT 0
@ -110,14 +124,6 @@
#define WASM_ENABLE_WAMR_COMPILER 0 #define WASM_ENABLE_WAMR_COMPILER 0
#endif #endif
#if WASM_ENABLE_WAMR_COMPILER != 0
#ifndef WASM_ENABLE_LLVM_LEGACY_PM
/* Whether to use LLVM legacy pass manager when building wamrc,
by default it is disabled and LLVM new pass manager is used */
#define WASM_ENABLE_LLVM_LEGACY_PM 0
#endif
#endif
#ifndef WASM_ENABLE_LIBC_BUILTIN #ifndef WASM_ENABLE_LIBC_BUILTIN
#define WASM_ENABLE_LIBC_BUILTIN 0 #define WASM_ENABLE_LIBC_BUILTIN 0
#endif #endif

View File

@ -1321,6 +1321,9 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
} }
argc = func_type->param_cell_num; argc = func_type->param_cell_num;
/* func pointer was looked up previously */
bh_assert(function->u.func.func_ptr != NULL);
/* set thread handle and stack boundary */ /* set thread handle and stack boundary */
wasm_exec_env_set_thread_info(exec_env); wasm_exec_env_set_thread_info(exec_env);
@ -1828,6 +1831,11 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx,
func_type_idx = func_type_indexes[func_idx]; func_type_idx = func_type_indexes[func_idx];
func_type = aot_module->func_types[func_type_idx]; func_type = aot_module->func_types[func_type_idx];
if (func_idx >= aot_module->import_func_count) {
/* func pointer was looked up previously */
bh_assert(func_ptrs[func_idx] != NULL);
}
if (!(func_ptr = func_ptrs[func_idx])) { if (!(func_ptr = func_ptrs[func_idx])) {
bh_assert(func_idx < aot_module->import_func_count); bh_assert(func_idx < aot_module->import_func_count);
import_func = aot_module->import_funcs + func_idx; import_func = aot_module->import_funcs + func_idx;

View File

@ -148,9 +148,9 @@ typedef struct AOTModule {
/* function info */ /* function info */
uint32 func_count; uint32 func_count;
/* point to AOTed functions */ /* func pointers of AOTed (un-imported) functions */
void **func_ptrs; void **func_ptrs;
/* function type indexes */ /* func type indexes of AOTed (un-imported) functions */
uint32 *func_type_indexes; uint32 *func_type_indexes;
/* export info */ /* export info */

View File

@ -2602,7 +2602,6 @@ veriy_module(AOTCompContext *comp_ctx)
char *msg = NULL; char *msg = NULL;
bool ret; bool ret;
#if WASM_ENABLE_LAZY_JIT == 0
ret = LLVMVerifyModule(comp_ctx->module, LLVMPrintMessageAction, &msg); ret = LLVMVerifyModule(comp_ctx->module, LLVMPrintMessageAction, &msg);
if (!ret && msg) { if (!ret && msg) {
if (msg[0] != '\0') { if (msg[0] != '\0') {
@ -2612,135 +2611,10 @@ veriy_module(AOTCompContext *comp_ctx)
} }
LLVMDisposeMessage(msg); LLVMDisposeMessage(msg);
} }
#else
uint32 i;
for (i = 0; i < comp_ctx->func_ctx_count; i++) {
ret = LLVMVerifyModule(comp_ctx->modules[i], LLVMPrintMessageAction,
&msg);
if (!ret && msg) {
if (msg[0] != '\0') {
aot_set_last_error(msg);
LLVMDisposeMessage(msg);
return false;
}
LLVMDisposeMessage(msg);
}
}
#endif
return true; return true;
} }
static bool
apply_func_passes(AOTCompContext *comp_ctx)
{
LLVMPassManagerRef pass_mgr;
uint32 i;
#if WASM_ENABLE_LAZY_JIT == 0
pass_mgr = LLVMCreateFunctionPassManagerForModule(comp_ctx->module);
#else
pass_mgr = LLVMCreatePassManager();
#endif
if (!pass_mgr) {
aot_set_last_error("create LLVM pass manager failed.");
return false;
}
LLVMAddPromoteMemoryToRegisterPass(pass_mgr);
LLVMAddInstructionCombiningPass(pass_mgr);
LLVMAddCFGSimplificationPass(pass_mgr);
LLVMAddJumpThreadingPass(pass_mgr);
#if LLVM_VERSION_MAJOR < 12
LLVMAddConstantPropagationPass(pass_mgr);
#endif
LLVMAddIndVarSimplifyPass(pass_mgr);
if (!comp_ctx->is_jit_mode) {
/* Put Vectorize passes before GVN/LICM passes as the former
might gain more performance improvement and the latter might
break the optimizations for the former */
LLVMAddLoopVectorizePass(pass_mgr);
LLVMAddSLPVectorizePass(pass_mgr);
LLVMAddLoopRotatePass(pass_mgr);
#if LLVM_VERSION_MAJOR < 15
LLVMAddLoopUnswitchPass(pass_mgr);
#else
aot_add_simple_loop_unswitch_pass(pass_mgr);
#endif
LLVMAddInstructionCombiningPass(pass_mgr);
LLVMAddCFGSimplificationPass(pass_mgr);
if (!comp_ctx->enable_thread_mgr) {
/* These two passes may destroy the volatile semantics,
disable them when building as multi-thread mode */
LLVMAddGVNPass(pass_mgr);
LLVMAddLICMPass(pass_mgr);
LLVMAddInstructionCombiningPass(pass_mgr);
LLVMAddCFGSimplificationPass(pass_mgr);
}
}
#if WASM_ENABLE_LAZY_JIT == 0
LLVMInitializeFunctionPassManager(pass_mgr);
for (i = 0; i < comp_ctx->func_ctx_count; i++) {
LLVMRunFunctionPassManager(pass_mgr, comp_ctx->func_ctxes[i]->func);
}
LLVMFinalizeFunctionPassManager(pass_mgr);
#else
for (i = 0; i < comp_ctx->func_ctx_count; i++) {
LLVMRunPassManager(pass_mgr, comp_ctx->modules[i]);
}
#endif
LLVMDisposePassManager(pass_mgr);
return true;
}
#if WASM_ENABLE_LLVM_LEGACY_PM != 0 || LLVM_VERSION_MAJOR < 12
static bool
apply_lto_passes(AOTCompContext *comp_ctx)
{
LLVMPassManagerRef common_pass_mgr;
LLVMPassManagerBuilderRef pass_mgr_builder;
#if WASM_ENABLE_LAZY_JIT != 0
uint32 i;
#endif
if (!(common_pass_mgr = LLVMCreatePassManager())) {
aot_set_last_error("create LLVM pass manager failed");
return false;
}
if (!(pass_mgr_builder = LLVMPassManagerBuilderCreate())) {
aot_set_last_error("create LLVM pass manager builder failed");
LLVMDisposePassManager(common_pass_mgr);
return false;
}
LLVMPassManagerBuilderSetOptLevel(pass_mgr_builder, comp_ctx->opt_level);
LLVMPassManagerBuilderPopulateModulePassManager(pass_mgr_builder,
common_pass_mgr);
#if LLVM_VERSION_MAJOR < 15
LLVMPassManagerBuilderPopulateLTOPassManager(pass_mgr_builder,
common_pass_mgr, true, true);
#endif
#if WASM_ENABLE_LAZY_JIT == 0
LLVMRunPassManager(common_pass_mgr, comp_ctx->module);
#else
for (i = 0; i < comp_ctx->func_ctx_count; i++) {
LLVMRunPassManager(common_pass_mgr, comp_ctx->modules[i]);
}
#endif
LLVMDisposePassManager(common_pass_mgr);
LLVMPassManagerBuilderDispose(pass_mgr_builder);
return true;
}
#endif /* end of WASM_ENABLE_LLVM_LEGACY_PM != 0 || LLVM_VERSION_MAJOR < 12 */
/* Check whether the target supports hardware atomic instructions */ /* Check whether the target supports hardware atomic instructions */
static bool static bool
aot_require_lower_atomic_pass(AOTCompContext *comp_ctx) aot_require_lower_atomic_pass(AOTCompContext *comp_ctx)
@ -2779,9 +2653,6 @@ static bool
apply_passes_for_indirect_mode(AOTCompContext *comp_ctx) apply_passes_for_indirect_mode(AOTCompContext *comp_ctx)
{ {
LLVMPassManagerRef common_pass_mgr; LLVMPassManagerRef common_pass_mgr;
#if WASM_ENABLE_LAZY_JIT != 0
uint32 i;
#endif
if (!(common_pass_mgr = LLVMCreatePassManager())) { if (!(common_pass_mgr = LLVMCreatePassManager())) {
aot_set_last_error("create pass manager failed"); aot_set_last_error("create pass manager failed");
@ -2796,13 +2667,7 @@ apply_passes_for_indirect_mode(AOTCompContext *comp_ctx)
if (aot_require_lower_switch_pass(comp_ctx)) if (aot_require_lower_switch_pass(comp_ctx))
LLVMAddLowerSwitchPass(common_pass_mgr); LLVMAddLowerSwitchPass(common_pass_mgr);
#if WASM_ENABLE_LAZY_JIT == 0
LLVMRunPassManager(common_pass_mgr, comp_ctx->module); LLVMRunPassManager(common_pass_mgr, comp_ctx->module);
#else
for (i = 0; i < comp_ctx->func_ctx_count; i++) {
LLVMRunPassManager(common_pass_mgr, comp_ctx->modules[i]);
}
#endif
LLVMDisposePassManager(common_pass_mgr); LLVMDisposePassManager(common_pass_mgr);
return true; return true;
@ -2812,11 +2677,6 @@ bool
aot_compile_wasm(AOTCompContext *comp_ctx) aot_compile_wasm(AOTCompContext *comp_ctx)
{ {
uint32 i; uint32 i;
#if WASM_ENABLE_LAZY_JIT != 0
LLVMErrorRef err;
LLVMOrcJITDylibRef orc_main_dylib;
LLVMOrcThreadSafeModuleRef orc_thread_safe_module;
#endif
if (!aot_validate_wasm(comp_ctx)) { if (!aot_validate_wasm(comp_ctx)) {
return false; return false;
@ -2833,87 +2693,72 @@ aot_compile_wasm(AOTCompContext *comp_ctx)
LLVMDIBuilderFinalize(comp_ctx->debug_builder); LLVMDIBuilderFinalize(comp_ctx->debug_builder);
#endif #endif
bh_print_time("Begin to verify LLVM module"); /* Disable LLVM module verification for jit mode to speedup
if (!veriy_module(comp_ctx)) { the compilation process */
return false; if (!comp_ctx->is_jit_mode) {
bh_print_time("Begin to verify LLVM module");
if (!veriy_module(comp_ctx)) {
return false;
}
} }
/* Run IR optimization before feeding in ORCJIT and AOT codegen */
if (comp_ctx->optimize) { if (comp_ctx->optimize) {
if (comp_ctx->is_jit_mode) { /* Run specific passes for AOT indirect mode */
/* Only run func passes for JIT mode */ if (!comp_ctx->is_jit_mode && comp_ctx->is_indirect_mode) {
bh_print_time("Begin to run func optimization passes"); bh_print_time("Begin to run optimization passes "
if (!apply_func_passes(comp_ctx)) { "for indirect mode");
if (!apply_passes_for_indirect_mode(comp_ctx)) {
return false; return false;
} }
} }
else {
#if WASM_ENABLE_LLVM_LEGACY_PM == 0 && LLVM_VERSION_MAJOR >= 12 /* Run passes for AOT/JIT mode.
/* Run llvm new pass manager for AOT compiler if llvm TODO: Apply these passes in the do_ir_transform callback of
legacy pass manager isn't used */ TransformLayer when compiling each jit function, so as to
bh_print_time("Begin to run llvm optimization passes"); speedup the launch process. Now there are two issues in the
aot_apply_llvm_new_pass_manager(comp_ctx); JIT: one is memory leak in do_ir_transform, the other is
#else possible core dump. */
/* Run func passes and lto passes for AOT compiler if llvm bh_print_time("Begin to run llvm optimization passes");
legacy pass manager is used */ aot_apply_llvm_new_pass_manager(comp_ctx, comp_ctx->module);
bh_print_time("Begin to run func optimization passes"); bh_print_time("Finish llvm optimization passes");
if (!apply_func_passes(comp_ctx)) { }
return false;
} #ifdef DUMP_MODULE
if (!comp_ctx->disable_llvm_lto) { LLVMDumpModule(comp_ctx->module);
bh_print_time("Begin to run lto optimization passes"); os_printf("\n");
if (!apply_lto_passes(comp_ctx)) {
return false;
}
}
#endif #endif
/* Run passes for AOT indirect mode */
if (comp_ctx->is_indirect_mode) { if (comp_ctx->is_jit_mode) {
bh_print_time("Begin to run optimization passes " LLVMErrorRef err;
"for indirect mode"); LLVMOrcJITDylibRef orc_main_dylib;
if (!apply_passes_for_indirect_mode(comp_ctx)) { LLVMOrcThreadSafeModuleRef orc_thread_safe_module;
return false;
} orc_main_dylib = LLVMOrcLLLazyJITGetMainJITDylib(comp_ctx->orc_jit);
} if (!orc_main_dylib) {
aot_set_last_error(
"failed to get orc orc_jit main dynmaic library");
return false;
} }
}
#if WASM_ENABLE_LAZY_JIT != 0
orc_main_dylib = LLVMOrcLLJITGetMainJITDylib(comp_ctx->orc_lazyjit);
if (!orc_main_dylib) {
aot_set_last_error("failed to get orc jit main dynmaic library");
return false;
}
for (i = 0; i < comp_ctx->func_ctx_count; i++) {
orc_thread_safe_module = LLVMOrcCreateNewThreadSafeModule( orc_thread_safe_module = LLVMOrcCreateNewThreadSafeModule(
comp_ctx->modules[i], comp_ctx->orc_thread_safe_context); comp_ctx->module, comp_ctx->orc_thread_safe_context);
if (!orc_thread_safe_module) { if (!orc_thread_safe_module) {
aot_set_last_error("failed to create thread safe module"); aot_set_last_error("failed to create thread safe module");
return false; return false;
} }
if ((err = LLVMOrcLLJITAddLLVMIRModule(comp_ctx->orc_lazyjit, if ((err = LLVMOrcLLLazyJITAddLLVMIRModule(
orc_main_dylib, comp_ctx->orc_jit, orc_main_dylib, orc_thread_safe_module))) {
orc_thread_safe_module))) {
/* If adding the ThreadSafeModule fails then we need to clean it up /* If adding the ThreadSafeModule fails then we need to clean it up
by ourselves, otherwise the orc jit will manage the memory. */ by ourselves, otherwise the orc orc_jit will manage the memory.
*/
LLVMOrcDisposeThreadSafeModule(orc_thread_safe_module); LLVMOrcDisposeThreadSafeModule(orc_thread_safe_module);
aot_handle_llvm_errmsg("failed to addIRModule", err); aot_handle_llvm_errmsg("failed to addIRModule", err);
return false; return false;
} }
} }
#endif
#if 0
#if WASM_ENABLE_LAZY_JIT == 0
LLVMDumpModule(comp_ctx->module);
#else
for (i = 0; i < comp_ctx->func_ctx_count; i++) {
LLVMDumpModule(comp_ctx->modules[i]);
os_printf("\n");
}
#endif
#endif
return true; return true;
} }
@ -2947,7 +2792,6 @@ aot_generate_tempfile_name(const char *prefix, const char *extension,
} }
#endif /* end of !(defined(_WIN32) || defined(_WIN32_)) */ #endif /* end of !(defined(_WIN32) || defined(_WIN32_)) */
#if WASM_ENABLE_LAZY_JIT == 0
bool bool
aot_emit_llvm_file(AOTCompContext *comp_ctx, const char *file_name) aot_emit_llvm_file(AOTCompContext *comp_ctx, const char *file_name)
{ {
@ -3071,4 +2915,3 @@ aot_emit_object_file(AOTCompContext *comp_ctx, char *file_name)
return true; return true;
} }
#endif /* end of WASM_ENABLE_LAZY_JIT == 0 */

View File

@ -6,8 +6,6 @@
#include "aot_compiler.h" #include "aot_compiler.h"
#include "../aot/aot_runtime.h" #include "../aot/aot_runtime.h"
#if WASM_ENABLE_LAZY_JIT == 0
#define PUT_U64_TO_ADDR(addr, value) \ #define PUT_U64_TO_ADDR(addr, value) \
do { \ do { \
union { \ union { \
@ -2794,16 +2792,18 @@ aot_obj_data_create(AOTCompContext *comp_ctx)
} }
#endif /* end of defined(_WIN32) || defined(_WIN32_) */ #endif /* end of defined(_WIN32) || defined(_WIN32_) */
} }
else if (LLVMTargetMachineEmitToMemoryBuffer( else {
comp_ctx->target_machine, comp_ctx->module, LLVMObjectFile, if (LLVMTargetMachineEmitToMemoryBuffer(
&err, &obj_data->mem_buf) comp_ctx->target_machine, comp_ctx->module, LLVMObjectFile,
!= 0) { &err, &obj_data->mem_buf)
if (err) { != 0) {
LLVMDisposeMessage(err); if (err) {
err = NULL; LLVMDisposeMessage(err);
err = NULL;
}
aot_set_last_error("llvm emit to memory buffer failed.");
goto fail;
} }
aot_set_last_error("llvm emit to memory buffer failed.");
goto fail;
} }
if (!(obj_data->binary = LLVMCreateBinary(obj_data->mem_buf, NULL, &err))) { if (!(obj_data->binary = LLVMCreateBinary(obj_data->mem_buf, NULL, &err))) {
@ -2928,4 +2928,3 @@ fail1:
return ret; return ret;
} }
#endif /* end of WASM_ENABLE_LAZY_JIT == 0 */

View File

@ -267,131 +267,6 @@ call_aot_invoke_native_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
return true; return true;
} }
#if WASM_ENABLE_LAZY_JIT != 0
static bool
lookup_orcjit_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMValueRef func_idx, LLVMValueRef *p_func)
{
LLVMBasicBlockRef block_curr, block_resolve_func, block_func_resolved;
LLVMValueRef param_values[3], func, value, func_ptr, cmp, phi;
LLVMTypeRef param_types[3], ret_type, func_type, func_ptr_type;
block_curr = LLVMGetInsertBlock(comp_ctx->builder);
if (!(block_resolve_func = LLVMAppendBasicBlockInContext(
comp_ctx->context, func_ctx->func, "resolve_func"))) {
aot_set_last_error("llvm add basic block failed.");
return false;
}
if (!(block_func_resolved = LLVMAppendBasicBlockInContext(
comp_ctx->context, func_ctx->func, "func_resolved"))) {
aot_set_last_error("llvm add basic block failed.");
return false;
}
LLVMMoveBasicBlockAfter(block_resolve_func, block_curr);
LLVMMoveBasicBlockAfter(block_func_resolved, block_resolve_func);
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_func_resolved);
if (!(phi = LLVMBuildPhi(comp_ctx->builder, INT8_PTR_TYPE, "phi"))) {
aot_set_last_error("llvm build phi failed.");
return false;
}
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr);
/* Load function pointer */
if (!(func_ptr = LLVMBuildInBoundsGEP2(comp_ctx->builder, OPQ_PTR_TYPE,
func_ctx->func_ptrs, &func_idx, 1,
"func_ptr_tmp"))) {
aot_set_last_error("llvm build inbounds gep failed.");
return false;
}
if (!(func = LLVMBuildLoad2(comp_ctx->builder, OPQ_PTR_TYPE, func_ptr,
"func_ptr"))) {
aot_set_last_error("llvm build load failed.");
return false;
}
/* If func ptr is NULL, call aot_lookup_orcjit_func to resolve it */
if (!(cmp = LLVMBuildIsNull(comp_ctx->builder, func, "cmp"))) {
aot_set_last_error("llvm build is null failed");
return false;
}
/* Create condition br */
if (!LLVMBuildCondBr(comp_ctx->builder, cmp, block_resolve_func,
block_func_resolved)) {
aot_set_last_error("llvm build cond br failed.");
return false;
}
LLVMAddIncoming(phi, &func, &block_curr, 1);
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_resolve_func);
param_types[0] = INT8_PTR_TYPE;
param_types[1] = comp_ctx->aot_inst_type;
param_types[2] = I32_TYPE;
ret_type = INT8_PTR_TYPE;
if (!(func_type = LLVMFunctionType(ret_type, param_types, 3, false))
|| !(func_ptr_type = LLVMPointerType(func_type, 0))) {
aot_set_last_error("llvm add function type failed.");
return false;
}
if (!(value = I64_CONST((uint64)(uintptr_t)aot_lookup_orcjit_func))
|| !(func = LLVMConstIntToPtr(value, func_ptr_type))) {
aot_set_last_error("create LLVM value failed.");
return false;
}
param_values[0] = I64_CONST((uintptr_t)comp_ctx->orc_lazyjit);
if (!param_values[0]) {
aot_set_last_error("llvm build const failed.");
return false;
}
if (!(param_values[0] =
LLVMConstIntToPtr(param_values[0], INT8_PTR_TYPE))) {
aot_set_last_error("llvm build bit cast failed.");
return false;
}
param_values[1] = func_ctx->aot_inst;
param_values[2] = func_idx;
if (!param_values[2]) {
aot_set_last_error("llvm build const failed.");
return false;
}
/* Call the function */
if (!(func = LLVMBuildCall2(comp_ctx->builder, func_type, func,
param_values, 3, "call_orcjit_lookup"))) {
aot_set_last_error("LLVM build call failed.");
return false;
}
/* Check whether exception was thrown when looking up func */
if (!check_exception_thrown(comp_ctx, func_ctx)) {
return false;
}
block_curr = LLVMGetInsertBlock(comp_ctx->builder);
LLVMAddIncoming(phi, &func, &block_curr, 1);
if (!LLVMBuildBr(comp_ctx->builder, block_func_resolved)) {
aot_set_last_error("llvm build br failed.");
return false;
}
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_func_resolved);
*p_func = phi;
return true;
}
#endif
#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0) #if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
static bool static bool
call_aot_alloc_frame_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, call_aot_alloc_frame_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
@ -909,43 +784,13 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
} }
} }
else { else {
#if WASM_ENABLE_LAZY_JIT == 0
func = func_ctxes[func_idx - import_func_count]->func;
#else
if (func_ctxes[func_idx - import_func_count] == func_ctx) { if (func_ctxes[func_idx - import_func_count] == func_ctx) {
/* recursive call */ /* recursive call */
func = func_ctx->func; func = func_ctx->func;
} }
else { else {
LLVMTypeRef func_ptr_type; func = func_ctxes[func_idx - import_func_count]->func;
LLVMValueRef func_idx_const = I32_CONST(func_idx);
if (!func_idx_const) {
aot_set_last_error("llvm build const failed.");
goto fail;
}
/* For LAZY JIT, each function belongs to its own module,
we call aot_lookup_orcjit_func to get the func pointer */
if (!lookup_orcjit_func(comp_ctx, func_ctx, func_idx_const,
&func)) {
goto fail;
}
if (!(func_ptr_type = LLVMPointerType(
func_ctxes[func_idx - import_func_count]->func_type,
0))) {
aot_set_last_error("construct func ptr type failed.");
goto fail;
}
if (!(func = LLVMBuildBitCast(comp_ctx->builder, func,
func_ptr_type, "aot_func"))) {
aot_set_last_error("llvm bit cast failed.");
goto fail;
}
} }
#endif
} }
aot_func = func_ctxes[func_idx - import_func_count]->aot_func; aot_func = func_ctxes[func_idx - import_func_count]->aot_func;
@ -1574,7 +1419,6 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+ 16)) + 16))
goto fail; goto fail;
#if WASM_ENABLE_LAZY_JIT == 0
/* Load function pointer */ /* Load function pointer */
if (!(func_ptr = LLVMBuildInBoundsGEP2(comp_ctx->builder, OPQ_PTR_TYPE, if (!(func_ptr = LLVMBuildInBoundsGEP2(comp_ctx->builder, OPQ_PTR_TYPE,
func_ctx->func_ptrs, &func_idx, 1, func_ctx->func_ptrs, &func_idx, 1,
@ -1588,12 +1432,6 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
aot_set_last_error("llvm build load failed."); aot_set_last_error("llvm build load failed.");
goto fail; goto fail;
} }
#else
/* For LAZY JIT, each function belongs to its own module,
we call aot_lookup_orcjit_func to get the func pointer */
if (!lookup_orcjit_func(comp_ctx, func_ctx, func_idx, &func_ptr))
goto fail;
#endif
if (!(llvm_func_type = if (!(llvm_func_type =
LLVMFunctionType(ret_type, param_types, total_param_count, false)) LLVMFunctionType(ret_type, param_types, total_param_count, false))

View File

@ -977,14 +977,6 @@ fail:
return false; return false;
} }
#if WASM_ENABLE_LAZY_JIT != 0
static void *
jit_memmove(void *dest, const void *src, size_t n)
{
return memmove(dest, src, n);
}
#endif
bool bool
aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{ {
@ -1001,18 +993,10 @@ aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
if (!(dst_addr = check_bulk_memory_overflow(comp_ctx, func_ctx, dst, len))) if (!(dst_addr = check_bulk_memory_overflow(comp_ctx, func_ctx, dst, len)))
return false; return false;
#if WASM_ENABLE_LAZY_JIT != 0 call_aot_memmove = comp_ctx->is_indirect_mode || comp_ctx->is_jit_mode;
call_aot_memmove = true;
#endif
if (comp_ctx->is_indirect_mode)
call_aot_memmove = true;
if (call_aot_memmove) { if (call_aot_memmove) {
LLVMTypeRef param_types[3], ret_type, func_type, func_ptr_type; LLVMTypeRef param_types[3], ret_type, func_type, func_ptr_type;
LLVMValueRef func, params[3]; LLVMValueRef func, params[3];
#if WASM_ENABLE_LAZY_JIT == 0
int32 func_idx;
#endif
param_types[0] = INT8_PTR_TYPE; param_types[0] = INT8_PTR_TYPE;
param_types[1] = INT8_PTR_TYPE; param_types[1] = INT8_PTR_TYPE;
@ -1029,22 +1013,25 @@ aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
return false; return false;
} }
#if WASM_ENABLE_LAZY_JIT == 0 if (comp_ctx->is_jit_mode) {
func_idx = aot_get_native_symbol_index(comp_ctx, "memmove"); if (!(func = I64_CONST((uint64)(uintptr_t)aot_memmove))
if (func_idx < 0) { || !(func = LLVMConstIntToPtr(func, func_ptr_type))) {
return false; aot_set_last_error("create LLVM value failed.");
return false;
}
} }
if (!(func = aot_get_func_from_table(comp_ctx, func_ctx->native_symbol, else {
func_ptr_type, func_idx))) { int32 func_index;
return false; func_index = aot_get_native_symbol_index(comp_ctx, "memmove");
if (func_index < 0) {
return false;
}
if (!(func =
aot_get_func_from_table(comp_ctx, func_ctx->native_symbol,
func_ptr_type, func_index))) {
return false;
}
} }
#else
if (!(func = I64_CONST((uint64)(uintptr_t)jit_memmove))
|| !(func = LLVMConstIntToPtr(func, func_ptr_type))) {
aot_set_last_error("create LLVM value failed.");
return false;
}
#endif
params[0] = dst_addr; params[0] = dst_addr;
params[1] = src_addr; params[1] = src_addr;

View File

@ -48,7 +48,10 @@ aot_add_llvm_func(AOTCompContext *comp_ctx, LLVMModuleRef module,
LLVMValueRef func = NULL; LLVMValueRef func = NULL;
LLVMTypeRef *param_types, ret_type, func_type; LLVMTypeRef *param_types, ret_type, func_type;
LLVMValueRef local_value; LLVMValueRef local_value;
char func_name[32]; LLVMTypeRef func_type_wrapper;
LLVMValueRef func_wrapper;
LLVMBasicBlockRef func_begin;
char func_name[48];
uint64 size; uint64 size;
uint32 i, j = 0, param_count = (uint64)aot_func_type->param_count; uint32 i, j = 0, param_count = (uint64)aot_func_type->param_count;
@ -116,6 +119,34 @@ aot_add_llvm_func(AOTCompContext *comp_ctx, LLVMModuleRef module,
if (p_func_type) if (p_func_type)
*p_func_type = func_type; *p_func_type = func_type;
if (comp_ctx->is_jit_mode) {
func_type_wrapper = LLVMFunctionType(VOID_TYPE, NULL, 0, false);
if (!func_type_wrapper) {
aot_set_last_error("create LLVM function type failed.");
goto fail;
}
snprintf(func_name, sizeof(func_name), "%s%d%s", AOT_FUNC_PREFIX,
func_index, "_wrapper");
if (!(func_wrapper =
LLVMAddFunction(module, func_name, func_type_wrapper))) {
aot_set_last_error("add LLVM function failed.");
goto fail;
}
if (!(func_begin = LLVMAppendBasicBlockInContext(
comp_ctx->context, func_wrapper, "func_begin"))) {
aot_set_last_error("add LLVM basic block failed.");
goto fail;
}
LLVMPositionBuilderAtEnd(comp_ctx->builder, func_begin);
if (!LLVMBuildRetVoid(comp_ctx->builder)) {
aot_set_last_error("llvm build ret failed.");
goto fail;
}
}
fail: fail:
wasm_runtime_free(param_types); wasm_runtime_free(param_types);
return func; return func;
@ -646,11 +677,7 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx,
memset(func_ctx, 0, (uint32)size); memset(func_ctx, 0, (uint32)size);
func_ctx->aot_func = func; func_ctx->aot_func = func;
#if WASM_ENABLE_LAZY_JIT == 0
func_ctx->module = comp_ctx->module; func_ctx->module = comp_ctx->module;
#else
func_ctx->module = comp_ctx->modules[func_index];
#endif
/* Add LLVM function */ /* Add LLVM function */
if (!(func_ctx->func = if (!(func_ctx->func =
@ -1244,16 +1271,6 @@ get_target_arch_from_triple(const char *triple, char *arch_buf, uint32 buf_size)
bh_assert(*triple == '-' || *triple == '\0'); bh_assert(*triple == '-' || *triple == '\0');
} }
LLVMBool
WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT,
LLVMModuleRef M,
struct LLVMMCJITCompilerOptions *Options,
size_t SizeOfOptions, char **OutError);
void
LLVMAddPromoteMemoryToRegisterPass(LLVMPassManagerRef PM);
#if WASM_ENABLE_LAZY_JIT != 0
void void
aot_handle_llvm_errmsg(const char *string, LLVMErrorRef err) aot_handle_llvm_errmsg(const char *string, LLVMErrorRef err)
{ {
@ -1262,41 +1279,67 @@ aot_handle_llvm_errmsg(const char *string, LLVMErrorRef err)
LLVMDisposeErrorMessage(err_msg); LLVMDisposeErrorMessage(err_msg);
} }
static bool #ifndef NDEBUG
orc_lazyjit_create(AOTCompContext *comp_ctx, uint32 func_count) static LLVMErrorRef
run_pass(void *ctx, LLVMModuleRef module)
{ {
uint32 i; /*AOTCompContext *comp_ctx = (AOTCompContext *)ctx;*/
size_t len;
LOG_VERBOSE("--- In IRTransformLayer @ T#%ld---",
LLVMGetModuleIdentifier(module, &len), pthread_self());
/* TODO: enable this for JIT mode after fixing LLVM issues */
/*aot_apply_llvm_new_pass_manager(comp_ctx, module);*/
bh_print_time("Begin to generate machine code");
return LLVMErrorSuccess;
}
static LLVMErrorRef
do_ir_transform(void *ctx, LLVMOrcThreadSafeModuleRef *module,
LLVMOrcMaterializationResponsibilityRef mr)
{
(void)mr;
return LLVMOrcThreadSafeModuleWithModuleDo(*module, run_pass, ctx);
}
static LLVMErrorRef
do_obj_transform(void *Ctx, LLVMMemoryBufferRef *ObjInOut)
{
bh_print_time("Finish generating machine code");
LOG_VERBOSE("--- In ObjectTransformLayer @ T#%ld ---", pthread_self());
(void)Ctx;
(void)ObjInOut;
return LLVMErrorSuccess;
}
#endif
static bool
create_target_machine_detect_host(AOTCompContext *comp_ctx)
{
char *triple = NULL;
LLVMTargetRef target = NULL;
char *err_msg = NULL; char *err_msg = NULL;
char *cpu = NULL; char *cpu = NULL;
char *features = NULL; char *features = NULL;
char *llvm_triple = NULL; LLVMTargetMachineRef target_machine = NULL;
char func_name[32] = { 0 }; bool ret = false;
LLVMErrorRef err;
LLVMTargetRef llvm_targetref = NULL;
LLVMTargetMachineRef target_machine_for_orcjit = NULL;
LLVMOrcLLJITRef orc_lazyjit = NULL;
LLVMOrcJITTargetMachineBuilderRef target_machine_builder = NULL;
LLVMOrcLLJITBuilderRef orc_lazyjit_builder = NULL;
LLVMOrcMaterializationUnitRef orc_material_unit = NULL;
LLVMOrcExecutionSessionRef orc_execution_session = NULL;
LLVMOrcLazyCallThroughManagerRef orc_call_through_mgr = NULL;
LLVMOrcIndirectStubsManagerRef orc_indirect_stub_mgr = NULL;
LLVMOrcCSymbolAliasMapPair *orc_symbol_map_pairs = NULL;
llvm_triple = LLVMGetDefaultTargetTriple(); triple = LLVMGetDefaultTargetTriple();
if (llvm_triple == NULL) { if (triple == NULL) {
aot_set_last_error("failed to get default target triple."); aot_set_last_error("failed to get default target triple.");
goto fail; goto fail;
} }
if (LLVMGetTargetFromTriple(llvm_triple, &llvm_targetref, &err_msg) != 0) { if (LLVMGetTargetFromTriple(triple, &target, &err_msg) != 0) {
aot_set_last_error_v("failed to get llvm target from triple %s.", aot_set_last_error_v("failed to get llvm target from triple %s.",
err_msg); err_msg);
LLVMDisposeMessage(err_msg); LLVMDisposeMessage(err_msg);
goto fail; goto fail;
} }
if (!LLVMTargetHasJIT(llvm_targetref)) { if (!LLVMTargetHasJIT(target)) {
aot_set_last_error("unspported JIT on this platform."); aot_set_last_error("unspported JIT on this platform.");
goto fail; goto fail;
} }
@ -1316,161 +1359,98 @@ orc_lazyjit_create(AOTCompContext *comp_ctx, uint32 func_count)
LOG_VERBOSE("LLVM ORCJIT detected CPU \"%s\", with features \"%s\"\n", cpu, LOG_VERBOSE("LLVM ORCJIT detected CPU \"%s\", with features \"%s\"\n", cpu,
features); features);
comp_ctx->target_machine = LLVMCreateTargetMachine( /* create TargetMachine */
llvm_targetref, llvm_triple, cpu, features, LLVMCodeGenLevelDefault, target_machine = LLVMCreateTargetMachine(
target, triple, cpu, features, LLVMCodeGenLevelDefault,
LLVMRelocDefault, LLVMCodeModelJITDefault); LLVMRelocDefault, LLVMCodeModelJITDefault);
if (!comp_ctx->target_machine) { if (!target_machine) {
aot_set_last_error("failed to create target machine."); aot_set_last_error("failed to create target machine.");
goto fail; goto fail;
} }
comp_ctx->target_machine = target_machine;
target_machine_for_orcjit = LLVMCreateTargetMachine( /* Save target arch */
llvm_targetref, llvm_triple, cpu, features, LLVMCodeGenLevelDefault, get_target_arch_from_triple(triple, comp_ctx->target_arch,
LLVMRelocDefault, LLVMCodeModelJITDefault); sizeof(comp_ctx->target_arch));
if (!target_machine_for_orcjit) { ret = true;
aot_set_last_error("failed to create target machine.");
goto fail;
}
target_machine_builder =
LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(
target_machine_for_orcjit);
if (!target_machine_builder) {
aot_set_last_error("failed to create target machine builder.");
goto fail;
}
/* The target_machine_for_orcjit has been disposed before
LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine() returns */
target_machine_for_orcjit = NULL;
orc_lazyjit_builder = LLVMOrcCreateLLJITBuilder();
if (!orc_lazyjit_builder) {
aot_set_last_error("failed to create lazy jit builder.");
goto fail;
}
LLVMOrcLLJITBuilderSetNumCompileThreads(orc_lazyjit_builder,
WASM_LAZY_JIT_COMPILE_THREAD_NUM);
LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(orc_lazyjit_builder,
target_machine_builder);
/* Should not dispose of the JITTargetMachineBuilder after calling
LLVMOrcLLJITBuilderSetJITTargetMachineBuilder() */
target_machine_builder = NULL;
err = LLVMOrcCreateLLJIT(&orc_lazyjit, orc_lazyjit_builder);
if (err) {
aot_handle_llvm_errmsg("failed to create llvm lazy orcjit instance",
err);
goto fail;
}
/* The orc_lazyjit_builder is managed by orc_lazyjit after calling
LLVMOrcCreateLLJIT(), here we should not dispose it again */
orc_lazyjit_builder = NULL;
if (func_count > 0) {
orc_execution_session = LLVMOrcLLJITGetExecutionSession(orc_lazyjit);
if (!orc_execution_session) {
aot_set_last_error("failed to get orc execution session");
goto fail;
}
err = LLVMOrcCreateLocalLazyCallThroughManager(
llvm_triple, orc_execution_session, 0, &orc_call_through_mgr);
if (err) {
aot_handle_llvm_errmsg("failed to create orc call through manager",
err);
goto fail;
}
orc_indirect_stub_mgr =
LLVMOrcCreateLocalIndirectStubsManager(llvm_triple);
if (!orc_indirect_stub_mgr) {
aot_set_last_error("failed to create orc indirect stub manager");
goto fail;
}
if (!(orc_symbol_map_pairs = wasm_runtime_malloc(
sizeof(LLVMOrcCSymbolAliasMapPair) * func_count))) {
aot_set_last_error("failed to allocate memory");
goto fail;
}
memset(orc_symbol_map_pairs, 0,
sizeof(LLVMOrcCSymbolAliasMapPair) * func_count);
for (i = 0; i < func_count; i++) {
snprintf(func_name, sizeof(func_name), "orcjit_%s%d",
AOT_FUNC_PREFIX, i);
orc_symbol_map_pairs[i].Name =
LLVMOrcExecutionSessionIntern(orc_execution_session, func_name);
snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i);
orc_symbol_map_pairs[i].Entry.Name =
LLVMOrcExecutionSessionIntern(orc_execution_session, func_name);
orc_symbol_map_pairs[i].Entry.Flags.GenericFlags =
LLVMJITSymbolGenericFlagsExported
| LLVMJITSymbolGenericFlagsCallable;
orc_symbol_map_pairs[i].Entry.Flags.TargetFlags =
LLVMJITSymbolGenericFlagsExported
| LLVMJITSymbolGenericFlagsCallable;
if (!orc_symbol_map_pairs[i].Name
|| !orc_symbol_map_pairs[i].Entry.Name) {
aot_set_last_error("failed to allocate memory");
goto fail;
}
}
orc_material_unit =
LLVMOrcLazyReexports(orc_call_through_mgr, orc_indirect_stub_mgr,
LLVMOrcLLJITGetMainJITDylib(orc_lazyjit),
orc_symbol_map_pairs, func_count);
if (!orc_material_unit) {
aot_set_last_error("failed to orc re-exports");
goto fail;
}
}
comp_ctx->orc_lazyjit = orc_lazyjit;
comp_ctx->orc_material_unit = orc_material_unit;
comp_ctx->orc_symbol_map_pairs = orc_symbol_map_pairs;
comp_ctx->orc_call_through_mgr = orc_call_through_mgr;
comp_ctx->orc_indirect_stub_mgr = orc_indirect_stub_mgr;
LLVMDisposeMessage(llvm_triple);
LLVMDisposeMessage(cpu);
LLVMDisposeMessage(features);
return true;
fail: fail:
if (orc_symbol_map_pairs) if (triple)
wasm_runtime_free(orc_symbol_map_pairs); LLVMDisposeMessage(triple);
if (orc_call_through_mgr)
LLVMOrcDisposeLazyCallThroughManager(orc_call_through_mgr);
if (orc_indirect_stub_mgr)
LLVMOrcDisposeIndirectStubsManager(orc_indirect_stub_mgr);
if (orc_lazyjit)
LLVMOrcDisposeLLJIT(orc_lazyjit);
if (target_machine_builder)
LLVMOrcDisposeJITTargetMachineBuilder(target_machine_builder);
if (orc_lazyjit_builder)
LLVMOrcDisposeLLJITBuilder(orc_lazyjit_builder);
if (target_machine_for_orcjit)
LLVMDisposeTargetMachine(target_machine_for_orcjit);
if (features) if (features)
LLVMDisposeMessage(features); LLVMDisposeMessage(features);
if (cpu) if (cpu)
LLVMDisposeMessage(cpu); LLVMDisposeMessage(cpu);
if (llvm_triple)
LLVMDisposeMessage(llvm_triple); return ret;
return false; }
static bool
orc_jit_create(AOTCompContext *comp_ctx)
{
LLVMErrorRef err;
LLVMOrcLLLazyJITRef orc_jit = NULL;
LLVMOrcLLLazyJITBuilderRef builder = NULL;
LLVMOrcJITTargetMachineBuilderRef jtmb = NULL;
bool ret = false;
builder = LLVMOrcCreateLLLazyJITBuilder();
if (builder == NULL) {
aot_set_last_error("failed to create jit builder.");
goto fail;
}
err = LLVMOrcJITTargetMachineBuilderDetectHost(&jtmb);
if (err != LLVMErrorSuccess) {
aot_handle_llvm_errmsg(
"quited to create LLVMOrcJITTargetMachineBuilderRef", err);
goto fail;
}
LLVMOrcLLLazyJITBuilderSetNumCompileThreads(
builder, WASM_ORC_JIT_COMPILE_THREAD_NUM);
/* Ownership transfer:
LLVMOrcJITTargetMachineBuilderRef -> LLVMOrcLLJITBuilderRef */
LLVMOrcLLLazyJITBuilderSetJITTargetMachineBuilder(builder, jtmb);
err = LLVMOrcCreateLLLazyJIT(&orc_jit, builder);
if (err != LLVMErrorSuccess) {
aot_handle_llvm_errmsg("quited to create llvm lazy orcjit instance",
err);
goto fail;
}
/* Ownership transfer: LLVMOrcLLJITBuilderRef -> LLVMOrcLLJITRef */
builder = NULL;
#ifndef NDEBUG
/* Setup TransformLayer */
LLVMOrcIRTransformLayerSetTransform(
LLVMOrcLLLazyJITGetIRTransformLayer(orc_jit), *do_ir_transform,
comp_ctx);
LLVMOrcObjectTransformLayerSetTransform(
LLVMOrcLLLazyJITGetObjTransformLayer(orc_jit), *do_obj_transform,
comp_ctx);
#endif
/* Ownership transfer: local -> AOTCompContext */
comp_ctx->orc_jit = orc_jit;
orc_jit = NULL;
ret = true;
fail:
if (builder)
LLVMOrcDisposeLLLazyJITBuilder(builder);
if (orc_jit)
LLVMOrcDisposeLLLazyJIT(orc_jit);
return ret;
} }
#endif /* WASM_ENABLE_LAZY_JIT != 0 */
AOTCompContext * AOTCompContext *
aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option)
{ {
AOTCompContext *comp_ctx, *ret = NULL; AOTCompContext *comp_ctx, *ret = NULL;
#if WASM_ENABLE_LAZY_JIT == 0
struct LLVMMCJITCompilerOptions jit_options;
#endif
LLVMTargetRef target; LLVMTargetRef target;
char *triple = NULL, *triple_norm, *arch, *abi; char *triple = NULL, *triple_norm, *arch, *abi;
char *cpu = NULL, *features, buf[128]; char *cpu = NULL, *features, buf[128];
@ -1483,18 +1463,13 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option)
LLVMTargetDataRef target_data_ref; LLVMTargetDataRef target_data_ref;
/* Initialize LLVM environment */ /* Initialize LLVM environment */
#if WASM_ENABLE_LAZY_JIT != 0
LLVMInitializeCore(LLVMGetGlobalPassRegistry()); LLVMInitializeCore(LLVMGetGlobalPassRegistry());
LLVMInitializeNativeTarget(); /* To all available target */
LLVMInitializeNativeAsmPrinter();
LLVMInitializeNativeAsmParser();
#else
LLVMInitializeAllTargetInfos(); LLVMInitializeAllTargetInfos();
LLVMInitializeAllTargets(); LLVMInitializeAllTargets();
LLVMInitializeAllTargetMCs(); LLVMInitializeAllTargetMCs();
LLVMInitializeAllAsmPrinters(); LLVMInitializeAllAsmPrinters();
LLVMLinkInMCJIT(); LLVMInitializeAllAsmParsers();
#endif
/* Allocate memory */ /* Allocate memory */
if (!(comp_ctx = wasm_runtime_malloc(sizeof(AOTCompContext)))) { if (!(comp_ctx = wasm_runtime_malloc(sizeof(AOTCompContext)))) {
@ -1506,7 +1481,6 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option)
comp_ctx->comp_data = comp_data; comp_ctx->comp_data = comp_data;
/* Create LLVM context, module and builder */ /* Create LLVM context, module and builder */
#if WASM_ENABLE_LAZY_JIT != 0
comp_ctx->orc_thread_safe_context = LLVMOrcCreateNewThreadSafeContext(); comp_ctx->orc_thread_safe_context = LLVMOrcCreateNewThreadSafeContext();
if (!comp_ctx->orc_thread_safe_context) { if (!comp_ctx->orc_thread_safe_context) {
aot_set_last_error("create LLVM ThreadSafeContext failed."); aot_set_last_error("create LLVM ThreadSafeContext failed.");
@ -1521,53 +1495,26 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option)
aot_set_last_error("get context from LLVM ThreadSafeContext failed."); aot_set_last_error("get context from LLVM ThreadSafeContext failed.");
goto fail; goto fail;
} }
#else
if (!(comp_ctx->context = LLVMContextCreate())) {
aot_set_last_error("create LLVM context failed.");
goto fail;
}
#endif
if (!(comp_ctx->builder = LLVMCreateBuilderInContext(comp_ctx->context))) { if (!(comp_ctx->builder = LLVMCreateBuilderInContext(comp_ctx->context))) {
aot_set_last_error("create LLVM builder failed."); aot_set_last_error("create LLVM builder failed.");
goto fail; goto fail;
} }
#if WASM_ENABLE_LAZY_JIT == 0 /* Create LLVM module for each jit function, note:
different from non ORC JIT mode, no need to dispose it,
it will be disposed when the thread safe context is disposed */
if (!(comp_ctx->module = LLVMModuleCreateWithNameInContext( if (!(comp_ctx->module = LLVMModuleCreateWithNameInContext(
"WASM Module", comp_ctx->context))) { "WASM Module", comp_ctx->context))) {
aot_set_last_error("create LLVM module failed."); aot_set_last_error("create LLVM module failed.");
goto fail; goto fail;
} }
#else
if (comp_data->func_count > 0) {
if (!(comp_ctx->modules = wasm_runtime_malloc(
sizeof(LLVMModuleRef) * comp_data->func_count))) {
aot_set_last_error("allocate memory failed.");
goto fail;
}
memset(comp_ctx->modules, 0,
sizeof(LLVMModuleRef) * comp_data->func_count);
for (i = 0; i < comp_data->func_count; i++) {
char module_name[32];
snprintf(module_name, sizeof(module_name), "WASM Module %d", i);
/* Create individual modules for each aot function, note:
different from non LAZY JIT mode, no need to dispose them,
they will be disposed when the thread safe context is disposed */
if (!(comp_ctx->modules[i] = LLVMModuleCreateWithNameInContext(
module_name, comp_ctx->context))) {
aot_set_last_error("create LLVM module failed.");
goto fail;
}
}
}
#endif
if (BH_LIST_ERROR == bh_list_init(&comp_ctx->native_symbols)) { if (BH_LIST_ERROR == bh_list_init(&comp_ctx->native_symbols)) {
goto fail; goto fail;
} }
#if WASM_ENABLE_DEBUG_AOT != 0 && WASM_ENABLE_LAZY_JIT == 0 #if WASM_ENABLE_DEBUG_AOT != 0
if (!(comp_ctx->debug_builder = LLVMCreateDIBuilder(comp_ctx->module))) { if (!(comp_ctx->debug_builder = LLVMCreateDIBuilder(comp_ctx->module))) {
aot_set_last_error("create LLVM Debug Infor builder failed."); aot_set_last_error("create LLVM Debug Infor builder failed.");
goto fail; goto fail;
@ -1624,65 +1571,21 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option)
comp_ctx->custom_sections_count = option->custom_sections_count; comp_ctx->custom_sections_count = option->custom_sections_count;
if (option->is_jit_mode) { if (option->is_jit_mode) {
char *triple_jit = NULL;
comp_ctx->is_jit_mode = true; comp_ctx->is_jit_mode = true;
#if WASM_ENABLE_LAZY_JIT != 0 /* Create TargetMachine */
/* Create LLJIT Instance */ if (!create_target_machine_detect_host(comp_ctx))
if (!orc_lazyjit_create(comp_ctx, comp_data->func_count)) {
goto fail; goto fail;
}
#else /* Create LLJIT Instance */
/* Create LLVM execution engine */ if (!orc_jit_create(comp_ctx))
LLVMInitializeMCJITCompilerOptions(&jit_options, sizeof(jit_options));
jit_options.OptLevel = LLVMCodeGenLevelAggressive;
jit_options.EnableFastISel = true;
/*jit_options.CodeModel = LLVMCodeModelSmall;*/
if (WAMRCreateMCJITCompilerForModule(&comp_ctx->exec_engine,
comp_ctx->module, &jit_options,
sizeof(jit_options), &err)
!= 0) {
if (err) {
LLVMDisposeMessage(err);
err = NULL;
}
aot_set_last_error("create LLVM JIT compiler failed.");
goto fail; goto fail;
}
comp_ctx->target_machine =
LLVMGetExecutionEngineTargetMachine(comp_ctx->exec_engine);
#endif
#ifndef OS_ENABLE_HW_BOUND_CHECK #ifndef OS_ENABLE_HW_BOUND_CHECK
comp_ctx->enable_bound_check = true; comp_ctx->enable_bound_check = true;
#else #else
comp_ctx->enable_bound_check = false; comp_ctx->enable_bound_check = false;
#endif #endif
#if WASM_ENABLE_LAZY_JIT != 0
if (!(triple_jit =
(char *)LLVMOrcLLJITGetTripleString(comp_ctx->orc_lazyjit))) {
aot_set_last_error("can not get triple from the target machine");
goto fail;
}
/* Save target arch */
get_target_arch_from_triple(triple_jit, comp_ctx->target_arch,
sizeof(comp_ctx->target_arch));
#else
if (!(triple_jit =
LLVMGetTargetMachineTriple(comp_ctx->target_machine))) {
aot_set_last_error("can not get triple from the target machine");
goto fail;
}
/* Save target arch */
get_target_arch_from_triple(triple_jit, comp_ctx->target_arch,
sizeof(comp_ctx->target_arch));
LLVMDisposeMessage(triple_jit);
#endif
} }
else { else {
/* Create LLVM target machine */ /* Create LLVM target machine */
@ -1942,17 +1845,9 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option)
aot_set_last_error("create metadata string failed."); aot_set_last_error("create metadata string failed.");
goto fail; goto fail;
} }
#if WASM_ENABLE_LAZY_JIT == 0
LLVMAddModuleFlag(comp_ctx->module, LLVMModuleFlagBehaviorError, LLVMAddModuleFlag(comp_ctx->module, LLVMModuleFlagBehaviorError,
"target-abi", strlen("target-abi"), "target-abi", strlen("target-abi"),
meta_target_abi); meta_target_abi);
#else
for (i = 0; i < comp_data->func_count; i++) {
LLVMAddModuleFlag(comp_ctx->modules[i],
LLVMModuleFlagBehaviorError, "target-abi",
strlen("target-abi"), meta_target_abi);
}
#endif
if (!strcmp(abi, "lp64d") || !strcmp(abi, "ilp32d")) { if (!strcmp(abi, "lp64d") || !strcmp(abi, "ilp32d")) {
if (features) { if (features) {
@ -2059,10 +1954,6 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option)
aot_set_last_error("create LLVM target machine failed."); aot_set_last_error("create LLVM target machine failed.");
goto fail; goto fail;
} }
#if WASM_ENABLE_LAZY_JIT == 0
LLVMSetTarget(comp_ctx->module, triple_norm);
#endif
} }
if (option->enable_simd && strcmp(comp_ctx->target_arch, "x86_64") != 0 if (option->enable_simd && strcmp(comp_ctx->target_arch, "x86_64") != 0
@ -2171,56 +2062,23 @@ aot_destroy_comp_context(AOTCompContext *comp_ctx)
if (!comp_ctx) if (!comp_ctx)
return; return;
#if WASM_ENABLE_LAZY_JIT != 0
if (comp_ctx->orc_symbol_map_pairs)
wasm_runtime_free(comp_ctx->orc_symbol_map_pairs);
if (comp_ctx->orc_call_through_mgr)
LLVMOrcDisposeLazyCallThroughManager(comp_ctx->orc_call_through_mgr);
if (comp_ctx->orc_indirect_stub_mgr)
LLVMOrcDisposeIndirectStubsManager(comp_ctx->orc_indirect_stub_mgr);
if (comp_ctx->orc_material_unit)
LLVMOrcDisposeMaterializationUnit(comp_ctx->orc_material_unit);
if (comp_ctx->target_machine) if (comp_ctx->target_machine)
LLVMDisposeTargetMachine(comp_ctx->target_machine); LLVMDisposeTargetMachine(comp_ctx->target_machine);
if (comp_ctx->builder) if (comp_ctx->builder)
LLVMDisposeBuilder(comp_ctx->builder); LLVMDisposeBuilder(comp_ctx->builder);
if (comp_ctx->orc_lazyjit)
LLVMOrcDisposeLLJIT(comp_ctx->orc_lazyjit);
if (comp_ctx->orc_thread_safe_context) if (comp_ctx->orc_thread_safe_context)
LLVMOrcDisposeThreadSafeContext(comp_ctx->orc_thread_safe_context); LLVMOrcDisposeThreadSafeContext(comp_ctx->orc_thread_safe_context);
if (comp_ctx->modules) /* Note: don't dispose comp_ctx->context and comp_ctx->module as
wasm_runtime_free(comp_ctx->modules);
/* Note: don't dispose comp_ctx->context and comp_ctx->modules[i] as
they are disposed when disposing the thread safe context */ they are disposed when disposing the thread safe context */
/* Has to be the last one */
if (comp_ctx->orc_jit)
LLVMOrcDisposeLLLazyJIT(comp_ctx->orc_jit);
LLVMShutdown(); LLVMShutdown();
#else
if (comp_ctx->target_machine && !comp_ctx->is_jit_mode)
LLVMDisposeTargetMachine(comp_ctx->target_machine);
if (comp_ctx->builder)
LLVMDisposeBuilder(comp_ctx->builder);
if (comp_ctx->exec_engine) {
LLVMDisposeExecutionEngine(comp_ctx->exec_engine);
/* The LLVM module is freed when disposing execution engine,
no need to dispose it again. */
}
else if (comp_ctx->module)
LLVMDisposeModule(comp_ctx->module);
if (comp_ctx->context)
LLVMContextDispose(comp_ctx->context);
#endif
if (comp_ctx->func_ctxes) if (comp_ctx->func_ctxes)
aot_destroy_func_contexts(comp_ctx->func_ctxes, aot_destroy_func_contexts(comp_ctx->func_ctxes,

View File

@ -20,20 +20,18 @@
#include "llvm-c/Transforms/Vectorize.h" #include "llvm-c/Transforms/Vectorize.h"
#include "llvm-c/Transforms/PassManagerBuilder.h" #include "llvm-c/Transforms/PassManagerBuilder.h"
#if WASM_ENABLE_LAZY_JIT != 0
#include "llvm-c/Orc.h" #include "llvm-c/Orc.h"
#include "llvm-c/Error.h" #include "llvm-c/Error.h"
#include "llvm-c/Support.h" #include "llvm-c/Support.h"
#include "llvm-c/Initialization.h" #include "llvm-c/Initialization.h"
#include "llvm-c/TargetMachine.h" #include "llvm-c/TargetMachine.h"
#if LLVM_VERSION_MAJOR >= 12
#include "llvm-c/LLJIT.h" #include "llvm-c/LLJIT.h"
#endif
#endif
#if WASM_ENABLE_DEBUG_AOT != 0 #if WASM_ENABLE_DEBUG_AOT != 0
#include "llvm-c/DebugInfo.h" #include "llvm-c/DebugInfo.h"
#endif #endif
#include "aot_orc_extra.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -52,6 +50,16 @@ extern "C" {
#define OPQ_PTR_TYPE INT8_PTR_TYPE #define OPQ_PTR_TYPE INT8_PTR_TYPE
#endif #endif
#ifndef NDEBUG
#undef DEBUG_PASS
#undef DUMP_MODULE
// #define DEBUG_PASS
// #define DUMP_MODULE
#else
#undef DEBUG_PASS
#undef DUMP_MODULE
#endif
/** /**
* Value in the WASM operation stack, each stack element * Value in the WASM operation stack, each stack element
* is an LLVM value * is an LLVM value
@ -270,12 +278,6 @@ typedef struct AOTCompContext {
/* LLVM variables required to emit LLVM IR */ /* LLVM variables required to emit LLVM IR */
LLVMContextRef context; LLVMContextRef context;
#if WASM_ENABLE_LAZY_JIT == 0
/* Create one module only for non LAZY JIT mode,
for LAZY JIT mode, modules are created, each
aot function has its own module */
LLVMModuleRef module;
#endif
LLVMBuilderRef builder; LLVMBuilderRef builder;
#if WASM_ENABLE_DEBUG_AOT #if WASM_ENABLE_DEBUG_AOT
LLVMDIBuilderRef debug_builder; LLVMDIBuilderRef debug_builder;
@ -290,19 +292,11 @@ typedef struct AOTCompContext {
/* Hardware intrinsic compability flags */ /* Hardware intrinsic compability flags */
uint64 flags[8]; uint64 flags[8];
/* LLVM execution engine required by JIT */ /* required by JIT */
#if WASM_ENABLE_LAZY_JIT != 0 LLVMOrcLLLazyJITRef orc_jit;
LLVMOrcLLJITRef orc_lazyjit;
LLVMOrcMaterializationUnitRef orc_material_unit;
LLVMOrcLazyCallThroughManagerRef orc_call_through_mgr;
LLVMOrcIndirectStubsManagerRef orc_indirect_stub_mgr;
LLVMOrcCSymbolAliasMapPairs orc_symbol_map_pairs;
LLVMOrcThreadSafeContextRef orc_thread_safe_context; LLVMOrcThreadSafeContextRef orc_thread_safe_context;
/* Each aot function has its own module */
LLVMModuleRef *modules; LLVMModuleRef module;
#else
LLVMExecutionEngineRef exec_engine;
#endif
bool is_jit_mode; bool is_jit_mode;
@ -361,6 +355,7 @@ typedef struct AOTCompContext {
AOTLLVMConsts llvm_consts; AOTLLVMConsts llvm_consts;
/* Function contexts */ /* Function contexts */
/* TODO: */
AOTFuncContext **func_ctxes; AOTFuncContext **func_ctxes;
uint32 func_ctx_count; uint32 func_ctx_count;
char **custom_sections_wp; char **custom_sections_wp;
@ -503,24 +498,11 @@ void
aot_add_simple_loop_unswitch_pass(LLVMPassManagerRef pass); aot_add_simple_loop_unswitch_pass(LLVMPassManagerRef pass);
void void
aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx); aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module);
#if WASM_ENABLE_LAZY_JIT != 0
LLVMOrcJITTargetMachineBuilderRef
LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(LLVMTargetMachineRef TM);
void
LLVMOrcLLJITBuilderSetNumCompileThreads(LLVMOrcLLJITBuilderRef orcjit_builder,
unsigned num_compile_threads);
void void
aot_handle_llvm_errmsg(const char *string, LLVMErrorRef err); aot_handle_llvm_errmsg(const char *string, LLVMErrorRef err);
void *
aot_lookup_orcjit_func(LLVMOrcLLJITRef orc_lazyjit, void *module_inst,
uint32 func_idx);
#endif
#ifdef __cplusplus #ifdef __cplusplus
} /* end of extern "C" */ } /* end of extern "C" */
#endif #endif

View File

@ -3,6 +3,8 @@
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/ */
#include <llvm/Passes/StandardInstrumentations.h>
#include <llvm/Support/Error.h>
#include <llvm/ADT/SmallVector.h> #include <llvm/ADT/SmallVector.h>
#include <llvm/ADT/Twine.h> #include <llvm/ADT/Twine.h>
#include <llvm/ADT/Triple.h> #include <llvm/ADT/Triple.h>
@ -42,23 +44,15 @@
#if LLVM_VERSION_MAJOR >= 12 #if LLVM_VERSION_MAJOR >= 12
#include <llvm/Analysis/AliasAnalysis.h> #include <llvm/Analysis/AliasAnalysis.h>
#endif #endif
#include <cstring>
#if WASM_ENABLE_LAZY_JIT != 0
#include "../aot/aot_runtime.h"
#endif
#include <cstring>
#include "../aot/aot_runtime.h"
#include "aot_llvm.h" #include "aot_llvm.h"
using namespace llvm; using namespace llvm;
using namespace llvm::orc; using namespace llvm::orc;
extern "C" { LLVM_C_EXTERN_C_BEGIN
LLVMBool
WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT,
LLVMModuleRef M,
LLVMMCJITCompilerOptions *PassedOptions,
size_t SizeOfPassedOptions, char **OutError);
bool bool
aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str); aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str);
@ -70,93 +64,11 @@ void
aot_add_simple_loop_unswitch_pass(LLVMPassManagerRef pass); aot_add_simple_loop_unswitch_pass(LLVMPassManagerRef pass);
void void
aot_func_disable_tce(LLVMValueRef func); aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module);
void LLVM_C_EXTERN_C_END
aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx);
}
static TargetMachine * ExitOnError ExitOnErr;
unwrap(LLVMTargetMachineRef P)
{
return reinterpret_cast<TargetMachine *>(P);
}
LLVMBool
WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT,
LLVMModuleRef M,
LLVMMCJITCompilerOptions *PassedOptions,
size_t SizeOfPassedOptions, char **OutError)
{
LLVMMCJITCompilerOptions options;
// If the user passed a larger sized options struct, then they were compiled
// against a newer LLVM. Tell them that something is wrong.
if (SizeOfPassedOptions > sizeof(options)) {
*OutError = strdup("Refusing to use options struct that is larger than "
"my own; assuming LLVM library mismatch.");
return 1;
}
// Defend against the user having an old version of the API by ensuring that
// any fields they didn't see are cleared. We must defend against fields
// being set to the bitwise equivalent of zero, and assume that this means
// "do the default" as if that option hadn't been available.
LLVMInitializeMCJITCompilerOptions(&options, sizeof(options));
memcpy(&options, PassedOptions, SizeOfPassedOptions);
TargetOptions targetOptions;
targetOptions.EnableFastISel = options.EnableFastISel;
std::unique_ptr<Module> Mod(unwrap(M));
if (Mod) {
// Set function attribute "frame-pointer" based on
// NoFramePointerElim.
for (auto &F : *Mod) {
auto Attrs = F.getAttributes();
StringRef Value = options.NoFramePointerElim ? "all" : "none";
#if LLVM_VERSION_MAJOR <= 13
Attrs =
Attrs.addAttribute(F.getContext(), AttributeList::FunctionIndex,
"frame-pointer", Value);
#else
Attrs = Attrs.addAttributeAtIndex(F.getContext(),
AttributeList::FunctionIndex,
"frame-pointer", Value);
#endif
F.setAttributes(Attrs);
}
}
std::string Error;
bool JIT;
char *host_cpu = LLVMGetHostCPUName();
if (!host_cpu) {
*OutError = NULL;
return false;
}
std::string mcpu(host_cpu);
LLVMDisposeMessage(host_cpu);
EngineBuilder builder(std::move(Mod));
builder.setEngineKind(EngineKind::JIT)
.setErrorStr(&Error)
.setMCPU(mcpu)
.setOptLevel((CodeGenOpt::Level)options.OptLevel)
.setTargetOptions(targetOptions);
if (Optional<CodeModel::Model> CM = unwrap(options.CodeModel, JIT))
builder.setCodeModel(*CM);
if (options.MCJMM)
builder.setMCJITMemoryManager(
std::unique_ptr<RTDyldMemoryManager>(unwrap(options.MCJMM)));
if (ExecutionEngine *JIT = builder.create()) {
*OutJIT = wrap(JIT);
return 0;
}
*OutError = strdup(Error.c_str());
return 1;
}
class ExpandMemoryOpPass : public llvm::ModulePass class ExpandMemoryOpPass : public llvm::ModulePass
{ {
@ -258,13 +170,15 @@ ExpandMemoryOpPass::runOnModule(Module &M)
void void
aot_add_expand_memory_op_pass(LLVMPassManagerRef pass) aot_add_expand_memory_op_pass(LLVMPassManagerRef pass)
{ {
unwrap(pass)->add(new ExpandMemoryOpPass()); reinterpret_cast<legacy::PassManager *>(pass)->add(
new ExpandMemoryOpPass());
} }
void void
aot_add_simple_loop_unswitch_pass(LLVMPassManagerRef pass) aot_add_simple_loop_unswitch_pass(LLVMPassManagerRef pass)
{ {
unwrap(pass)->add(createSimpleLoopUnswitchLegacyPass()); reinterpret_cast<legacy::PassManager *>(pass)->add(
createSimpleLoopUnswitchLegacyPass());
} }
bool bool
@ -308,123 +222,54 @@ aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str)
#endif /* WASM_ENABLE_SIMD */ #endif /* WASM_ENABLE_SIMD */
} }
#if WASM_ENABLE_LAZY_JIT != 0
#if LLVM_VERSION_MAJOR < 12
LLVMOrcJITTargetMachineBuilderRef
LLVMOrcJITTargetMachineBuilderFromTargetMachine(LLVMTargetMachineRef TM);
LLVMOrcJITTargetMachineBuilderRef
LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(LLVMTargetMachineRef TM)
{
return LLVMOrcJITTargetMachineBuilderFromTargetMachine(TM);
}
#endif
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLJITBuilder, LLVMOrcLLJITBuilderRef)
void void
LLVMOrcLLJITBuilderSetNumCompileThreads(LLVMOrcLLJITBuilderRef orcjit_builder, aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module)
unsigned num_compile_threads)
{ {
unwrap(orcjit_builder)->setNumCompileThreads(num_compile_threads); TargetMachine *TM =
} reinterpret_cast<TargetMachine *>(comp_ctx->target_machine);
void *
aot_lookup_orcjit_func(LLVMOrcLLJITRef orc_lazyjit, void *module_inst,
uint32 func_idx)
{
char func_name[32], buf[128], *err_msg = NULL;
LLVMErrorRef error;
LLVMOrcJITTargetAddress func_addr = 0;
AOTModuleInstance *aot_inst = (AOTModuleInstance *)module_inst;
AOTModule *aot_module = (AOTModule *)aot_inst->module;
void **func_ptrs = aot_inst->func_ptrs;
/**
* No need to lock the func_ptr[func_idx] here as it is basic
* data type, the load/store for it can be finished by one cpu
* instruction, and there can be only one cpu instruction
* loading/storing at the same time.
*/
if (func_ptrs[func_idx])
return func_ptrs[func_idx];
snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX,
func_idx - aot_module->import_func_count);
if ((error = LLVMOrcLLJITLookup(orc_lazyjit, &func_addr, func_name))) {
err_msg = LLVMGetErrorMessage(error);
snprintf(buf, sizeof(buf), "failed to lookup orcjit function: %s",
err_msg);
aot_set_exception(aot_inst, buf);
LLVMDisposeErrorMessage(err_msg);
return NULL;
}
func_ptrs[func_idx] = (void *)func_addr;
return (void *)func_addr;
}
#endif /* end of WASM_ENABLE_LAZY_JIT != 0 */
void
aot_func_disable_tce(LLVMValueRef func)
{
Function *F = unwrap<Function>(func);
auto Attrs = F->getAttributes();
#if LLVM_VERSION_MAJOR <= 13
Attrs = Attrs.addAttribute(F->getContext(), AttributeList::FunctionIndex,
"disable-tail-calls", "true");
#else
Attrs =
Attrs.addAttributeAtIndex(F->getContext(), AttributeList::FunctionIndex,
"disable-tail-calls", "true");
#endif
F->setAttributes(Attrs);
}
#if LLVM_VERSION_MAJOR >= 12
void
aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx)
{
Module *M;
TargetMachine *TM = unwrap(comp_ctx->target_machine);
bool disable_llvm_lto = false;
LoopAnalysisManager LAM;
FunctionAnalysisManager FAM;
CGSCCAnalysisManager CGAM;
ModuleAnalysisManager MAM;
PipelineTuningOptions PTO; PipelineTuningOptions PTO;
PTO.LoopVectorization = true; PTO.LoopVectorization = true;
PTO.SLPVectorization = true; PTO.SLPVectorization = true;
PTO.LoopUnrolling = true; PTO.LoopUnrolling = true;
#ifdef DEBUG_PASS
PassInstrumentationCallbacks PIC;
PassBuilder PB(TM, PTO, None, &PIC);
#else
#if LLVM_VERSION_MAJOR == 12 #if LLVM_VERSION_MAJOR == 12
PassBuilder PB(false, TM, PTO); PassBuilder PB(false, TM, PTO);
#else #else
PassBuilder PB(TM, PTO); PassBuilder PB(TM, PTO);
#endif
#endif #endif
// Register the target library analysis directly and give it a /* Register all the basic analyses with the managers */
// customized preset TLI. LoopAnalysisManager LAM;
FunctionAnalysisManager FAM;
CGSCCAnalysisManager CGAM;
ModuleAnalysisManager MAM;
/* Register the target library analysis directly and give it a
customized preset TLI */
std::unique_ptr<TargetLibraryInfoImpl> TLII( std::unique_ptr<TargetLibraryInfoImpl> TLII(
new TargetLibraryInfoImpl(Triple(TM->getTargetTriple()))); new TargetLibraryInfoImpl(Triple(TM->getTargetTriple())));
FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); }); FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
// Register the AA manager first so that our version is the one used. /* Register the AA manager first so that our version is the one used */
AAManager AA = PB.buildDefaultAAPipeline(); AAManager AA = PB.buildDefaultAAPipeline();
FAM.registerPass([&] { return std::move(AA); }); FAM.registerPass([&] { return std::move(AA); });
// Register all the basic analyses with the managers. #ifdef DEBUG_PASS
PB.registerModuleAnalyses(MAM); StandardInstrumentations SI(true, false);
PB.registerCGSCCAnalyses(CGAM); SI.registerCallbacks(PIC, &FAM);
#endif
PB.registerFunctionAnalyses(FAM); PB.registerFunctionAnalyses(FAM);
PB.registerLoopAnalyses(LAM); PB.registerLoopAnalyses(LAM);
PB.registerModuleAnalyses(MAM);
PB.registerCGSCCAnalyses(CGAM);
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
ModulePassManager MPM;
#if LLVM_VERSION_MAJOR <= 13 #if LLVM_VERSION_MAJOR <= 13
PassBuilder::OptimizationLevel OL; PassBuilder::OptimizationLevel OL;
@ -463,25 +308,23 @@ aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx)
} }
#endif /* end of LLVM_VERSION_MAJOR */ #endif /* end of LLVM_VERSION_MAJOR */
if (comp_ctx->disable_llvm_lto) { bool disable_llvm_lto = comp_ctx->disable_llvm_lto;
disable_llvm_lto = true;
}
#if WASM_ENABLE_SPEC_TEST != 0 #if WASM_ENABLE_SPEC_TEST != 0
disable_llvm_lto = true; disable_llvm_lto = true;
#endif #endif
Module *M = reinterpret_cast<Module *>(module);
if (disable_llvm_lto) { if (disable_llvm_lto) {
uint32 i; for (Function &F : *M) {
F.addFnAttr("disable-tail-calls", "true");
for (i = 0; i < comp_ctx->func_ctx_count; i++) {
aot_func_disable_tce(comp_ctx->func_ctxes[i]->func);
} }
} }
ModulePassManager MPM;
if (comp_ctx->is_jit_mode) { if (comp_ctx->is_jit_mode) {
/* Apply normal pipeline for JIT mode, without const char *Passes =
Vectorize related passes, without LTO */ "mem2reg,instcombine,simplifycfg,jump-threading,indvars";
MPM.addPass(PB.buildPerModuleDefaultPipeline(OL)); ExitOnErr(PB.parsePassPipeline(MPM, Passes));
} }
else { else {
FunctionPassManager FPM; FunctionPassManager FPM;
@ -512,16 +355,5 @@ aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx)
} }
} }
#if WASM_ENABLE_LAZY_JIT == 0
M = unwrap(comp_ctx->module);
MPM.run(*M, MAM); MPM.run(*M, MAM);
#else
uint32 i;
for (i = 0; i < comp_ctx->func_ctx_count; i++) {
M = unwrap(comp_ctx->modules[i]);
MPM.run(*M, MAM);
}
#endif
} }
#endif /* end of LLVM_VERSION_MAJOR >= 12 */

View File

@ -0,0 +1,289 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "llvm-c/LLJIT.h"
#include "llvm-c/Orc.h"
#include "llvm-c/OrcEE.h"
#include "llvm-c/TargetMachine.h"
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/Support/CBindingWrapping.h"
#include "aot_orc_extra.h"
#include "aot.h"
using namespace llvm;
using namespace llvm::orc;
using GlobalValueSet = std::set<const GlobalValue *>;
namespace llvm {
namespace orc {
class InProgressLookupState;
class OrcV2CAPIHelper
{
public:
using PoolEntry = SymbolStringPtr::PoolEntry;
using PoolEntryPtr = SymbolStringPtr::PoolEntryPtr;
// Move from SymbolStringPtr to PoolEntryPtr (no change in ref count).
static PoolEntryPtr moveFromSymbolStringPtr(SymbolStringPtr S)
{
PoolEntryPtr Result = nullptr;
std::swap(Result, S.S);
return Result;
}
// Move from a PoolEntryPtr to a SymbolStringPtr (no change in ref count).
static SymbolStringPtr moveToSymbolStringPtr(PoolEntryPtr P)
{
SymbolStringPtr S;
S.S = P;
return S;
}
// Copy a pool entry to a SymbolStringPtr (increments ref count).
static SymbolStringPtr copyToSymbolStringPtr(PoolEntryPtr P)
{
return SymbolStringPtr(P);
}
static PoolEntryPtr getRawPoolEntryPtr(const SymbolStringPtr &S)
{
return S.S;
}
static void retainPoolEntry(PoolEntryPtr P)
{
SymbolStringPtr S(P);
S.S = nullptr;
}
static void releasePoolEntry(PoolEntryPtr P)
{
SymbolStringPtr S;
S.S = P;
}
static InProgressLookupState *extractLookupState(LookupState &LS)
{
return LS.IPLS.release();
}
static void resetLookupState(LookupState &LS, InProgressLookupState *IPLS)
{
return LS.reset(IPLS);
}
};
} // namespace orc
} // namespace llvm
// ORC.h
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ExecutionSession, LLVMOrcExecutionSessionRef)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(IRTransformLayer, LLVMOrcIRTransformLayerRef)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(JITDylib, LLVMOrcJITDylibRef)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(JITTargetMachineBuilder,
LLVMOrcJITTargetMachineBuilderRef)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ObjectTransformLayer,
LLVMOrcObjectTransformLayerRef)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(OrcV2CAPIHelper::PoolEntry,
LLVMOrcSymbolStringPoolEntryRef)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SymbolStringPool, LLVMOrcSymbolStringPoolRef)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThreadSafeModule, LLVMOrcThreadSafeModuleRef)
// LLJIT.h
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLJITBuilder, LLVMOrcLLJITBuilderRef)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLLazyJITBuilder, LLVMOrcLLLazyJITBuilderRef)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLLazyJIT, LLVMOrcLLLazyJITRef)
void
LLVMOrcLLJITBuilderSetNumCompileThreads(LLVMOrcLLJITBuilderRef Builder,
unsigned NumCompileThreads)
{
unwrap(Builder)->setNumCompileThreads(NumCompileThreads);
}
LLVMOrcLLLazyJITBuilderRef
LLVMOrcCreateLLLazyJITBuilder(void)
{
return wrap(new LLLazyJITBuilder());
}
void
LLVMOrcDisposeLLLazyJITBuilder(LLVMOrcLLLazyJITBuilderRef Builder)
{
delete unwrap(Builder);
}
void
LLVMOrcLLLazyJITBuilderSetNumCompileThreads(LLVMOrcLLLazyJITBuilderRef Builder,
unsigned NumCompileThreads)
{
unwrap(Builder)->setNumCompileThreads(NumCompileThreads);
}
void
LLVMOrcLLLazyJITBuilderSetJITTargetMachineBuilder(
LLVMOrcLLLazyJITBuilderRef Builder, LLVMOrcJITTargetMachineBuilderRef JTMP)
{
unwrap(Builder)->setJITTargetMachineBuilder(*unwrap(JTMP));
/* Destroy the JTMP, similar to
LLVMOrcLLJITBuilderSetJITTargetMachineBuilder */
LLVMOrcDisposeJITTargetMachineBuilder(JTMP);
}
static Optional<CompileOnDemandLayer::GlobalValueSet>
PartitionFunction(GlobalValueSet Requested)
{
std::vector<const GlobalValue *> GVsToAdd;
for (auto *GV : Requested) {
if (isa<Function>(GV) && GV->hasName()) {
auto &F = cast<Function>(*GV); /* get LLVM function */
const Module *M = F.getParent(); /* get LLVM module */
auto GVName = GV->getName(); /* get the function name */
const char *gvname = GVName.begin(); /* C function name */
const char *wrapper;
uint32 prefix_len = strlen(AOT_FUNC_PREFIX);
/* Convert "aot_func#n_wrapper" to "aot_func#n" */
if (strstr(gvname, AOT_FUNC_PREFIX)
&& (wrapper = strstr(gvname + prefix_len, "_wrapper"))) {
char buf[16] = { 0 };
char func_name[64];
int group_stride, i, j;
bh_assert(wrapper - (gvname + prefix_len) > 0);
/* Get AOT function index */
bh_memcpy_s(buf, (uint32)sizeof(buf), gvname + prefix_len,
(uint32)(wrapper - (gvname + prefix_len)));
i = atoi(buf);
group_stride = WASM_ORC_JIT_BACKEND_THREAD_NUM;
/* Compile some functions each time */
for (j = 0; j < WASM_ORC_JIT_COMPILE_THREAD_NUM; j++) {
snprintf(func_name, sizeof(func_name), "%s%d",
AOT_FUNC_PREFIX, i + j * group_stride);
Function *F1 = M->getFunction(func_name);
if (F1) {
LOG_DEBUG("compile func %s", func_name);
GVsToAdd.push_back(cast<GlobalValue>(F1));
}
}
}
}
}
for (auto *GV : GVsToAdd) {
Requested.insert(GV);
}
return Requested;
}
LLVMErrorRef
LLVMOrcCreateLLLazyJIT(LLVMOrcLLLazyJITRef *Result,
LLVMOrcLLLazyJITBuilderRef Builder)
{
assert(Result && "Result can not be null");
if (!Builder)
Builder = LLVMOrcCreateLLLazyJITBuilder();
auto J = unwrap(Builder)->create();
LLVMOrcDisposeLLLazyJITBuilder(Builder);
if (!J) {
Result = nullptr;
return 0;
}
LLLazyJIT *lazy_jit = J->release();
lazy_jit->setPartitionFunction(PartitionFunction);
*Result = wrap(lazy_jit);
return LLVMErrorSuccess;
}
LLVMErrorRef
LLVMOrcDisposeLLLazyJIT(LLVMOrcLLLazyJITRef J)
{
delete unwrap(J);
return LLVMErrorSuccess;
}
LLVMErrorRef
LLVMOrcLLLazyJITAddLLVMIRModule(LLVMOrcLLLazyJITRef J, LLVMOrcJITDylibRef JD,
LLVMOrcThreadSafeModuleRef TSM)
{
std::unique_ptr<ThreadSafeModule> TmpTSM(unwrap(TSM));
return wrap(unwrap(J)->addLazyIRModule(*unwrap(JD), std::move(*TmpTSM)));
}
LLVMErrorRef
LLVMOrcLLLazyJITLookup(LLVMOrcLLLazyJITRef J, LLVMOrcExecutorAddress *Result,
const char *Name)
{
assert(Result && "Result can not be null");
auto Sym = unwrap(J)->lookup(Name);
if (!Sym) {
*Result = 0;
return wrap(Sym.takeError());
}
#if LLVM_VERSION_MAJOR < 15
*Result = Sym->getAddress();
#else
*Result = Sym->getValue();
#endif
return LLVMErrorSuccess;
}
LLVMOrcSymbolStringPoolEntryRef
LLVMOrcLLLazyJITMangleAndIntern(LLVMOrcLLLazyJITRef J,
const char *UnmangledName)
{
return wrap(OrcV2CAPIHelper::moveFromSymbolStringPtr(
unwrap(J)->mangleAndIntern(UnmangledName)));
}
LLVMOrcJITDylibRef
LLVMOrcLLLazyJITGetMainJITDylib(LLVMOrcLLLazyJITRef J)
{
return wrap(&unwrap(J)->getMainJITDylib());
}
const char *
LLVMOrcLLLazyJITGetTripleString(LLVMOrcLLLazyJITRef J)
{
return unwrap(J)->getTargetTriple().str().c_str();
}
LLVMOrcExecutionSessionRef
LLVMOrcLLLazyJITGetExecutionSession(LLVMOrcLLLazyJITRef J)
{
return wrap(&unwrap(J)->getExecutionSession());
}
LLVMOrcIRTransformLayerRef
LLVMOrcLLLazyJITGetIRTransformLayer(LLVMOrcLLLazyJITRef J)
{
return wrap(&unwrap(J)->getIRTransformLayer());
}
LLVMOrcObjectTransformLayerRef
LLVMOrcLLLazyJITGetObjTransformLayer(LLVMOrcLLLazyJITRef J)
{
return wrap(&unwrap(J)->getObjTransformLayer());
}

View File

@ -0,0 +1,75 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _AOT_ORC_LAZINESS_H_
#define _AOT_ORC_LAZINESS_H_
#include "llvm-c/Error.h"
#include "llvm-c/ExternC.h"
#include "llvm-c/LLJIT.h"
#include "llvm-c/Orc.h"
#include "llvm-c/Types.h"
LLVM_C_EXTERN_C_BEGIN
typedef struct LLVMOrcOpaqueLLLazyJITBuilder *LLVMOrcLLLazyJITBuilderRef;
typedef struct LLVMOrcOpaqueLLLazyJIT *LLVMOrcLLLazyJITRef;
// Extra bindings for LLJIT
void
LLVMOrcLLJITBuilderSetNumCompileThreads(LLVMOrcLLJITBuilderRef Builder,
unsigned NumCompileThreads);
// Extra bindings for LLLazyJIT
LLVMOrcLLLazyJITBuilderRef
LLVMOrcCreateLLLazyJITBuilder(void);
void
LLVMOrcDisposeLLLazyJITBuilder(LLVMOrcLLLazyJITBuilderRef Builder);
void
LLVMOrcLLLazyJITBuilderSetJITTargetMachineBuilder(
LLVMOrcLLLazyJITBuilderRef Builder, LLVMOrcJITTargetMachineBuilderRef JTMP);
void
LLVMOrcLLLazyJITBuilderSetNumCompileThreads(LLVMOrcLLLazyJITBuilderRef Builder,
unsigned NumCompileThreads);
LLVMErrorRef
LLVMOrcCreateLLLazyJIT(LLVMOrcLLLazyJITRef *Result,
LLVMOrcLLLazyJITBuilderRef Builder);
LLVMErrorRef
LLVMOrcDisposeLLLazyJIT(LLVMOrcLLLazyJITRef J);
LLVMErrorRef
LLVMOrcLLLazyJITAddLLVMIRModule(LLVMOrcLLLazyJITRef J, LLVMOrcJITDylibRef JD,
LLVMOrcThreadSafeModuleRef TSM);
LLVMErrorRef
LLVMOrcLLLazyJITLookup(LLVMOrcLLLazyJITRef J, LLVMOrcExecutorAddress *Result,
const char *Name);
LLVMOrcSymbolStringPoolEntryRef
LLVMOrcLLLazyJITMangleAndIntern(LLVMOrcLLLazyJITRef J,
const char *UnmangledName);
LLVMOrcJITDylibRef
LLVMOrcLLLazyJITGetMainJITDylib(LLVMOrcLLLazyJITRef J);
const char *
LLVMOrcLLLazyJITGetTripleString(LLVMOrcLLLazyJITRef J);
LLVMOrcExecutionSessionRef
LLVMOrcLLLazyJITGetExecutionSession(LLVMOrcLLLazyJITRef J);
LLVMOrcIRTransformLayerRef
LLVMOrcLLLazyJITGetIRTransformLayer(LLVMOrcLLLazyJITRef J);
LLVMOrcObjectTransformLayerRef
LLVMOrcLLLazyJITGetObjTransformLayer(LLVMOrcLLLazyJITRef J);
LLVM_C_EXTERN_C_END
#endif

View File

@ -369,6 +369,13 @@ typedef struct WASMCustomSection {
#if WASM_ENABLE_JIT != 0 #if WASM_ENABLE_JIT != 0
struct AOTCompData; struct AOTCompData;
struct AOTCompContext; struct AOTCompContext;
/* Orc JIT thread arguments */
typedef struct OrcJitThreadArg {
struct AOTCompContext *comp_ctx;
struct WASMModule *module;
uint32 group_idx;
} OrcJitThreadArg;
#endif #endif
struct WASMModule { struct WASMModule {
@ -501,14 +508,20 @@ struct WASMModule {
#endif #endif
#if WASM_ENABLE_FAST_JIT != 0 #if WASM_ENABLE_FAST_JIT != 0
/* point to JITed functions */ /* func pointers of Fast JITed (un-imported) functions */
void **fast_jit_func_ptrs; void **fast_jit_func_ptrs;
#endif #endif
#if WASM_ENABLE_JIT != 0 #if WASM_ENABLE_JIT != 0
struct AOTCompData *comp_data; struct AOTCompData *comp_data;
struct AOTCompContext *comp_ctx; struct AOTCompContext *comp_ctx;
/* func pointers of LLVM JITed (un-imported) functions */
void **func_ptrs; void **func_ptrs;
/* whether the func pointers are compiled */
bool *func_ptrs_compiled;
bool orcjit_stop_compiling;
korp_tid orcjit_threads[WASM_ORC_JIT_BACKEND_THREAD_NUM];
OrcJitThreadArg orcjit_thread_args[WASM_ORC_JIT_BACKEND_THREAD_NUM];
#endif #endif
}; };

View File

@ -2953,20 +2953,91 @@ calculate_global_data_offset(WASMModule *module)
} }
#if WASM_ENABLE_JIT != 0 #if WASM_ENABLE_JIT != 0
static void *
orcjit_thread_callback(void *arg)
{
LLVMOrcJITTargetAddress func_addr = 0;
OrcJitThreadArg *thread_arg = (OrcJitThreadArg *)arg;
AOTCompContext *comp_ctx = thread_arg->comp_ctx;
WASMModule *module = thread_arg->module;
uint32 group_idx = thread_arg->group_idx;
uint32 group_stride = WASM_ORC_JIT_BACKEND_THREAD_NUM;
uint32 func_count = module->function_count;
uint32 i, j;
typedef void (*F)(void);
LLVMErrorRef error;
char func_name[48];
union {
F f;
void *v;
} u;
/* Compile jit functions of this group */
for (i = group_idx; i < func_count;
i += group_stride * WASM_ORC_JIT_COMPILE_THREAD_NUM) {
snprintf(func_name, sizeof(func_name), "%s%d%s", AOT_FUNC_PREFIX, i,
"_wrapper");
LOG_DEBUG("compile func %s", func_name);
error =
LLVMOrcLLLazyJITLookup(comp_ctx->orc_jit, &func_addr, func_name);
if (error != LLVMErrorSuccess) {
char *err_msg = LLVMGetErrorMessage(error);
os_printf("failed to compile orc jit function: %s", err_msg);
LLVMDisposeErrorMessage(err_msg);
continue;
}
/* Call the jit wrapper function to trigger its compilation, so as
to compile the actual jit functions, since we add the latter to
function list in the PartitionFunction callback */
u.v = (void *)func_addr;
u.f();
for (j = 0; j < WASM_ORC_JIT_COMPILE_THREAD_NUM; j++) {
if (i + j * group_stride < func_count)
module->func_ptrs_compiled[i + j * group_stride] = true;
}
if (module->orcjit_stop_compiling) {
break;
}
}
return NULL;
}
static void
orcjit_stop_compile_threads(WASMModule *module)
{
uint32 i, thread_num = (uint32)(sizeof(module->orcjit_thread_args)
/ sizeof(OrcJitThreadArg));
module->orcjit_stop_compiling = true;
for (i = 0; i < thread_num; i++) {
if (module->orcjit_threads[i])
os_thread_join(module->orcjit_threads[i], NULL);
}
}
static bool static bool
compile_llvm_jit_functions(WASMModule *module, char *error_buf, compile_llvm_jit_functions(WASMModule *module, char *error_buf,
uint32 error_buf_size) uint32 error_buf_size)
{ {
AOTCompOption option = { 0 }; AOTCompOption option = { 0 };
char func_name[32], *aot_last_error; char *aot_last_error;
uint64 size; uint64 size;
uint32 i; uint32 thread_num, i;
size = sizeof(void *) * (uint64)module->function_count; if (module->function_count > 0) {
if (size > 0 size = sizeof(void *) * (uint64)module->function_count
&& !(module->func_ptrs = + sizeof(bool) * (uint64)module->function_count;
loader_malloc(size, error_buf, error_buf_size))) { if (!(module->func_ptrs =
return false; loader_malloc(size, error_buf, error_buf_size))) {
return false;
}
module->func_ptrs_compiled =
(bool *)((uint8 *)module->func_ptrs
+ sizeof(void *) * module->function_count);
} }
module->comp_data = aot_create_comp_data(module); module->comp_data = aot_create_comp_data(module);
@ -3015,20 +3086,24 @@ compile_llvm_jit_functions(WASMModule *module, char *error_buf,
return false; return false;
} }
#if WASM_ENABLE_LAZY_JIT != 0 bh_print_time("Begin to lookup jit functions");
for (i = 0; i < module->comp_data->func_count; i++) {
LLVMErrorRef error; for (i = 0; i < module->function_count; i++) {
LLVMOrcJITTargetAddress func_addr = 0; LLVMOrcJITTargetAddress func_addr = 0;
LLVMErrorRef error;
char func_name[48];
snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i); snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i);
if ((error = LLVMOrcLLJITLookup(module->comp_ctx->orc_lazyjit, error = LLVMOrcLLLazyJITLookup(module->comp_ctx->orc_jit, &func_addr,
&func_addr, func_name))) { func_name);
if (error != LLVMErrorSuccess) {
char *err_msg = LLVMGetErrorMessage(error); char *err_msg = LLVMGetErrorMessage(error);
set_error_buf_v(error_buf, error_buf_size, set_error_buf_v(error_buf, error_buf_size,
"failed to compile orc jit function: %s", err_msg); "failed to compile orc jit function: %s", err_msg);
LLVMDisposeErrorMessage(err_msg); LLVMDisposeErrorMessage(err_msg);
return false; return false;
} }
/** /**
* No need to lock the func_ptr[func_idx] here as it is basic * No need to lock the func_ptr[func_idx] here as it is basic
* data type, the load/store for it can be finished by one cpu * data type, the load/store for it can be finished by one cpu
@ -3038,20 +3113,43 @@ compile_llvm_jit_functions(WASMModule *module, char *error_buf,
module->func_ptrs[i] = (void *)func_addr; module->func_ptrs[i] = (void *)func_addr;
module->functions[i]->llvm_jit_func_ptr = (void *)func_addr; module->functions[i]->llvm_jit_func_ptr = (void *)func_addr;
} }
#else
/* Resolve function addresses */ bh_print_time("Begin to compile jit functions");
bh_assert(module->comp_ctx->exec_engine);
for (i = 0; i < module->comp_data->func_count; i++) { thread_num =
snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i); (uint32)(sizeof(module->orcjit_thread_args) / sizeof(OrcJitThreadArg));
if (!(module->func_ptrs[i] = (void *)LLVMGetFunctionAddress(
module->comp_ctx->exec_engine, func_name))) { /* Create threads to compile the jit functions */
for (i = 0; i < thread_num; i++) {
module->orcjit_thread_args[i].comp_ctx = module->comp_ctx;
module->orcjit_thread_args[i].module = module;
module->orcjit_thread_args[i].group_idx = i;
if (os_thread_create(&module->orcjit_threads[i], orcjit_thread_callback,
(void *)&module->orcjit_thread_args[i],
APP_THREAD_STACK_SIZE_DEFAULT)
!= 0) {
uint32 j;
set_error_buf(error_buf, error_buf_size, set_error_buf(error_buf, error_buf_size,
"failed to compile llvm mc jit function"); "create orcjit compile thread failed");
/* Terminate the threads created */
module->orcjit_stop_compiling = true;
for (j = 0; j < i; j++) {
os_thread_join(module->orcjit_threads[j], NULL);
}
return false; return false;
} }
module->functions[i]->llvm_jit_func_ptr = module->func_ptrs[i];
} }
#endif /* end of WASM_ENABLE_LAZY_JIT != 0 */
#if WASM_ENABLE_LAZY_JIT == 0
/* Wait until all jit functions are compiled for eager mode */
for (i = 0; i < thread_num; i++) {
os_thread_join(module->orcjit_threads[i], NULL);
}
#endif
bh_print_time("End compile jit functions");
return true; return true;
} }
@ -3893,6 +3991,18 @@ wasm_loader_unload(WASMModule *module)
if (!module) if (!module)
return; return;
#if WASM_ENABLE_JIT != 0
/* Stop LLVM JIT compilation firstly to avoid accessing
module internal data after they were freed */
orcjit_stop_compile_threads(module);
if (module->func_ptrs)
wasm_runtime_free(module->func_ptrs);
if (module->comp_ctx)
aot_destroy_comp_context(module->comp_ctx);
if (module->comp_data)
aot_destroy_comp_data(module->comp_data);
#endif
if (module->types) { if (module->types) {
for (i = 0; i < module->type_count; i++) { for (i = 0; i < module->type_count; i++) {
if (module->types[i]) if (module->types[i])
@ -4018,15 +4128,6 @@ wasm_loader_unload(WASMModule *module)
} }
#endif #endif
#if WASM_ENABLE_JIT != 0
if (module->func_ptrs)
wasm_runtime_free(module->func_ptrs);
if (module->comp_ctx)
aot_destroy_comp_context(module->comp_ctx);
if (module->comp_data)
aot_destroy_comp_data(module->comp_data);
#endif
wasm_runtime_free(module); wasm_runtime_free(module);
} }

View File

@ -1784,20 +1784,91 @@ calculate_global_data_offset(WASMModule *module)
} }
#if WASM_ENABLE_JIT != 0 #if WASM_ENABLE_JIT != 0
static void *
orcjit_thread_callback(void *arg)
{
LLVMOrcJITTargetAddress func_addr = 0;
OrcJitThreadArg *thread_arg = (OrcJitThreadArg *)arg;
AOTCompContext *comp_ctx = thread_arg->comp_ctx;
WASMModule *module = thread_arg->module;
uint32 group_idx = thread_arg->group_idx;
uint32 group_stride = WASM_ORC_JIT_BACKEND_THREAD_NUM;
uint32 func_count = module->function_count;
uint32 i, j;
typedef void (*F)(void);
LLVMErrorRef error;
char func_name[48];
union {
F f;
void *v;
} u;
/* Compile jit functions of this group */
for (i = group_idx; i < func_count;
i += group_stride * WASM_ORC_JIT_COMPILE_THREAD_NUM) {
snprintf(func_name, sizeof(func_name), "%s%d%s", AOT_FUNC_PREFIX, i,
"_wrapper");
LOG_DEBUG("compile func %s", func_name);
error =
LLVMOrcLLLazyJITLookup(comp_ctx->orc_jit, &func_addr, func_name);
if (error != LLVMErrorSuccess) {
char *err_msg = LLVMGetErrorMessage(error);
os_printf("failed to compile orc jit function: %s", err_msg);
LLVMDisposeErrorMessage(err_msg);
continue;
}
/* Call the jit wrapper function to trigger its compilation, so as
to compile the actual jit functions, since we add the latter to
function list in the PartitionFunction callback */
u.v = (void *)func_addr;
u.f();
for (j = 0; j < WASM_ORC_JIT_COMPILE_THREAD_NUM; j++) {
if (i + j * group_stride < func_count)
module->func_ptrs_compiled[i + j * group_stride] = true;
}
if (module->orcjit_stop_compiling) {
break;
}
}
return NULL;
}
static void
orcjit_stop_compile_threads(WASMModule *module)
{
uint32 i, thread_num = (uint32)(sizeof(module->orcjit_thread_args)
/ sizeof(OrcJitThreadArg));
module->orcjit_stop_compiling = true;
for (i = 0; i < thread_num; i++) {
if (module->orcjit_threads[i])
os_thread_join(module->orcjit_threads[i], NULL);
}
}
static bool static bool
compile_llvm_jit_functions(WASMModule *module, char *error_buf, compile_llvm_jit_functions(WASMModule *module, char *error_buf,
uint32 error_buf_size) uint32 error_buf_size)
{ {
AOTCompOption option = { 0 }; AOTCompOption option = { 0 };
char func_name[32], *aot_last_error; char *aot_last_error;
uint64 size; uint64 size;
uint32 i; uint32 thread_num, i;
size = sizeof(void *) * (uint64)module->function_count; if (module->function_count > 0) {
if (size > 0 size = sizeof(void *) * (uint64)module->function_count
&& !(module->func_ptrs = + sizeof(bool) * (uint64)module->function_count;
loader_malloc(size, error_buf, error_buf_size))) { if (!(module->func_ptrs =
return false; loader_malloc(size, error_buf, error_buf_size))) {
return false;
}
module->func_ptrs_compiled =
(bool *)((uint8 *)module->func_ptrs
+ sizeof(void *) * module->function_count);
} }
module->comp_data = aot_create_comp_data(module); module->comp_data = aot_create_comp_data(module);
@ -1846,20 +1917,26 @@ compile_llvm_jit_functions(WASMModule *module, char *error_buf,
return false; return false;
} }
#if WASM_ENABLE_LAZY_JIT != 0 bh_print_time("Begin to lookup jit functions");
for (i = 0; i < module->comp_data->func_count; i++) {
LLVMErrorRef error; for (i = 0; i < module->function_count; i++) {
LLVMOrcJITTargetAddress func_addr = 0; LLVMOrcJITTargetAddress func_addr = 0;
LLVMErrorRef error;
char func_name[48];
snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i); snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i);
if ((error = LLVMOrcLLJITLookup(module->comp_ctx->orc_lazyjit, error = LLVMOrcLLLazyJITLookup(module->comp_ctx->orc_jit, &func_addr,
&func_addr, func_name))) { func_name);
if (error != LLVMErrorSuccess) {
char *err_msg = LLVMGetErrorMessage(error); char *err_msg = LLVMGetErrorMessage(error);
set_error_buf_v(error_buf, error_buf_size, char buf[128];
"failed to compile orc jit function: %s", err_msg); snprintf(buf, sizeof(buf), "failed to compile orc jit function: %s",
err_msg);
set_error_buf(error_buf, error_buf_size, buf);
LLVMDisposeErrorMessage(err_msg); LLVMDisposeErrorMessage(err_msg);
return false; return false;
} }
/** /**
* No need to lock the func_ptr[func_idx] here as it is basic * No need to lock the func_ptr[func_idx] here as it is basic
* data type, the load/store for it can be finished by one cpu * data type, the load/store for it can be finished by one cpu
@ -1869,20 +1946,43 @@ compile_llvm_jit_functions(WASMModule *module, char *error_buf,
module->func_ptrs[i] = (void *)func_addr; module->func_ptrs[i] = (void *)func_addr;
module->functions[i]->llvm_jit_func_ptr = (void *)func_addr; module->functions[i]->llvm_jit_func_ptr = (void *)func_addr;
} }
#else
/* Resolve function addresses */ bh_print_time("Begin to compile jit functions");
bh_assert(module->comp_ctx->exec_engine);
for (i = 0; i < module->comp_data->func_count; i++) { thread_num =
snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i); (uint32)(sizeof(module->orcjit_thread_args) / sizeof(OrcJitThreadArg));
if (!(module->func_ptrs[i] = (void *)LLVMGetFunctionAddress(
module->comp_ctx->exec_engine, func_name))) { /* Create threads to compile the jit functions */
for (i = 0; i < thread_num; i++) {
module->orcjit_thread_args[i].comp_ctx = module->comp_ctx;
module->orcjit_thread_args[i].module = module;
module->orcjit_thread_args[i].group_idx = i;
if (os_thread_create(&module->orcjit_threads[i], orcjit_thread_callback,
(void *)&module->orcjit_thread_args[i],
APP_THREAD_STACK_SIZE_DEFAULT)
!= 0) {
uint32 j;
set_error_buf(error_buf, error_buf_size, set_error_buf(error_buf, error_buf_size,
"failed to compile llvm mc jit function"); "create orcjit compile thread failed");
/* Terminate the threads created */
module->orcjit_stop_compiling = true;
for (j = 0; j < i; j++) {
os_thread_join(module->orcjit_threads[j], NULL);
}
return false; return false;
} }
module->functions[i]->llvm_jit_func_ptr = module->func_ptrs[i];
} }
#endif /* end of WASM_ENABLE_LAZY_JIT != 0 */
#if WASM_ENABLE_LAZY_JIT == 0
/* Wait until all jit functions are compiled for eager mode */
for (i = 0; i < thread_num; i++) {
os_thread_join(module->orcjit_threads[i], NULL);
}
#endif
bh_print_time("End compile jit functions");
return true; return true;
} }
@ -2586,6 +2686,18 @@ wasm_loader_unload(WASMModule *module)
if (!module) if (!module)
return; return;
#if WASM_ENABLE_JIT != 0
/* Stop LLVM JIT compilation firstly to avoid accessing
module internal data after they were freed */
orcjit_stop_compile_threads(module);
if (module->func_ptrs)
wasm_runtime_free(module->func_ptrs);
if (module->comp_ctx)
aot_destroy_comp_context(module->comp_ctx);
if (module->comp_data)
aot_destroy_comp_data(module->comp_data);
#endif
if (module->types) { if (module->types) {
for (i = 0; i < module->type_count; i++) { for (i = 0; i < module->type_count; i++) {
if (module->types[i]) if (module->types[i])
@ -2673,15 +2785,6 @@ wasm_loader_unload(WASMModule *module)
} }
#endif #endif
#if WASM_ENABLE_JIT != 0
if (module->func_ptrs)
wasm_runtime_free(module->func_ptrs);
if (module->comp_ctx)
aot_destroy_comp_context(module->comp_ctx);
if (module->comp_data)
aot_destroy_comp_data(module->comp_data);
#endif
wasm_runtime_free(module); wasm_runtime_free(module);
} }

View File

@ -41,7 +41,6 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM
- **WAMR_BUILD_AOT**=1/0, enable AOT or not, default to enable if not set - **WAMR_BUILD_AOT**=1/0, enable AOT or not, default to enable if not set
- **WAMR_BUILD_JIT**=1/0, enable LLVM JIT or not, default to disable if not set - **WAMR_BUILD_JIT**=1/0, enable LLVM JIT or not, default to disable if not set
- **WAMR_BUILD_LAZY_JIT**=1/0, whether to use Lazy JIT mode or not when *WAMR_BUILD_JIT* is set, default to enable if not set
- **WAMR_BUILD_FAST_JIT**=1/0, enable Fast JIT or not, default to disable if not set - **WAMR_BUILD_FAST_JIT**=1/0, enable Fast JIT or not, default to disable if not set
#### **Configure LIBC** #### **Configure LIBC**
@ -224,7 +223,7 @@ make
By default in Linux, the `fast interpreter`, `AOT` and `Libc WASI` are enabled, and JIT is disabled. By default in Linux, the `fast interpreter`, `AOT` and `Libc WASI` are enabled, and JIT is disabled.
And the build target is set to X86_64 or X86_32 depending on the platform's bitwidth. And the build target is set to X86_64 or X86_32 depending on the platform's bitwidth.
There are total 6 running modes supported: fast interpreter, classi interpreter, AOT, LLVM Lazy JIT, LLVM MC JIT and Fast JIT. There are total 5 running modes supported: fast interpreter, classi interpreter, AOT, LLVM JIT and Fast JIT.
(1) To run a wasm file with `fast interpreter` mode - build iwasm with default build and then: (1) To run a wasm file with `fast interpreter` mode - build iwasm with default build and then:
```Bash ```Bash
@ -250,32 +249,34 @@ wamrc -o <AOT file> <WASM file>
iwasm <AOT file> iwasm <AOT file>
``` ```
(4) To enable the `LLVM Lazy JIT` mode, firstly we should build LLVM library: (4) To enable the `LLVM JIT` mode, firstly we should build the LLVM library:
``` Bash ``` Bash
cd product-mini/platforms/linux/ cd product-mini/platforms/linux/
./build_llvm.sh (The llvm source code is cloned under <wamr_root_dir>/core/deps/llvm and auto built) ./build_llvm.sh (The llvm source code is cloned under <wamr_root_dir>/core/deps/llvm and auto built)
``` ```
Then pass argument `-DWAMR_BUILD_JIT=1` to cmake to enable LLVM Lazy JIT: Then pass argument `-DWAMR_BUILD_JIT=1` to cmake to enable LLVM JIT:
``` Bash ``` Bash
mkdir build && cd build mkdir build && cd build
cmake .. -DWAMR_BUILD_JIT=1 cmake .. -DWAMR_BUILD_JIT=1
make make
``` ```
(5) Or disable `LLVM Lazy JIT` and enable `LLVM MC JIT` instead: Note:
```Bash By default, the LLVM Orc JIT with Lazy compilation is enabled to speedup the lanuching process and reduce
the JIT compilation time by creating backend threads to compile the WASM functions parallely, and for the
main thread, the functions in the module will not be compiled until they are firstly called and haven't been
compiled by the compilation threads.
If developer wants to disable the Lazy compilation, we can:
``` Bash
mkdir build && cd build mkdir build && cd build
cmake .. -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0 cmake .. -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0
make make
``` ```
In which all the WASM functions will be previously compiled before main thread starts to run the wasm module.
By default, the LLVM Orc Lazy JIT is enabled to speedup the lanuching process and reduce the JIT compilation time (5) To enable the `Fast JIT` mode:
by creating threads to compile the WASM functions parallely, and for the main thread, the functions in the
module will not be compiled until they are firstly called and haven't been compiled by the compilation threads.
To disable it and enable LLVM MC JIT instead, please pass argument `-DWAMR_BUILD_LAZY_JIT=0` to cmake.
(6) To enable the `Fast JIT` mode:
``` Bash ``` Bash
mkdir build && cd build mkdir build && cd build
cmake .. -DWAMR_BUILD_FAST_JIT=1 cmake .. -DWAMR_BUILD_FAST_JIT=1

View File

@ -173,10 +173,18 @@ readonly FAST_INTERP_COMPILE_FLAGS="\
# jit: report linking error if set COLLECT_CODE_COVERAGE, # jit: report linking error if set COLLECT_CODE_COVERAGE,
# now we don't collect code coverage of jit type # now we don't collect code coverage of jit type
readonly JIT_COMPILE_FLAGS="\ readonly ORC_EAGER_JIT_COMPILE_FLAGS="\
-DWAMR_BUILD_TARGET=${TARGET} \ -DWAMR_BUILD_TARGET=${TARGET} \
-DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_INTERP=0 \ -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_INTERP=0 \
-DWAMR_BUILD_JIT=1 -DWAMR_BUILD_AOT=1 \ -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_AOT=1 \
-DWAMR_BUILD_LAZY_JIT=0 \
-DWAMR_BUILD_SPEC_TEST=1"
readonly ORC_LAZY_JIT_COMPILE_FLAGS="\
-DWAMR_BUILD_TARGET=${TARGET} \
-DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_INTERP=0 \
-DWAMR_BUILD_JIT=1 -DWAMR_BUILD_AOT=1 \
-DWAMR_BUILD_LAZY_JIT=1 \
-DWAMR_BUILD_SPEC_TEST=1" -DWAMR_BUILD_SPEC_TEST=1"
readonly AOT_COMPILE_FLAGS="\ readonly AOT_COMPILE_FLAGS="\
@ -196,7 +204,8 @@ readonly FAST_JIT_COMPILE_FLAGS="\
readonly COMPILE_FLAGS=( readonly COMPILE_FLAGS=(
"${CLASSIC_INTERP_COMPILE_FLAGS}" "${CLASSIC_INTERP_COMPILE_FLAGS}"
"${FAST_INTERP_COMPILE_FLAGS}" "${FAST_INTERP_COMPILE_FLAGS}"
"${JIT_COMPILE_FLAGS}" "${ORC_EAGER_JIT_COMPILE_FLAGS}"
"${ORC_LAZY_JIT_COMPILE_FLAGS}"
"${AOT_COMPILE_FLAGS}" "${AOT_COMPILE_FLAGS}"
"${FAST_JIT_COMPILE_FLAGS}" "${FAST_JIT_COMPILE_FLAGS}"
) )
@ -600,9 +609,16 @@ function trigger()
continue continue
fi fi
echo "work in jit mode" echo "work in orc jit eager compilation mode"
# jit BUILD_FLAGS="$ORC_EAGER_JIT_COMPILE_FLAGS $EXTRA_COMPILE_FLAGS"
BUILD_FLAGS="$JIT_COMPILE_FLAGS $EXTRA_COMPILE_FLAGS" build_iwasm_with_cfg $BUILD_FLAGS
build_wamrc
for suite in "${TEST_CASE_ARR[@]}"; do
$suite"_test" jit
done
echo "work in orc jit lazy compilation mode"
BUILD_FLAGS="$ORC_EAGER_JIT_COMPILE_FLAGS $EXTRA_COMPILE_FLAGS"
build_iwasm_with_cfg $BUILD_FLAGS build_iwasm_with_cfg $BUILD_FLAGS
build_wamrc build_wamrc
for suite in "${TEST_CASE_ARR[@]}"; do for suite in "${TEST_CASE_ARR[@]}"; do