| author | |
| committer | |
| log | 97c0373fa7ee125d2d4e73f9b1dc8ea0e2c2e86a |
| tree | d2aa342a53aef95f88456a63fa7874f3c51ba3b8 |
| parent | 75f3e7a4a05db7ea805e581f78117a41768945ae |
| parent | 516945d7d9b4d8b969d037076799d4ed29cecdda |
| signature |
Implement @prefetch()16 files changed, 395 insertions(+), 7 deletions(-)
doc/langref.html.in+44| ... | ... | @@ -8674,6 +8674,50 @@ test "@wasmMemoryGrow" { |
| 8674 | 8674 | {#see_also|@ctz|@clz#} |
| 8675 | 8675 | {#header_close#} |
| 8676 | 8676 | |
| 8677 | {#header_open|@prefetch#} | |
| 8678 | <pre>{#syntax#}@prefetch(ptr: anytype, comptime options: std.builtin.PrefetchOptions){#endsyntax#}</pre> | |
| 8679 | <p> | |
| 8680 | This builtin tells the compiler to emit a prefetch instruction if supported by the | |
| 8681 | target CPU. If the target CPU does not support the requested prefetch instruction, | |
| 8682 | this builtin is a noop. This function has no effect on the behavior of the program, | |
| 8683 | only on the performance characteristics. | |
| 8684 | </p> | |
| 8685 | <p> | |
| 8686 | The {#syntax#}ptr{#endsyntax#} argument may be any pointer type and determines the memory | |
| 8687 | address to prefetch. This function does not dereference the pointer, it is perfectly legal | |
| 8688 | to pass a pointer to invalid memory to this function and no illegal behavior will result. | |
| 8689 | </p> | |
| 8690 | <p> | |
| 8691 | The {#syntax#}options{#endsyntax#} argument is the following struct: | |
| 8692 | </p> | |
| 8693 | {#code_begin|syntax|builtin#} | |
| 8694 | /// This data structure is used by the Zig language code generation and | |
| 8695 | /// therefore must be kept in sync with the compiler implementation. | |
| 8696 | pub const PrefetchOptions = struct { | |
| 8697 | /// Whether the prefetch should prepare for a read or a write. | |
| 8698 | rw: Rw = .read, | |
| 8699 | /// 0 means no temporal locality. That is, the data can be immediately | |
| 8700 | /// dropped from the cache after it is accessed. | |
| 8701 | /// | |
| 8702 | /// 3 means high temporal locality. That is, the data should be kept in | |
| 8703 | /// the cache as it is likely to be accessed again soon. | |
| 8704 | locality: u2 = 3, | |
| 8705 | /// The cache that the prefetch should be preformed on. | |
| 8706 | cache: Cache = .data, | |
| 8707 | ||
| 8708 | pub const Rw = enum { | |
| 8709 | read, | |
| 8710 | write, | |
| 8711 | }; | |
| 8712 | ||
| 8713 | pub const Cache = enum { | |
| 8714 | instruction, | |
| 8715 | data, | |
| 8716 | }; | |
| 8717 | }; | |
| 8718 | {#code_end#} | |
| 8719 | {#header_close#} | |
| 8720 | ||
| 8677 | 8721 | {#header_open|@ptrCast#} |
| 8678 | 8722 | <pre>{#syntax#}@ptrCast(comptime DestType: type, value: anytype) DestType{#endsyntax#}</pre> |
| 8679 | 8723 | <p> |
lib/std/builtin.zig+25| ... | ... | @@ -651,6 +651,31 @@ pub const CallOptions = struct { |
| 651 | 651 | }; |
| 652 | 652 | }; |
| 653 | 653 | |
| 654 | /// This data structure is used by the Zig language code generation and | |
| 655 | /// therefore must be kept in sync with the compiler implementation. | |
| 656 | pub const PrefetchOptions = struct { | |
| 657 | /// Whether the prefetch should prepare for a read or a write. | |
| 658 | rw: Rw = .read, | |
| 659 | /// 0 means no temporal locality. That is, the data can be immediately | |
| 660 | /// dropped from the cache after it is accessed. | |
| 661 | /// | |
| 662 | /// 3 means high temporal locality. That is, the data should be kept in | |
| 663 | /// the cache as it is likely to be accessed again soon. | |
| 664 | locality: u2 = 3, | |
| 665 | /// The cache that the prefetch should be preformed on. | |
| 666 | cache: Cache = .data, | |
| 667 | ||
| 668 | pub const Rw = enum { | |
| 669 | read, | |
| 670 | write, | |
| 671 | }; | |
| 672 | ||
| 673 | pub const Cache = enum { | |
| 674 | instruction, | |
| 675 | data, | |
| 676 | }; | |
| 677 | }; | |
| 678 | ||
| 654 | 679 | /// This data structure is used by the Zig language code generation and |
| 655 | 680 | /// therefore must be kept in sync with the compiler implementation. |
| 656 | 681 | pub const ExportOptions = struct { |
src/AstGen.zig+20-6| ... | ... | @@ -6739,7 +6739,6 @@ fn builtinCall( |
| 6739 | 6739 | } |
| 6740 | 6740 | } |
| 6741 | 6741 | |
| 6742 | // zig fmt: off | |
| 6743 | 6742 | switch (info.tag) { |
| 6744 | 6743 | .import => { |
| 6745 | 6744 | const node_tags = tree.nodes.items(.tag); |
| ... | ... | @@ -6768,7 +6767,7 @@ fn builtinCall( |
| 6768 | 6767 | astgen.extra.items[extra_index] = @enumToInt(param_ref); |
| 6769 | 6768 | extra_index += 1; |
| 6770 | 6769 | } |
| 6771 | const result = try gz.addExtendedMultiOpPayloadIndex(.compile_log,payload_index, params.len); | |
| 6770 | const result = try gz.addExtendedMultiOpPayloadIndex(.compile_log, payload_index, params.len); | |
| 6772 | 6771 | return rvalue(gz, rl, result, node); |
| 6773 | 6772 | }, |
| 6774 | 6773 | .field => { |
| ... | ... | @@ -6784,11 +6783,14 @@ fn builtinCall( |
| 6784 | 6783 | }); |
| 6785 | 6784 | return rvalue(gz, rl, result, node); |
| 6786 | 6785 | }, |
| 6786 | ||
| 6787 | // zig fmt: off | |
| 6787 | 6788 | .as => return as( gz, scope, rl, node, params[0], params[1]), |
| 6788 | 6789 | .bit_cast => return bitCast( gz, scope, rl, node, params[0], params[1]), |
| 6789 | 6790 | .TypeOf => return typeOf( gz, scope, rl, node, params), |
| 6790 | 6791 | .union_init => return unionInit(gz, scope, rl, node, params), |
| 6791 | 6792 | .c_import => return cImport( gz, scope, node, params[0]), |
| 6793 | // zig fmt: on | |
| 6792 | 6794 | |
| 6793 | 6795 | .@"export" => { |
| 6794 | 6796 | const node_tags = tree.nodes.items(.tag); |
| ... | ... | @@ -6858,9 +6860,7 @@ fn builtinCall( |
| 6858 | 6860 | const field_ident = dot_token + 1; |
| 6859 | 6861 | decl_name = try astgen.identAsString(field_ident); |
| 6860 | 6862 | }, |
| 6861 | else => return astgen.failNode( | |
| 6862 | params[0], "symbol to export must identify a declaration", .{}, | |
| 6863 | ), | |
| 6863 | else => return astgen.failNode(params[0], "symbol to export must identify a declaration", .{}), | |
| 6864 | 6864 | } |
| 6865 | 6865 | const options = try comptimeExpr(gz, scope, .{ .ty = .export_options_type }, params[1]); |
| 6866 | 6866 | _ = try gz.addPlNode(.@"export", node, Zir.Inst.Export{ |
| ... | ... | @@ -6888,6 +6888,7 @@ fn builtinCall( |
| 6888 | 6888 | |
| 6889 | 6889 | .breakpoint => return simpleNoOpVoid(gz, rl, node, .breakpoint), |
| 6890 | 6890 | |
| 6891 | // zig fmt: off | |
| 6891 | 6892 | .This => return rvalue(gz, rl, try gz.addNodeExtended(.this, node), node), |
| 6892 | 6893 | .return_address => return rvalue(gz, rl, try gz.addNodeExtended(.ret_addr, node), node), |
| 6893 | 6894 | .src => return rvalue(gz, rl, try gz.addNodeExtended(.builtin_src, node), node), |
| ... | ... | @@ -6942,6 +6943,8 @@ fn builtinCall( |
| 6942 | 6943 | .err_set_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .err_set_cast), |
| 6943 | 6944 | .ptr_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .ptr_cast), |
| 6944 | 6945 | .truncate => return typeCast(gz, scope, rl, node, params[0], params[1], .truncate), |
| 6946 | // zig fmt: on | |
| 6947 | ||
| 6945 | 6948 | .align_cast => { |
| 6946 | 6949 | const dest_align = try comptimeExpr(gz, scope, align_rl, params[0]); |
| 6947 | 6950 | const rhs = try expr(gz, scope, .none, params[1]); |
| ... | ... | @@ -6952,6 +6955,7 @@ fn builtinCall( |
| 6952 | 6955 | return rvalue(gz, rl, result, node); |
| 6953 | 6956 | }, |
| 6954 | 6957 | |
| 6958 | // zig fmt: off | |
| 6955 | 6959 | .has_decl => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_decl), |
| 6956 | 6960 | .has_field => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_field), |
| 6957 | 6961 | |
| ... | ... | @@ -6978,6 +6982,7 @@ fn builtinCall( |
| 6978 | 6982 | |
| 6979 | 6983 | .cmpxchg_strong => return cmpxchg(gz, scope, rl, node, params, .cmpxchg_strong), |
| 6980 | 6984 | .cmpxchg_weak => return cmpxchg(gz, scope, rl, node, params, .cmpxchg_weak), |
| 6985 | // zig fmt: on | |
| 6981 | 6986 | |
| 6982 | 6987 | .wasm_memory_size => { |
| 6983 | 6988 | const operand = try expr(gz, scope, .{ .ty = .u32_type }, params[0]); |
| ... | ... | @@ -7221,8 +7226,17 @@ fn builtinCall( |
| 7221 | 7226 | }); |
| 7222 | 7227 | return rvalue(gz, rl, result, node); |
| 7223 | 7228 | }, |
| 7229 | .prefetch => { | |
| 7230 | const ptr = try expr(gz, scope, .none, params[0]); | |
| 7231 | const options = try comptimeExpr(gz, scope, .{ .ty = .prefetch_options_type }, params[1]); | |
| 7232 | const result = try gz.addExtendedPayload(.prefetch, Zir.Inst.BinNode{ | |
| 7233 | .node = gz.nodeIndexToRelative(node), | |
| 7234 | .lhs = ptr, | |
| 7235 | .rhs = options, | |
| 7236 | }); | |
| 7237 | return rvalue(gz, rl, result, node); | |
| 7238 | }, | |
| 7224 | 7239 | } |
| 7225 | // zig fmt: on | |
| 7226 | 7240 | } |
| 7227 | 7241 | |
| 7228 | 7242 | fn simpleNoOpVoid( |
src/BuiltinFn.zig+8| ... | ... | @@ -67,6 +67,7 @@ pub const Tag = enum { |
| 67 | 67 | mul_with_overflow, |
| 68 | 68 | panic, |
| 69 | 69 | pop_count, |
| 70 | prefetch, | |
| 70 | 71 | ptr_cast, |
| 71 | 72 | ptr_to_int, |
| 72 | 73 | rem, |
| ... | ... | @@ -615,6 +616,13 @@ pub const list = list: { |
| 615 | 616 | .param_count = 2, |
| 616 | 617 | }, |
| 617 | 618 | }, |
| 619 | .{ | |
| 620 | "@prefetch", | |
| 621 | .{ | |
| 622 | .tag = .prefetch, | |
| 623 | .param_count = 2, | |
| 624 | }, | |
| 625 | }, | |
| 618 | 626 | .{ |
| 619 | 627 | "@ptrCast", |
| 620 | 628 | .{ |
src/Sema.zig+14| ... | ... | @@ -1042,6 +1042,7 @@ fn zirExtended(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 1042 | 1042 | .c_define => return sema.zirCDefine( block, extended), |
| 1043 | 1043 | .wasm_memory_size => return sema.zirWasmMemorySize( block, extended), |
| 1044 | 1044 | .wasm_memory_grow => return sema.zirWasmMemoryGrow( block, extended), |
| 1045 | .prefetch => return sema.zirPrefetch( block, extended), | |
| 1045 | 1046 | // zig fmt: on |
| 1046 | 1047 | } |
| 1047 | 1048 | } |
| ... | ... | @@ -11104,6 +11105,16 @@ fn zirWasmMemoryGrow( |
| 11104 | 11105 | return sema.fail(block, src, "TODO: implement Sema.zirWasmMemoryGrow", .{}); |
| 11105 | 11106 | } |
| 11106 | 11107 | |
| 11108 | fn zirPrefetch( | |
| 11109 | sema: *Sema, | |
| 11110 | block: *Block, | |
| 11111 | extended: Zir.Inst.Extended.InstData, | |
| 11112 | ) CompileError!Air.Inst.Ref { | |
| 11113 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; | |
| 11114 | const src: LazySrcLoc = .{ .node_offset = extra.node }; | |
| 11115 | return sema.fail(block, src, "TODO: implement Sema.zirPrefetch", .{}); | |
| 11116 | } | |
| 11117 | ||
| 11107 | 11118 | fn zirBuiltinExtern( |
| 11108 | 11119 | sema: *Sema, |
| 11109 | 11120 | block: *Block, |
| ... | ... | @@ -14231,6 +14242,7 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp |
| 14231 | 14242 | .float_mode => return sema.resolveBuiltinTypeFields(block, src, "FloatMode"), |
| 14232 | 14243 | .reduce_op => return sema.resolveBuiltinTypeFields(block, src, "ReduceOp"), |
| 14233 | 14244 | .call_options => return sema.resolveBuiltinTypeFields(block, src, "CallOptions"), |
| 14245 | .prefetch_options => return sema.resolveBuiltinTypeFields(block, src, "PrefetchOptions"), | |
| 14234 | 14246 | |
| 14235 | 14247 | .@"union", .union_tagged => { |
| 14236 | 14248 | const union_obj = ty.cast(Type.Payload.Union).?.data; |
| ... | ... | @@ -14819,6 +14831,7 @@ fn typeHasOnePossibleValue( |
| 14819 | 14831 | .float_mode, |
| 14820 | 14832 | .reduce_op, |
| 14821 | 14833 | .call_options, |
| 14834 | .prefetch_options, | |
| 14822 | 14835 | .export_options, |
| 14823 | 14836 | .extern_options, |
| 14824 | 14837 | .type_info, |
| ... | ... | @@ -15032,6 +15045,7 @@ pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref { |
| 15032 | 15045 | .float_mode => return .float_mode_type, |
| 15033 | 15046 | .reduce_op => return .reduce_op_type, |
| 15034 | 15047 | .call_options => return .call_options_type, |
| 15048 | .prefetch_options => return .prefetch_options_type, | |
| 15035 | 15049 | .export_options => return .export_options_type, |
| 15036 | 15050 | .extern_options => return .extern_options_type, |
| 15037 | 15051 | .type_info => return .type_info_type, |
src/Zir.zig+8| ... | ... | @@ -1572,6 +1572,9 @@ pub const Inst = struct { |
| 1572 | 1572 | wasm_memory_size, |
| 1573 | 1573 | /// `operand` is payload index to `BinNode`. |
| 1574 | 1574 | wasm_memory_grow, |
| 1575 | /// The `@prefetch` builtin. | |
| 1576 | /// `operand` is payload index to `BinNode`. | |
| 1577 | prefetch, | |
| 1575 | 1578 | |
| 1576 | 1579 | pub const InstData = struct { |
| 1577 | 1580 | opcode: Extended, |
| ... | ... | @@ -1648,6 +1651,7 @@ pub const Inst = struct { |
| 1648 | 1651 | float_mode_type, |
| 1649 | 1652 | reduce_op_type, |
| 1650 | 1653 | call_options_type, |
| 1654 | prefetch_options_type, | |
| 1651 | 1655 | export_options_type, |
| 1652 | 1656 | extern_options_type, |
| 1653 | 1657 | type_info_type, |
| ... | ... | @@ -1917,6 +1921,10 @@ pub const Inst = struct { |
| 1917 | 1921 | .ty = Type.initTag(.type), |
| 1918 | 1922 | .val = Value.initTag(.call_options_type), |
| 1919 | 1923 | }, |
| 1924 | .prefetch_options_type = .{ | |
| 1925 | .ty = Type.initTag(.type), | |
| 1926 | .val = Value.initTag(.prefetch_options_type), | |
| 1927 | }, | |
| 1920 | 1928 | .export_options_type = .{ |
| 1921 | 1929 | .ty = Type.initTag(.type), |
| 1922 | 1930 | .val = Value.initTag(.export_options_type), |
src/print_zir.zig+1-1| ... | ... | @@ -477,7 +477,7 @@ const Writer = struct { |
| 477 | 477 | try self.writeSrc(stream, src); |
| 478 | 478 | }, |
| 479 | 479 | |
| 480 | .builtin_extern, .c_define, .wasm_memory_grow => { | |
| 480 | .builtin_extern, .c_define, .wasm_memory_grow, .prefetch => { | |
| 481 | 481 | const inst_data = self.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 482 | 482 | const src: LazySrcLoc = .{ .node_offset = inst_data.node }; |
| 483 | 483 | try self.writeInstRef(stream, inst_data.lhs); |
src/stage1/all_types.hpp+34| ... | ... | @@ -898,6 +898,18 @@ struct AstNodeFnCallExpr { |
| 898 | 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 | 913 | struct AstNodeArrayAccessExpr { |
| 902 | 914 | AstNode *array_ref_expr; |
| 903 | 915 | AstNode *subscript; |
| ... | ... | @@ -1818,6 +1830,7 @@ enum BuiltinFnId { |
| 1818 | 1830 | BuiltinFnIdReduce, |
| 1819 | 1831 | BuiltinFnIdMaximum, |
| 1820 | 1832 | BuiltinFnIdMinimum, |
| 1833 | BuiltinFnIdPrefetch, | |
| 1821 | 1834 | }; |
| 1822 | 1835 | |
| 1823 | 1836 | struct BuiltinFnEntry { |
| ... | ... | @@ -2021,6 +2034,7 @@ struct CodeGen { |
| 2021 | 2034 | LLVMValueRef return_err_fn; |
| 2022 | 2035 | LLVMValueRef wasm_memory_size; |
| 2023 | 2036 | LLVMValueRef wasm_memory_grow; |
| 2037 | LLVMValueRef prefetch; | |
| 2024 | 2038 | LLVMTypeRef anyframe_fn_type; |
| 2025 | 2039 | |
| 2026 | 2040 | // reminder: hash tables must be initialized before use |
| ... | ... | @@ -2647,6 +2661,7 @@ enum Stage1ZirInstId : uint8_t { |
| 2647 | 2661 | Stage1ZirInstIdWasmMemorySize, |
| 2648 | 2662 | Stage1ZirInstIdWasmMemoryGrow, |
| 2649 | 2663 | Stage1ZirInstIdSrc, |
| 2664 | Stage1ZirInstIdPrefetch, | |
| 2650 | 2665 | }; |
| 2651 | 2666 | |
| 2652 | 2667 | // ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR. |
| ... | ... | @@ -2743,6 +2758,7 @@ enum Stage1AirInstId : uint8_t { |
| 2743 | 2758 | Stage1AirInstIdWasmMemorySize, |
| 2744 | 2759 | Stage1AirInstIdWasmMemoryGrow, |
| 2745 | 2760 | Stage1AirInstIdExtern, |
| 2761 | Stage1AirInstIdPrefetch, | |
| 2746 | 2762 | }; |
| 2747 | 2763 | |
| 2748 | 2764 | struct Stage1ZirInst { |
| ... | ... | @@ -3683,6 +3699,24 @@ struct Stage1ZirInstSrc { |
| 3683 | 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 | 3720 | struct Stage1ZirInstSlice { |
| 3687 | 3721 | Stage1ZirInst base; |
| 3688 | 3722 |
src/stage1/astgen.cpp+44| ... | ... | @@ -349,6 +349,8 @@ void destroy_instruction_src(Stage1ZirInst *inst) { |
| 349 | 349 | return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstWasmMemoryGrow *>(inst)); |
| 350 | 350 | case Stage1ZirInstIdSrc: |
| 351 | 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 | 355 | zig_unreachable(); |
| 354 | 356 | } |
| ... | ... | @@ -941,6 +943,10 @@ static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSrc *) { |
| 941 | 943 | return Stage1ZirInstIdSrc; |
| 942 | 944 | } |
| 943 | 945 | |
| 946 | static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPrefetch *) { | |
| 947 | return Stage1ZirInstIdPrefetch; | |
| 948 | } | |
| 949 | ||
| 944 | 950 | template<typename T> |
| 945 | 951 | static T *ir_create_instruction(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { |
| 946 | 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 | 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 | 2894 | static void ir_count_defers(Stage1AstGen *ag, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 2874 | 2895 | results[ReturnKindUnconditional] = 0; |
| 2875 | 2896 | results[ReturnKindError] = 0; |
| ... | ... | @@ -5416,6 +5437,29 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast |
| 5416 | 5437 | Stage1ZirInst *src_inst = ir_build_src(ag, scope, node); |
| 5417 | 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 | 5464 | zig_unreachable(); |
| 5421 | 5465 | } |
src/stage1/codegen.cpp+67| ... | ... | @@ -1139,6 +1139,24 @@ static LLVMValueRef gen_wasm_memory_grow(CodeGen *g) { |
| 1139 | 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 | 1160 | static LLVMValueRef get_stacksave_fn_val(CodeGen *g) { |
| 1143 | 1161 | if (g->stacksave_fn_val) |
| 1144 | 1162 | return g->stacksave_fn_val; |
| ... | ... | @@ -5899,6 +5917,52 @@ static LLVMValueRef ir_render_wasm_memory_grow(CodeGen *g, Stage1Air *executable |
| 5899 | 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 | 5966 | static LLVMValueRef ir_render_slice(CodeGen *g, Stage1Air *executable, Stage1AirInstSlice *instruction) { |
| 5903 | 5967 | Error err; |
| 5904 | 5968 | |
| ... | ... | @@ -7150,6 +7214,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, Stage1Air *executable, Sta |
| 7150 | 7214 | return ir_render_wasm_memory_grow(g, executable, (Stage1AirInstWasmMemoryGrow *) instruction); |
| 7151 | 7215 | case Stage1AirInstIdExtern: |
| 7152 | 7216 | return ir_render_extern(g, executable, (Stage1AirInstExtern *) instruction); |
| 7217 | case Stage1AirInstIdPrefetch: | |
| 7218 | return ir_render_prefetch(g, executable, (Stage1AirInstPrefetch *) instruction); | |
| 7153 | 7219 | } |
| 7154 | 7220 | zig_unreachable(); |
| 7155 | 7221 | } |
| ... | ... | @@ -9120,6 +9186,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 9120 | 9186 | create_builtin_fn(g, BuiltinFnIdReduce, "reduce", 2); |
| 9121 | 9187 | create_builtin_fn(g, BuiltinFnIdMaximum, "maximum", 2); |
| 9122 | 9188 | create_builtin_fn(g, BuiltinFnIdMinimum, "minimum", 2); |
| 9189 | create_builtin_fn(g, BuiltinFnIdPrefetch, "prefetch", 2); | |
| 9123 | 9190 | } |
| 9124 | 9191 | |
| 9125 | 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 | 467 | return heap::c_allocator.destroy(reinterpret_cast<Stage1AirInstWasmMemoryGrow *>(inst)); |
| 468 | 468 | case Stage1AirInstIdExtern: |
| 469 | 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 | 473 | zig_unreachable(); |
| 472 | 474 | } |
| ... | ... | @@ -1115,6 +1117,10 @@ static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstExtern *) { |
| 1115 | 1117 | return Stage1AirInstIdExtern; |
| 1116 | 1118 | } |
| 1117 | 1119 | |
| 1120 | static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstPrefetch *) { | |
| 1121 | return Stage1AirInstIdPrefetch; | |
| 1122 | } | |
| 1123 | ||
| 1118 | 1124 | template<typename T> |
| 1119 | 1125 | static T *ir_create_inst_gen(IrBuilderGen *irb, Scope *scope, AstNode *source_node) { |
| 1120 | 1126 | T *special_instruction = heap::c_allocator.create<T>(); |
| ... | ... | @@ -24853,6 +24859,52 @@ static Stage1AirInst *ir_analyze_instruction_src(IrAnalyze *ira, Stage1ZirInstSr |
| 24853 | 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 | 24908 | static Stage1AirInst *ir_analyze_instruction_base(IrAnalyze *ira, Stage1ZirInst *instruction) { |
| 24857 | 24909 | switch (instruction->id) { |
| 24858 | 24910 | case Stage1ZirInstIdInvalid: |
| ... | ... | @@ -25138,6 +25190,8 @@ static Stage1AirInst *ir_analyze_instruction_base(IrAnalyze *ira, Stage1ZirInst |
| 25138 | 25190 | return ir_analyze_instruction_wasm_memory_grow(ira, (Stage1ZirInstWasmMemoryGrow *)instruction); |
| 25139 | 25191 | case Stage1ZirInstIdSrc: |
| 25140 | 25192 | return ir_analyze_instruction_src(ira, (Stage1ZirInstSrc *)instruction); |
| 25193 | case Stage1ZirInstIdPrefetch: | |
| 25194 | return ir_analyze_instruction_prefetch(ira, (Stage1ZirInstPrefetch *)instruction); | |
| 25141 | 25195 | } |
| 25142 | 25196 | zig_unreachable(); |
| 25143 | 25197 | } |
| ... | ... | @@ -25305,6 +25359,7 @@ bool ir_inst_gen_has_side_effects(Stage1AirInst *instruction) { |
| 25305 | 25359 | case Stage1AirInstIdSpillBegin: |
| 25306 | 25360 | case Stage1AirInstIdWasmMemoryGrow: |
| 25307 | 25361 | case Stage1AirInstIdExtern: |
| 25362 | case Stage1AirInstIdPrefetch: | |
| 25308 | 25363 | return true; |
| 25309 | 25364 | |
| 25310 | 25365 | case Stage1AirInstIdPhi: |
| ... | ... | @@ -25444,6 +25499,7 @@ bool ir_inst_src_has_side_effects(Stage1ZirInst *instruction) { |
| 25444 | 25499 | case Stage1ZirInstIdAwait: |
| 25445 | 25500 | case Stage1ZirInstIdSpillBegin: |
| 25446 | 25501 | case Stage1ZirInstIdWasmMemoryGrow: |
| 25502 | case Stage1ZirInstIdPrefetch: | |
| 25447 | 25503 | return true; |
| 25448 | 25504 | |
| 25449 | 25505 | case Stage1ZirInstIdPhi: |
src/stage1/ir_print.cpp+22| ... | ... | @@ -371,6 +371,8 @@ const char* ir_inst_src_type_str(Stage1ZirInstId id) { |
| 371 | 371 | return "SrcWasmMemoryGrow"; |
| 372 | 372 | case Stage1ZirInstIdSrc: |
| 373 | 373 | return "SrcSrc"; |
| 374 | case Stage1ZirInstIdPrefetch: | |
| 375 | return "SrcPrefetch"; | |
| 374 | 376 | } |
| 375 | 377 | zig_unreachable(); |
| 376 | 378 | } |
| ... | ... | @@ -559,6 +561,8 @@ const char* ir_inst_gen_type_str(Stage1AirInstId id) { |
| 559 | 561 | return "GenWasmMemoryGrow"; |
| 560 | 562 | case Stage1AirInstIdExtern: |
| 561 | 563 | return "GenExtern"; |
| 564 | case Stage1AirInstIdPrefetch: | |
| 565 | return "GenPrefetch"; | |
| 562 | 566 | } |
| 563 | 567 | zig_unreachable(); |
| 564 | 568 | } |
| ... | ... | @@ -2436,6 +2440,18 @@ static void ir_print_extern(IrPrintSrc *irp, Stage1ZirInstExtern *instruction) { |
| 2436 | 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 | 2455 | static void ir_print_error_return_trace(IrPrintSrc *irp, Stage1ZirInstErrorReturnTrace *instruction) { |
| 2440 | 2456 | fprintf(irp->f, "@errorReturnTrace("); |
| 2441 | 2457 | switch (instruction->optional) { |
| ... | ... | @@ -3108,6 +3124,9 @@ static void ir_print_inst_src(IrPrintSrc *irp, Stage1ZirInst *instruction, bool |
| 3108 | 3124 | case Stage1ZirInstIdSrc: |
| 3109 | 3125 | ir_print_builtin_src(irp, (Stage1ZirInstSrc *)instruction); |
| 3110 | 3126 | break; |
| 3127 | case Stage1ZirInstIdPrefetch: | |
| 3128 | ir_print_prefetch(irp, (Stage1ZirInstPrefetch *)instruction); | |
| 3129 | break; | |
| 3111 | 3130 | } |
| 3112 | 3131 | fprintf(irp->f, "\n"); |
| 3113 | 3132 | } |
| ... | ... | @@ -3387,6 +3406,9 @@ static void ir_print_inst_gen(IrPrintGen *irp, Stage1AirInst *instruction, bool |
| 3387 | 3406 | case Stage1AirInstIdExtern: |
| 3388 | 3407 | ir_print_extern(irp, (Stage1AirInstExtern *)instruction); |
| 3389 | 3408 | break; |
| 3409 | case Stage1AirInstIdPrefetch: | |
| 3410 | ir_print_prefetch(irp, (Stage1AirInstPrefetch *)instruction); | |
| 3411 | break; | |
| 3390 | 3412 | |
| 3391 | 3413 | } |
| 3392 | 3414 | fprintf(irp->f, "\n"); |
src/type.zig+19| ... | ... | @@ -123,6 +123,7 @@ pub const Type = extern union { |
| 123 | 123 | .empty_struct_literal, |
| 124 | 124 | .@"struct", |
| 125 | 125 | .call_options, |
| 126 | .prefetch_options, | |
| 126 | 127 | .export_options, |
| 127 | 128 | .extern_options, |
| 128 | 129 | => return .Struct, |
| ... | ... | @@ -798,6 +799,7 @@ pub const Type = extern union { |
| 798 | 799 | .float_mode, |
| 799 | 800 | .reduce_op, |
| 800 | 801 | .call_options, |
| 802 | .prefetch_options, | |
| 801 | 803 | .export_options, |
| 802 | 804 | .extern_options, |
| 803 | 805 | .type_info, |
| ... | ... | @@ -1027,6 +1029,7 @@ pub const Type = extern union { |
| 1027 | 1029 | .float_mode => return writer.writeAll("std.builtin.FloatMode"), |
| 1028 | 1030 | .reduce_op => return writer.writeAll("std.builtin.ReduceOp"), |
| 1029 | 1031 | .call_options => return writer.writeAll("std.builtin.CallOptions"), |
| 1032 | .prefetch_options => return writer.writeAll("std.builtin.PrefetchOptions"), | |
| 1030 | 1033 | .export_options => return writer.writeAll("std.builtin.ExportOptions"), |
| 1031 | 1034 | .extern_options => return writer.writeAll("std.builtin.ExternOptions"), |
| 1032 | 1035 | .type_info => return writer.writeAll("std.builtin.TypeInfo"), |
| ... | ... | @@ -1318,6 +1321,7 @@ pub const Type = extern union { |
| 1318 | 1321 | .float_mode => return "FloatMode", |
| 1319 | 1322 | .reduce_op => return "ReduceOp", |
| 1320 | 1323 | .call_options => return "CallOptions", |
| 1324 | .prefetch_options => return "PrefetchOptions", | |
| 1321 | 1325 | .export_options => return "ExportOptions", |
| 1322 | 1326 | .extern_options => return "ExternOptions", |
| 1323 | 1327 | .type_info => return "TypeInfo", |
| ... | ... | @@ -1376,6 +1380,7 @@ pub const Type = extern union { |
| 1376 | 1380 | .float_mode, |
| 1377 | 1381 | .reduce_op, |
| 1378 | 1382 | .call_options, |
| 1383 | .prefetch_options, | |
| 1379 | 1384 | .export_options, |
| 1380 | 1385 | .extern_options, |
| 1381 | 1386 | .manyptr_u8, |
| ... | ... | @@ -1502,6 +1507,7 @@ pub const Type = extern union { |
| 1502 | 1507 | .float_mode => return Value.initTag(.float_mode_type), |
| 1503 | 1508 | .reduce_op => return Value.initTag(.reduce_op_type), |
| 1504 | 1509 | .call_options => return Value.initTag(.call_options_type), |
| 1510 | .prefetch_options => return Value.initTag(.prefetch_options_type), | |
| 1505 | 1511 | .export_options => return Value.initTag(.export_options_type), |
| 1506 | 1512 | .extern_options => return Value.initTag(.extern_options_type), |
| 1507 | 1513 | .type_info => return Value.initTag(.type_info_type), |
| ... | ... | @@ -1563,6 +1569,7 @@ pub const Type = extern union { |
| 1563 | 1569 | .float_mode, |
| 1564 | 1570 | .reduce_op, |
| 1565 | 1571 | .call_options, |
| 1572 | .prefetch_options, | |
| 1566 | 1573 | .export_options, |
| 1567 | 1574 | .extern_options, |
| 1568 | 1575 | .@"anyframe", |
| ... | ... | @@ -1750,6 +1757,7 @@ pub const Type = extern union { |
| 1750 | 1757 | .float_mode, |
| 1751 | 1758 | .reduce_op, |
| 1752 | 1759 | .call_options, |
| 1760 | .prefetch_options, | |
| 1753 | 1761 | .export_options, |
| 1754 | 1762 | .extern_options, |
| 1755 | 1763 | => return 1, |
| ... | ... | @@ -1929,6 +1937,7 @@ pub const Type = extern union { |
| 1929 | 1937 | .var_args_param => unreachable, |
| 1930 | 1938 | .generic_poison => unreachable, |
| 1931 | 1939 | .call_options => unreachable, // missing call to resolveTypeFields |
| 1940 | .prefetch_options => unreachable, // missing call to resolveTypeFields | |
| 1932 | 1941 | .export_options => unreachable, // missing call to resolveTypeFields |
| 1933 | 1942 | .extern_options => unreachable, // missing call to resolveTypeFields |
| 1934 | 1943 | .type_info => unreachable, // missing call to resolveTypeFields |
| ... | ... | @@ -2269,6 +2278,7 @@ pub const Type = extern union { |
| 2269 | 2278 | .float_mode, |
| 2270 | 2279 | .reduce_op, |
| 2271 | 2280 | .call_options, |
| 2281 | .prefetch_options, | |
| 2272 | 2282 | .export_options, |
| 2273 | 2283 | .extern_options, |
| 2274 | 2284 | .type_info, |
| ... | ... | @@ -2794,6 +2804,7 @@ pub const Type = extern union { |
| 2794 | 2804 | .float_mode, |
| 2795 | 2805 | .reduce_op, |
| 2796 | 2806 | .call_options, |
| 2807 | .prefetch_options, | |
| 2797 | 2808 | .export_options, |
| 2798 | 2809 | .extern_options, |
| 2799 | 2810 | .type_info, |
| ... | ... | @@ -3294,6 +3305,7 @@ pub const Type = extern union { |
| 3294 | 3305 | .float_mode, |
| 3295 | 3306 | .reduce_op, |
| 3296 | 3307 | .call_options, |
| 3308 | .prefetch_options, | |
| 3297 | 3309 | .export_options, |
| 3298 | 3310 | .extern_options, |
| 3299 | 3311 | .type_info, |
| ... | ... | @@ -3502,6 +3514,7 @@ pub const Type = extern union { |
| 3502 | 3514 | .float_mode, |
| 3503 | 3515 | .reduce_op, |
| 3504 | 3516 | .call_options, |
| 3517 | .prefetch_options, | |
| 3505 | 3518 | .export_options, |
| 3506 | 3519 | .extern_options, |
| 3507 | 3520 | => @panic("TODO resolve std.builtin types"), |
| ... | ... | @@ -3577,6 +3590,7 @@ pub const Type = extern union { |
| 3577 | 3590 | .float_mode, |
| 3578 | 3591 | .reduce_op, |
| 3579 | 3592 | .call_options, |
| 3593 | .prefetch_options, | |
| 3580 | 3594 | .export_options, |
| 3581 | 3595 | .extern_options, |
| 3582 | 3596 | => @panic("TODO resolve std.builtin types"), |
| ... | ... | @@ -3701,6 +3715,7 @@ pub const Type = extern union { |
| 3701 | 3715 | .float_mode, |
| 3702 | 3716 | .reduce_op, |
| 3703 | 3717 | .call_options, |
| 3718 | .prefetch_options, | |
| 3704 | 3719 | .export_options, |
| 3705 | 3720 | .extern_options, |
| 3706 | 3721 | .type_info, |
| ... | ... | @@ -3741,6 +3756,7 @@ pub const Type = extern union { |
| 3741 | 3756 | .float_mode, |
| 3742 | 3757 | .reduce_op, |
| 3743 | 3758 | .call_options, |
| 3759 | .prefetch_options, | |
| 3744 | 3760 | .export_options, |
| 3745 | 3761 | .extern_options, |
| 3746 | 3762 | .type_info, |
| ... | ... | @@ -3801,6 +3817,7 @@ pub const Type = extern union { |
| 3801 | 3817 | .float_mode, |
| 3802 | 3818 | .reduce_op, |
| 3803 | 3819 | .call_options, |
| 3820 | .prefetch_options, | |
| 3804 | 3821 | .export_options, |
| 3805 | 3822 | .extern_options, |
| 3806 | 3823 | => @panic("TODO resolve std.builtin types"), |
| ... | ... | @@ -3862,6 +3879,7 @@ pub const Type = extern union { |
| 3862 | 3879 | float_mode, |
| 3863 | 3880 | reduce_op, |
| 3864 | 3881 | call_options, |
| 3882 | prefetch_options, | |
| 3865 | 3883 | export_options, |
| 3866 | 3884 | extern_options, |
| 3867 | 3885 | type_info, |
| ... | ... | @@ -3989,6 +4007,7 @@ pub const Type = extern union { |
| 3989 | 4007 | .float_mode, |
| 3990 | 4008 | .reduce_op, |
| 3991 | 4009 | .call_options, |
| 4010 | .prefetch_options, | |
| 3992 | 4011 | .export_options, |
| 3993 | 4012 | .extern_options, |
| 3994 | 4013 | .type_info, |
src/value.zig+5| ... | ... | @@ -67,6 +67,7 @@ pub const Value = extern union { |
| 67 | 67 | float_mode_type, |
| 68 | 68 | reduce_op_type, |
| 69 | 69 | call_options_type, |
| 70 | prefetch_options_type, | |
| 70 | 71 | export_options_type, |
| 71 | 72 | extern_options_type, |
| 72 | 73 | type_info_type, |
| ... | ... | @@ -244,6 +245,7 @@ pub const Value = extern union { |
| 244 | 245 | .float_mode_type, |
| 245 | 246 | .reduce_op_type, |
| 246 | 247 | .call_options_type, |
| 248 | .prefetch_options_type, | |
| 247 | 249 | .export_options_type, |
| 248 | 250 | .extern_options_type, |
| 249 | 251 | .type_info_type, |
| ... | ... | @@ -434,6 +436,7 @@ pub const Value = extern union { |
| 434 | 436 | .float_mode_type, |
| 435 | 437 | .reduce_op_type, |
| 436 | 438 | .call_options_type, |
| 439 | .prefetch_options_type, | |
| 437 | 440 | .export_options_type, |
| 438 | 441 | .extern_options_type, |
| 439 | 442 | .type_info_type, |
| ... | ... | @@ -652,6 +655,7 @@ pub const Value = extern union { |
| 652 | 655 | .float_mode_type => return out_stream.writeAll("std.builtin.FloatMode"), |
| 653 | 656 | .reduce_op_type => return out_stream.writeAll("std.builtin.ReduceOp"), |
| 654 | 657 | .call_options_type => return out_stream.writeAll("std.builtin.CallOptions"), |
| 658 | .prefetch_options_type => return out_stream.writeAll("std.builtin.PrefetchOptions"), | |
| 655 | 659 | .export_options_type => return out_stream.writeAll("std.builtin.ExportOptions"), |
| 656 | 660 | .extern_options_type => return out_stream.writeAll("std.builtin.ExternOptions"), |
| 657 | 661 | .type_info_type => return out_stream.writeAll("std.builtin.TypeInfo"), |
| ... | ... | @@ -829,6 +833,7 @@ pub const Value = extern union { |
| 829 | 833 | .float_mode_type => Type.initTag(.float_mode), |
| 830 | 834 | .reduce_op_type => Type.initTag(.reduce_op), |
| 831 | 835 | .call_options_type => Type.initTag(.call_options), |
| 836 | .prefetch_options_type => Type.initTag(.prefetch_options), | |
| 832 | 837 | .export_options_type => Type.initTag(.export_options), |
| 833 | 838 | .extern_options_type => Type.initTag(.extern_options), |
| 834 | 839 | .type_info_type => Type.initTag(.type_info), |
test/behavior.zig+1| ... | ... | @@ -169,6 +169,7 @@ test { |
| 169 | 169 | _ = @import("behavior/optional_stage1.zig"); |
| 170 | 170 | _ = @import("behavior/pointers_stage1.zig"); |
| 171 | 171 | _ = @import("behavior/popcount_stage1.zig"); |
| 172 | _ = @import("behavior/prefetch.zig"); | |
| 172 | 173 | _ = @import("behavior/ptrcast_stage1.zig"); |
| 173 | 174 | _ = @import("behavior/reflection.zig"); |
| 174 | 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 | } |