| ... | ... | @@ -152,6 +152,7 @@ base_line: u32, |
| 152 | 152 | block_label: Id = .none, |
| 153 | 153 | next_arg_index: u32 = 0, |
| 154 | 154 | args: std.ArrayList(Id) = .empty, |
| 155 | virtual_allocas: std.AutoHashMapUnmanaged(Id, ?Id) = .empty, |
| 155 | 156 | inst_results: std.AutoHashMapUnmanaged(Air.Inst.Index, Id) = .empty, |
| 156 | 157 | id_scratch: std.ArrayList(Id) = .empty, |
| 157 | 158 | prologue: Section = .{}, |
| ... | ... | @@ -161,6 +162,7 @@ pub fn deinit(cg: *CodeGen) void { |
| 161 | 162 | const gpa = cg.module.gpa; |
| 162 | 163 | cg.control_flow.deinit(gpa); |
| 163 | 164 | cg.args.deinit(gpa); |
| 165 | cg.virtual_allocas.deinit(gpa); |
| 164 | 166 | cg.inst_results.deinit(gpa); |
| 165 | 167 | cg.id_scratch.deinit(gpa); |
| 166 | 168 | cg.prologue.deinit(gpa); |
| ... | ... | @@ -269,23 +271,19 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { |
| 269 | 271 | |
| 270 | 272 | switch (target.os.tag) { |
| 271 | 273 | .vulkan, .opengl => { |
| 272 | | if (ty.zigTypeTag(zcu) == .@"struct") { |
| 273 | | switch (storage_class) { |
| 274 | | .uniform, |
| 275 | | .push_constant, |
| 276 | | .storage_buffer, |
| 277 | | => { |
| 274 | switch (storage_class) { |
| 275 | .uniform, .push_constant, .storage_buffer, .physical_storage_buffer => { |
| 276 | if (ty.zigTypeTag(zcu) == .@"struct" and storage_class != .physical_storage_buffer) { |
| 278 | 277 | try cg.module.decorate(ty_id, .block); |
| 279 | | try cg.decorateBlockOffsets(ty, ty_id); |
| 280 | | }, |
| 281 | | else => {}, |
| 282 | | } |
| 278 | } |
| 279 | try cg.module.decorate(ptr_ty_id, .{ |
| 280 | .array_stride = .{ .array_stride = @intCast(ty.abiSize(zcu)) }, |
| 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 | 287 | if (key.decoration) |decoration| switch (decoration) { |
| 290 | 288 | .location => |location| { |
| 291 | 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 | 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 | 380 | const zcu = cg.module.zcu; |
| 383 | 381 | const ip = &zcu.intern_pool; |
| 384 | | const struct_type = ip.loadStructType(ty.toIntern()); |
| 385 | | var it = struct_type.iterateRuntimeOrder(ip); |
| 386 | | var member: u32 = 0; |
| 387 | | while (it.next()) |field_index| { |
| 388 | | const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]); |
| 389 | | if (!field_ty.hasRuntimeBits(zcu)) continue; |
| 390 | | const offset: u32 = @intCast(ty.structFieldOffset(field_index, zcu)); |
| 391 | | try cg.module.decorateMember(ty_id, member, .{ .offset = .{ .byte_offset = offset } }); |
| 392 | | member += 1; |
| 382 | switch (ty.zigTypeTag(zcu)) { |
| 383 | .array => { |
| 384 | const elem_ty = ty.childType(zcu); |
| 385 | if (!elem_ty.hasRuntimeBits(zcu)) return; |
| 386 | try cg.module.decorate(ty_id, .{ |
| 387 | .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) }, |
| 388 | }); |
| 389 | try cg.decorateLayout(elem_ty, try cg.resolveType(elem_ty, .indirect)); |
| 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 | 1470 | return try cg.module.arrayType(len_id, elem_ty_id); |
| 1409 | 1471 | } else { |
| 1410 | 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); |
| 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; |
| 1473 | return try cg.module.arrayType(total_len_id, elem_ty_id); |
| 1423 | 1474 | } |
| 1424 | 1475 | }, |
| 1425 | 1476 | .vector => { |
| ... | ... | @@ -2518,11 +2569,12 @@ fn generateTestEntryPoint( |
| 2518 | 2569 | const spv_err_decl_index = try cg.module.allocDecl(.global); |
| 2519 | 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( |
| 2522 | | &.{anyerror_ty_id}, |
| 2523 | | &.{"error_out"}, |
| 2524 | | .none, |
| 2525 | | ); |
| 2572 | const buffer_struct_ty_id = cg.module.allocId(); |
| 2573 | try cg.module.sections.globals.emit(gpa, .OpTypeStruct, .{ |
| 2574 | .id_result = buffer_struct_ty_id, |
| 2575 | .id_ref = &.{anyerror_ty_id}, |
| 2576 | }); |
| 2577 | try cg.module.memberDebugName(buffer_struct_ty_id, 0, "error_out"); |
| 2526 | 2578 | try cg.module.decorate(buffer_struct_ty_id, .block); |
| 2527 | 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 | 2846 | |
| 2795 | 2847 | .slice_ptr => try cg.airSliceField(inst, 0), |
| 2796 | 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 | 2851 | .spirv_runtime_array_len => try cg.airSpirvRuntimeArrayLen(inst), |
| 2798 | 2852 | .slice_elem_ptr => try cg.airSliceElemPtr(inst), |
| 2799 | 2853 | .slice_elem_val => try cg.airSliceElemVal(inst), |
| ... | ... | @@ -4052,6 +4106,7 @@ fn airBitCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4052 | 4106 | return try result.materialize(cg); |
| 4053 | 4107 | } |
| 4054 | 4108 | const operand_id = try cg.resolve(ty_op.operand); |
| 4109 | if (cg.virtual_allocas.contains(operand_id)) return operand_id; |
| 4055 | 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 | 4936 | const target = zcu.getTarget(); |
| 4882 | 4937 | const ptr_ty = cg.typeOfIndex(inst); |
| 4883 | 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 | 4954 | const child_ty_id = try cg.resolveType(child_ty, .indirect); |
| 4885 | 4955 | const ptr_align = ptr_ty.ptrAlignment(zcu); |
| 4886 | 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 | 5425 | const operand = try cg.resolve(ty_op.operand); |
| 5356 | 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 | 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 | 5438 | const ptr = try cg.resolve(bin_op.lhs); |
| 5367 | 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 | 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 | 6010 | fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void { |
| 5934 | 6011 | const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 5935 | 6012 | const target_id = try cg.resolve(pl_op.operand); |
| 6013 | if (cg.virtual_allocas.contains(target_id)) return; |
| 5936 | 6014 | const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); |
| 5937 | 6015 | try cg.module.debugName(target_id, name.toSlice(cg.air)); |
| 5938 | 6016 | } |