| ... | ... | @@ -225,7 +225,21 @@ pub const DeclGen = struct { |
| 225 | 225 | /// Fetch the result-id for a previously generated instruction or constant. |
| 226 | 226 | fn resolve(self: *DeclGen, inst: Air.Inst.Ref) !IdRef { |
| 227 | 227 | if (self.air.value(inst)) |val| { |
| 228 | | return self.genConstant(self.air.typeOf(inst), val, .direct); |
| 228 | const ty = self.air.typeOf(inst); |
| 229 | if (ty.zigTypeTag() == .Fn) { |
| 230 | const fn_decl_index = switch (val.tag()) { |
| 231 | .extern_fn => val.castTag(.extern_fn).?.data.owner_decl, |
| 232 | .function => val.castTag(.function).?.data.owner_decl, |
| 233 | else => unreachable, |
| 234 | }; |
| 235 | const decl = self.module.declPtr(fn_decl_index); |
| 236 | self.module.markDeclAlive(decl); |
| 237 | return self.ids.get(fn_decl_index).?; |
| 238 | } |
| 239 | |
| 240 | const result_id = self.spv.allocId(); |
| 241 | try self.genConstant(result_id, ty, val, .direct); |
| 242 | return result_id; |
| 229 | 243 | } |
| 230 | 244 | const index = Air.refToIndex(inst).?; |
| 231 | 245 | return self.inst_results.get(index).?; // Assertion means instruction does not dominate usage. |
| ... | ... | @@ -339,7 +353,7 @@ pub const DeclGen = struct { |
| 339 | 353 | }; |
| 340 | 354 | } |
| 341 | 355 | |
| 342 | | fn constInt(self: *DeclGen, ty_ref: SpvType.Ref, value: anytype) !IdRef { |
| 356 | fn genConstInt(self: *DeclGen, ty_ref: SpvType.Ref, result_id: IdRef, value: anytype) !void { |
| 343 | 357 | const ty = self.spv.typeRefType(ty_ref); |
| 344 | 358 | const ty_id = self.typeId(ty_ref); |
| 345 | 359 | |
| ... | ... | @@ -356,51 +370,44 @@ pub const DeclGen = struct { |
| 356 | 370 | }, |
| 357 | 371 | }; |
| 358 | 372 | |
| 359 | | return try self.spv.emitConstant(ty_id, literal); |
| 373 | try self.spv.emitConstant(ty_id, result_id, literal); |
| 374 | } |
| 375 | |
| 376 | fn constInt(self: *DeclGen, ty_ref: SpvType.Ref, value: anytype) !IdRef { |
| 377 | const result_id = self.spv.allocId(); |
| 378 | try self.genConstInt(ty_ref, result_id, value); |
| 379 | return result_id; |
| 360 | 380 | } |
| 361 | 381 | |
| 362 | 382 | /// Generate a constant representing `val`. |
| 363 | 383 | /// TODO: Deduplication? |
| 364 | | fn genConstant(self: *DeclGen, ty: Type, val: Value, repr: Repr) Error!IdRef { |
| 365 | | if (ty.zigTypeTag() == .Fn) { |
| 366 | | const fn_decl_index = switch (val.tag()) { |
| 367 | | .extern_fn => val.castTag(.extern_fn).?.data.owner_decl, |
| 368 | | .function => val.castTag(.function).?.data.owner_decl, |
| 369 | | else => unreachable, |
| 370 | | }; |
| 371 | | const decl = self.module.declPtr(fn_decl_index); |
| 372 | | self.module.markDeclAlive(decl); |
| 373 | | return self.ids.get(fn_decl_index).?; |
| 374 | | } |
| 375 | | |
| 384 | fn genConstant(self: *DeclGen, result_id: IdRef, ty: Type, val: Value, repr: Repr) Error!void { |
| 376 | 385 | const target = self.getTarget(); |
| 377 | 386 | const section = &self.spv.sections.types_globals_constants; |
| 378 | 387 | const result_ty_ref = try self.resolveType(ty, repr); |
| 379 | 388 | const result_ty_id = self.typeId(result_ty_ref); |
| 380 | 389 | |
| 390 | log.debug("genConstant: ty = {}, val = {}", .{ ty.fmtDebug(), val.fmtDebug() }); |
| 391 | |
| 381 | 392 | if (val.isUndef()) { |
| 382 | | const result_id = self.spv.allocId(); |
| 383 | 393 | try section.emit(self.spv.gpa, .OpUndef, .{ .id_result_type = result_ty_id, .id_result = result_id }); |
| 384 | | return result_id; |
| 385 | 394 | } |
| 386 | 395 | |
| 387 | 396 | switch (ty.zigTypeTag()) { |
| 388 | 397 | .Int => { |
| 389 | 398 | const int_bits = if (ty.isSignedInt()) @bitCast(u64, val.toSignedInt(target)) else val.toUnsignedInt(target); |
| 390 | | return self.constInt(result_ty_ref, int_bits); |
| 399 | try self.genConstInt(result_ty_ref, result_id, int_bits); |
| 391 | 400 | }, |
| 392 | 401 | .Bool => switch (repr) { |
| 393 | 402 | .direct => { |
| 394 | | const result_id = self.spv.allocId(); |
| 395 | 403 | const operands = .{ .id_result_type = result_ty_id, .id_result = result_id }; |
| 396 | 404 | if (val.toBool()) { |
| 397 | 405 | try section.emit(self.spv.gpa, .OpConstantTrue, operands); |
| 398 | 406 | } else { |
| 399 | 407 | try section.emit(self.spv.gpa, .OpConstantFalse, operands); |
| 400 | 408 | } |
| 401 | | return result_id; |
| 402 | 409 | }, |
| 403 | | .indirect => return try self.constInt(result_ty_ref, @boolToInt(val.toBool())), |
| 410 | .indirect => try self.genConstInt(result_ty_ref, result_id, @boolToInt(val.toBool())), |
| 404 | 411 | }, |
| 405 | 412 | .Float => { |
| 406 | 413 | // At this point we are guaranteed that the target floating point type is supported, otherwise the function |
| ... | ... | @@ -415,7 +422,7 @@ pub const DeclGen = struct { |
| 415 | 422 | else => unreachable, |
| 416 | 423 | }; |
| 417 | 424 | |
| 418 | | return try self.spv.emitConstant(result_ty_id, literal); |
| 425 | try self.spv.emitConstant(result_ty_id, result_id, literal); |
| 419 | 426 | }, |
| 420 | 427 | .Array => switch (val.tag()) { |
| 421 | 428 | .aggregate => { // todo: combine with Vector |
| ... | ... | @@ -425,15 +432,14 @@ pub const DeclGen = struct { |
| 425 | 432 | const constituents = try self.spv.gpa.alloc(IdRef, len); |
| 426 | 433 | defer self.spv.gpa.free(constituents); |
| 427 | 434 | for (elem_vals[0..len], 0..) |elem_val, i| { |
| 428 | | constituents[i] = try self.genConstant(elem_ty, elem_val, repr); |
| 435 | constituents[i] = self.spv.allocId(); |
| 436 | try self.genConstant(constituents[i], elem_ty, elem_val, repr); |
| 429 | 437 | } |
| 430 | | const result_id = self.spv.allocId(); |
| 431 | 438 | try section.emit(self.spv.gpa, .OpConstantComposite, .{ |
| 432 | 439 | .id_result_type = result_ty_id, |
| 433 | 440 | .id_result = result_id, |
| 434 | 441 | .constituents = constituents, |
| 435 | 442 | }); |
| 436 | | return result_id; |
| 437 | 443 | }, |
| 438 | 444 | .repeated => { |
| 439 | 445 | const elem_val = val.castTag(.repeated).?.data; |
| ... | ... | @@ -442,20 +448,20 @@ pub const DeclGen = struct { |
| 442 | 448 | const constituents = try self.spv.gpa.alloc(IdRef, len); |
| 443 | 449 | defer self.spv.gpa.free(constituents); |
| 444 | 450 | |
| 445 | | const elem_val_id = try self.genConstant(elem_ty, elem_val, repr); |
| 451 | const elem_val_id = self.spv.allocId(); |
| 452 | try self.genConstant(elem_val_id, elem_ty, elem_val, repr); |
| 446 | 453 | for (constituents[0..len]) |*elem| { |
| 447 | 454 | elem.* = elem_val_id; |
| 448 | 455 | } |
| 449 | 456 | if (ty.sentinel()) |sentinel| { |
| 450 | | constituents[len] = try self.genConstant(elem_ty, sentinel, repr); |
| 457 | constituents[len] = self.spv.allocId(); |
| 458 | try self.genConstant(constituents[len], elem_ty, sentinel, repr); |
| 451 | 459 | } |
| 452 | | const result_id = self.spv.allocId(); |
| 453 | 460 | try section.emit(self.spv.gpa, .OpConstantComposite, .{ |
| 454 | 461 | .id_result_type = result_ty_id, |
| 455 | 462 | .id_result = result_id, |
| 456 | 463 | .constituents = constituents, |
| 457 | 464 | }); |
| 458 | | return result_id; |
| 459 | 465 | }, |
| 460 | 466 | else => return self.todo("array constant with tag {s}", .{@tagName(val.tag())}), |
| 461 | 467 | }, |
| ... | ... | @@ -468,22 +474,21 @@ pub const DeclGen = struct { |
| 468 | 474 | const elem_refs = try self.gpa.alloc(IdRef, vector_len); |
| 469 | 475 | defer self.gpa.free(elem_refs); |
| 470 | 476 | for (elem_refs, 0..) |*elem, i| { |
| 471 | | elem.* = try self.genConstant(elem_ty, elem_vals[i], repr); |
| 477 | elem.* = self.spv.allocId(); |
| 478 | try self.genConstant(elem.*, elem_ty, elem_vals[i], repr); |
| 472 | 479 | } |
| 473 | | const result_id = self.spv.allocId(); |
| 474 | 480 | try section.emit(self.spv.gpa, .OpConstantComposite, .{ |
| 475 | 481 | .id_result_type = result_ty_id, |
| 476 | 482 | .id_result = result_id, |
| 477 | 483 | .constituents = elem_refs, |
| 478 | 484 | }); |
| 479 | | return result_id; |
| 480 | 485 | }, |
| 481 | 486 | else => return self.todo("vector constant with tag {s}", .{@tagName(val.tag())}), |
| 482 | 487 | }, |
| 483 | 488 | .Enum => { |
| 484 | 489 | var int_buffer: Value.Payload.U64 = undefined; |
| 485 | 490 | const int_val = val.enumToInt(ty, &int_buffer).toUnsignedInt(target); // TODO: composite integer constants |
| 486 | | return self.constInt(result_ty_ref, int_val); |
| 491 | return self.genConstInt(result_ty_ref, result_id, int_val); |
| 487 | 492 | }, |
| 488 | 493 | .Struct => { |
| 489 | 494 | const constituents = if (ty.isSimpleTupleOrAnonStruct()) blk: { |
| ... | ... | @@ -495,7 +500,9 @@ pub const DeclGen = struct { |
| 495 | 500 | for (tuple.types, 0..) |field_ty, i| { |
| 496 | 501 | const field_val = tuple.values[i]; |
| 497 | 502 | if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits()) continue; |
| 498 | | constituents[member_index] = try self.genConstant(field_ty, field_val, repr); |
| 503 | const member_id = self.spv.allocId(); |
| 504 | try self.genConstant(member_id, field_ty, field_val, repr); |
| 505 | constituents[member_index] = member_id; |
| 499 | 506 | member_index += 1; |
| 500 | 507 | } |
| 501 | 508 | |
| ... | ... | @@ -513,7 +520,9 @@ pub const DeclGen = struct { |
| 513 | 520 | var member_index: usize = 0; |
| 514 | 521 | for (struct_ty.fields.values(), 0..) |field, i| { |
| 515 | 522 | if (field.is_comptime or !field.ty.hasRuntimeBits()) continue; |
| 516 | | constituents[member_index] = try self.genConstant(field.ty, field_vals[i], repr); |
| 523 | const member_id = self.spv.allocId(); |
| 524 | try self.genConstant(member_id, field.ty, field_vals[i], repr); |
| 525 | constituents[member_index] = member_id; |
| 517 | 526 | member_index += 1; |
| 518 | 527 | } |
| 519 | 528 | |
| ... | ... | @@ -521,16 +530,17 @@ pub const DeclGen = struct { |
| 521 | 530 | }; |
| 522 | 531 | defer self.spv.gpa.free(constituents); |
| 523 | 532 | |
| 524 | | const result_id = self.spv.allocId(); |
| 525 | 533 | try section.emit(self.spv.gpa, .OpConstantComposite, .{ |
| 526 | 534 | .id_result_type = result_ty_id, |
| 527 | 535 | .id_result = result_id, |
| 528 | 536 | .constituents = constituents, |
| 529 | 537 | }); |
| 530 | | return result_id; |
| 538 | }, |
| 539 | .Fn => switch (repr) { |
| 540 | .direct => unreachable, |
| 541 | .indirect => return self.todo("function pointers", .{}), |
| 531 | 542 | }, |
| 532 | 543 | .Void => unreachable, |
| 533 | | .Fn => unreachable, |
| 534 | 544 | else => return self.todo("constant generation of type {s}: {}", .{ @tagName(ty.zigTypeTag()), ty.fmtDebug() }), |
| 535 | 545 | } |
| 536 | 546 | } |
| ... | ... | @@ -579,6 +589,7 @@ pub const DeclGen = struct { |
| 579 | 589 | |
| 580 | 590 | /// Turn a Zig type into a SPIR-V Type, and return a reference to it. |
| 581 | 591 | fn resolveType(self: *DeclGen, ty: Type, repr: Repr) Error!SpvType.Ref { |
| 592 | log.debug("resolveType: ty = {}", .{ty.fmtDebug()}); |
| 582 | 593 | const target = self.getTarget(); |
| 583 | 594 | switch (ty.zigTypeTag()) { |
| 584 | 595 | .Void, .NoReturn => return try self.spv.resolveType(SpvType.initTag(.void)), |
| ... | ... | @@ -808,8 +819,7 @@ pub const DeclGen = struct { |
| 808 | 819 | .name = fqn, |
| 809 | 820 | }); |
| 810 | 821 | } else { |
| 811 | | // TODO |
| 812 | | // return self.todo("generate decl type {}", .{decl.ty.zigTypeTag()}); |
| 822 | try self.genConstant(result_id, decl.ty, decl.val, .direct); |
| 813 | 823 | } |
| 814 | 824 | } |
| 815 | 825 | |
| ... | ... | @@ -1417,7 +1427,8 @@ pub const DeclGen = struct { |
| 1417 | 1427 | .Packed => unreachable, // TODO |
| 1418 | 1428 | else => { |
| 1419 | 1429 | const u32_ty_id = self.typeId(try self.intType(.unsigned, 32)); |
| 1420 | | const field_index_id = try self.spv.emitConstant(u32_ty_id, .{ .uint32 = field_index }); |
| 1430 | const field_index_id = self.spv.allocId(); |
| 1431 | try self.spv.emitConstant(u32_ty_id, field_index_id, .{ .uint32 = field_index }); |
| 1421 | 1432 | const result_id = self.spv.allocId(); |
| 1422 | 1433 | const result_type_id = try self.resolveTypeId(result_ptr_ty); |
| 1423 | 1434 | const indexes = [_]IdRef{field_index_id}; |
| ... | ... | @@ -1960,7 +1971,7 @@ pub const DeclGen = struct { |
| 1960 | 1971 | return null; |
| 1961 | 1972 | } |
| 1962 | 1973 | |
| 1963 | | fn airCall(self: *DeclGen, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.Modifier) !?IdRef { |
| 1974 | fn airCall(self: *DeclGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !?IdRef { |
| 1964 | 1975 | _ = modifier; |
| 1965 | 1976 | |
| 1966 | 1977 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |