diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-01-18 10:49:54 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-01-18 11:59:09 -0700 |
| commit | 30efcf22d799c055d8ec987aa2f55a11c133b709 (patch) | |
| tree | 35febf72fdea7d3f571f01005823442701e02dd0 | |
| parent | f423b5949b8722d4b290f57c3d06d015e39217b0 (diff) | |
| download | zig-30efcf22d799c055d8ec987aa2f55a11c133b709.tar.gz zig-30efcf22d799c055d8ec987aa2f55a11c133b709.zip | |
stage2: implement `@prefetch`
This reverts commit f423b5949b8722d4b290f57c3d06d015e39217b0,
re-instating commit d48e4245b68bf25c7f41804a5012ac157a5ee546.
| -rw-r--r-- | lib/std/builtin.zig | 4 | ||||
| -rw-r--r-- | src/Air.zig | 12 | ||||
| -rw-r--r-- | src/Liveness.zig | 5 | ||||
| -rw-r--r-- | src/Sema.zig | 120 | ||||
| -rw-r--r-- | src/arch/aarch64/CodeGen.zig | 6 | ||||
| -rw-r--r-- | src/arch/arm/CodeGen.zig | 6 | ||||
| -rw-r--r-- | src/arch/riscv64/CodeGen.zig | 6 | ||||
| -rw-r--r-- | src/arch/wasm/CodeGen.zig | 67 | ||||
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 6 | ||||
| -rw-r--r-- | src/codegen/c.zig | 20 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 62 | ||||
| -rw-r--r-- | src/link/C/zig.h | 6 | ||||
| -rw-r--r-- | src/print_air.zig | 10 | ||||
| -rw-r--r-- | test/behavior.zig | 2 |
14 files changed, 287 insertions, 45 deletions
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 72503b7d2f..ba5801e936 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -643,12 +643,12 @@ pub const PrefetchOptions = struct { /// The cache that the prefetch should be preformed on. cache: Cache = .data, - pub const Rw = enum { + pub const Rw = enum(u1) { read, write, }; - pub const Cache = enum { + pub const Cache = enum(u1) { instruction, data, }; diff --git a/src/Air.zig b/src/Air.zig index 274c30167a..0f9542af1b 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -515,6 +515,11 @@ pub const Inst = struct { /// is a `Ref`. Length of the array is given by the vector type. vector_init, + /// Communicates an intent to load memory. + /// Result is always unused. + /// Uses the `prefetch` field. + prefetch, + pub fn fromCmpOp(op: std.math.CompareOperator) Tag { return switch (op) { .lt => .cmp_lt, @@ -586,6 +591,12 @@ pub const Inst = struct { ptr: Ref, order: std.builtin.AtomicOrder, }, + prefetch: struct { + ptr: Ref, + rw: std.builtin.PrefetchOptions.Rw, + locality: u2, + cache: std.builtin.PrefetchOptions.Cache, + }, // Make sure we don't accidentally add a field to make this union // bigger than expected. Note that in Debug builds, Zig is allowed @@ -823,6 +834,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { .memset, .memcpy, .set_union_tag, + .prefetch, => return Type.initTag(.void), .ptrtoint, diff --git a/src/Liveness.zig b/src/Liveness.zig index 92ec51e574..1bdbab6788 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -342,6 +342,11 @@ fn analyzeInst( return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none }); }, + .prefetch => { + const prefetch = inst_datas[inst].prefetch; + return trackOperands(a, new_set, inst, main_tomb, .{ prefetch.ptr, .none, .none }); + }, + .call => { const inst_data = inst_datas[inst].pl_op; const callee = inst_data.operand; diff --git a/src/Sema.zig b/src/Sema.zig index 616ec3e7ac..82af87bd4d 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -10316,49 +10316,53 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE const inst_data = sema.code.instructions.items(.data)[inst].un_node; const src = inst_data.src(); const obj_ty = try sema.resolveType(block, src, inst_data.operand); - const gpa = sema.gpa; switch (obj_ty.zigTypeTag()) { - .Struct => { - // This logic must be synchronized with that in `zirStructInit`. - const struct_ty = try sema.resolveTypeFields(block, src, obj_ty); - const struct_obj = struct_ty.castTag(.@"struct").?.data; - - // The init values to use for the struct instance. - const field_inits = try gpa.alloc(Air.Inst.Ref, struct_obj.fields.count()); - defer gpa.free(field_inits); - - var root_msg: ?*Module.ErrorMsg = null; - - for (struct_obj.fields.values()) |field, i| { - if (field.default_val.tag() == .unreachable_value) { - const field_name = struct_obj.fields.keys()[i]; - const template = "missing struct field: {s}"; - const args = .{field_name}; - if (root_msg) |msg| { - try sema.errNote(block, src, msg, template, args); - } else { - root_msg = try sema.errMsg(block, src, template, args); - } - } else { - field_inits[i] = try sema.addConstant(field.ty, field.default_val); - } - } - return sema.finishStructInit(block, src, field_inits, root_msg, struct_obj, struct_ty, false); - }, - .Array => { - if (obj_ty.sentinel()) |sentinel| { - const val = try Value.Tag.empty_array_sentinel.create(sema.arena, sentinel); - return sema.addConstant(obj_ty, val); - } else { - return sema.addConstant(obj_ty, Value.initTag(.empty_array)); - } - }, + .Struct => return structInitEmpty(sema, block, obj_ty, src, src), + .Array => return arrayInitEmpty(sema, obj_ty), .Void => return sema.addConstant(obj_ty, Value.void), else => unreachable, } } +fn structInitEmpty(sema: *Sema, block: *Block, obj_ty: Type, dest_src: LazySrcLoc, init_src: LazySrcLoc) CompileError!Air.Inst.Ref { + const gpa = sema.gpa; + // This logic must be synchronized with that in `zirStructInit`. + const struct_ty = try sema.resolveTypeFields(block, dest_src, obj_ty); + const struct_obj = struct_ty.castTag(.@"struct").?.data; + + // The init values to use for the struct instance. + const field_inits = try gpa.alloc(Air.Inst.Ref, struct_obj.fields.count()); + defer gpa.free(field_inits); + + var root_msg: ?*Module.ErrorMsg = null; + + for (struct_obj.fields.values()) |field, i| { + if (field.default_val.tag() == .unreachable_value) { + const field_name = struct_obj.fields.keys()[i]; + const template = "missing struct field: {s}"; + const args = .{field_name}; + if (root_msg) |msg| { + try sema.errNote(block, init_src, msg, template, args); + } else { + root_msg = try sema.errMsg(block, init_src, template, args); + } + } else { + field_inits[i] = try sema.addConstant(field.ty, field.default_val); + } + } + return sema.finishStructInit(block, dest_src, field_inits, root_msg, struct_obj, struct_ty, false); +} + +fn arrayInitEmpty(sema: *Sema, obj_ty: Type) CompileError!Air.Inst.Ref { + if (obj_ty.sentinel()) |sentinel| { + const val = try Value.Tag.empty_array_sentinel.create(sema.arena, sentinel); + return sema.addConstant(obj_ty, val); + } else { + return sema.addConstant(obj_ty, Value.initTag(.empty_array)); + } +} + fn zirUnionInitPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const src = inst_data.src(); @@ -12326,8 +12330,38 @@ fn zirPrefetch( extended: Zir.Inst.Extended.InstData, ) CompileError!Air.Inst.Ref { const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; - const src: LazySrcLoc = .{ .node_offset = extra.node }; - return sema.fail(block, src, "TODO: implement Sema.zirPrefetch", .{}); + const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; + const opts_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; + const options_ty = try sema.getBuiltinType(block, opts_src, "PrefetchOptions"); + const ptr = sema.resolveInst(extra.lhs); + try sema.checkPtrType(block, ptr_src, sema.typeOf(ptr)); + const options = try sema.coerce(block, options_ty, sema.resolveInst(extra.rhs), opts_src); + + const rw = try sema.fieldVal(block, opts_src, options, "rw", opts_src); + const rw_val = try sema.resolveConstValue(block, opts_src, rw); + const rw_tag = rw_val.toEnum(std.builtin.PrefetchOptions.Rw); + + const locality = try sema.fieldVal(block, opts_src, options, "locality", opts_src); + const locality_val = try sema.resolveConstValue(block, opts_src, locality); + const locality_int = @intCast(u2, locality_val.toUnsignedInt()); + + const cache = try sema.fieldVal(block, opts_src, options, "cache", opts_src); + const cache_val = try sema.resolveConstValue(block, opts_src, cache); + const cache_tag = cache_val.toEnum(std.builtin.PrefetchOptions.Cache); + + if (!block.is_comptime) { + _ = try block.addInst(.{ + .tag = .prefetch, + .data = .{ .prefetch = .{ + .ptr = ptr, + .rw = rw_tag, + .locality = locality_int, + .cache = cache_tag, + } }, + }); + } + + return Air.Inst.Ref.void_value; } fn zirBuiltinExtern( @@ -13787,6 +13821,11 @@ fn coerce( }, .Array => switch (inst_ty.zigTypeTag()) { .Vector => return sema.coerceVectorInMemory(block, dest_ty, dest_ty_src, inst, inst_src), + .Struct => { + if (inst == .empty_struct) { + return arrayInitEmpty(sema, dest_ty); + } + }, else => {}, }, .Vector => switch (inst_ty.zigTypeTag()) { @@ -13794,6 +13833,11 @@ fn coerce( .Vector => return sema.coerceVectors(block, dest_ty, dest_ty_src, inst, inst_src), else => {}, }, + .Struct => { + if (inst == .empty_struct) { + return structInitEmpty(sema, block, dest_ty, dest_ty_src, inst_src); + } + }, else => {}, } diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index f8a774af3b..d5993ea5d7 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -595,6 +595,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .error_name => try self.airErrorName(inst), .splat => try self.airSplat(inst), .vector_init => try self.airVectorInit(inst), + .prefetch => try self.airPrefetch(inst), .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), @@ -2597,6 +2598,11 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void { return bt.finishAir(result); } +fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void { + const prefetch = self.air.instructions.items(.data)[inst].prefetch; + return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none }); +} + fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { // First section of indexes correspond to a set number of constant values. const ref_int = @enumToInt(inst); diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index cae5164491..66c5a7a429 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -586,6 +586,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .error_name => try self.airErrorName(inst), .splat => try self.airSplat(inst), .vector_init => try self.airVectorInit(inst), + .prefetch => try self.airPrefetch(inst), .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), @@ -3693,6 +3694,11 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void { return bt.finishAir(result); } +fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void { + const prefetch = self.air.instructions.items(.data)[inst].prefetch; + return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none }); +} + fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { // First section of indexes correspond to a set number of constant values. const ref_int = @enumToInt(inst); diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index c5f0d4fb25..0c310d5680 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -574,6 +574,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .error_name => try self.airErrorName(inst), .splat => try self.airSplat(inst), .vector_init => try self.airVectorInit(inst), + .prefetch => try self.airPrefetch(inst), .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), @@ -2096,6 +2097,11 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void { return bt.finishAir(result); } +fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void { + const prefetch = self.air.instructions.items(.data)[inst].prefetch; + return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none }); +} + fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { // First section of indexes correspond to a set number of constant values. const ref_int = @enumToInt(inst); diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 7a8efdfcc2..46a8e114e6 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1297,6 +1297,9 @@ fn copyLocal(self: *Self, value: WValue, ty: Type) InnerError!WValue { fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { const air_tags = self.air.instructions.items(.tag); return switch (air_tags[inst]) { + .constant => unreachable, + .const_ty => unreachable, + .add => self.airBinOp(inst, .add), .addwrap => self.airWrapBinOp(inst, .add), .sub => self.airBinOp(inst, .sub), @@ -1330,7 +1333,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { .bool_to_int => self.airBoolToInt(inst), .call => self.airCall(inst), .cond_br => self.airCondBr(inst), - .constant => unreachable, .dbg_stmt => WValue.none, .intcast => self.airIntcast(inst), .float_to_int => self.airFloatToInt(inst), @@ -1358,6 +1360,9 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { .ret => self.airRet(inst), .ret_ptr => self.airRetPtr(inst), .ret_load => self.airRetLoad(inst), + .splat => self.airSplat(inst), + .vector_init => self.airVectorInit(inst), + .prefetch => self.airPrefetch(inst), .slice => self.airSlice(inst), .slice_len => self.airSliceLen(inst), @@ -1382,7 +1387,55 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { .unwrap_errunion_err => self.airUnwrapErrUnionError(inst), .wrap_errunion_payload => self.airWrapErrUnionPayload(inst), .wrap_errunion_err => self.airWrapErrUnionErr(inst), - else => |tag| self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}), + + .add_sat, + .sub_sat, + .mul_sat, + .div_float, + .div_floor, + .div_exact, + .rem, + .mod, + .max, + .min, + .assembly, + .shl_exact, + .shl_sat, + .ret_addr, + .clz, + .ctz, + .popcount, + .is_err_ptr, + .is_non_err_ptr, + .fptrunc, + .fpext, + .unwrap_errunion_payload_ptr, + .unwrap_errunion_err_ptr, + .set_union_tag, + .get_union_tag, + .ptr_slice_len_ptr, + .ptr_slice_ptr_ptr, + .int_to_float, + .memcpy, + .cmpxchg_weak, + .cmpxchg_strong, + .fence, + .atomic_load, + .atomic_store_unordered, + .atomic_store_monotonic, + .atomic_store_release, + .atomic_store_seq_cst, + .atomic_rmw, + .tag_name, + .error_name, + + // For these 4, probably best to wait until https://github.com/ziglang/zig/issues/10248 + // is implemented in the frontend before implementing them here in the wasm backend. + .add_with_overflow, + .sub_with_overflow, + .mul_with_overflow, + .shl_with_overflow, + => |tag| self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}), }; } @@ -3211,7 +3264,7 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue { return result; } -fn airSplat(self: *Self, inst: Air.Inst.Index) !void { +fn airSplat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { if (self.liveness.isUnused(inst)) return WValue{ .none = {} }; const ty_op = self.air.instructions.items(.data)[inst].ty_op; @@ -3222,7 +3275,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { return self.fail("TODO: Implement wasm airSplat", .{}); } -fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void { +fn airVectorInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue { if (self.liveness.isUnused(inst)) return WValue{ .none = {} }; const vector_ty = self.air.typeOfIndex(inst); @@ -3234,6 +3287,12 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void { return self.fail("TODO: Wasm backend: implement airVectorInit", .{}); } +fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue { + const prefetch = self.air.instructions.items(.data)[inst].prefetch; + _ = prefetch; + return WValue{ .none = {} }; +} + fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue { assert(operand_ty.hasCodeGenBits()); assert(op == .eq or op == .neq); diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index a68674501c..2cf585fe4e 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -638,6 +638,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .error_name => try self.airErrorName(inst), .splat => try self.airSplat(inst), .vector_init => try self.airVectorInit(inst), + .prefetch => try self.airPrefetch(inst), .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), @@ -3746,6 +3747,11 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void { return bt.finishAir(result); } +fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void { + const prefetch = self.air.instructions.items(.data)[inst].prefetch; + return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none }); +} + fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { // First section of indexes correspond to a set number of constant values. const ref_int = @enumToInt(inst); diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 3f3147ca80..42778bccf8 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -1278,6 +1278,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .error_name => try airErrorName(f, inst), .splat => try airSplat(f, inst), .vector_init => try airVectorInit(f, inst), + .prefetch => try airPrefetch(f, inst), .int_to_float, .float_to_int, @@ -3089,6 +3090,25 @@ fn airVectorInit(f: *Function, inst: Air.Inst.Index) !CValue { return f.fail("TODO: C backend: implement airVectorInit", .{}); } +fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue { + const prefetch = f.air.instructions.items(.data)[inst].prefetch; + switch (prefetch.cache) { + .data => {}, + // The available prefetch intrinsics do not accept a cache argument; only + // address, rw, and locality. So unless the cache is data, we do not lower + // this instruction. + .instruction => return CValue.none, + } + const ptr = try f.resolveInst(prefetch.ptr); + const writer = f.object.writer(); + try writer.writeAll("zig_prefetch("); + try f.writeCValue(writer, ptr); + try writer.print(", {d}, {d});\n", .{ + @enumToInt(prefetch.rw), prefetch.locality, + }); + return CValue.none; +} + fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 { return switch (order) { .Unordered => "memory_order_relaxed", diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index d8c9589213..7a496af7b1 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -2073,6 +2073,7 @@ pub const FuncGen = struct { .error_name => try self.airErrorName(inst), .splat => try self.airSplat(inst), .vector_init => try self.airVectorInit(inst), + .prefetch => try self.airPrefetch(inst), .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), @@ -4384,6 +4385,67 @@ pub const FuncGen = struct { return vector; } + fn airPrefetch(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { + const prefetch = self.air.instructions.items(.data)[inst].prefetch; + + comptime assert(@enumToInt(std.builtin.PrefetchOptions.Rw.read) == 0); + comptime assert(@enumToInt(std.builtin.PrefetchOptions.Rw.write) == 1); + + // TODO these two asserts should be able to be comptime because the type is a u2 + assert(prefetch.locality >= 0); + assert(prefetch.locality <= 3); + + comptime assert(@enumToInt(std.builtin.PrefetchOptions.Cache.instruction) == 0); + comptime assert(@enumToInt(std.builtin.PrefetchOptions.Cache.data) == 1); + + // LLVM fails during codegen of instruction cache prefetchs for these architectures. + // This is an LLVM bug as the prefetch intrinsic should be a noop if not supported + // by the target. + // To work around this, don't emit llvm.prefetch in this case. + // See https://bugs.llvm.org/show_bug.cgi?id=21037 + const target = self.dg.module.getTarget(); + switch (prefetch.cache) { + .instruction => switch (target.cpu.arch) { + .x86_64, .i386 => return null, + .arm, .armeb, .thumb, .thumbeb => { + switch (prefetch.rw) { + .write => return null, + else => {}, + } + }, + else => {}, + }, + .data => {}, + } + + const llvm_u8 = self.context.intType(8); + const llvm_ptr_u8 = llvm_u8.pointerType(0); + const llvm_u32 = self.context.intType(32); + + const llvm_fn_name = "llvm.prefetch.p0i8"; + const fn_val = self.dg.object.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: { + // declare void @llvm.prefetch(i8*, i32, i32, i32) + const llvm_void = self.context.voidType(); + const param_types = [_]*const llvm.Type{ + llvm_ptr_u8, llvm_u32, llvm_u32, llvm_u32, + }; + const fn_type = llvm.functionType(llvm_void, ¶m_types, param_types.len, .False); + break :blk self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type); + }; + + const ptr = try self.resolveInst(prefetch.ptr); + const ptr_u8 = self.builder.buildBitCast(ptr, llvm_ptr_u8, ""); + + const params = [_]*const llvm.Value{ + ptr_u8, + llvm_u32.constInt(@enumToInt(prefetch.rw), .False), + llvm_u32.constInt(prefetch.locality, .False), + llvm_u32.constInt(@enumToInt(prefetch.cache), .False), + }; + _ = self.builder.buildCall(fn_val, ¶ms, params.len, .C, .Auto, ""); + return null; + } + fn getErrorNameTable(self: *FuncGen) !*const llvm.Value { if (self.dg.object.error_name_table) |table| { return table; diff --git a/src/link/C/zig.h b/src/link/C/zig.h index b14aaaaf34..eeda93894b 100644 --- a/src/link/C/zig.h +++ b/src/link/C/zig.h @@ -74,6 +74,12 @@ #define zig_frame_address() 0 #endif +#if defined(__GNUC__) +#define zig_prefetch(addr, rw, locality) __builtin_prefetch(addr, rw, locality) +#else +#define zig_prefetch(addr, rw, locality) +#endif + #if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) #include <stdatomic.h> #define zig_cmpxchg_strong(obj, expected, desired, succ, fail) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail) diff --git a/src/print_air.zig b/src/print_air.zig index 10ca034d1f..4e0b7cd4fd 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -226,6 +226,7 @@ const Writer = struct { .cmpxchg_weak, .cmpxchg_strong => try w.writeCmpxchg(s, inst), .fence => try w.writeFence(s, inst), .atomic_load => try w.writeAtomicLoad(s, inst), + .prefetch => try w.writePrefetch(s, inst), .atomic_store_unordered => try w.writeAtomicStore(s, inst, .Unordered), .atomic_store_monotonic => try w.writeAtomicStore(s, inst, .Monotonic), .atomic_store_release => try w.writeAtomicStore(s, inst, .Release), @@ -350,6 +351,15 @@ const Writer = struct { try s.print(", {s}", .{@tagName(atomic_load.order)}); } + fn writePrefetch(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + const prefetch = w.air.instructions.items(.data)[inst].prefetch; + + try w.writeOperand(s, inst, 0, prefetch.ptr); + try s.print(", {s}, {d}, {s}", .{ + @tagName(prefetch.rw), prefetch.locality, @tagName(prefetch.cache), + }); + } + fn writeAtomicStore( w: *Writer, s: anytype, diff --git a/test/behavior.zig b/test/behavior.zig index 25db4919ae..fe73529810 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -10,6 +10,7 @@ test { _ = @import("behavior/fn_in_struct_in_comptime.zig"); _ = @import("behavior/hasdecl.zig"); _ = @import("behavior/hasfield.zig"); + _ = @import("behavior/prefetch.zig"); _ = @import("behavior/pub_enum.zig"); _ = @import("behavior/type_info.zig"); _ = @import("behavior/type.zig"); @@ -178,7 +179,6 @@ test { _ = @import("behavior/optional_stage1.zig"); _ = @import("behavior/pointers_stage1.zig"); _ = @import("behavior/popcount_stage1.zig"); - _ = @import("behavior/prefetch.zig"); _ = @import("behavior/ptrcast_stage1.zig"); _ = @import("behavior/reflection.zig"); _ = @import("behavior/saturating_arithmetic_stage1.zig"); |
