| ... | ... | @@ -55,7 +55,7 @@ const BlockData = struct { |
| 55 | 55 | result: CValue, |
| 56 | 56 | }; |
| 57 | 57 | |
| 58 | | pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue); |
| 58 | pub const CValueMap = std.AutoHashMap(Air.Inst.Index, CValue); |
| 59 | 59 | |
| 60 | 60 | pub const LazyFnKey = union(enum) { |
| 61 | 61 | tag_name: Decl.Index, |
| ... | ... | @@ -289,29 +289,31 @@ pub const Function = struct { |
| 289 | 289 | /// Needed for memory used by the keys of free_locals_map entries. |
| 290 | 290 | arena: std.heap.ArenaAllocator, |
| 291 | 291 | |
| 292 | | fn resolveInst(f: *Function, inst: Air.Inst.Ref) !CValue { |
| 293 | | const gop = try f.value_map.getOrPut(inst); |
| 294 | | if (gop.found_existing) return gop.value_ptr.*; |
| 295 | | |
| 296 | | const val = f.air.value(inst).?; |
| 297 | | const ty = f.air.typeOf(inst); |
| 298 | | |
| 299 | | const result: CValue = if (lowersToArray(ty, f.object.dg.module.getTarget())) result: { |
| 300 | | const writer = f.object.code_header.writer(); |
| 301 | | const alignment = 0; |
| 302 | | const decl_c_value = try f.allocLocalValue(ty, alignment); |
| 303 | | const gpa = f.object.dg.gpa; |
| 304 | | try f.allocs.put(gpa, decl_c_value.new_local, true); |
| 305 | | try writer.writeAll("static "); |
| 306 | | try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, alignment, .complete); |
| 307 | | try writer.writeAll(" = "); |
| 308 | | try f.object.dg.renderValue(writer, ty, val, .StaticInitializer); |
| 309 | | try writer.writeAll(";\n "); |
| 310 | | break :result decl_c_value; |
| 311 | | } else .{ .constant = inst }; |
| 292 | fn resolveInst(f: *Function, ref: Air.Inst.Ref) !CValue { |
| 293 | if (Air.refToIndex(ref)) |inst| { |
| 294 | const gop = try f.value_map.getOrPut(inst); |
| 295 | if (gop.found_existing) return gop.value_ptr.*; |
| 312 | 296 | |
| 313 | | gop.value_ptr.* = result; |
| 314 | | return result; |
| 297 | const val = f.air.value(ref).?; |
| 298 | const ty = f.air.typeOf(ref); |
| 299 | |
| 300 | const result: CValue = if (lowersToArray(ty, f.object.dg.module.getTarget())) result: { |
| 301 | const writer = f.object.code_header.writer(); |
| 302 | const alignment = 0; |
| 303 | const decl_c_value = try f.allocLocalValue(ty, alignment); |
| 304 | const gpa = f.object.dg.gpa; |
| 305 | try f.allocs.put(gpa, decl_c_value.new_local, true); |
| 306 | try writer.writeAll("static "); |
| 307 | try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, alignment, .complete); |
| 308 | try writer.writeAll(" = "); |
| 309 | try f.object.dg.renderValue(writer, ty, val, .StaticInitializer); |
| 310 | try writer.writeAll(";\n "); |
| 311 | break :result decl_c_value; |
| 312 | } else .{ .constant = ref }; |
| 313 | |
| 314 | gop.value_ptr.* = result; |
| 315 | return result; |
| 316 | } else return .{ .constant = ref }; |
| 315 | 317 | } |
| 316 | 318 | |
| 317 | 319 | fn wantSafety(f: *Function) bool { |
| ... | ... | @@ -2594,6 +2596,7 @@ pub fn genFunc(f: *Function) !void { |
| 2594 | 2596 | // missing. These are added now to complete the map. Then we can sort by |
| 2595 | 2597 | // alignment, descending. |
| 2596 | 2598 | const free_locals = &f.free_locals_map; |
| 2599 | assert(f.value_map.count() == 0); // there must not be any unfreed locals |
| 2597 | 2600 | for (f.allocs.keys(), f.allocs.values()) |local_index, value| { |
| 2598 | 2601 | if (value) continue; // static |
| 2599 | 2602 | const local = f.locals.items[local_index]; |
| ... | ... | @@ -2995,7 +2998,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 2995 | 2998 | if (result_value == .new_local) { |
| 2996 | 2999 | log.debug("map %{d} to t{d}", .{ inst, result_value.new_local }); |
| 2997 | 3000 | } |
| 2998 | | try f.value_map.putNoClobber(Air.indexToRef(inst), switch (result_value) { |
| 3001 | try f.value_map.putNoClobber(inst, switch (result_value) { |
| 2999 | 3002 | .none => continue, |
| 3000 | 3003 | .new_local => |i| .{ .local = i }, |
| 3001 | 3004 | else => result_value, |
| ... | ... | @@ -3081,17 +3084,21 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3081 | 3084 | const child_ty = ptr_ty.childType(); |
| 3082 | 3085 | |
| 3083 | 3086 | const ptr = try f.resolveInst(bin_op.lhs); |
| 3084 | | if (!child_ty.hasRuntimeBitsIgnoreComptime()) { |
| 3085 | | if (f.liveness.operandDies(inst, 1)) try die(f, inst, bin_op.rhs); |
| 3086 | | return ptr; |
| 3087 | | } |
| 3088 | 3087 | const index = try f.resolveInst(bin_op.rhs); |
| 3089 | 3088 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 3090 | 3089 | |
| 3091 | 3090 | const writer = f.object.writer(); |
| 3092 | 3091 | const local = try f.allocLocal(inst, f.air.typeOfIndex(inst)); |
| 3093 | 3092 | try f.writeCValue(writer, local, .Other); |
| 3094 | | try writer.writeAll(" = ("); |
| 3093 | try writer.writeAll(" = "); |
| 3094 | |
| 3095 | if (!child_ty.hasRuntimeBitsIgnoreComptime()) { |
| 3096 | try f.writeCValue(writer, ptr, .Initializer); |
| 3097 | try writer.writeAll(";\n"); |
| 3098 | return local; |
| 3099 | } |
| 3100 | |
| 3101 | try writer.writeByte('('); |
| 3095 | 3102 | try f.renderType(writer, inst_ty); |
| 3096 | 3103 | try writer.writeAll(")&("); |
| 3097 | 3104 | if (ptr_ty.ptrSize() == .One) { |
| ... | ... | @@ -3217,12 +3224,11 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3217 | 3224 | } |
| 3218 | 3225 | |
| 3219 | 3226 | fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3220 | | const inst_ty = f.air.typeOfIndex(inst); |
| 3227 | if (f.liveness.isUnused(inst)) return .none; |
| 3221 | 3228 | |
| 3229 | const inst_ty = f.air.typeOfIndex(inst); |
| 3222 | 3230 | const elem_type = inst_ty.elemType(); |
| 3223 | | if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) { |
| 3224 | | return .{ .undef = inst_ty }; |
| 3225 | | } |
| 3231 | if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) return .{ .undef = inst_ty }; |
| 3226 | 3232 | |
| 3227 | 3233 | const target = f.object.dg.module.getTarget(); |
| 3228 | 3234 | const local = try f.allocAlignedLocal( |
| ... | ... | @@ -3237,12 +3243,11 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3237 | 3243 | } |
| 3238 | 3244 | |
| 3239 | 3245 | fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3240 | | const inst_ty = f.air.typeOfIndex(inst); |
| 3246 | if (f.liveness.isUnused(inst)) return .none; |
| 3241 | 3247 | |
| 3248 | const inst_ty = f.air.typeOfIndex(inst); |
| 3242 | 3249 | const elem_ty = inst_ty.elemType(); |
| 3243 | | if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) { |
| 3244 | | return .{ .undef = inst_ty }; |
| 3245 | | } |
| 3250 | if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return .{ .undef = inst_ty }; |
| 3246 | 3251 | |
| 3247 | 3252 | const target = f.object.dg.module.getTarget(); |
| 3248 | 3253 | const local = try f.allocAlignedLocal( |
| ... | ... | @@ -3262,10 +3267,22 @@ fn airArg(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3262 | 3267 | |
| 3263 | 3268 | const i = f.next_arg_index; |
| 3264 | 3269 | f.next_arg_index += 1; |
| 3265 | | return if (inst_cty != try f.typeToIndex(inst_ty, .complete)) |
| 3270 | const result: CValue = if (inst_cty != try f.typeToIndex(inst_ty, .complete)) |
| 3266 | 3271 | .{ .arg_array = i } |
| 3267 | 3272 | else |
| 3268 | 3273 | .{ .arg = i }; |
| 3274 | |
| 3275 | if (f.liveness.isUnused(inst)) { |
| 3276 | const writer = f.object.writer(); |
| 3277 | try writer.writeByte('('); |
| 3278 | try f.renderType(writer, Type.void); |
| 3279 | try writer.writeByte(')'); |
| 3280 | try f.writeCValue(writer, result, .Other); |
| 3281 | try writer.writeAll(";\n"); |
| 3282 | return .none; |
| 3283 | } |
| 3284 | |
| 3285 | return result; |
| 3269 | 3286 | } |
| 3270 | 3287 | |
| 3271 | 3288 | fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| ... | ... | @@ -4179,21 +4196,23 @@ fn airCall( |
| 4179 | 4196 | var lowered_ret_buf: LowerFnRetTyBuffer = undefined; |
| 4180 | 4197 | const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target); |
| 4181 | 4198 | |
| 4182 | | const result_local = if (modifier == .always_tail) r: { |
| 4183 | | try writer.writeAll("zig_always_tail return "); |
| 4184 | | break :r .none; |
| 4185 | | } else if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) |
| 4186 | | .none |
| 4187 | | else if (f.liveness.isUnused(inst)) r: { |
| 4188 | | try writer.writeByte('('); |
| 4189 | | try f.renderType(writer, Type.void); |
| 4190 | | try writer.writeByte(')'); |
| 4191 | | break :r .none; |
| 4192 | | } else r: { |
| 4193 | | const local = try f.allocLocal(inst, try lowered_ret_ty.copy(f.arena.allocator())); |
| 4194 | | try f.writeCValue(writer, local, .Other); |
| 4195 | | try writer.writeAll(" = "); |
| 4196 | | break :r local; |
| 4199 | const result_local = result: { |
| 4200 | if (modifier == .always_tail) { |
| 4201 | try writer.writeAll("zig_always_tail return "); |
| 4202 | break :result .none; |
| 4203 | } else if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) { |
| 4204 | break :result .none; |
| 4205 | } else if (f.liveness.isUnused(inst)) { |
| 4206 | try writer.writeByte('('); |
| 4207 | try f.renderType(writer, Type.void); |
| 4208 | try writer.writeByte(')'); |
| 4209 | break :result .none; |
| 4210 | } else { |
| 4211 | const local = try f.allocLocal(inst, try lowered_ret_ty.copy(f.arena.allocator())); |
| 4212 | try f.writeCValue(writer, local, .Other); |
| 4213 | try writer.writeAll(" = "); |
| 4214 | break :result local; |
| 4215 | } |
| 4197 | 4216 | }; |
| 4198 | 4217 | |
| 4199 | 4218 | callee: { |
| ... | ... | @@ -4238,9 +4257,9 @@ fn airCall( |
| 4238 | 4257 | } |
| 4239 | 4258 | try writer.writeAll(");\n"); |
| 4240 | 4259 | |
| 4241 | | const result = r: { |
| 4260 | const result = result: { |
| 4242 | 4261 | if (result_local == .none or !lowersToArray(ret_ty, target)) |
| 4243 | | break :r result_local; |
| 4262 | break :result result_local; |
| 4244 | 4263 | |
| 4245 | 4264 | const array_local = try f.allocLocal(inst, ret_ty); |
| 4246 | 4265 | try writer.writeAll("memcpy("); |
| ... | ... | @@ -4251,7 +4270,7 @@ fn airCall( |
| 4251 | 4270 | try f.renderType(writer, ret_ty); |
| 4252 | 4271 | try writer.writeAll("));\n"); |
| 4253 | 4272 | try freeLocal(f, inst, result_local.new_local, 0); |
| 4254 | | break :r array_local; |
| 4273 | break :result array_local; |
| 4255 | 4274 | }; |
| 4256 | 4275 | |
| 4257 | 4276 | return result; |
| ... | ... | @@ -4468,7 +4487,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4468 | 4487 | { |
| 4469 | 4488 | try f.writeCValue(writer, local, .Other); |
| 4470 | 4489 | try writer.writeAll(" = "); |
| 4471 | | try f.writeCValue(writer, operand, .Other); |
| 4490 | try f.writeCValue(writer, operand, .Initializer); |
| 4472 | 4491 | try writer.writeAll(";\n"); |
| 4473 | 4492 | return local; |
| 4474 | 4493 | } |
| ... | ... | @@ -4835,8 +4854,8 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4835 | 4854 | const inputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.inputs_len]); |
| 4836 | 4855 | extra_i += inputs.len; |
| 4837 | 4856 | |
| 4838 | | const result = r: { |
| 4839 | | if (!is_volatile and f.liveness.isUnused(inst)) break :r .none; |
| 4857 | const result = result: { |
| 4858 | if (!is_volatile and f.liveness.isUnused(inst)) break :result .none; |
| 4840 | 4859 | |
| 4841 | 4860 | const writer = f.object.writer(); |
| 4842 | 4861 | const inst_ty = f.air.typeOfIndex(inst); |
| ... | ... | @@ -5064,7 +5083,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5064 | 5083 | } |
| 5065 | 5084 | } |
| 5066 | 5085 | |
| 5067 | | break :r local; |
| 5086 | break :result if (f.liveness.isUnused(inst)) .none else local; |
| 5068 | 5087 | }; |
| 5069 | 5088 | |
| 5070 | 5089 | var bt = iterateBigTomb(f, inst); |
| ... | ... | @@ -7036,21 +7055,22 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7036 | 7055 | |
| 7037 | 7056 | fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7038 | 7057 | const prefetch = f.air.instructions.items(.data)[inst].prefetch; |
| 7039 | | switch (prefetch.cache) { |
| 7040 | | .data => {}, |
| 7041 | | // The available prefetch intrinsics do not accept a cache argument; only |
| 7042 | | // address, rw, and locality. So unless the cache is data, we do not lower |
| 7043 | | // this instruction. |
| 7044 | | .instruction => return .none, |
| 7045 | | } |
| 7058 | |
| 7046 | 7059 | const ptr = try f.resolveInst(prefetch.ptr); |
| 7047 | 7060 | try reap(f, inst, &.{prefetch.ptr}); |
| 7061 | |
| 7048 | 7062 | const writer = f.object.writer(); |
| 7049 | | try writer.writeAll("zig_prefetch("); |
| 7050 | | try f.writeCValue(writer, ptr, .FunctionArgument); |
| 7051 | | try writer.print(", {d}, {d});\n", .{ |
| 7052 | | @enumToInt(prefetch.rw), prefetch.locality, |
| 7053 | | }); |
| 7063 | switch (prefetch.cache) { |
| 7064 | .data => { |
| 7065 | try writer.writeAll("zig_prefetch("); |
| 7066 | try f.writeCValue(writer, ptr, .FunctionArgument); |
| 7067 | try writer.print(", {d}, {d});\n", .{ @enumToInt(prefetch.rw), prefetch.locality }); |
| 7068 | }, |
| 7069 | // The available prefetch intrinsics do not accept a cache argument; only |
| 7070 | // address, rw, and locality. |
| 7071 | .instruction => {}, |
| 7072 | } |
| 7073 | |
| 7054 | 7074 | return .none; |
| 7055 | 7075 | } |
| 7056 | 7076 | |
| ... | ... | @@ -7830,8 +7850,8 @@ fn reap(f: *Function, inst: Air.Inst.Index, operands: []const Air.Inst.Ref) !voi |
| 7830 | 7850 | |
| 7831 | 7851 | fn die(f: *Function, inst: Air.Inst.Index, ref: Air.Inst.Ref) !void { |
| 7832 | 7852 | const ref_inst = Air.refToIndex(ref) orelse return; |
| 7853 | const c_value = (f.value_map.fetchRemove(ref_inst) orelse return).value; |
| 7833 | 7854 | if (f.air.instructions.items(.tag)[ref_inst] == .constant) return; |
| 7834 | | const c_value = (f.value_map.fetchRemove(ref) orelse return).value; |
| 7835 | 7855 | const local_index = switch (c_value) { |
| 7836 | 7856 | .local, .new_local => |l| l, |
| 7837 | 7857 | else => return, |