-
Notifications
You must be signed in to change notification settings - Fork 19
CLI
The compiler CLI allows compiling a single or multiple TypeScript files.
node packages/compiler/cli.js
Pass either a config file or the files to use
Usage: cli [options] [files ...]
Options:
-h, --help output usage information
-V, --version output the version number
-c --config <configFile> The path to the tsconfig.json
--unsafe Use the unsafe runtime system
--emit-llvm Emit LLVM Assembly Code instead of WASM files
--save-wast Saves the WAST file in the output directory if compiling all the way to WebAssembly
--save-bc Saves a copy of the bitcode to the output directory if compiling all the way to WebAssembly. The file includes the linked and optimized code.
--binaryen-opt Optimize using Binaryen opt
--expose-gc Exposes the speedy js garbage collector in the module as speedyJsGc
--export-gc Exposes and exports the speedy js garbage collector as the symbol speedyJsGc
--disable-heap-nuke-on-exit Disables nuking of the heap before the exit of the entry function (it's your responsible for calling the gc in this case!)
--optimization-level [value] The optimization level to use. One of the following values: '0, 1, 2, 3, s or z'
-s --settings [value] additional settings
A single file can be compiled using:
node packages/compiler/cli.js packages/benchmark/cases/tspInt-spdy.ts
The compiler emits the JavaScript file next to the TypeScript file. Multiple files can either be compiled by passing each file name to the compiler or by calling the compiler from a directory that contains a tsconfig.json
.
The compiler offers various options that allow examining the generated code. This is useful for curious people or to analyze performance issues. The files containing the intermediate representations are emitted to the output directory --- by default side by side with the TypeScript file.
The example use the following TypeScript file as input:
export async function fib(value: int): Promise<int> {
"use speedyjs";
return fibSync(value);
}
function fibSync(value: int): int {
"use speedyjs";
if (value <= 2) {
return 1;
}
return fibSync(value - 2) + fibSync(value - 1);
}
The --emit-llvm
option emits the LLVM-IR code generated by the Speedy.js compiler before any optimizations are applied. The output file has the file ending .ll
.
node packages/compiler/cli.js packages/benchmark/cases/fib-spdy.ts --emit-llvm
cat packages/benchmark/cases/fib-spdy.ll
; ModuleID = 'fib-spdy.ts'
source_filename = "fib-spdy.ts"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-unknown"
%class.Math = type { { [5 x i8]* }* }
@Array_name = private unnamed_addr constant [6 x i8] c"Array\00"
@Array_type_descriptor = private constant { [6 x i8]* } { [6 x i8]* @Array_name }
@Math_name = private unnamed_addr constant [5 x i8] c"Math\00"
@Math_type_descriptor = private constant { [5 x i8]* } { [5 x i8]* @Math_name }
@Math_object = private constant %class.Math { { [5 x i8]* }* @Math_type_descriptor }
@Math_ptr = private constant %class.Math* @Math_object
define i32 @_fib(i32 %value) {
entry:
%value.addr = alloca i32, align 4
%return = alloca i32, align 4
store i32 %value, i32* %value.addr, align 4
%value.addr1 = load i32, i32* %value.addr, align 4
%fibSyncReturnValue = call i32 @"fib_spdy.ts$$7fibSynci"(i32 %value.addr1)
store i32 %fibSyncReturnValue, i32* %return, align 4
br label %returnBlock
returnBlock: ; preds = %entry
%return2 = load i32, i32* %return, align 4
ret i32 %return2
}
define linkonce_odr hidden i32 @"fib_spdy.ts$$7fibSynci"(i32 %value) {
entry:
%value.addr = alloca i32, align 4
%return = alloca i32, align 4
store i32 %value, i32* %value.addr, align 4
%value.addr1 = load i32, i32* %value.addr, align 4
%cmpLE = icmp sle i32 %value.addr1, 2
br i1 %cmpLE, label %if.then, label %if.end
if.then: ; preds = %entry
store i32 1, i32* %return, align 4
br label %returnBlock
if.end: ; preds = %entry
%value.addr2 = load i32, i32* %value.addr, align 4
%sub = sub i32 %value.addr2, 2
%fibSyncReturnValue = call i32 @"fib_spdy.ts$$7fibSynci"(i32 %sub)
%value.addr3 = load i32, i32* %value.addr, align 4
%sub4 = sub i32 %value.addr3, 1
%fibSyncReturnValue5 = call i32 @"fib_spdy.ts$$7fibSynci"(i32 %sub4)
%add = add i32 %fibSyncReturnValue, %fibSyncReturnValue5
store i32 %add, i32* %return, align 4
br label %returnBlock
returnBlock: ; preds = %if.end, %if.then
%return6 = load i32, i32* %return, align 4
ret i32 %return6
}
The --save-bc
option saves the optimized and linked program as LLVM bitcode file. The bitcode file is used as input to the LLVM WebAssembly backend. The bitcode file is useful to inspect the applied optimizations. The bitcode file has the file ending .bc
. It is needed to disassemble the file using llvm-dis
to get a human readable representation. llvm-dis
saves the disassembled output with the file ending .ll
(as is --emit-llvm
).
node packages/compiler/cli.js packages/benchmark/cases/fib-spdy.ts --save-bc
packages/compiler/tools/llvm/bin/llvm-dis packages/benchmark/cases/fib-spdy.bc
cat packages/benchmark/cases/fib-spdy.ll
; ModuleID = 'packages/benchmark/cases/fib-spdy.bc'
source_filename = "llvm-link"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-unknown"
define i32 @_fib(i32 %value) local_unnamed_addr {
entry:
%fibSyncReturnValue = tail call i32 @"fib_spdy.ts$$7fibSynci"(i32 %value)
ret i32 %fibSyncReturnValue
}
define internal i32 @"fib_spdy.ts$$7fibSynci"(i32 %value) local_unnamed_addr {
entry:
%cmpLE3 = icmp slt i32 %value, 3
br i1 %cmpLE3, label %returnBlock, label %if.end
if.end: ; preds = %entry, %if.end
%value.tr5 = phi i32 [ %sub4, %if.end ], [ %value, %entry ]
%accumulator.tr4 = phi i32 [ %add, %if.end ], [ 1, %entry ]
%sub = add i32 %value.tr5, -2
%fibSyncReturnValue = tail call i32 @"fib_spdy.ts$$7fibSynci"(i32 %sub)
%sub4 = add nsw i32 %value.tr5, -1
%add = add i32 %fibSyncReturnValue, %accumulator.tr4
%cmpLE = icmp slt i32 %value.tr5, 4
br i1 %cmpLE, label %returnBlock, label %if.end
returnBlock: ; preds = %if.end, %entry
%accumulator.tr.lcssa = phi i32 [ 1, %entry ], [ %add, %if.end ]
ret i32 %accumulator.tr.lcssa
}
The ---save-wast
option saves the final WebAssembly module in its textual representation (using s-expressions). The compiler emits the file with the .wast
file ending.
node packages/compiler/cli.js packages/benchmark/cases/fib-spdy.ts --save-wast
cat packages/benchmark/cases/fib-spdy.wast
(module
(import "env" "memory" (memory $0 256))
(table 0 anyfunc)
(export "_fib" (func $_fib))
(func $_fib (param $0 i32) (result i32)
(call $fib_spdy.ts$$7fibSynci
(get_local $0)
)
)
(func $fib_spdy.ts$$7fibSynci (param $0 i32) (result i32)
(local $1 i32)
(set_local $1
(i32.const 1)
)
(block $label$0
(br_if $label$0
(i32.lt_s
(get_local $0)
(i32.const 3)
)
)
(set_local $1
(i32.const 1)
)
(set_local $0
(i32.add
(get_local $0)
(i32.const 1)
)
)
(loop $label$1
(set_local $1
(i32.add
(call $fib_spdy.ts$$7fibSynci
(i32.add
(get_local $0)
(i32.const -3)
)
)
(get_local $1)
)
)
(br_if $label$1
(i32.gt_s
(tee_local $0
(i32.add
(get_local $0)
(i32.const -1)
)
)
(i32.const 3)
)
)
)
)
(get_local $1)
)
)
;; METADATA: { "asmConsts": {},"staticBump": 8, "initializers": [] }
The following additional settings are supported.
INITIAL_MEMORY: The initial size of the WebAssembly memory in bytes. The default value is 16 MB. The initially allocated memory grows if the application requires more. However, growing is potentially an expensive operation. Therefore, it is preferred to initialize the value with a reasonable value. The initial memory needs to be a multiple of the WebAssembly page size of 64KB.
TOTAL_STACK: The size of a stack in bytes. The default value is 5 MB.
GLOBAL_BASE: Where global data begins; the start of static memory.
The following environment variables are respected by the CLI:
DEBUG: Enables the debug output. By setting DEBUG=*
all debug output is logged to the console. For more details see debug. For example, on Unix systems use DEBUG=* node cli.js ...
.