authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-09 00:22:43-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-09 00:22:43-04:00
log4302f276ed3083b4f261f9e50a9546c9877d2785
treec857775bf067e7838764125d68210376491058c5
parent12051b02f1f455b85d5a519dd1747a67d4bb68d0
parent42c95a64d67ec6fc2839fad36ef50bacc7545258

Merge branch 'kubkon-wasm-instrinsics'

closes #5507

9 files changed, 361 insertions(+), 6 deletions(-)

doc/langref.html.in+43
...@@ -7643,6 +7643,49 @@ mem.copy(u8, dest[0..byte_count], source[0..byte_count]);{#endsyntax#}</pre>...@@ -7643,6 +7643,49 @@ mem.copy(u8, dest[0..byte_count], source[0..byte_count]);{#endsyntax#}</pre>
7643mem.set(u8, dest, c);{#endsyntax#}</pre>7643mem.set(u8, dest, c);{#endsyntax#}</pre>
7644 {#header_close#}7644 {#header_close#}
76457645
7646 {#header_open|@wasmMemorySize#}
7647 <pre>{#syntax#}@wasmMemorySize(index: u32) u32{#endsyntax#}</pre>
7648 <p>
7649 This function returns the size of the Wasm memory identified by {#syntax#}index{#endsyntax#} as
7650 an unsigned value in units of Wasm pages. Note that each Wasm page is 64KB in size.
7651 </p>
7652 <p>
7653 This function is a low level intrinsic with no safety mechanisms usually useful for allocator
7654 designers targeting Wasm. So unless you are writing a new allocator from scratch, you should use
7655 something like {#syntax#}@import("std").heap.WasmPageAllocator{#endsyntax#}.
7656 </p>
7657 {#see_also|@wasmMemoryGrow#}
7658 {#header_close#}
7659
7660 {#header_open|@wasmMemoryGrow#}
7661 <pre>{#syntax#}@wasmMemoryGrow(index: u32, delta: u32) i32{#endsyntax#}</pre>
7662 <p>
7663 This function increases the size of the Wasm memory identified by {#syntax#}index{#endsyntax#} by
7664 {#syntax#}delta{#endsyntax#} in units of unsigned number of Wasm pages. Note that each Wasm page
7665 is 64KB in size. On success, returns previous memory size; on failure, if the allocation fails,
7666 returns -1.
7667 </p>
7668 <p>
7669 This function is a low level intrinsic with no safety mechanisms usually useful for allocator
7670 designers targeting Wasm. So unless you are writing a new allocator from scratch, you should use
7671 something like {#syntax#}@import("std").heap.WasmPageAllocator{#endsyntax#}.
7672 </p>
7673 {#code_begin|test#}
7674const std = @import("std");
7675const builtin = @import("builtin");
7676const assert = std.debug.assert;
7677
7678test "@wasmMemoryGrow" {
7679 if (builtin.arch != .wasm32) return error.SkipZigTest;
7680
7681 var prev = @wasmMemorySize(0);
7682 assert(prev == @wasmMemoryGrow(0, 1));
7683 assert(prev + 1 == @wasmMemorySize(0));
7684}
7685 {#code_end#}
7686 {#see_also|@wasmMemorySize#}
7687 {#header_close#}
7688
7646 {#header_open|@mod#}7689 {#header_open|@mod#}
7647 <pre>{#syntax#}@mod(numerator: T, denominator: T) T{#endsyntax#}</pre>7690 <pre>{#syntax#}@mod(numerator: T, denominator: T) T{#endsyntax#}</pre>
7648 <p>7691 <p>
lib/std/heap.zig+1-6
...@@ -250,11 +250,6 @@ const PageAllocator = struct {...@@ -250,11 +250,6 @@ const PageAllocator = struct {
250 }250 }
251};251};
252252
253// TODO Exposed LLVM intrinsics is a bug
254// See: https://github.com/ziglang/zig/issues/2291
255extern fn @"llvm.wasm.memory.size.i32"(u32) u32;
256extern fn @"llvm.wasm.memory.grow.i32"(u32, u32) i32;
257
258const WasmPageAllocator = struct {253const WasmPageAllocator = struct {
259 comptime {254 comptime {
260 if (!std.Target.current.isWasm()) {255 if (!std.Target.current.isWasm()) {
...@@ -357,7 +352,7 @@ const WasmPageAllocator = struct {...@@ -357,7 +352,7 @@ const WasmPageAllocator = struct {
357 return idx + extendedOffset();352 return idx + extendedOffset();
358 }353 }
359354
360 const prev_page_count = @"llvm.wasm.memory.grow.i32"(0, @intCast(u32, page_count));355 const prev_page_count = @wasmMemoryGrow(0, @intCast(u32, page_count));
361 if (prev_page_count <= 0) {356 if (prev_page_count <= 0) {
362 return error.OutOfMemory;357 return error.OutOfMemory;
363 }358 }
src/all_types.hpp+34
...@@ -1825,6 +1825,8 @@ enum BuiltinFnId {...@@ -1825,6 +1825,8 @@ enum BuiltinFnId {
1825 BuiltinFnIdAs,1825 BuiltinFnIdAs,
1826 BuiltinFnIdCall,1826 BuiltinFnIdCall,
1827 BuiltinFnIdBitSizeof,1827 BuiltinFnIdBitSizeof,
1828 BuiltinFnIdWasmMemorySize,
1829 BuiltinFnIdWasmMemoryGrow,
1828};1830};
18291831
1830struct BuiltinFnEntry {1832struct BuiltinFnEntry {
...@@ -2075,6 +2077,8 @@ struct CodeGen {...@@ -2075,6 +2077,8 @@ struct CodeGen {
2075 LLVMValueRef err_name_table;2077 LLVMValueRef err_name_table;
2076 LLVMValueRef safety_crash_err_fn;2078 LLVMValueRef safety_crash_err_fn;
2077 LLVMValueRef return_err_fn;2079 LLVMValueRef return_err_fn;
2080 LLVMValueRef wasm_memory_size;
2081 LLVMValueRef wasm_memory_grow;
2078 LLVMTypeRef anyframe_fn_type;2082 LLVMTypeRef anyframe_fn_type;
20792083
2080 // reminder: hash tables must be initialized before use2084 // reminder: hash tables must be initialized before use
...@@ -2748,6 +2752,8 @@ enum IrInstSrcId {...@@ -2748,6 +2752,8 @@ enum IrInstSrcId {
2748 IrInstSrcIdResume,2752 IrInstSrcIdResume,
2749 IrInstSrcIdSpillBegin,2753 IrInstSrcIdSpillBegin,
2750 IrInstSrcIdSpillEnd,2754 IrInstSrcIdSpillEnd,
2755 IrInstSrcIdWasmMemorySize,
2756 IrInstSrcIdWasmMemoryGrow,
2751};2757};
27522758
2753// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR.2759// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR.
...@@ -2840,6 +2846,8 @@ enum IrInstGenId {...@@ -2840,6 +2846,8 @@ enum IrInstGenId {
2840 IrInstGenIdVectorExtractElem,2846 IrInstGenIdVectorExtractElem,
2841 IrInstGenIdAlloca,2847 IrInstGenIdAlloca,
2842 IrInstGenIdConst,2848 IrInstGenIdConst,
2849 IrInstGenIdWasmMemorySize,
2850 IrInstGenIdWasmMemoryGrow,
2843};2851};
28442852
2845// Common fields between IrInstSrc and IrInstGen. This allows future passes2853// Common fields between IrInstSrc and IrInstGen. This allows future passes
...@@ -3727,6 +3735,32 @@ struct IrInstGenMemcpy {...@@ -3727,6 +3735,32 @@ struct IrInstGenMemcpy {
3727 IrInstGen *count;3735 IrInstGen *count;
3728};3736};
37293737
3738struct IrInstSrcWasmMemorySize {
3739 IrInstSrc base;
3740
3741 IrInstSrc *index;
3742};
3743
3744struct IrInstGenWasmMemorySize {
3745 IrInstGen base;
3746
3747 IrInstGen *index;
3748};
3749
3750struct IrInstSrcWasmMemoryGrow {
3751 IrInstSrc base;
3752
3753 IrInstSrc *index;
3754 IrInstSrc *delta;
3755};
3756
3757struct IrInstGenWasmMemoryGrow {
3758 IrInstGen base;
3759
3760 IrInstGen *index;
3761 IrInstGen *delta;
3762};
3763
3730struct IrInstSrcSlice {3764struct IrInstSrcSlice {
3731 IrInstSrc base;3765 IrInstSrc base;
37323766
src/codegen.cpp+54
...@@ -1045,6 +1045,37 @@ static void gen_assertion(CodeGen *g, PanicMsgId msg_id, IrInstGen *source_instr...@@ -1045,6 +1045,37 @@ 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 // TODO adjust for wasm64 as well
1053 // declare i32 @llvm.wasm.memory.size.i32(i32) nounwind readonly
1054 LLVMTypeRef param_type = LLVMInt32Type();
1055 LLVMTypeRef fn_type = LLVMFunctionType(LLVMInt32Type(), &param_type, 1, false);
1056 g->wasm_memory_size = LLVMAddFunction(g->module, "llvm.wasm.memory.size.i32", fn_type);
1057 assert(LLVMGetIntrinsicID(g->wasm_memory_size));
1058
1059 return g->wasm_memory_size;
1060}
1061
1062static LLVMValueRef gen_wasm_memory_grow(CodeGen *g) {
1063 if (g->wasm_memory_grow)
1064 return g->wasm_memory_grow;
1065
1066 // TODO adjust for wasm64 as well
1067 // declare i32 @llvm.wasm.memory.grow.i32(i32, i32) nounwind
1068 LLVMTypeRef param_types[] = {
1069 LLVMInt32Type(),
1070 LLVMInt32Type(),
1071 };
1072 LLVMTypeRef fn_type = LLVMFunctionType(LLVMInt32Type(), param_types, 2, false);
1073 g->wasm_memory_grow = LLVMAddFunction(g->module, "llvm.wasm.memory.grow.i32", fn_type);
1074 assert(LLVMGetIntrinsicID(g->wasm_memory_grow));
1075
1076 return g->wasm_memory_grow;
1077}
1078
1048static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {1079static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {
1049 if (g->stacksave_fn_val)1080 if (g->stacksave_fn_val)
1050 return g->stacksave_fn_val;1081 return g->stacksave_fn_val;
...@@ -5588,6 +5619,23 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutableGen *executable, Ir...@@ -5588,6 +5619,23 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutableGen *executable, Ir
5588 return nullptr;5619 return nullptr;
5589}5620}
55905621
5622static LLVMValueRef ir_render_wasm_memory_size(CodeGen *g, IrExecutableGen *executable, IrInstGenWasmMemorySize *instruction) {
5623 // TODO adjust for wasm64
5624 LLVMValueRef param = ir_llvm_value(g, instruction->index);
5625 LLVMValueRef val = LLVMBuildCall(g->builder, gen_wasm_memory_size(g), &param, 1, "");
5626 return val;
5627}
5628
5629static LLVMValueRef ir_render_wasm_memory_grow(CodeGen *g, IrExecutableGen *executable, IrInstGenWasmMemoryGrow *instruction) {
5630 // TODO adjust for wasm64
5631 LLVMValueRef params[] = {
5632 ir_llvm_value(g, instruction->index),
5633 ir_llvm_value(g, instruction->delta),
5634 };
5635 LLVMValueRef val = LLVMBuildCall(g->builder, gen_wasm_memory_grow(g), params, 2, "");
5636 return val;
5637}
5638
5591static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrInstGenSlice *instruction) {5639static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrInstGenSlice *instruction) {
5592 Error err;5640 Error err;
55935641
...@@ -6798,6 +6846,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutableGen *executabl...@@ -6798,6 +6846,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutableGen *executabl
6798 return ir_render_splat(g, executable, (IrInstGenSplat *) instruction);6846 return ir_render_splat(g, executable, (IrInstGenSplat *) instruction);
6799 case IrInstGenIdVectorExtractElem:6847 case IrInstGenIdVectorExtractElem:
6800 return ir_render_vector_extract_elem(g, executable, (IrInstGenVectorExtractElem *) instruction);6848 return ir_render_vector_extract_elem(g, executable, (IrInstGenVectorExtractElem *) instruction);
6849 case IrInstGenIdWasmMemorySize:
6850 return ir_render_wasm_memory_size(g, executable, (IrInstGenWasmMemorySize *) instruction);
6851 case IrInstGenIdWasmMemoryGrow:
6852 return ir_render_wasm_memory_grow(g, executable, (IrInstGenWasmMemoryGrow *) instruction);
6801 }6853 }
6802 zig_unreachable();6854 zig_unreachable();
6803}6855}
...@@ -8660,6 +8712,8 @@ static void define_builtin_fns(CodeGen *g) {...@@ -8660,6 +8712,8 @@ static void define_builtin_fns(CodeGen *g) {
8660 create_builtin_fn(g, BuiltinFnIdAs, "as", 2);8712 create_builtin_fn(g, BuiltinFnIdAs, "as", 2);
8661 create_builtin_fn(g, BuiltinFnIdCall, "call", 3);8713 create_builtin_fn(g, BuiltinFnIdCall, "call", 3);
8662 create_builtin_fn(g, BuiltinFnIdBitSizeof, "bitSizeOf", 1);8714 create_builtin_fn(g, BuiltinFnIdBitSizeof, "bitSizeOf", 1);
8715 create_builtin_fn(g, BuiltinFnIdWasmMemorySize, "wasmMemorySize", 1);
8716 create_builtin_fn(g, BuiltinFnIdWasmMemoryGrow, "wasmMemoryGrow", 2);
8663}8717}
86648718
8665static const char *bool_to_str(bool b) {8719static const char *bool_to_str(bool b) {
src/ir.cpp+152
...@@ -556,6 +556,10 @@ static void destroy_instruction_src(IrInstSrc *inst) {...@@ -556,6 +556,10 @@ 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));
561 case IrInstSrcIdWasmMemoryGrow:
562 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcWasmMemoryGrow *>(inst));
559 }563 }
560 zig_unreachable();564 zig_unreachable();
561}565}
...@@ -736,6 +740,10 @@ void destroy_instruction_gen(IrInstGen *inst) {...@@ -736,6 +740,10 @@ void destroy_instruction_gen(IrInstGen *inst) {
736 return heap::c_allocator.destroy(reinterpret_cast<IrInstGenNegation *>(inst));740 return heap::c_allocator.destroy(reinterpret_cast<IrInstGenNegation *>(inst));
737 case IrInstGenIdNegationWrapping:741 case IrInstGenIdNegationWrapping:
738 return heap::c_allocator.destroy(reinterpret_cast<IrInstGenNegationWrapping *>(inst));742 return heap::c_allocator.destroy(reinterpret_cast<IrInstGenNegationWrapping *>(inst));
743 case IrInstGenIdWasmMemorySize:
744 return heap::c_allocator.destroy(reinterpret_cast<IrInstGenWasmMemorySize *>(inst));
745 case IrInstGenIdWasmMemoryGrow:
746 return heap::c_allocator.destroy(reinterpret_cast<IrInstGenWasmMemoryGrow *>(inst));
739 }747 }
740 zig_unreachable();748 zig_unreachable();
741}749}
...@@ -1610,6 +1618,14 @@ static constexpr IrInstSrcId ir_inst_id(IrInstSrcSpillEnd *) {...@@ -1610,6 +1618,14 @@ static constexpr IrInstSrcId ir_inst_id(IrInstSrcSpillEnd *) {
1610 return IrInstSrcIdSpillEnd;1618 return IrInstSrcIdSpillEnd;
1611}1619}
16121620
1621static constexpr IrInstSrcId ir_inst_id(IrInstSrcWasmMemorySize *) {
1622 return IrInstSrcIdWasmMemorySize;
1623}
1624
1625static constexpr IrInstSrcId ir_inst_id(IrInstSrcWasmMemoryGrow *) {
1626 return IrInstSrcIdWasmMemoryGrow;
1627}
1628
16131629
1614static constexpr IrInstGenId ir_inst_id(IrInstGenDeclVar *) {1630static constexpr IrInstGenId ir_inst_id(IrInstGenDeclVar *) {
1615 return IrInstGenIdDeclVar;1631 return IrInstGenIdDeclVar;
...@@ -1955,6 +1971,14 @@ static constexpr IrInstGenId ir_inst_id(IrInstGenConst *) {...@@ -1955,6 +1971,14 @@ static constexpr IrInstGenId ir_inst_id(IrInstGenConst *) {
1955 return IrInstGenIdConst;1971 return IrInstGenIdConst;
1956}1972}
19571973
1974static constexpr IrInstGenId ir_inst_id(IrInstGenWasmMemorySize *) {
1975 return IrInstGenIdWasmMemorySize;
1976}
1977
1978static constexpr IrInstGenId ir_inst_id(IrInstGenWasmMemoryGrow *) {
1979 return IrInstGenIdWasmMemoryGrow;
1980}
1981
1958template<typename T>1982template<typename T>
1959static T *ir_create_instruction(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) {1983static T *ir_create_instruction(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) {
1960 T *special_instruction = heap::c_allocator.create<T>();1984 T *special_instruction = heap::c_allocator.create<T>();
...@@ -4961,6 +4985,51 @@ static IrInstGen *ir_build_vector_extract_elem(IrAnalyze *ira, IrInst *source_in...@@ -4961,6 +4985,51 @@ static IrInstGen *ir_build_vector_extract_elem(IrAnalyze *ira, IrInst *source_in
4961 return &instruction->base;4985 return &instruction->base;
4962}4986}
49634987
4988static IrInstSrc *ir_build_wasm_memory_size_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *index) {
4989 IrInstSrcWasmMemorySize *instruction = ir_build_instruction<IrInstSrcWasmMemorySize>(irb, scope, source_node);
4990 instruction->index = index;
4991
4992 ir_ref_instruction(index, irb->current_basic_block);
4993
4994 return &instruction->base;
4995}
4996
4997static IrInstGen *ir_build_wasm_memory_size_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *index) {
4998 IrInstGenWasmMemorySize *instruction = ir_build_inst_gen<IrInstGenWasmMemorySize>(&ira->new_irb,
4999 source_instr->scope, source_instr->source_node);
5000 instruction->base.value->type = ira->codegen->builtin_types.entry_u32;
5001 instruction->index = index;
5002
5003 ir_ref_inst_gen(index);
5004
5005 return &instruction->base;
5006}
5007
5008static IrInstSrc *ir_build_wasm_memory_grow_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *index, IrInstSrc *delta) {
5009 IrInstSrcWasmMemoryGrow *instruction = ir_build_instruction<IrInstSrcWasmMemoryGrow>(irb, scope, source_node);
5010 instruction->index = index;
5011 instruction->delta = delta;
5012
5013 ir_ref_instruction(index, irb->current_basic_block);
5014 ir_ref_instruction(delta, irb->current_basic_block);
5015
5016 return &instruction->base;
5017}
5018
5019static IrInstGen *ir_build_wasm_memory_grow_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *index, IrInstGen *delta) {
5020 IrInstGenWasmMemoryGrow *instruction = ir_build_inst_gen<IrInstGenWasmMemoryGrow>(&ira->new_irb,
5021 source_instr->scope, source_instr->source_node);
5022 instruction->base.value->type = ira->codegen->builtin_types.entry_i32;
5023 instruction->index = index;
5024 instruction->delta = delta;
5025
5026 ir_ref_inst_gen(index);
5027 ir_ref_inst_gen(delta);
5028
5029 return &instruction->base;
5030}
5031
5032
4964static void ir_count_defers(IrBuilderSrc *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {5033static void ir_count_defers(IrBuilderSrc *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
4965 results[ReturnKindUnconditional] = 0;5034 results[ReturnKindUnconditional] = 0;
4966 results[ReturnKindError] = 0;5035 results[ReturnKindError] = 0;
...@@ -6754,6 +6823,31 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod...@@ -6754,6 +6823,31 @@ 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);6823 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);6824 return ir_lval_wrap(irb, scope, ir_memset, lval, result_loc);
6756 }6825 }
6826 case BuiltinFnIdWasmMemorySize:
6827 {
6828 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
6829 IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope);
6830 if (arg0_value == irb->codegen->invalid_inst_src)
6831 return arg0_value;
6832
6833 IrInstSrc *ir_wasm_memory_size = ir_build_wasm_memory_size_src(irb, scope, node, arg0_value);
6834 return ir_lval_wrap(irb, scope, ir_wasm_memory_size, lval, result_loc);
6835 }
6836 case BuiltinFnIdWasmMemoryGrow:
6837 {
6838 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
6839 IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope);
6840 if (arg0_value == irb->codegen->invalid_inst_src)
6841 return arg0_value;
6842
6843 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
6844 IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope);
6845 if (arg1_value == irb->codegen->invalid_inst_src)
6846 return arg1_value;
6847
6848 IrInstSrc *ir_wasm_memory_grow = ir_build_wasm_memory_grow_src(irb, scope, node, arg0_value, arg1_value);
6849 return ir_lval_wrap(irb, scope, ir_wasm_memory_grow, lval, result_loc);
6850 }
6757 case BuiltinFnIdField:6851 case BuiltinFnIdField:
6758 {6852 {
6759 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);6853 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
...@@ -27651,6 +27745,56 @@ static IrInstGen *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstSrcHasF...@@ -27651,6 +27745,56 @@ static IrInstGen *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstSrcHasF
27651 return ir_const_bool(ira, &instruction->base.base, result);27745 return ir_const_bool(ira, &instruction->base.base, result);
27652}27746}
2765327747
27748static IrInstGen *ir_analyze_instruction_wasm_memory_size(IrAnalyze *ira, IrInstSrcWasmMemorySize *instruction) {
27749 // TODO generate compile error for target_arch different than 32bit
27750 if (!target_is_wasm(ira->codegen->zig_target)) {
27751 ir_add_error_node(ira, instruction->base.base.source_node,
27752 buf_sprintf("@wasmMemorySize is a wasm32 feature only"));
27753 return ira->codegen->invalid_inst_gen;
27754 }
27755
27756 IrInstGen *index = instruction->index->child;
27757 if (type_is_invalid(index->value->type))
27758 return ira->codegen->invalid_inst_gen;
27759
27760 ZigType *u32 = ira->codegen->builtin_types.entry_u32;
27761
27762 IrInstGen *casted_index = ir_implicit_cast(ira, index, u32);
27763 if (type_is_invalid(casted_index->value->type))
27764 return ira->codegen->invalid_inst_gen;
27765
27766 return ir_build_wasm_memory_size_gen(ira, &instruction->base.base, casted_index);
27767}
27768
27769static IrInstGen *ir_analyze_instruction_wasm_memory_grow(IrAnalyze *ira, IrInstSrcWasmMemoryGrow *instruction) {
27770 // TODO generate compile error for target_arch different than 32bit
27771 if (!target_is_wasm(ira->codegen->zig_target)) {
27772 ir_add_error_node(ira, instruction->base.base.source_node,
27773 buf_sprintf("@wasmMemoryGrow is a wasm32 feature only"));
27774 return ira->codegen->invalid_inst_gen;
27775 }
27776
27777 IrInstGen *index = instruction->index->child;
27778 if (type_is_invalid(index->value->type))
27779 return ira->codegen->invalid_inst_gen;
27780
27781 ZigType *u32 = ira->codegen->builtin_types.entry_u32;
27782
27783 IrInstGen *casted_index = ir_implicit_cast(ira, index, u32);
27784 if (type_is_invalid(casted_index->value->type))
27785 return ira->codegen->invalid_inst_gen;
27786
27787 IrInstGen *delta = instruction->delta->child;
27788 if (type_is_invalid(delta->value->type))
27789 return ira->codegen->invalid_inst_gen;
27790
27791 IrInstGen *casted_delta = ir_implicit_cast(ira, delta, u32);
27792 if (type_is_invalid(casted_delta->value->type))
27793 return ira->codegen->invalid_inst_gen;
27794
27795 return ir_build_wasm_memory_grow_gen(ira, &instruction->base.base, casted_index, casted_delta);
27796}
27797
27654static IrInstGen *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstSrcBreakpoint *instruction) {27798static IrInstGen *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstSrcBreakpoint *instruction) {
27655 return ir_build_breakpoint_gen(ira, &instruction->base.base);27799 return ir_build_breakpoint_gen(ira, &instruction->base.base);
27656}27800}
...@@ -30892,6 +31036,10 @@ static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruc...@@ -30892,6 +31036,10 @@ static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruc
30892 return ir_analyze_instruction_spill_begin(ira, (IrInstSrcSpillBegin *)instruction);31036 return ir_analyze_instruction_spill_begin(ira, (IrInstSrcSpillBegin *)instruction);
30893 case IrInstSrcIdSpillEnd:31037 case IrInstSrcIdSpillEnd:
30894 return ir_analyze_instruction_spill_end(ira, (IrInstSrcSpillEnd *)instruction);31038 return ir_analyze_instruction_spill_end(ira, (IrInstSrcSpillEnd *)instruction);
31039 case IrInstSrcIdWasmMemorySize:
31040 return ir_analyze_instruction_wasm_memory_size(ira, (IrInstSrcWasmMemorySize *)instruction);
31041 case IrInstSrcIdWasmMemoryGrow:
31042 return ir_analyze_instruction_wasm_memory_grow(ira, (IrInstSrcWasmMemoryGrow *)instruction);
30895 }31043 }
30896 zig_unreachable();31044 zig_unreachable();
30897}31045}
...@@ -31068,6 +31216,7 @@ bool ir_inst_gen_has_side_effects(IrInstGen *instruction) {...@@ -31068,6 +31216,7 @@ bool ir_inst_gen_has_side_effects(IrInstGen *instruction) {
31068 case IrInstGenIdResume:31216 case IrInstGenIdResume:
31069 case IrInstGenIdAwait:31217 case IrInstGenIdAwait:
31070 case IrInstGenIdSpillBegin:31218 case IrInstGenIdSpillBegin:
31219 case IrInstGenIdWasmMemoryGrow:
31071 return true;31220 return true;
3107231221
31073 case IrInstGenIdPhi:31222 case IrInstGenIdPhi:
...@@ -31117,6 +31266,7 @@ bool ir_inst_gen_has_side_effects(IrInstGen *instruction) {...@@ -31117,6 +31266,7 @@ bool ir_inst_gen_has_side_effects(IrInstGen *instruction) {
31117 case IrInstGenIdBinaryNot:31266 case IrInstGenIdBinaryNot:
31118 case IrInstGenIdNegation:31267 case IrInstGenIdNegation:
31119 case IrInstGenIdNegationWrapping:31268 case IrInstGenIdNegationWrapping:
31269 case IrInstGenIdWasmMemorySize:
31120 return false;31270 return false;
3112131271
31122 case IrInstGenIdAsm:31272 case IrInstGenIdAsm:
...@@ -31199,6 +31349,7 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) {...@@ -31199,6 +31349,7 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) {
31199 case IrInstSrcIdResume:31349 case IrInstSrcIdResume:
31200 case IrInstSrcIdAwait:31350 case IrInstSrcIdAwait:
31201 case IrInstSrcIdSpillBegin:31351 case IrInstSrcIdSpillBegin:
31352 case IrInstSrcIdWasmMemoryGrow:
31202 return true;31353 return true;
3120331354
31204 case IrInstSrcIdPhi:31355 case IrInstSrcIdPhi:
...@@ -31283,6 +31434,7 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) {...@@ -31283,6 +31434,7 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) {
31283 case IrInstSrcIdHasDecl:31434 case IrInstSrcIdHasDecl:
31284 case IrInstSrcIdAlloca:31435 case IrInstSrcIdAlloca:
31285 case IrInstSrcIdSpillEnd:31436 case IrInstSrcIdSpillEnd:
31437 case IrInstSrcIdWasmMemorySize:
31286 return false;31438 return false;
3128731439
31288 case IrInstSrcIdAsm:31440 case IrInstSrcIdAsm:
src/ir_print.cpp+48
...@@ -321,6 +321,10 @@ const char* ir_inst_src_type_str(IrInstSrcId id) {...@@ -321,6 +321,10 @@ 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";
326 case IrInstSrcIdWasmMemoryGrow:
327 return "SrcWasmMemoryGrow";
324 }328 }
325 zig_unreachable();329 zig_unreachable();
326}330}
...@@ -501,6 +505,10 @@ const char* ir_inst_gen_type_str(IrInstGenId id) {...@@ -501,6 +505,10 @@ const char* ir_inst_gen_type_str(IrInstGenId id) {
501 return "GenNegation";505 return "GenNegation";
502 case IrInstGenIdNegationWrapping:506 case IrInstGenIdNegationWrapping:
503 return "GenNegationWrapping";507 return "GenNegationWrapping";
508 case IrInstGenIdWasmMemorySize:
509 return "GenWasmMemorySize";
510 case IrInstGenIdWasmMemoryGrow:
511 return "GenWasmMemoryGrow";
504 }512 }
505 zig_unreachable();513 zig_unreachable();
506}514}
...@@ -1708,6 +1716,34 @@ static void ir_print_bool_not(IrPrintGen *irp, IrInstGenBoolNot *instruction) {...@@ -1708,6 +1716,34 @@ static void ir_print_bool_not(IrPrintGen *irp, IrInstGenBoolNot *instruction) {
1708 ir_print_other_inst_gen(irp, instruction->value);1716 ir_print_other_inst_gen(irp, instruction->value);
1709}1717}
17101718
1719static void ir_print_wasm_memory_size(IrPrintSrc *irp, IrInstSrcWasmMemorySize *instruction) {
1720 fprintf(irp->f, "@wasmMemorySize(");
1721 ir_print_other_inst_src(irp, instruction->index);
1722 fprintf(irp->f, ")");
1723}
1724
1725static void ir_print_wasm_memory_size(IrPrintGen *irp, IrInstGenWasmMemorySize *instruction) {
1726 fprintf(irp->f, "@wasmMemorySize(");
1727 ir_print_other_inst_gen(irp, instruction->index);
1728 fprintf(irp->f, ")");
1729}
1730
1731static void ir_print_wasm_memory_grow(IrPrintSrc *irp, IrInstSrcWasmMemoryGrow *instruction) {
1732 fprintf(irp->f, "@wasmMemoryGrow(");
1733 ir_print_other_inst_src(irp, instruction->index);
1734 fprintf(irp->f, ", ");
1735 ir_print_other_inst_src(irp, instruction->delta);
1736 fprintf(irp->f, ")");
1737}
1738
1739static void ir_print_wasm_memory_grow(IrPrintGen *irp, IrInstGenWasmMemoryGrow *instruction) {
1740 fprintf(irp->f, "@wasmMemoryGrow(");
1741 ir_print_other_inst_gen(irp, instruction->index);
1742 fprintf(irp->f, ", ");
1743 ir_print_other_inst_gen(irp, instruction->delta);
1744 fprintf(irp->f, ")");
1745}
1746
1711static void ir_print_memset(IrPrintSrc *irp, IrInstSrcMemset *instruction) {1747static void ir_print_memset(IrPrintSrc *irp, IrInstSrcMemset *instruction) {
1712 fprintf(irp->f, "@memset(");1748 fprintf(irp->f, "@memset(");
1713 ir_print_other_inst_src(irp, instruction->dest_ptr);1749 ir_print_other_inst_src(irp, instruction->dest_ptr);
...@@ -2952,6 +2988,12 @@ static void ir_print_inst_src(IrPrintSrc *irp, IrInstSrc *instruction, bool trai...@@ -2952,6 +2988,12 @@ static void ir_print_inst_src(IrPrintSrc *irp, IrInstSrc *instruction, bool trai
2952 case IrInstSrcIdClz:2988 case IrInstSrcIdClz:
2953 ir_print_clz(irp, (IrInstSrcClz *)instruction);2989 ir_print_clz(irp, (IrInstSrcClz *)instruction);
2954 break;2990 break;
2991 case IrInstSrcIdWasmMemorySize:
2992 ir_print_wasm_memory_size(irp, (IrInstSrcWasmMemorySize *)instruction);
2993 break;
2994 case IrInstSrcIdWasmMemoryGrow:
2995 ir_print_wasm_memory_grow(irp, (IrInstSrcWasmMemoryGrow *)instruction);
2996 break;
2955 }2997 }
2956 fprintf(irp->f, "\n");2998 fprintf(irp->f, "\n");
2957}2999}
...@@ -3219,6 +3261,12 @@ static void ir_print_inst_gen(IrPrintGen *irp, IrInstGen *instruction, bool trai...@@ -3219,6 +3261,12 @@ static void ir_print_inst_gen(IrPrintGen *irp, IrInstGen *instruction, bool trai
3219 case IrInstGenIdNegationWrapping:3261 case IrInstGenIdNegationWrapping:
3220 ir_print_negation_wrapping(irp, (IrInstGenNegationWrapping *)instruction);3262 ir_print_negation_wrapping(irp, (IrInstGenNegationWrapping *)instruction);
3221 break;3263 break;
3264 case IrInstGenIdWasmMemorySize:
3265 ir_print_wasm_memory_size(irp, (IrInstGenWasmMemorySize *)instruction);
3266 break;
3267 case IrInstGenIdWasmMemoryGrow:
3268 ir_print_wasm_memory_grow(irp, (IrInstGenWasmMemoryGrow *)instruction);
3269 break;
3222 }3270 }
3223 fprintf(irp->f, "\n");3271 fprintf(irp->f, "\n");
3224}3272}
test/compile_errors.zig+18
...@@ -7504,4 +7504,22 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -7504,4 +7504,22 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
7504 , &[_][]const u8{7504 , &[_][]const u8{
7505 ":3:52: error: slice '[]const u8' cannot have its bytes reinterpreted",7505 ":3:52: error: slice '[]const u8' cannot have its bytes reinterpreted",
7506 });7506 });
7507
7508 cases.add("wasmMemorySize is a compile error in non-Wasm targets",
7509 \\export fn foo() void {
7510 \\ _ = @wasmMemorySize(0);
7511 \\ return;
7512 \\}
7513 , &[_][]const u8{
7514 "tmp.zig:2:9: error: @wasmMemorySize is a wasm32 feature only",
7515 });
7516
7517 cases.add("wasmMemoryGrow is a compile error in non-Wasm targets",
7518 \\export fn foo() void {
7519 \\ _ = @wasmMemoryGrow(0, 1);
7520 \\ return;
7521 \\}
7522 , &[_][]const u8{
7523 "tmp.zig:2:9: error: @wasmMemoryGrow is a wasm32 feature only",
7524 });
7507}7525}
test/stage1/behavior.zig+3
...@@ -126,6 +126,9 @@ comptime {...@@ -126,6 +126,9 @@ comptime {
126 _ = @import("behavior/var_args.zig");126 _ = @import("behavior/var_args.zig");
127 _ = @import("behavior/vector.zig");127 _ = @import("behavior/vector.zig");
128 _ = @import("behavior/void.zig");128 _ = @import("behavior/void.zig");
129 if (builtin.arch == .wasm32) {
130 _ = @import("behavior/wasm.zig");
131 }
129 _ = @import("behavior/while.zig");132 _ = @import("behavior/while.zig");
130 _ = @import("behavior/widening.zig");133 _ = @import("behavior/widening.zig");
131}134}
test/stage1/behavior/wasm.zig created+8
...@@ -0,0 +1,8 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
4test "memory size and grow" {
5 var prev = @wasmMemorySize(0);
6 expect(prev == @wasmMemoryGrow(0, 1));
7 expect(prev + 1 == @wasmMemorySize(0));
8}