| ... | @@ -152,6 +152,7 @@ base_line: u32, | ... | @@ -152,6 +152,7 @@ base_line: u32, |
| 152 | block_label: Id = .none, | 152 | block_label: Id = .none, |
| 153 | next_arg_index: u32 = 0, | 153 | next_arg_index: u32 = 0, |
| 154 | args: std.ArrayList(Id) = .empty, | 154 | args: std.ArrayList(Id) = .empty, |
| | 155 | virtual_allocas: std.AutoHashMapUnmanaged(Id, ?Id) = .empty, |
| 155 | inst_results: std.AutoHashMapUnmanaged(Air.Inst.Index, Id) = .empty, | 156 | inst_results: std.AutoHashMapUnmanaged(Air.Inst.Index, Id) = .empty, |
| 156 | id_scratch: std.ArrayList(Id) = .empty, | 157 | id_scratch: std.ArrayList(Id) = .empty, |
| 157 | prologue: Section = .{}, | 158 | prologue: Section = .{}, |
| ... | @@ -161,6 +162,7 @@ pub fn deinit(cg: *CodeGen) void { | ... | @@ -161,6 +162,7 @@ pub fn deinit(cg: *CodeGen) void { |
| 161 | const gpa = cg.module.gpa; | 162 | const gpa = cg.module.gpa; |
| 162 | cg.control_flow.deinit(gpa); | 163 | cg.control_flow.deinit(gpa); |
| 163 | cg.args.deinit(gpa); | 164 | cg.args.deinit(gpa); |
| | 165 | cg.virtual_allocas.deinit(gpa); |
| 164 | cg.inst_results.deinit(gpa); | 166 | cg.inst_results.deinit(gpa); |
| 165 | cg.id_scratch.deinit(gpa); | 167 | cg.id_scratch.deinit(gpa); |
| 166 | cg.prologue.deinit(gpa); | 168 | cg.prologue.deinit(gpa); |
| ... | @@ -269,23 +271,19 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { | ... | @@ -269,23 +271,19 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { |
| 269 | | 271 | |
| 270 | switch (target.os.tag) { | 272 | switch (target.os.tag) { |
| 271 | .vulkan, .opengl => { | 273 | .vulkan, .opengl => { |
| 272 | if (ty.zigTypeTag(zcu) == .@"struct") { | 274 | switch (storage_class) { |
| 273 | switch (storage_class) { | 275 | .uniform, .push_constant, .storage_buffer, .physical_storage_buffer => { |
| 274 | .uniform, | 276 | if (ty.zigTypeTag(zcu) == .@"struct" and storage_class != .physical_storage_buffer) { |
| 275 | .push_constant, | | |
| 276 | .storage_buffer, | | |
| 277 | => { | | |
| 278 | try cg.module.decorate(ty_id, .block); | 277 | try cg.module.decorate(ty_id, .block); |
| 279 | try cg.decorateBlockOffsets(ty, ty_id); | 278 | } |
| 280 | }, | 279 | try cg.module.decorate(ptr_ty_id, .{ |
| 281 | else => {}, | 280 | .array_stride = .{ .array_stride = @intCast(ty.abiSize(zcu)) }, |
| 282 | } | 281 | }); |
| | 282 | try cg.decorateLayout(ty, ty_id); |
| | 283 | }, |
| | 284 | else => {}, |
| 283 | } | 285 | } |
| 284 | | 286 | |
| 285 | try cg.module.decorate(ptr_ty_id, .{ | | |
| 286 | .array_stride = .{ .array_stride = @intCast(ty.abiSize(zcu)) }, | | |
| 287 | }); | | |
| 288 | | | |
| 289 | if (key.decoration) |decoration| switch (decoration) { | 287 | if (key.decoration) |decoration| switch (decoration) { |
| 290 | .location => |location| { | 288 | .location => |location| { |
| 291 | if (storage_class != .output and storage_class != .input and storage_class != .uniform_constant) { | 289 | if (storage_class != .output and storage_class != .input and storage_class != .uniform_constant) { |
| ... | @@ -378,18 +376,82 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { | ... | @@ -378,18 +376,82 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { |
| 378 | cg.module.declPtr(spv_decl_index).end_dep = cg.module.decl_deps.items.len; | 376 | cg.module.declPtr(spv_decl_index).end_dep = cg.module.decl_deps.items.len; |
| 379 | } | 377 | } |
| 380 | | 378 | |
| 381 | fn decorateBlockOffsets(cg: *CodeGen, ty: Type, ty_id: spec.Id) !void { | 379 | fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void { |
| 382 | const zcu = cg.module.zcu; | 380 | const zcu = cg.module.zcu; |
| 383 | const ip = &zcu.intern_pool; | 381 | const ip = &zcu.intern_pool; |
| 384 | const struct_type = ip.loadStructType(ty.toIntern()); | 382 | switch (ty.zigTypeTag(zcu)) { |
| 385 | var it = struct_type.iterateRuntimeOrder(ip); | 383 | .array => { |
| 386 | var member: u32 = 0; | 384 | const elem_ty = ty.childType(zcu); |
| 387 | while (it.next()) |field_index| { | 385 | if (!elem_ty.hasRuntimeBits(zcu)) return; |
| 388 | const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]); | 386 | try cg.module.decorate(ty_id, .{ |
| 389 | if (!field_ty.hasRuntimeBits(zcu)) continue; | 387 | .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) }, |
| 390 | const offset: u32 = @intCast(ty.structFieldOffset(field_index, zcu)); | 388 | }); |
| 391 | try cg.module.decorateMember(ty_id, member, .{ .offset = .{ .byte_offset = offset } }); | 389 | try cg.decorateLayout(elem_ty, try cg.resolveType(elem_ty, .indirect)); |
| 392 | member += 1; | 390 | }, |
| | 391 | .vector => { |
| | 392 | const elem_ty = ty.childType(zcu); |
| | 393 | try cg.decorateLayout(elem_ty, try cg.resolveType(elem_ty, .indirect)); |
| | 394 | if (cg.isSpvVector(ty)) return; |
| | 395 | try cg.module.decorate(ty_id, .{ |
| | 396 | .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) }, |
| | 397 | }); |
| | 398 | }, |
| | 399 | .@"struct" => switch (ip.indexToKey(ty.toIntern())) { |
| | 400 | .struct_type => { |
| | 401 | const struct_type = ip.loadStructType(ty.toIntern()); |
| | 402 | if (struct_type.layout == .@"packed") return; |
| | 403 | var it = struct_type.iterateRuntimeOrder(ip); |
| | 404 | var member: u32 = 0; |
| | 405 | while (it.next()) |field_index| { |
| | 406 | const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]); |
| | 407 | if (!field_ty.hasRuntimeBits(zcu)) continue; |
| | 408 | const offset: u32 = @intCast(ty.structFieldOffset(field_index, zcu)); |
| | 409 | try cg.module.decorateMember(ty_id, member, .{ .offset = .{ .byte_offset = offset } }); |
| | 410 | try cg.decorateLayout(field_ty, try cg.resolveType(field_ty, .indirect)); |
| | 411 | member += 1; |
| | 412 | } |
| | 413 | }, |
| | 414 | .tuple_type => |tuple| { |
| | 415 | for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, field_val| { |
| | 416 | if (field_val != .none) continue; |
| | 417 | const ft: Type = .fromInterned(field_ty); |
| | 418 | if (ft.hasRuntimeBits(zcu)) try cg.decorateLayout(ft, try cg.resolveType(ft, .indirect)); |
| | 419 | } |
| | 420 | }, |
| | 421 | else => {}, |
| | 422 | }, |
| | 423 | .@"union" => { |
| | 424 | const union_obj = zcu.typeToUnion(ty).?; |
| | 425 | if (union_obj.layout == .@"packed") return; |
| | 426 | const layout = cg.unionLayout(ty); |
| | 427 | if (layout.tag_size != 0) { |
| | 428 | const tag_ty: Type = .fromInterned(union_obj.enum_tag_type); |
| | 429 | try cg.decorateLayout(tag_ty, try cg.resolveType(tag_ty, .indirect)); |
| | 430 | } |
| | 431 | if (layout.has_payload) { |
| | 432 | try cg.decorateLayout(layout.payload_ty, try cg.resolveType(layout.payload_ty, .indirect)); |
| | 433 | } |
| | 434 | const u8_id = try cg.resolveType(.u8, .direct); |
| | 435 | if (layout.payload_padding_size != 0) { |
| | 436 | const len_id = try cg.constInt(.u32, layout.payload_padding_size); |
| | 437 | const arr_id = try cg.module.arrayType(len_id, u8_id); |
| | 438 | try cg.module.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } }); |
| | 439 | } |
| | 440 | if (layout.padding_size != 0) { |
| | 441 | const len_id = try cg.constInt(.u32, layout.padding_size); |
| | 442 | const arr_id = try cg.module.arrayType(len_id, u8_id); |
| | 443 | try cg.module.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } }); |
| | 444 | } |
| | 445 | }, |
| | 446 | .optional => { |
| | 447 | const payload_ty = ty.optionalChild(zcu); |
| | 448 | if (payload_ty.hasRuntimeBits(zcu)) try cg.decorateLayout(payload_ty, try cg.resolveType(payload_ty, .indirect)); |
| | 449 | }, |
| | 450 | .error_union => { |
| | 451 | const payload_ty = ty.errorUnionPayload(zcu); |
| | 452 | if (payload_ty.hasRuntimeBits(zcu)) try cg.decorateLayout(payload_ty, try cg.resolveType(payload_ty, .indirect)); |
| | 453 | }, |
| | 454 | else => {}, |
| 393 | } | 455 | } |
| 394 | } | 456 | } |
| 395 | | 457 | |
| ... | @@ -1408,18 +1470,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { | ... | @@ -1408,18 +1470,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 1408 | return try cg.module.arrayType(len_id, elem_ty_id); | 1470 | return try cg.module.arrayType(len_id, elem_ty_id); |
| 1409 | } else { | 1471 | } else { |
| 1410 | const total_len_id = try cg.constInt(.u32, total_len); | 1472 | const total_len_id = try cg.constInt(.u32, total_len); |
| 1411 | const result_id = try cg.module.arrayType(total_len_id, elem_ty_id); | 1473 | return try cg.module.arrayType(total_len_id, elem_ty_id); |
| 1412 | switch (target.os.tag) { | | |
| 1413 | .vulkan, .opengl => { | | |
| 1414 | try cg.module.decorate(result_id, .{ | | |
| 1415 | .array_stride = .{ | | |
| 1416 | .array_stride = @intCast(elem_ty.abiSize(zcu)), | | |
| 1417 | }, | | |
| 1418 | }); | | |
| 1419 | }, | | |
| 1420 | else => {}, | | |
| 1421 | } | | |
| 1422 | return result_id; | | |
| 1423 | } | 1474 | } |
| 1424 | }, | 1475 | }, |
| 1425 | .vector => { | 1476 | .vector => { |
| ... | @@ -2518,11 +2569,12 @@ fn generateTestEntryPoint( | ... | @@ -2518,11 +2569,12 @@ fn generateTestEntryPoint( |
| 2518 | const spv_err_decl_index = try cg.module.allocDecl(.global); | 2569 | const spv_err_decl_index = try cg.module.allocDecl(.global); |
| 2519 | const err_buf_result_id = cg.module.declPtr(spv_err_decl_index).result_id; | 2570 | const err_buf_result_id = cg.module.declPtr(spv_err_decl_index).result_id; |
| 2520 | | 2571 | |
| 2521 | const buffer_struct_ty_id = try cg.module.structType( | 2572 | const buffer_struct_ty_id = cg.module.allocId(); |
| 2522 | &.{anyerror_ty_id}, | 2573 | try cg.module.sections.globals.emit(gpa, .OpTypeStruct, .{ |
| 2523 | &.{"error_out"}, | 2574 | .id_result = buffer_struct_ty_id, |
| 2524 | .none, | 2575 | .id_ref = &.{anyerror_ty_id}, |
| 2525 | ); | 2576 | }); |
| | 2577 | try cg.module.memberDebugName(buffer_struct_ty_id, 0, "error_out"); |
| 2526 | try cg.module.decorate(buffer_struct_ty_id, .block); | 2578 | try cg.module.decorate(buffer_struct_ty_id, .block); |
| 2527 | try cg.module.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } }); | 2579 | try cg.module.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } }); |
| 2528 | | 2580 | |
| ... | @@ -2794,6 +2846,8 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void { | ... | @@ -2794,6 +2846,8 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void { |
| 2794 | | 2846 | |
| 2795 | .slice_ptr => try cg.airSliceField(inst, 0), | 2847 | .slice_ptr => try cg.airSliceField(inst, 0), |
| 2796 | .slice_len => try cg.airSliceField(inst, 1), | 2848 | .slice_len => try cg.airSliceField(inst, 1), |
| | 2849 | .ptr_slice_ptr_ptr => try cg.airStructFieldPtrIndex(inst, 0), |
| | 2850 | .ptr_slice_len_ptr => try cg.airStructFieldPtrIndex(inst, 1), |
| 2797 | .spirv_runtime_array_len => try cg.airSpirvRuntimeArrayLen(inst), | 2851 | .spirv_runtime_array_len => try cg.airSpirvRuntimeArrayLen(inst), |
| 2798 | .slice_elem_ptr => try cg.airSliceElemPtr(inst), | 2852 | .slice_elem_ptr => try cg.airSliceElemPtr(inst), |
| 2799 | .slice_elem_val => try cg.airSliceElemVal(inst), | 2853 | .slice_elem_val => try cg.airSliceElemVal(inst), |
| ... | @@ -4052,6 +4106,7 @@ fn airBitCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -4052,6 +4106,7 @@ fn airBitCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4052 | return try result.materialize(cg); | 4106 | return try result.materialize(cg); |
| 4053 | } | 4107 | } |
| 4054 | const operand_id = try cg.resolve(ty_op.operand); | 4108 | const operand_id = try cg.resolve(ty_op.operand); |
| | 4109 | if (cg.virtual_allocas.contains(operand_id)) return operand_id; |
| 4055 | return try cg.bitCast(result_ty, operand_ty, operand_id); | 4110 | return try cg.bitCast(result_ty, operand_ty, operand_id); |
| 4056 | } | 4111 | } |
| 4057 | | 4112 | |
| ... | @@ -4881,6 +4936,21 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -4881,6 +4936,21 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4881 | const target = zcu.getTarget(); | 4936 | const target = zcu.getTarget(); |
| 4882 | const ptr_ty = cg.typeOfIndex(inst); | 4937 | const ptr_ty = cg.typeOfIndex(inst); |
| 4883 | const child_ty = ptr_ty.childType(zcu); | 4938 | const child_ty = ptr_ty.childType(zcu); |
| | 4939 | |
| | 4940 | switch (target.os.tag) { |
| | 4941 | .vulkan, .opengl => { |
| | 4942 | if (child_ty.zigTypeTag(zcu) == .pointer and !child_ty.isSlice(zcu)) { |
| | 4943 | const as = child_ty.ptrAddressSpace(zcu); |
| | 4944 | if (cg.module.storageClass(as) == .function) { |
| | 4945 | const result_id = cg.module.allocId(); |
| | 4946 | try cg.virtual_allocas.put(cg.module.gpa, result_id, null); |
| | 4947 | return result_id; |
| | 4948 | } |
| | 4949 | } |
| | 4950 | }, |
| | 4951 | else => {}, |
| | 4952 | } |
| | 4953 | |
| 4884 | const child_ty_id = try cg.resolveType(child_ty, .indirect); | 4954 | const child_ty_id = try cg.resolveType(child_ty, .indirect); |
| 4885 | const ptr_align = ptr_ty.ptrAlignment(zcu); | 4955 | const ptr_align = ptr_ty.ptrAlignment(zcu); |
| 4886 | const result_id = try cg.alloc(child_ty_id, null); | 4956 | const result_id = try cg.alloc(child_ty_id, null); |
| ... | @@ -5355,6 +5425,8 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -5355,6 +5425,8 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 5355 | const operand = try cg.resolve(ty_op.operand); | 5425 | const operand = try cg.resolve(ty_op.operand); |
| 5356 | if (!ptr_ty.isVolatilePtr(zcu) and cg.liveness.isUnused(inst)) return null; | 5426 | if (!ptr_ty.isVolatilePtr(zcu) and cg.liveness.isUnused(inst)) return null; |
| 5357 | | 5427 | |
| | 5428 | if (cg.virtual_allocas.get(operand)) |stored| return stored.?; |
| | 5429 | |
| 5358 | return try cg.load(elem_ty, operand, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) }); | 5430 | return try cg.load(elem_ty, operand, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) }); |
| 5359 | } | 5431 | } |
| 5360 | | 5432 | |
| ... | @@ -5366,6 +5438,11 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void { | ... | @@ -5366,6 +5438,11 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void { |
| 5366 | const ptr = try cg.resolve(bin_op.lhs); | 5438 | const ptr = try cg.resolve(bin_op.lhs); |
| 5367 | const value = try cg.resolve(bin_op.rhs); | 5439 | const value = try cg.resolve(bin_op.rhs); |
| 5368 | | 5440 | |
| | 5441 | if (cg.virtual_allocas.getPtr(ptr)) |slot| { |
| | 5442 | slot.* = value; |
| | 5443 | return; |
| | 5444 | } |
| | 5445 | |
| 5369 | try cg.store(elem_ty, ptr, value, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) }); | 5446 | try cg.store(elem_ty, ptr, value, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) }); |
| 5370 | } | 5447 | } |
| 5371 | | 5448 | |
| ... | @@ -5933,6 +6010,7 @@ fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -5933,6 +6010,7 @@ fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 5933 | fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void { | 6010 | fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void { |
| 5934 | const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; | 6011 | const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 5935 | const target_id = try cg.resolve(pl_op.operand); | 6012 | const target_id = try cg.resolve(pl_op.operand); |
| | 6013 | if (cg.virtual_allocas.contains(target_id)) return; |
| 5936 | const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); | 6014 | const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); |
| 5937 | try cg.module.debugName(target_id, name.toSlice(cg.air)); | 6015 | try cg.module.debugName(target_id, name.toSlice(cg.air)); |
| 5938 | } | 6016 | } |