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 {...@@ -1825,6 +1825,7 @@ enum BuiltinFnId {
1825 BuiltinFnIdAs,1825 BuiltinFnIdAs,
1826 BuiltinFnIdCall,1826 BuiltinFnIdCall,
1827 BuiltinFnIdBitSizeof,1827 BuiltinFnIdBitSizeof,
1828 BuiltinFnIdWasmMemorySize,
1828};1829};
18291830
1830struct BuiltinFnEntry {1831struct BuiltinFnEntry {
...@@ -2075,6 +2076,7 @@ struct CodeGen {...@@ -2075,6 +2076,7 @@ struct CodeGen {
2075 LLVMValueRef err_name_table;2076 LLVMValueRef err_name_table;
2076 LLVMValueRef safety_crash_err_fn;2077 LLVMValueRef safety_crash_err_fn;
2077 LLVMValueRef return_err_fn;2078 LLVMValueRef return_err_fn;
2079 LLVMValueRef wasm_memory_size;
2078 LLVMTypeRef anyframe_fn_type;2080 LLVMTypeRef anyframe_fn_type;
20792081
2080 // reminder: hash tables must be initialized before use2082 // reminder: hash tables must be initialized before use
...@@ -2748,6 +2750,7 @@ enum IrInstSrcId {...@@ -2748,6 +2750,7 @@ enum IrInstSrcId {
2748 IrInstSrcIdResume,2750 IrInstSrcIdResume,
2749 IrInstSrcIdSpillBegin,2751 IrInstSrcIdSpillBegin,
2750 IrInstSrcIdSpillEnd,2752 IrInstSrcIdSpillEnd,
2753 IrInstSrcIdWasmMemorySize,
2751};2754};
27522755
2753// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR.2756// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR.
...@@ -2840,6 +2843,7 @@ enum IrInstGenId {...@@ -2840,6 +2843,7 @@ enum IrInstGenId {
2840 IrInstGenIdVectorExtractElem,2843 IrInstGenIdVectorExtractElem,
2841 IrInstGenIdAlloca,2844 IrInstGenIdAlloca,
2842 IrInstGenIdConst,2845 IrInstGenIdConst,
2846 IrInstGenIdWasmMemorySize,
2843};2847};
28442848
2845// Common fields between IrInstSrc and IrInstGen. This allows future passes2849// Common fields between IrInstSrc and IrInstGen. This allows future passes
...@@ -3727,6 +3731,14 @@ struct IrInstGenMemcpy {...@@ -3727,6 +3731,14 @@ struct IrInstGenMemcpy {
3727 IrInstGen *count;3731 IrInstGen *count;
3728};3732};
37293733
3734struct IrInstSrcWasmMemorySize {
3735 IrInstSrc base;
3736};
3737
3738struct IrInstGenWasmMemorySize {
3739 IrInstGen base;
3740};
3741
3730struct IrInstSrcSlice {3742struct IrInstSrcSlice {
3731 IrInstSrc base;3743 IrInstSrc base;
37323744
src/codegen.cpp+27
...@@ -1045,6 +1045,19 @@ static void gen_assertion(CodeGen *g, PanicMsgId msg_id, IrInstGen *source_instr...@@ -1045,6 +1045,19 @@ static void gen_assertion(CodeGen *g, PanicMsgId msg_id, IrInstGen *source_instr
1045 return gen_assertion_scope(g, msg_id, source_instruction->base.scope);1045 return gen_assertion_scope(g, msg_id, source_instruction->base.scope);
1046}1046}
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
1048static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {1061static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {
1049 if (g->stacksave_fn_val)1062 if (g->stacksave_fn_val)
1050 return g->stacksave_fn_val;1063 return g->stacksave_fn_val;
...@@ -5588,6 +5601,17 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutableGen *executable, Ir...@@ -5588,6 +5601,17 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutableGen *executable, Ir
5588 return nullptr;5601 return nullptr;
5589}5602}
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
5591static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrInstGenSlice *instruction) {5615static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrInstGenSlice *instruction) {
5592 Error err;5616 Error err;
55935617
...@@ -6798,6 +6822,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutableGen *executabl...@@ -6798,6 +6822,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutableGen *executabl
6798 return ir_render_splat(g, executable, (IrInstGenSplat *) instruction);6822 return ir_render_splat(g, executable, (IrInstGenSplat *) instruction);
6799 case IrInstGenIdVectorExtractElem:6823 case IrInstGenIdVectorExtractElem:
6800 return ir_render_vector_extract_elem(g, executable, (IrInstGenVectorExtractElem *) instruction);6824 return ir_render_vector_extract_elem(g, executable, (IrInstGenVectorExtractElem *) instruction);
6825 case IrInstGenIdWasmMemorySize:
6826 return ir_render_wasm_memory_size(g, executable, (IrInstGenWasmMemorySize *) instruction);
6801 }6827 }
6802 zig_unreachable();6828 zig_unreachable();
6803}6829}
...@@ -8660,6 +8686,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -8660,6 +8686,7 @@ static void define_builtin_fns(CodeGen *g) {
8660 create_builtin_fn(g, BuiltinFnIdAs, "as", 2);8686 create_builtin_fn(g, BuiltinFnIdAs, "as", 2);
8661 create_builtin_fn(g, BuiltinFnIdCall, "call", 3);8687 create_builtin_fn(g, BuiltinFnIdCall, "call", 3);
8662 create_builtin_fn(g, BuiltinFnIdBitSizeof, "bitSizeOf", 1);8688 create_builtin_fn(g, BuiltinFnIdBitSizeof, "bitSizeOf", 1);
8689 create_builtin_fn(g, BuiltinFnIdWasmMemorySize, "wasmMemorySize", 0);
8663}8690}
86648691
8665static const char *bool_to_str(bool b) {8692static const char *bool_to_str(bool b) {
src/ir.cpp+45
...@@ -556,6 +556,8 @@ static void destroy_instruction_src(IrInstSrc *inst) {...@@ -556,6 +556,8 @@ static void destroy_instruction_src(IrInstSrc *inst) {
556 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSpillEnd *>(inst));556 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSpillEnd *>(inst));
557 case IrInstSrcIdCallArgs:557 case IrInstSrcIdCallArgs:
558 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCallArgs *>(inst));558 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCallArgs *>(inst));
559 case IrInstSrcIdWasmMemorySize:
560 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcWasmMemorySize *>(inst));
559 }561 }
560 zig_unreachable();562 zig_unreachable();
561}563}
...@@ -736,6 +738,8 @@ void destroy_instruction_gen(IrInstGen *inst) {...@@ -736,6 +738,8 @@ void destroy_instruction_gen(IrInstGen *inst) {
736 return heap::c_allocator.destroy(reinterpret_cast<IrInstGenNegation *>(inst));738 return heap::c_allocator.destroy(reinterpret_cast<IrInstGenNegation *>(inst));
737 case IrInstGenIdNegationWrapping:739 case IrInstGenIdNegationWrapping:
738 return heap::c_allocator.destroy(reinterpret_cast<IrInstGenNegationWrapping *>(inst));740 return heap::c_allocator.destroy(reinterpret_cast<IrInstGenNegationWrapping *>(inst));
741 case IrInstGenIdWasmMemorySize:
742 return heap::c_allocator.destroy(reinterpret_cast<IrInstGenWasmMemorySize *>(inst));
739 }743 }
740 zig_unreachable();744 zig_unreachable();
741}745}
...@@ -1334,6 +1338,10 @@ static constexpr IrInstSrcId ir_inst_id(IrInstSrcBoolNot *) {...@@ -1334,6 +1338,10 @@ static constexpr IrInstSrcId ir_inst_id(IrInstSrcBoolNot *) {
1334 return IrInstSrcIdBoolNot;1338 return IrInstSrcIdBoolNot;
1335}1339}
13361340
1341static constexpr IrInstSrcId ir_inst_id(IrInstSrcWasmMemorySize *) {
1342 return IrInstSrcIdWasmMemorySize;
1343}
1344
1337static constexpr IrInstSrcId ir_inst_id(IrInstSrcMemset *) {1345static constexpr IrInstSrcId ir_inst_id(IrInstSrcMemset *) {
1338 return IrInstSrcIdMemset;1346 return IrInstSrcIdMemset;
1339}1347}
...@@ -1955,6 +1963,10 @@ static constexpr IrInstGenId ir_inst_id(IrInstGenConst *) {...@@ -1955,6 +1963,10 @@ static constexpr IrInstGenId ir_inst_id(IrInstGenConst *) {
1955 return IrInstGenIdConst;1963 return IrInstGenIdConst;
1956}1964}
19571965
1966static constexpr IrInstGenId ir_inst_id(IrInstGenWasmMemorySize *) {
1967 return IrInstGenIdWasmMemorySize;
1968}
1969
1958template<typename T>1970template<typename T>
1959static T *ir_create_instruction(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) {1971static T *ir_create_instruction(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) {
1960 T *special_instruction = heap::c_allocator.create<T>();1972 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...@@ -3642,6 +3654,20 @@ static IrInstGen *ir_build_bool_not_gen(IrAnalyze *ira, IrInst *source_instr, Ir
3642 return &instruction->base;3654 return &instruction->base;
3643}3655}
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
3645static IrInstSrc *ir_build_memset_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,3671static IrInstSrc *ir_build_memset_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,
3646 IrInstSrc *dest_ptr, IrInstSrc *byte, IrInstSrc *count)3672 IrInstSrc *dest_ptr, IrInstSrc *byte, IrInstSrc *count)
3647{3673{
...@@ -6754,6 +6780,11 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod...@@ -6754,6 +6780,11 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod
6754 IrInstSrc *ir_memset = ir_build_memset_src(irb, scope, node, arg0_value, arg1_value, arg2_value);6780 IrInstSrc *ir_memset = ir_build_memset_src(irb, scope, node, arg0_value, arg1_value, arg2_value);
6755 return ir_lval_wrap(irb, scope, ir_memset, lval, result_loc);6781 return ir_lval_wrap(irb, scope, ir_memset, lval, result_loc);
6756 }6782 }
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 }
6757 case BuiltinFnIdField:6788 case BuiltinFnIdField:
6758 {6789 {
6759 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);6790 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...@@ -27651,6 +27682,16 @@ static IrInstGen *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstSrcHasF
27651 return ir_const_bool(ira, &instruction->base.base, result);27682 return ir_const_bool(ira, &instruction->base.base, result);
27652}27683}
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
27654static IrInstGen *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstSrcBreakpoint *instruction) {27695static IrInstGen *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstSrcBreakpoint *instruction) {
27655 return ir_build_breakpoint_gen(ira, &instruction->base.base);27696 return ir_build_breakpoint_gen(ira, &instruction->base.base);
27656}27697}
...@@ -30892,6 +30933,8 @@ static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruc...@@ -30892,6 +30933,8 @@ static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruc
30892 return ir_analyze_instruction_spill_begin(ira, (IrInstSrcSpillBegin *)instruction);30933 return ir_analyze_instruction_spill_begin(ira, (IrInstSrcSpillBegin *)instruction);
30893 case IrInstSrcIdSpillEnd:30934 case IrInstSrcIdSpillEnd:
30894 return ir_analyze_instruction_spill_end(ira, (IrInstSrcSpillEnd *)instruction);30935 return ir_analyze_instruction_spill_end(ira, (IrInstSrcSpillEnd *)instruction);
30936 case IrInstSrcIdWasmMemorySize:
30937 return ir_analyze_instruction_wasm_memory_size(ira, (IrInstSrcWasmMemorySize *)instruction);
30895 }30938 }
30896 zig_unreachable();30939 zig_unreachable();
30897}30940}
...@@ -31117,6 +31160,7 @@ bool ir_inst_gen_has_side_effects(IrInstGen *instruction) {...@@ -31117,6 +31160,7 @@ bool ir_inst_gen_has_side_effects(IrInstGen *instruction) {
31117 case IrInstGenIdBinaryNot:31160 case IrInstGenIdBinaryNot:
31118 case IrInstGenIdNegation:31161 case IrInstGenIdNegation:
31119 case IrInstGenIdNegationWrapping:31162 case IrInstGenIdNegationWrapping:
31163 case IrInstGenIdWasmMemorySize:
31120 return false;31164 return false;
3112131165
31122 case IrInstGenIdAsm:31166 case IrInstGenIdAsm:
...@@ -31283,6 +31327,7 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) {...@@ -31283,6 +31327,7 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) {
31283 case IrInstSrcIdHasDecl:31327 case IrInstSrcIdHasDecl:
31284 case IrInstSrcIdAlloca:31328 case IrInstSrcIdAlloca:
31285 case IrInstSrcIdSpillEnd:31329 case IrInstSrcIdSpillEnd:
31330 case IrInstSrcIdWasmMemorySize:
31286 return false;31331 return false;
3128731332
31288 case IrInstSrcIdAsm:31333 case IrInstSrcIdAsm:
src/ir_print.cpp+18
...@@ -321,6 +321,8 @@ const char* ir_inst_src_type_str(IrInstSrcId id) {...@@ -321,6 +321,8 @@ const char* ir_inst_src_type_str(IrInstSrcId id) {
321 return "SrcSpillBegin";321 return "SrcSpillBegin";
322 case IrInstSrcIdSpillEnd:322 case IrInstSrcIdSpillEnd:
323 return "SrcSpillEnd";323 return "SrcSpillEnd";
324 case IrInstSrcIdWasmMemorySize:
325 return "SrcWasmMemorySize";
324 }326 }
325 zig_unreachable();327 zig_unreachable();
326}328}
...@@ -501,6 +503,8 @@ const char* ir_inst_gen_type_str(IrInstGenId id) {...@@ -501,6 +503,8 @@ const char* ir_inst_gen_type_str(IrInstGenId id) {
501 return "GenNegation";503 return "GenNegation";
502 case IrInstGenIdNegationWrapping:504 case IrInstGenIdNegationWrapping:
503 return "GenNegationWrapping";505 return "GenNegationWrapping";
506 case IrInstGenIdWasmMemorySize:
507 return "GenWasmMemorySize";
504 }508 }
505 zig_unreachable();509 zig_unreachable();
506}510}
...@@ -1708,6 +1712,14 @@ static void ir_print_bool_not(IrPrintGen *irp, IrInstGenBoolNot *instruction) {...@@ -1708,6 +1712,14 @@ static void ir_print_bool_not(IrPrintGen *irp, IrInstGenBoolNot *instruction) {
1708 ir_print_other_inst_gen(irp, instruction->value);1712 ir_print_other_inst_gen(irp, instruction->value);
1709}1713}
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
1711static void ir_print_memset(IrPrintSrc *irp, IrInstSrcMemset *instruction) {1723static void ir_print_memset(IrPrintSrc *irp, IrInstSrcMemset *instruction) {
1712 fprintf(irp->f, "@memset(");1724 fprintf(irp->f, "@memset(");
1713 ir_print_other_inst_src(irp, instruction->dest_ptr);1725 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...@@ -2952,6 +2964,9 @@ static void ir_print_inst_src(IrPrintSrc *irp, IrInstSrc *instruction, bool trai
2952 case IrInstSrcIdClz:2964 case IrInstSrcIdClz:
2953 ir_print_clz(irp, (IrInstSrcClz *)instruction);2965 ir_print_clz(irp, (IrInstSrcClz *)instruction);
2954 break;2966 break;
2967 case IrInstSrcIdWasmMemorySize:
2968 ir_print_wasm_memory_size(irp, (IrInstSrcWasmMemorySize *)instruction);
2969 break;
2955 }2970 }
2956 fprintf(irp->f, "\n");2971 fprintf(irp->f, "\n");
2957}2972}
...@@ -3219,6 +3234,9 @@ static void ir_print_inst_gen(IrPrintGen *irp, IrInstGen *instruction, bool trai...@@ -3219,6 +3234,9 @@ static void ir_print_inst_gen(IrPrintGen *irp, IrInstGen *instruction, bool trai
3219 case IrInstGenIdNegationWrapping:3234 case IrInstGenIdNegationWrapping:
3220 ir_print_negation_wrapping(irp, (IrInstGenNegationWrapping *)instruction);3235 ir_print_negation_wrapping(irp, (IrInstGenNegationWrapping *)instruction);
3221 break;3236 break;
3237 case IrInstGenIdWasmMemorySize:
3238 ir_print_wasm_memory_size(irp, (IrInstGenWasmMemorySize *)instruction);
3239 break;
3222 }3240 }
3223 fprintf(irp->f, "\n");3241 fprintf(irp->f, "\n");
3224}3242}