authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-05-31 21:11:06+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-09 00:22:17-04:00
logce3f0077cf3c5ae8edc116177f2f3d33258be9f7
treea8cc4c5d9721c90b4ccd0304049551952f662dfd
parent12051b02f1f455b85d5a519dd1747a67d4bb68d0

Add builtin for llvm.wasm.memory.size.i32 instrinsic

This will allow the developer to poll the runtime for currently allocated memory in the number of Wasm pages. Typical usage: ```zig var wasm_pages = @wasmMemorySize(); @import("std").debug.assert(wasm_pages > 0); ```

4 files changed, 102 insertions(+), 0 deletions(-)

src/all_types.hpp+12
......@@ -1825,6 +1825,7 @@ enum BuiltinFnId {
18251825 BuiltinFnIdAs,
18261826 BuiltinFnIdCall,
18271827 BuiltinFnIdBitSizeof,
1828 BuiltinFnIdWasmMemorySize,
18281829};
18291830
18301831struct BuiltinFnEntry {
......@@ -2075,6 +2076,7 @@ struct CodeGen {
20752076 LLVMValueRef err_name_table;
20762077 LLVMValueRef safety_crash_err_fn;
20772078 LLVMValueRef return_err_fn;
2079 LLVMValueRef wasm_memory_size;
20782080 LLVMTypeRef anyframe_fn_type;
20792081
20802082 // reminder: hash tables must be initialized before use
......@@ -2748,6 +2750,7 @@ enum IrInstSrcId {
27482750 IrInstSrcIdResume,
27492751 IrInstSrcIdSpillBegin,
27502752 IrInstSrcIdSpillEnd,
2753 IrInstSrcIdWasmMemorySize,
27512754};
27522755
27532756// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR.
......@@ -2840,6 +2843,7 @@ enum IrInstGenId {
28402843 IrInstGenIdVectorExtractElem,
28412844 IrInstGenIdAlloca,
28422845 IrInstGenIdConst,
2846 IrInstGenIdWasmMemorySize,
28432847};
28442848
28452849// Common fields between IrInstSrc and IrInstGen. This allows future passes
......@@ -3727,6 +3731,14 @@ struct IrInstGenMemcpy {
37273731 IrInstGen *count;
37283732};
37293733
3734struct IrInstSrcWasmMemorySize {
3735 IrInstSrc base;
3736};
3737
3738struct IrInstGenWasmMemorySize {
3739 IrInstGen base;
3740};
3741
37303742struct IrInstSrcSlice {
37313743 IrInstSrc base;
37323744
src/codegen.cpp+27
......@@ -1045,6 +1045,19 @@ static void gen_assertion(CodeGen *g, PanicMsgId msg_id, IrInstGen *source_instr
10451045 return gen_assertion_scope(g, msg_id, source_instruction->base.scope);
10461046}
10471047
1048static LLVMValueRef gen_wasm_memory_size(CodeGen *g) {
1049 if (g->wasm_memory_size)
1050 return g->wasm_memory_size;
1051
1052 // declare i32 @llvm.wasm.memory.size.i32(i32) nounwind readonly
1053 LLVMTypeRef param_type = LLVMInt32Type();
1054 LLVMTypeRef fn_type = LLVMFunctionType(LLVMInt32Type(), &param_type, 1, false);
1055 g->wasm_memory_size = LLVMAddFunction(g->module, "llvm.wasm.memory.size.i32", fn_type);
1056 assert(LLVMGetIntrinsicID(g->wasm_memory_size));
1057
1058 return g->wasm_memory_size;
1059}
1060
10481061static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {
10491062 if (g->stacksave_fn_val)
10501063 return g->stacksave_fn_val;
......@@ -5588,6 +5601,17 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutableGen *executable, Ir
55885601 return nullptr;
55895602}
55905603
5604static LLVMValueRef ir_render_wasm_memory_size(CodeGen *g, IrExecutableGen *executable, IrInstGenWasmMemorySize *instruction) {
5605 // When Wasm lands multi-memory support, we can relax this to permit the user specify
5606 // memory index to inquire about. For now, we pass in the recommended default of index 0.
5607 //
5608 // More info:
5609 // https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#current-linear-memory-size
5610 LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->llvm_type);
5611 LLVMValueRef val = LLVMBuildCall(g->builder, gen_wasm_memory_size(g), &zero, 1, "");
5612 return val;
5613}
5614
55915615static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrInstGenSlice *instruction) {
55925616 Error err;
55935617
......@@ -6798,6 +6822,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutableGen *executabl
67986822 return ir_render_splat(g, executable, (IrInstGenSplat *) instruction);
67996823 case IrInstGenIdVectorExtractElem:
68006824 return ir_render_vector_extract_elem(g, executable, (IrInstGenVectorExtractElem *) instruction);
6825 case IrInstGenIdWasmMemorySize:
6826 return ir_render_wasm_memory_size(g, executable, (IrInstGenWasmMemorySize *) instruction);
68016827 }
68026828 zig_unreachable();
68036829}
......@@ -8660,6 +8686,7 @@ static void define_builtin_fns(CodeGen *g) {
86608686 create_builtin_fn(g, BuiltinFnIdAs, "as", 2);
86618687 create_builtin_fn(g, BuiltinFnIdCall, "call", 3);
86628688 create_builtin_fn(g, BuiltinFnIdBitSizeof, "bitSizeOf", 1);
8689 create_builtin_fn(g, BuiltinFnIdWasmMemorySize, "wasmMemorySize", 0);
86638690}
86648691
86658692static const char *bool_to_str(bool b) {
src/ir.cpp+45
......@@ -556,6 +556,8 @@ static void destroy_instruction_src(IrInstSrc *inst) {
556556 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSpillEnd *>(inst));
557557 case IrInstSrcIdCallArgs:
558558 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCallArgs *>(inst));
559 case IrInstSrcIdWasmMemorySize:
560 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcWasmMemorySize *>(inst));
559561 }
560562 zig_unreachable();
561563}
......@@ -736,6 +738,8 @@ void destroy_instruction_gen(IrInstGen *inst) {
736738 return heap::c_allocator.destroy(reinterpret_cast<IrInstGenNegation *>(inst));
737739 case IrInstGenIdNegationWrapping:
738740 return heap::c_allocator.destroy(reinterpret_cast<IrInstGenNegationWrapping *>(inst));
741 case IrInstGenIdWasmMemorySize:
742 return heap::c_allocator.destroy(reinterpret_cast<IrInstGenWasmMemorySize *>(inst));
739743 }
740744 zig_unreachable();
741745}
......@@ -1334,6 +1338,10 @@ static constexpr IrInstSrcId ir_inst_id(IrInstSrcBoolNot *) {
13341338 return IrInstSrcIdBoolNot;
13351339}
13361340
1341static constexpr IrInstSrcId ir_inst_id(IrInstSrcWasmMemorySize *) {
1342 return IrInstSrcIdWasmMemorySize;
1343}
1344
13371345static constexpr IrInstSrcId ir_inst_id(IrInstSrcMemset *) {
13381346 return IrInstSrcIdMemset;
13391347}
......@@ -1955,6 +1963,10 @@ static constexpr IrInstGenId ir_inst_id(IrInstGenConst *) {
19551963 return IrInstGenIdConst;
19561964}
19571965
1966static constexpr IrInstGenId ir_inst_id(IrInstGenWasmMemorySize *) {
1967 return IrInstGenIdWasmMemorySize;
1968}
1969
19581970template<typename T>
19591971static T *ir_create_instruction(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) {
19601972 T *special_instruction = heap::c_allocator.create<T>();
......@@ -3642,6 +3654,20 @@ static IrInstGen *ir_build_bool_not_gen(IrAnalyze *ira, IrInst *source_instr, Ir
36423654 return &instruction->base;
36433655}
36443656
3657static IrInstSrc *ir_build_wasm_memory_size_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) {
3658 IrInstSrcWasmMemorySize *instruction = ir_build_instruction<IrInstSrcWasmMemorySize>(irb, scope, source_node);
3659
3660 return &instruction->base;
3661}
3662
3663static IrInstGen *ir_build_wasm_memory_size_gen(IrAnalyze *ira, IrInst *source_instr) {
3664 IrInstGenWasmMemorySize *instruction = ir_build_inst_gen<IrInstGenWasmMemorySize>(&ira->new_irb,
3665 source_instr->scope, source_instr->source_node);
3666 instruction->base.value->type = ira->codegen->builtin_types.entry_i32;
3667
3668 return &instruction->base;
3669}
3670
36453671static IrInstSrc *ir_build_memset_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,
36463672 IrInstSrc *dest_ptr, IrInstSrc *byte, IrInstSrc *count)
36473673{
......@@ -6754,6 +6780,11 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod
67546780 IrInstSrc *ir_memset = ir_build_memset_src(irb, scope, node, arg0_value, arg1_value, arg2_value);
67556781 return ir_lval_wrap(irb, scope, ir_memset, lval, result_loc);
67566782 }
6783 case BuiltinFnIdWasmMemorySize:
6784 {
6785 IrInstSrc *ir_wasm_memory_size = ir_build_wasm_memory_size_src(irb, scope, node);
6786 return ir_lval_wrap(irb, scope, ir_wasm_memory_size, lval, result_loc);
6787 }
67576788 case BuiltinFnIdField:
67586789 {
67596790 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
......@@ -27651,6 +27682,16 @@ static IrInstGen *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstSrcHasF
2765127682 return ir_const_bool(ira, &instruction->base.base, result);
2765227683}
2765327684
27685static IrInstGen *ir_analyze_instruction_wasm_memory_size(IrAnalyze *ira, IrInstSrcWasmMemorySize *instruction) {
27686 if (!target_is_wasm(ira->codegen->zig_target)) {
27687 ir_add_error_node(ira, instruction->base.base.source_node,
27688 buf_sprintf("@wasmMemorySize is a wasm feature only"));
27689 return ira->codegen->invalid_inst_gen;
27690 }
27691
27692 return ir_build_wasm_memory_size_gen(ira, &instruction->base.base);
27693}
27694
2765427695static IrInstGen *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstSrcBreakpoint *instruction) {
2765527696 return ir_build_breakpoint_gen(ira, &instruction->base.base);
2765627697}
......@@ -30892,6 +30933,8 @@ static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruc
3089230933 return ir_analyze_instruction_spill_begin(ira, (IrInstSrcSpillBegin *)instruction);
3089330934 case IrInstSrcIdSpillEnd:
3089430935 return ir_analyze_instruction_spill_end(ira, (IrInstSrcSpillEnd *)instruction);
30936 case IrInstSrcIdWasmMemorySize:
30937 return ir_analyze_instruction_wasm_memory_size(ira, (IrInstSrcWasmMemorySize *)instruction);
3089530938 }
3089630939 zig_unreachable();
3089730940}
......@@ -31117,6 +31160,7 @@ bool ir_inst_gen_has_side_effects(IrInstGen *instruction) {
3111731160 case IrInstGenIdBinaryNot:
3111831161 case IrInstGenIdNegation:
3111931162 case IrInstGenIdNegationWrapping:
31163 case IrInstGenIdWasmMemorySize:
3112031164 return false;
3112131165
3112231166 case IrInstGenIdAsm:
......@@ -31283,6 +31327,7 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) {
3128331327 case IrInstSrcIdHasDecl:
3128431328 case IrInstSrcIdAlloca:
3128531329 case IrInstSrcIdSpillEnd:
31330 case IrInstSrcIdWasmMemorySize:
3128631331 return false;
3128731332
3128831333 case IrInstSrcIdAsm:
src/ir_print.cpp+18
......@@ -321,6 +321,8 @@ const char* ir_inst_src_type_str(IrInstSrcId id) {
321321 return "SrcSpillBegin";
322322 case IrInstSrcIdSpillEnd:
323323 return "SrcSpillEnd";
324 case IrInstSrcIdWasmMemorySize:
325 return "SrcWasmMemorySize";
324326 }
325327 zig_unreachable();
326328}
......@@ -501,6 +503,8 @@ const char* ir_inst_gen_type_str(IrInstGenId id) {
501503 return "GenNegation";
502504 case IrInstGenIdNegationWrapping:
503505 return "GenNegationWrapping";
506 case IrInstGenIdWasmMemorySize:
507 return "GenWasmMemorySize";
504508 }
505509 zig_unreachable();
506510}
......@@ -1708,6 +1712,14 @@ static void ir_print_bool_not(IrPrintGen *irp, IrInstGenBoolNot *instruction) {
17081712 ir_print_other_inst_gen(irp, instruction->value);
17091713}
17101714
1715static void ir_print_wasm_memory_size(IrPrintSrc *irp, IrInstSrcWasmMemorySize *instruction) {
1716 fprintf(irp->f, "@wasmMemorySize()");
1717}
1718
1719static void ir_print_wasm_memory_size(IrPrintGen *irp, IrInstGenWasmMemorySize *instruction) {
1720 fprintf(irp->f, "@wasmMemorySize()");
1721}
1722
17111723static void ir_print_memset(IrPrintSrc *irp, IrInstSrcMemset *instruction) {
17121724 fprintf(irp->f, "@memset(");
17131725 ir_print_other_inst_src(irp, instruction->dest_ptr);
......@@ -2952,6 +2964,9 @@ static void ir_print_inst_src(IrPrintSrc *irp, IrInstSrc *instruction, bool trai
29522964 case IrInstSrcIdClz:
29532965 ir_print_clz(irp, (IrInstSrcClz *)instruction);
29542966 break;
2967 case IrInstSrcIdWasmMemorySize:
2968 ir_print_wasm_memory_size(irp, (IrInstSrcWasmMemorySize *)instruction);
2969 break;
29552970 }
29562971 fprintf(irp->f, "\n");
29572972}
......@@ -3219,6 +3234,9 @@ static void ir_print_inst_gen(IrPrintGen *irp, IrInstGen *instruction, bool trai
32193234 case IrInstGenIdNegationWrapping:
32203235 ir_print_negation_wrapping(irp, (IrInstGenNegationWrapping *)instruction);
32213236 break;
3237 case IrInstGenIdWasmMemorySize:
3238 ir_print_wasm_memory_size(irp, (IrInstGenWasmMemorySize *)instruction);
3239 break;
32223240 }
32233241 fprintf(irp->f, "\n");
32243242}