authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2021-12-07 19:35:46+01:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2021-12-11 00:29:31+01:00
log7bb6393b593dcf4c8b929fc6b04b576e55f34607
treeb9deb3d1d49eb0818489b71e566e3a483fa4189d
parent175463d75dbde1e8e4c5a55159ab4e9446fd211c
signaturelock-open Commit is signed but in an unrecognized format.

stage1: implement @prefetch() builtin


7 files changed, 251 insertions(+), 0 deletions(-)

src/stage1/all_types.hpp+34
...@@ -898,6 +898,18 @@ struct AstNodeFnCallExpr {...@@ -898,6 +898,18 @@ struct AstNodeFnCallExpr {
898 bool seen; // used by @compileLog898 bool seen; // used by @compileLog
899};899};
900900
901// Must be kept in sync with std.builtin.PrefetchOptions.Rw
902enum PrefetchRw {
903 PrefetchRwRead,
904 PrefetchRwWrite,
905};
906
907// Must be kept in sync with std.builtin.PrefetchOptions.Cache
908enum PrefetchCache {
909 PrefetchCacheInstruction,
910 PrefetchCacheData,
911};
912
901struct AstNodeArrayAccessExpr {913struct AstNodeArrayAccessExpr {
902 AstNode *array_ref_expr;914 AstNode *array_ref_expr;
903 AstNode *subscript;915 AstNode *subscript;
...@@ -1818,6 +1830,7 @@ enum BuiltinFnId {...@@ -1818,6 +1830,7 @@ enum BuiltinFnId {
1818 BuiltinFnIdReduce,1830 BuiltinFnIdReduce,
1819 BuiltinFnIdMaximum,1831 BuiltinFnIdMaximum,
1820 BuiltinFnIdMinimum,1832 BuiltinFnIdMinimum,
1833 BuiltinFnIdPrefetch,
1821};1834};
18221835
1823struct BuiltinFnEntry {1836struct BuiltinFnEntry {
...@@ -2021,6 +2034,7 @@ struct CodeGen {...@@ -2021,6 +2034,7 @@ struct CodeGen {
2021 LLVMValueRef return_err_fn;2034 LLVMValueRef return_err_fn;
2022 LLVMValueRef wasm_memory_size;2035 LLVMValueRef wasm_memory_size;
2023 LLVMValueRef wasm_memory_grow;2036 LLVMValueRef wasm_memory_grow;
2037 LLVMValueRef prefetch;
2024 LLVMTypeRef anyframe_fn_type;2038 LLVMTypeRef anyframe_fn_type;
20252039
2026 // reminder: hash tables must be initialized before use2040 // reminder: hash tables must be initialized before use
...@@ -2647,6 +2661,7 @@ enum Stage1ZirInstId : uint8_t {...@@ -2647,6 +2661,7 @@ enum Stage1ZirInstId : uint8_t {
2647 Stage1ZirInstIdWasmMemorySize,2661 Stage1ZirInstIdWasmMemorySize,
2648 Stage1ZirInstIdWasmMemoryGrow,2662 Stage1ZirInstIdWasmMemoryGrow,
2649 Stage1ZirInstIdSrc,2663 Stage1ZirInstIdSrc,
2664 Stage1ZirInstIdPrefetch,
2650};2665};
26512666
2652// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR.2667// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR.
...@@ -2743,6 +2758,7 @@ enum Stage1AirInstId : uint8_t {...@@ -2743,6 +2758,7 @@ enum Stage1AirInstId : uint8_t {
2743 Stage1AirInstIdWasmMemorySize,2758 Stage1AirInstIdWasmMemorySize,
2744 Stage1AirInstIdWasmMemoryGrow,2759 Stage1AirInstIdWasmMemoryGrow,
2745 Stage1AirInstIdExtern,2760 Stage1AirInstIdExtern,
2761 Stage1AirInstIdPrefetch,
2746};2762};
27472763
2748struct Stage1ZirInst {2764struct Stage1ZirInst {
...@@ -3683,6 +3699,24 @@ struct Stage1ZirInstSrc {...@@ -3683,6 +3699,24 @@ struct Stage1ZirInstSrc {
3683 Stage1ZirInst base;3699 Stage1ZirInst base;
3684};3700};
36853701
3702struct Stage1ZirInstPrefetch {
3703 Stage1ZirInst base;
3704
3705 Stage1ZirInst *ptr;
3706 Stage1ZirInst *options;
3707};
3708
3709struct Stage1AirInstPrefetch {
3710 Stage1AirInst base;
3711
3712 Stage1AirInst *ptr;
3713 PrefetchRw rw;
3714 // Must be in the range 0-3 inclusive
3715 uint8_t locality;
3716 PrefetchCache cache;
3717};
3718
3719
3686struct Stage1ZirInstSlice {3720struct Stage1ZirInstSlice {
3687 Stage1ZirInst base;3721 Stage1ZirInst base;
36883722
src/stage1/astgen.cpp+44
...@@ -349,6 +349,8 @@ void destroy_instruction_src(Stage1ZirInst *inst) {...@@ -349,6 +349,8 @@ void destroy_instruction_src(Stage1ZirInst *inst) {
349 return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstWasmMemoryGrow *>(inst));349 return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstWasmMemoryGrow *>(inst));
350 case Stage1ZirInstIdSrc:350 case Stage1ZirInstIdSrc:
351 return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstSrc *>(inst));351 return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstSrc *>(inst));
352 case Stage1ZirInstIdPrefetch:
353 return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstPrefetch *>(inst));
352 }354 }
353 zig_unreachable();355 zig_unreachable();
354}356}
...@@ -941,6 +943,10 @@ static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSrc *) {...@@ -941,6 +943,10 @@ static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSrc *) {
941 return Stage1ZirInstIdSrc;943 return Stage1ZirInstIdSrc;
942}944}
943945
946static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPrefetch *) {
947 return Stage1ZirInstIdPrefetch;
948}
949
944template<typename T>950template<typename T>
945static T *ir_create_instruction(Stage1AstGen *ag, Scope *scope, AstNode *source_node) {951static T *ir_create_instruction(Stage1AstGen *ag, Scope *scope, AstNode *source_node) {
946 T *special_instruction = heap::c_allocator.create<T>();952 T *special_instruction = heap::c_allocator.create<T>();
...@@ -2870,6 +2876,21 @@ static Stage1ZirInst *ir_build_src(Stage1AstGen *ag, Scope *scope, AstNode *sour...@@ -2870,6 +2876,21 @@ static Stage1ZirInst *ir_build_src(Stage1AstGen *ag, Scope *scope, AstNode *sour
2870 return &instruction->base;2876 return &instruction->base;
2871}2877}
28722878
2879static Stage1ZirInst *ir_build_prefetch(Stage1AstGen *ag, Scope *scope, AstNode *source_node,
2880 Stage1ZirInst *ptr, Stage1ZirInst *options)
2881{
2882 Stage1ZirInstPrefetch *prefetch_instruction = ir_build_instruction<Stage1ZirInstPrefetch>(
2883 ag, scope, source_node);
2884 prefetch_instruction->ptr = ptr;
2885 prefetch_instruction->options = options;
2886
2887 ir_ref_instruction(ptr, ag->current_basic_block);
2888 ir_ref_instruction(options, ag->current_basic_block);
2889
2890 return &prefetch_instruction->base;
2891}
2892
2893
2873static void ir_count_defers(Stage1AstGen *ag, Scope *inner_scope, Scope *outer_scope, size_t *results) {2894static void ir_count_defers(Stage1AstGen *ag, Scope *inner_scope, Scope *outer_scope, size_t *results) {
2874 results[ReturnKindUnconditional] = 0;2895 results[ReturnKindUnconditional] = 0;
2875 results[ReturnKindError] = 0;2896 results[ReturnKindError] = 0;
...@@ -5416,6 +5437,29 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast...@@ -5416,6 +5437,29 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast
5416 Stage1ZirInst *src_inst = ir_build_src(ag, scope, node);5437 Stage1ZirInst *src_inst = ir_build_src(ag, scope, node);
5417 return ir_lval_wrap(ag, scope, src_inst, lval, result_loc);5438 return ir_lval_wrap(ag, scope, src_inst, lval, result_loc);
5418 }5439 }
5440 case BuiltinFnIdPrefetch:
5441 {
5442 ZigType *options_type = get_builtin_type(ag->codegen, "PrefetchOptions");
5443 Stage1ZirInst *options_type_inst = ir_build_const_type(ag, scope, node, options_type);
5444 ResultLocCast *result_loc_cast = ir_build_cast_result_loc(ag, options_type_inst, no_result_loc());
5445
5446 AstNode *ptr_node = node->data.fn_call_expr.params.at(0);
5447 Stage1ZirInst *ptr_value = astgen_node(ag, ptr_node, scope);
5448 if (ptr_value == ag->codegen->invalid_inst_src)
5449 return ptr_value;
5450
5451 AstNode *options_node = node->data.fn_call_expr.params.at(1);
5452 Stage1ZirInst *options_value = astgen_node_extra(ag, options_node,
5453 scope, LValNone, &result_loc_cast->base);
5454 if (options_value == ag->codegen->invalid_inst_src)
5455 return options_value;
5456
5457 Stage1ZirInst *casted_options_value = ir_build_implicit_cast(
5458 ag, scope, options_node, options_value, result_loc_cast);
5459
5460 Stage1ZirInst *ir_extern = ir_build_prefetch(ag, scope, node, ptr_value, casted_options_value);
5461 return ir_lval_wrap(ag, scope, ir_extern, lval, result_loc);
5462 }
5419 }5463 }
5420 zig_unreachable();5464 zig_unreachable();
5421}5465}
src/stage1/codegen.cpp+67
...@@ -1139,6 +1139,24 @@ static LLVMValueRef gen_wasm_memory_grow(CodeGen *g) {...@@ -1139,6 +1139,24 @@ static LLVMValueRef gen_wasm_memory_grow(CodeGen *g) {
1139 return g->wasm_memory_grow;1139 return g->wasm_memory_grow;
1140}1140}
11411141
1142static LLVMValueRef gen_prefetch(CodeGen *g) {
1143 if (g->prefetch)
1144 return g->prefetch;
1145
1146 // declare void @llvm.prefetch(i8*, i32, i32, i32)
1147 LLVMTypeRef param_types[] = {
1148 LLVMPointerType(LLVMInt8Type(), 0),
1149 LLVMInt32Type(),
1150 LLVMInt32Type(),
1151 LLVMInt32Type(),
1152 };
1153 LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 4, false);
1154 g->prefetch = LLVMAddFunction(g->module, "llvm.prefetch.p0i8", fn_type);
1155 assert(LLVMGetIntrinsicID(g->prefetch));
1156
1157 return g->prefetch;
1158}
1159
1142static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {1160static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {
1143 if (g->stacksave_fn_val)1161 if (g->stacksave_fn_val)
1144 return g->stacksave_fn_val;1162 return g->stacksave_fn_val;
...@@ -5899,6 +5917,52 @@ static LLVMValueRef ir_render_wasm_memory_grow(CodeGen *g, Stage1Air *executable...@@ -5899,6 +5917,52 @@ static LLVMValueRef ir_render_wasm_memory_grow(CodeGen *g, Stage1Air *executable
5899 return val;5917 return val;
5900}5918}
59015919
5920static LLVMValueRef ir_render_prefetch(CodeGen *g, Stage1Air *executable, Stage1AirInstPrefetch *instruction) {
5921 static_assert(PrefetchRwRead == 0, "");
5922 static_assert(PrefetchRwWrite == 1, "");
5923 assert(instruction->rw == PrefetchRwRead || instruction->rw == PrefetchRwWrite);
5924
5925 assert(instruction->locality >= 0 && instruction->locality <= 3);
5926
5927 static_assert(PrefetchCacheInstruction == 0, "");
5928 static_assert(PrefetchCacheData == 1, "");
5929 assert(instruction->cache == PrefetchCacheData || instruction->cache == PrefetchCacheInstruction);
5930
5931 // LLVM fails during codegen of instruction cache prefetchs for these architectures.
5932 // This is an LLVM bug as the prefetch intrinsic should be a noop if not supported by the target.
5933 // To work around this, simply don't emit llvm.prefetch in this case.
5934 // See https://bugs.llvm.org/show_bug.cgi?id=21037
5935 if (instruction->cache == PrefetchCacheInstruction) {
5936 switch (g->zig_target->arch) {
5937 case ZigLLVM_x86:
5938 case ZigLLVM_x86_64:
5939 return nullptr;
5940 default:
5941 break;
5942 }
5943 }
5944
5945 // Another case of the same LLVM bug described above
5946 if (instruction->rw == PrefetchRwWrite && instruction->cache == PrefetchCacheInstruction) {
5947 switch (g->zig_target->arch) {
5948 case ZigLLVM_arm:
5949 return nullptr;
5950 default:
5951 break;
5952 }
5953
5954 }
5955
5956 LLVMValueRef params[] = {
5957 LLVMBuildBitCast(g->builder, ir_llvm_value(g, instruction->ptr), LLVMPointerType(LLVMInt8Type(), 0), ""),
5958 LLVMConstInt(LLVMInt32Type(), instruction->rw, false),
5959 LLVMConstInt(LLVMInt32Type(), instruction->locality, false),
5960 LLVMConstInt(LLVMInt32Type(), instruction->cache, false),
5961 };
5962 LLVMValueRef val = LLVMBuildCall(g->builder, gen_prefetch(g), params, 4, "");
5963 return val;
5964}
5965
5902static LLVMValueRef ir_render_slice(CodeGen *g, Stage1Air *executable, Stage1AirInstSlice *instruction) {5966static LLVMValueRef ir_render_slice(CodeGen *g, Stage1Air *executable, Stage1AirInstSlice *instruction) {
5903 Error err;5967 Error err;
59045968
...@@ -7150,6 +7214,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, Stage1Air *executable, Sta...@@ -7150,6 +7214,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, Stage1Air *executable, Sta
7150 return ir_render_wasm_memory_grow(g, executable, (Stage1AirInstWasmMemoryGrow *) instruction);7214 return ir_render_wasm_memory_grow(g, executable, (Stage1AirInstWasmMemoryGrow *) instruction);
7151 case Stage1AirInstIdExtern:7215 case Stage1AirInstIdExtern:
7152 return ir_render_extern(g, executable, (Stage1AirInstExtern *) instruction);7216 return ir_render_extern(g, executable, (Stage1AirInstExtern *) instruction);
7217 case Stage1AirInstIdPrefetch:
7218 return ir_render_prefetch(g, executable, (Stage1AirInstPrefetch *) instruction);
7153 }7219 }
7154 zig_unreachable();7220 zig_unreachable();
7155}7221}
...@@ -9120,6 +9186,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -9120,6 +9186,7 @@ static void define_builtin_fns(CodeGen *g) {
9120 create_builtin_fn(g, BuiltinFnIdReduce, "reduce", 2);9186 create_builtin_fn(g, BuiltinFnIdReduce, "reduce", 2);
9121 create_builtin_fn(g, BuiltinFnIdMaximum, "maximum", 2);9187 create_builtin_fn(g, BuiltinFnIdMaximum, "maximum", 2);
9122 create_builtin_fn(g, BuiltinFnIdMinimum, "minimum", 2);9188 create_builtin_fn(g, BuiltinFnIdMinimum, "minimum", 2);
9189 create_builtin_fn(g, BuiltinFnIdPrefetch, "prefetch", 2);
9123}9190}
91249191
9125static const char *bool_to_str(bool b) {9192static const char *bool_to_str(bool b) {
src/stage1/ir.cpp+56
...@@ -467,6 +467,8 @@ void destroy_instruction_gen(Stage1AirInst *inst) {...@@ -467,6 +467,8 @@ void destroy_instruction_gen(Stage1AirInst *inst) {
467 return heap::c_allocator.destroy(reinterpret_cast<Stage1AirInstWasmMemoryGrow *>(inst));467 return heap::c_allocator.destroy(reinterpret_cast<Stage1AirInstWasmMemoryGrow *>(inst));
468 case Stage1AirInstIdExtern:468 case Stage1AirInstIdExtern:
469 return heap::c_allocator.destroy(reinterpret_cast<Stage1AirInstExtern *>(inst));469 return heap::c_allocator.destroy(reinterpret_cast<Stage1AirInstExtern *>(inst));
470 case Stage1AirInstIdPrefetch:
471 return heap::c_allocator.destroy(reinterpret_cast<Stage1AirInstPrefetch *>(inst));
470 }472 }
471 zig_unreachable();473 zig_unreachable();
472}474}
...@@ -1115,6 +1117,10 @@ static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstExtern *) {...@@ -1115,6 +1117,10 @@ static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstExtern *) {
1115 return Stage1AirInstIdExtern;1117 return Stage1AirInstIdExtern;
1116}1118}
11171119
1120static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstPrefetch *) {
1121 return Stage1AirInstIdPrefetch;
1122}
1123
1118template<typename T>1124template<typename T>
1119static T *ir_create_inst_gen(IrBuilderGen *irb, Scope *scope, AstNode *source_node) {1125static T *ir_create_inst_gen(IrBuilderGen *irb, Scope *scope, AstNode *source_node) {
1120 T *special_instruction = heap::c_allocator.create<T>();1126 T *special_instruction = heap::c_allocator.create<T>();
...@@ -24853,6 +24859,52 @@ static Stage1AirInst *ir_analyze_instruction_src(IrAnalyze *ira, Stage1ZirInstSr...@@ -24853,6 +24859,52 @@ static Stage1AirInst *ir_analyze_instruction_src(IrAnalyze *ira, Stage1ZirInstSr
24853 return ir_const_move(ira, instruction->base.scope, instruction->base.source_node, result);24859 return ir_const_move(ira, instruction->base.scope, instruction->base.source_node, result);
24854}24860}
2485524861
24862static Stage1AirInst *ir_analyze_instruction_prefetch(IrAnalyze *ira, Stage1ZirInstPrefetch *instruction) {
24863 Stage1AirInst *ptr = instruction->ptr->child;
24864 if (type_is_invalid(ptr->value->type))
24865 return ira->codegen->invalid_inst_gen;
24866
24867 Stage1AirInst *raw_options_inst = instruction->options->child;
24868 if (type_is_invalid(raw_options_inst->value->type))
24869 return ira->codegen->invalid_inst_gen;
24870
24871 ZigType *options_type = get_builtin_type(ira->codegen, "PrefetchOptions");
24872 Stage1AirInst *options_inst = ir_implicit_cast(ira, raw_options_inst, options_type);
24873 if (type_is_invalid(options_inst->value->type))
24874 return ira->codegen->invalid_inst_gen;
24875
24876 ZigValue *options_val = ir_resolve_const(ira, options_inst, UndefBad);
24877 if (options_val == nullptr)
24878 return ira->codegen->invalid_inst_gen;
24879
24880 ZigValue *rw_val = get_const_field(ira, options_inst->source_node, options_val, "rw", 0);
24881 if (rw_val == nullptr)
24882 return ira->codegen->invalid_inst_gen;
24883 PrefetchRw rw = (PrefetchRw)bigint_as_u8(&rw_val->data.x_enum_tag);
24884
24885 ZigValue *locality_val = get_const_field(ira, options_inst->source_node, options_val, "locality", 1);
24886 if (locality_val == nullptr)
24887 return ira->codegen->invalid_inst_gen;
24888 uint8_t locality = bigint_as_u8(&locality_val->data.x_bigint);
24889 assert(locality <= 3);
24890
24891 ZigValue *cache_val = get_const_field(ira, options_inst->source_node, options_val, "cache", 2);
24892 if (cache_val == nullptr)
24893 return ira->codegen->invalid_inst_gen;
24894 PrefetchCache cache = (PrefetchCache)bigint_as_u8(&cache_val->data.x_enum_tag);
24895
24896 Stage1AirInstPrefetch *air_instruction = ir_build_inst_void<Stage1AirInstPrefetch>(&ira->new_irb,
24897 instruction->base.scope, instruction->base.source_node);
24898 air_instruction->ptr = ptr;
24899 air_instruction->rw = rw;
24900 air_instruction->locality = locality;
24901 air_instruction->cache = cache;
24902
24903 ir_ref_inst_gen(ptr);
24904
24905 return &air_instruction->base;
24906}
24907
24856static Stage1AirInst *ir_analyze_instruction_base(IrAnalyze *ira, Stage1ZirInst *instruction) {24908static Stage1AirInst *ir_analyze_instruction_base(IrAnalyze *ira, Stage1ZirInst *instruction) {
24857 switch (instruction->id) {24909 switch (instruction->id) {
24858 case Stage1ZirInstIdInvalid:24910 case Stage1ZirInstIdInvalid:
...@@ -25138,6 +25190,8 @@ static Stage1AirInst *ir_analyze_instruction_base(IrAnalyze *ira, Stage1ZirInst...@@ -25138,6 +25190,8 @@ static Stage1AirInst *ir_analyze_instruction_base(IrAnalyze *ira, Stage1ZirInst
25138 return ir_analyze_instruction_wasm_memory_grow(ira, (Stage1ZirInstWasmMemoryGrow *)instruction);25190 return ir_analyze_instruction_wasm_memory_grow(ira, (Stage1ZirInstWasmMemoryGrow *)instruction);
25139 case Stage1ZirInstIdSrc:25191 case Stage1ZirInstIdSrc:
25140 return ir_analyze_instruction_src(ira, (Stage1ZirInstSrc *)instruction);25192 return ir_analyze_instruction_src(ira, (Stage1ZirInstSrc *)instruction);
25193 case Stage1ZirInstIdPrefetch:
25194 return ir_analyze_instruction_prefetch(ira, (Stage1ZirInstPrefetch *)instruction);
25141 }25195 }
25142 zig_unreachable();25196 zig_unreachable();
25143}25197}
...@@ -25305,6 +25359,7 @@ bool ir_inst_gen_has_side_effects(Stage1AirInst *instruction) {...@@ -25305,6 +25359,7 @@ bool ir_inst_gen_has_side_effects(Stage1AirInst *instruction) {
25305 case Stage1AirInstIdSpillBegin:25359 case Stage1AirInstIdSpillBegin:
25306 case Stage1AirInstIdWasmMemoryGrow:25360 case Stage1AirInstIdWasmMemoryGrow:
25307 case Stage1AirInstIdExtern:25361 case Stage1AirInstIdExtern:
25362 case Stage1AirInstIdPrefetch:
25308 return true;25363 return true;
2530925364
25310 case Stage1AirInstIdPhi:25365 case Stage1AirInstIdPhi:
...@@ -25444,6 +25499,7 @@ bool ir_inst_src_has_side_effects(Stage1ZirInst *instruction) {...@@ -25444,6 +25499,7 @@ bool ir_inst_src_has_side_effects(Stage1ZirInst *instruction) {
25444 case Stage1ZirInstIdAwait:25499 case Stage1ZirInstIdAwait:
25445 case Stage1ZirInstIdSpillBegin:25500 case Stage1ZirInstIdSpillBegin:
25446 case Stage1ZirInstIdWasmMemoryGrow:25501 case Stage1ZirInstIdWasmMemoryGrow:
25502 case Stage1ZirInstIdPrefetch:
25447 return true;25503 return true;
2544825504
25449 case Stage1ZirInstIdPhi:25505 case Stage1ZirInstIdPhi:
src/stage1/ir_print.cpp+22
...@@ -371,6 +371,8 @@ const char* ir_inst_src_type_str(Stage1ZirInstId id) {...@@ -371,6 +371,8 @@ const char* ir_inst_src_type_str(Stage1ZirInstId id) {
371 return "SrcWasmMemoryGrow";371 return "SrcWasmMemoryGrow";
372 case Stage1ZirInstIdSrc:372 case Stage1ZirInstIdSrc:
373 return "SrcSrc";373 return "SrcSrc";
374 case Stage1ZirInstIdPrefetch:
375 return "SrcPrefetch";
374 }376 }
375 zig_unreachable();377 zig_unreachable();
376}378}
...@@ -559,6 +561,8 @@ const char* ir_inst_gen_type_str(Stage1AirInstId id) {...@@ -559,6 +561,8 @@ const char* ir_inst_gen_type_str(Stage1AirInstId id) {
559 return "GenWasmMemoryGrow";561 return "GenWasmMemoryGrow";
560 case Stage1AirInstIdExtern:562 case Stage1AirInstIdExtern:
561 return "GenExtern";563 return "GenExtern";
564 case Stage1AirInstIdPrefetch:
565 return "GenPrefetch";
562 }566 }
563 zig_unreachable();567 zig_unreachable();
564}568}
...@@ -2436,6 +2440,18 @@ static void ir_print_extern(IrPrintSrc *irp, Stage1ZirInstExtern *instruction) {...@@ -2436,6 +2440,18 @@ static void ir_print_extern(IrPrintSrc *irp, Stage1ZirInstExtern *instruction) {
2436 fprintf(irp->f, ")");2440 fprintf(irp->f, ")");
2437}2441}
24382442
2443static void ir_print_prefetch(IrPrintSrc *irp, Stage1ZirInstPrefetch *instruction) {
2444 fprintf(irp->f, "@prefetch(");
2445 ir_print_other_inst_src(irp, instruction->ptr);
2446 fprintf(irp->f, ",");
2447 ir_print_other_inst_src(irp, instruction->options);
2448 fprintf(irp->f, ")");
2449}
2450
2451static void ir_print_prefetch(IrPrintGen *irp, Stage1AirInstPrefetch *instruction) {
2452 fprintf(irp->f, "@prefetch(...)");
2453}
2454
2439static void ir_print_error_return_trace(IrPrintSrc *irp, Stage1ZirInstErrorReturnTrace *instruction) {2455static void ir_print_error_return_trace(IrPrintSrc *irp, Stage1ZirInstErrorReturnTrace *instruction) {
2440 fprintf(irp->f, "@errorReturnTrace(");2456 fprintf(irp->f, "@errorReturnTrace(");
2441 switch (instruction->optional) {2457 switch (instruction->optional) {
...@@ -3108,6 +3124,9 @@ static void ir_print_inst_src(IrPrintSrc *irp, Stage1ZirInst *instruction, bool...@@ -3108,6 +3124,9 @@ static void ir_print_inst_src(IrPrintSrc *irp, Stage1ZirInst *instruction, bool
3108 case Stage1ZirInstIdSrc:3124 case Stage1ZirInstIdSrc:
3109 ir_print_builtin_src(irp, (Stage1ZirInstSrc *)instruction);3125 ir_print_builtin_src(irp, (Stage1ZirInstSrc *)instruction);
3110 break;3126 break;
3127 case Stage1ZirInstIdPrefetch:
3128 ir_print_prefetch(irp, (Stage1ZirInstPrefetch *)instruction);
3129 break;
3111 }3130 }
3112 fprintf(irp->f, "\n");3131 fprintf(irp->f, "\n");
3113}3132}
...@@ -3387,6 +3406,9 @@ static void ir_print_inst_gen(IrPrintGen *irp, Stage1AirInst *instruction, bool...@@ -3387,6 +3406,9 @@ static void ir_print_inst_gen(IrPrintGen *irp, Stage1AirInst *instruction, bool
3387 case Stage1AirInstIdExtern:3406 case Stage1AirInstIdExtern:
3388 ir_print_extern(irp, (Stage1AirInstExtern *)instruction);3407 ir_print_extern(irp, (Stage1AirInstExtern *)instruction);
3389 break;3408 break;
3409 case Stage1AirInstIdPrefetch:
3410 ir_print_prefetch(irp, (Stage1AirInstPrefetch *)instruction);
3411 break;
33903412
3391 }3413 }
3392 fprintf(irp->f, "\n");3414 fprintf(irp->f, "\n");
test/behavior.zig+1
...@@ -169,6 +169,7 @@ test {...@@ -169,6 +169,7 @@ test {
169 _ = @import("behavior/optional_stage1.zig");169 _ = @import("behavior/optional_stage1.zig");
170 _ = @import("behavior/pointers_stage1.zig");170 _ = @import("behavior/pointers_stage1.zig");
171 _ = @import("behavior/popcount_stage1.zig");171 _ = @import("behavior/popcount_stage1.zig");
172 _ = @import("behavior/prefetch.zig");
172 _ = @import("behavior/ptrcast_stage1.zig");173 _ = @import("behavior/ptrcast_stage1.zig");
173 _ = @import("behavior/reflection.zig");174 _ = @import("behavior/reflection.zig");
174 _ = @import("behavior/saturating_arithmetic_stage1.zig");175 _ = @import("behavior/saturating_arithmetic_stage1.zig");
test/behavior/prefetch.zig created+27
...@@ -0,0 +1,27 @@
1const std = @import("std");
2
3test "@prefetch()" {
4 var a: u32 = 42;
5
6 @prefetch(&a, .{});
7
8 @prefetch(&a, .{ .rw = .read, .locality = 3, .cache = .data });
9 @prefetch(&a, .{ .rw = .read, .locality = 2, .cache = .data });
10 @prefetch(&a, .{ .rw = .read, .locality = 1, .cache = .data });
11 @prefetch(&a, .{ .rw = .read, .locality = 0, .cache = .data });
12
13 @prefetch(&a, .{ .rw = .write, .locality = 3, .cache = .data });
14 @prefetch(&a, .{ .rw = .write, .locality = 2, .cache = .data });
15 @prefetch(&a, .{ .rw = .write, .locality = 1, .cache = .data });
16 @prefetch(&a, .{ .rw = .write, .locality = 0, .cache = .data });
17
18 @prefetch(&a, .{ .rw = .read, .locality = 3, .cache = .instruction });
19 @prefetch(&a, .{ .rw = .read, .locality = 2, .cache = .instruction });
20 @prefetch(&a, .{ .rw = .read, .locality = 1, .cache = .instruction });
21 @prefetch(&a, .{ .rw = .read, .locality = 0, .cache = .instruction });
22
23 @prefetch(&a, .{ .rw = .write, .locality = 3, .cache = .instruction });
24 @prefetch(&a, .{ .rw = .write, .locality = 2, .cache = .instruction });
25 @prefetch(&a, .{ .rw = .write, .locality = 1, .cache = .instruction });
26 @prefetch(&a, .{ .rw = .write, .locality = 0, .cache = .instruction });
27}