| author | |
| committer | |
| log | 7bb6393b593dcf4c8b929fc6b04b576e55f34607 |
| tree | b9deb3d1d49eb0818489b71e566e3a483fa4189d |
| parent | 175463d75dbde1e8e4c5a55159ab4e9446fd211c |
| signature |
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 @compileLog | 898 | bool seen; // used by @compileLog |
| 899 | }; | 899 | }; |
| 900 | 900 | ||
| 901 | // Must be kept in sync with std.builtin.PrefetchOptions.Rw | ||
| 902 | enum PrefetchRw { | ||
| 903 | PrefetchRwRead, | ||
| 904 | PrefetchRwWrite, | ||
| 905 | }; | ||
| 906 | |||
| 907 | // Must be kept in sync with std.builtin.PrefetchOptions.Cache | ||
| 908 | enum PrefetchCache { | ||
| 909 | PrefetchCacheInstruction, | ||
| 910 | PrefetchCacheData, | ||
| 911 | }; | ||
| 912 | |||
| 901 | struct AstNodeArrayAccessExpr { | 913 | struct 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 | }; |
| 1822 | 1835 | ||
| 1823 | struct BuiltinFnEntry { | 1836 | struct 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; |
| 2025 | 2039 | ||
| 2026 | // reminder: hash tables must be initialized before use | 2040 | // 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 | }; |
| 2651 | 2666 | ||
| 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 | }; |
| 2747 | 2763 | ||
| 2748 | struct Stage1ZirInst { | 2764 | struct Stage1ZirInst { |
| ... | @@ -3683,6 +3699,24 @@ struct Stage1ZirInstSrc { | ... | @@ -3683,6 +3699,24 @@ struct Stage1ZirInstSrc { |
| 3683 | Stage1ZirInst base; | 3699 | Stage1ZirInst base; |
| 3684 | }; | 3700 | }; |
| 3685 | 3701 | ||
| 3702 | struct Stage1ZirInstPrefetch { | ||
| 3703 | Stage1ZirInst base; | ||
| 3704 | |||
| 3705 | Stage1ZirInst *ptr; | ||
| 3706 | Stage1ZirInst *options; | ||
| 3707 | }; | ||
| 3708 | |||
| 3709 | struct 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 | |||
| 3686 | struct Stage1ZirInstSlice { | 3720 | struct Stage1ZirInstSlice { |
| 3687 | Stage1ZirInst base; | 3721 | Stage1ZirInst base; |
| 3688 | 3722 |
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 | } |
| 943 | 945 | ||
| 946 | static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPrefetch *) { | ||
| 947 | return Stage1ZirInstIdPrefetch; | ||
| 948 | } | ||
| 949 | |||
| 944 | template<typename T> | 950 | template<typename T> |
| 945 | static T *ir_create_instruction(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { | 951 | static 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 | } |
| 2872 | 2878 | ||
| 2879 | static 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 | |||
| 2873 | static void ir_count_defers(Stage1AstGen *ag, Scope *inner_scope, Scope *outer_scope, size_t *results) { | 2894 | static 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 | } |
| 1141 | 1141 | ||
| 1142 | static 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 | |||
| 1142 | static LLVMValueRef get_stacksave_fn_val(CodeGen *g) { | 1160 | static 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 | } |
| 5901 | 5919 | ||
| 5920 | static 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 | |||
| 5902 | static LLVMValueRef ir_render_slice(CodeGen *g, Stage1Air *executable, Stage1AirInstSlice *instruction) { | 5966 | static LLVMValueRef ir_render_slice(CodeGen *g, Stage1Air *executable, Stage1AirInstSlice *instruction) { |
| 5903 | Error err; | 5967 | Error err; |
| 5904 | 5968 | ||
| ... | @@ -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 | } |
| 9124 | 9191 | ||
| 9125 | static const char *bool_to_str(bool b) { | 9192 | static 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 | } |
| 1117 | 1119 | ||
| 1120 | static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstPrefetch *) { | ||
| 1121 | return Stage1AirInstIdPrefetch; | ||
| 1122 | } | ||
| 1123 | |||
| 1118 | template<typename T> | 1124 | template<typename T> |
| 1119 | static T *ir_create_inst_gen(IrBuilderGen *irb, Scope *scope, AstNode *source_node) { | 1125 | static 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 | } |
| 24855 | 24861 | ||
| 24862 | static 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 | |||
| 24856 | static Stage1AirInst *ir_analyze_instruction_base(IrAnalyze *ira, Stage1ZirInst *instruction) { | 24908 | static 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; |
| 25309 | 25364 | ||
| 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; |
| 25448 | 25504 | ||
| 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 | } |
| 2438 | 2442 | ||
| 2443 | static 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 | |||
| 2451 | static void ir_print_prefetch(IrPrintGen *irp, Stage1AirInstPrefetch *instruction) { | ||
| 2452 | fprintf(irp->f, "@prefetch(...)"); | ||
| 2453 | } | ||
| 2454 | |||
| 2439 | static void ir_print_error_return_trace(IrPrintSrc *irp, Stage1ZirInstErrorReturnTrace *instruction) { | 2455 | static 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; | ||
| 3390 | 3412 | ||
| 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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | test "@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 | } | ||