| ... | @@ -225,7 +225,21 @@ pub const DeclGen = struct { | ... | @@ -225,7 +225,21 @@ pub const DeclGen = struct { |
| 225 | /// Fetch the result-id for a previously generated instruction or constant. | 225 | /// Fetch the result-id for a previously generated instruction or constant. |
| 226 | fn resolve(self: *DeclGen, inst: Air.Inst.Ref) !IdRef { | 226 | fn resolve(self: *DeclGen, inst: Air.Inst.Ref) !IdRef { |
| 227 | if (self.air.value(inst)) |val| { | 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 | const index = Air.refToIndex(inst).?; | 244 | const index = Air.refToIndex(inst).?; |
| 231 | return self.inst_results.get(index).?; // Assertion means instruction does not dominate usage. | 245 | return self.inst_results.get(index).?; // Assertion means instruction does not dominate usage. |
| ... | @@ -339,7 +353,7 @@ pub const DeclGen = struct { | ... | @@ -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 | const ty = self.spv.typeRefType(ty_ref); | 357 | const ty = self.spv.typeRefType(ty_ref); |
| 344 | const ty_id = self.typeId(ty_ref); | 358 | const ty_id = self.typeId(ty_ref); |
| 345 | | 359 | |
| ... | @@ -356,51 +370,44 @@ pub const DeclGen = struct { | ... | @@ -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 | /// Generate a constant representing `val`. | 382 | /// Generate a constant representing `val`. |
| 363 | /// TODO: Deduplication? | 383 | /// TODO: Deduplication? |
| 364 | fn genConstant(self: *DeclGen, ty: Type, val: Value, repr: Repr) Error!IdRef { | 384 | fn genConstant(self: *DeclGen, result_id: IdRef, ty: Type, val: Value, repr: Repr) Error!void { |
| 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 | | | |
| 376 | const target = self.getTarget(); | 385 | const target = self.getTarget(); |
| 377 | const section = &self.spv.sections.types_globals_constants; | 386 | const section = &self.spv.sections.types_globals_constants; |
| 378 | const result_ty_ref = try self.resolveType(ty, repr); | 387 | const result_ty_ref = try self.resolveType(ty, repr); |
| 379 | const result_ty_id = self.typeId(result_ty_ref); | 388 | const result_ty_id = self.typeId(result_ty_ref); |
| 380 | | 389 | |
| | 390 | log.debug("genConstant: ty = {}, val = {}", .{ ty.fmtDebug(), val.fmtDebug() }); |
| | 391 | |
| 381 | if (val.isUndef()) { | 392 | if (val.isUndef()) { |
| 382 | const result_id = self.spv.allocId(); | | |
| 383 | try section.emit(self.spv.gpa, .OpUndef, .{ .id_result_type = result_ty_id, .id_result = result_id }); | 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 | switch (ty.zigTypeTag()) { | 396 | switch (ty.zigTypeTag()) { |
| 388 | .Int => { | 397 | .Int => { |
| 389 | const int_bits = if (ty.isSignedInt()) @bitCast(u64, val.toSignedInt(target)) else val.toUnsignedInt(target); | 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 | .Bool => switch (repr) { | 401 | .Bool => switch (repr) { |
| 393 | .direct => { | 402 | .direct => { |
| 394 | const result_id = self.spv.allocId(); | | |
| 395 | const operands = .{ .id_result_type = result_ty_id, .id_result = result_id }; | 403 | const operands = .{ .id_result_type = result_ty_id, .id_result = result_id }; |
| 396 | if (val.toBool()) { | 404 | if (val.toBool()) { |
| 397 | try section.emit(self.spv.gpa, .OpConstantTrue, operands); | 405 | try section.emit(self.spv.gpa, .OpConstantTrue, operands); |
| 398 | } else { | 406 | } else { |
| 399 | try section.emit(self.spv.gpa, .OpConstantFalse, operands); | 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 | .Float => { | 412 | .Float => { |
| 406 | // At this point we are guaranteed that the target floating point type is supported, otherwise the function | 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,7 +422,7 @@ pub const DeclGen = struct { |
| 415 | else => unreachable, | 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 | .Array => switch (val.tag()) { | 427 | .Array => switch (val.tag()) { |
| 421 | .aggregate => { // todo: combine with Vector | 428 | .aggregate => { // todo: combine with Vector |
| ... | @@ -425,15 +432,14 @@ pub const DeclGen = struct { | ... | @@ -425,15 +432,14 @@ pub const DeclGen = struct { |
| 425 | const constituents = try self.spv.gpa.alloc(IdRef, len); | 432 | const constituents = try self.spv.gpa.alloc(IdRef, len); |
| 426 | defer self.spv.gpa.free(constituents); | 433 | defer self.spv.gpa.free(constituents); |
| 427 | for (elem_vals[0..len], 0..) |elem_val, i| { | 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 | try section.emit(self.spv.gpa, .OpConstantComposite, .{ | 438 | try section.emit(self.spv.gpa, .OpConstantComposite, .{ |
| 432 | .id_result_type = result_ty_id, | 439 | .id_result_type = result_ty_id, |
| 433 | .id_result = result_id, | 440 | .id_result = result_id, |
| 434 | .constituents = constituents, | 441 | .constituents = constituents, |
| 435 | }); | 442 | }); |
| 436 | return result_id; | | |
| 437 | }, | 443 | }, |
| 438 | .repeated => { | 444 | .repeated => { |
| 439 | const elem_val = val.castTag(.repeated).?.data; | 445 | const elem_val = val.castTag(.repeated).?.data; |
| ... | @@ -442,20 +448,20 @@ pub const DeclGen = struct { | ... | @@ -442,20 +448,20 @@ pub const DeclGen = struct { |
| 442 | const constituents = try self.spv.gpa.alloc(IdRef, len); | 448 | const constituents = try self.spv.gpa.alloc(IdRef, len); |
| 443 | defer self.spv.gpa.free(constituents); | 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 | for (constituents[0..len]) |*elem| { | 453 | for (constituents[0..len]) |*elem| { |
| 447 | elem.* = elem_val_id; | 454 | elem.* = elem_val_id; |
| 448 | } | 455 | } |
| 449 | if (ty.sentinel()) |sentinel| { | 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 | try section.emit(self.spv.gpa, .OpConstantComposite, .{ | 460 | try section.emit(self.spv.gpa, .OpConstantComposite, .{ |
| 454 | .id_result_type = result_ty_id, | 461 | .id_result_type = result_ty_id, |
| 455 | .id_result = result_id, | 462 | .id_result = result_id, |
| 456 | .constituents = constituents, | 463 | .constituents = constituents, |
| 457 | }); | 464 | }); |
| 458 | return result_id; | | |
| 459 | }, | 465 | }, |
| 460 | else => return self.todo("array constant with tag {s}", .{@tagName(val.tag())}), | 466 | else => return self.todo("array constant with tag {s}", .{@tagName(val.tag())}), |
| 461 | }, | 467 | }, |
| ... | @@ -468,22 +474,21 @@ pub const DeclGen = struct { | ... | @@ -468,22 +474,21 @@ pub const DeclGen = struct { |
| 468 | const elem_refs = try self.gpa.alloc(IdRef, vector_len); | 474 | const elem_refs = try self.gpa.alloc(IdRef, vector_len); |
| 469 | defer self.gpa.free(elem_refs); | 475 | defer self.gpa.free(elem_refs); |
| 470 | for (elem_refs, 0..) |*elem, i| { | 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 | try section.emit(self.spv.gpa, .OpConstantComposite, .{ | 480 | try section.emit(self.spv.gpa, .OpConstantComposite, .{ |
| 475 | .id_result_type = result_ty_id, | 481 | .id_result_type = result_ty_id, |
| 476 | .id_result = result_id, | 482 | .id_result = result_id, |
| 477 | .constituents = elem_refs, | 483 | .constituents = elem_refs, |
| 478 | }); | 484 | }); |
| 479 | return result_id; | | |
| 480 | }, | 485 | }, |
| 481 | else => return self.todo("vector constant with tag {s}", .{@tagName(val.tag())}), | 486 | else => return self.todo("vector constant with tag {s}", .{@tagName(val.tag())}), |
| 482 | }, | 487 | }, |
| 483 | .Enum => { | 488 | .Enum => { |
| 484 | var int_buffer: Value.Payload.U64 = undefined; | 489 | var int_buffer: Value.Payload.U64 = undefined; |
| 485 | const int_val = val.enumToInt(ty, &int_buffer).toUnsignedInt(target); // TODO: composite integer constants | 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 | .Struct => { | 493 | .Struct => { |
| 489 | const constituents = if (ty.isSimpleTupleOrAnonStruct()) blk: { | 494 | const constituents = if (ty.isSimpleTupleOrAnonStruct()) blk: { |
| ... | @@ -495,7 +500,9 @@ pub const DeclGen = struct { | ... | @@ -495,7 +500,9 @@ pub const DeclGen = struct { |
| 495 | for (tuple.types, 0..) |field_ty, i| { | 500 | for (tuple.types, 0..) |field_ty, i| { |
| 496 | const field_val = tuple.values[i]; | 501 | const field_val = tuple.values[i]; |
| 497 | if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits()) continue; | 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 | member_index += 1; | 506 | member_index += 1; |
| 500 | } | 507 | } |
| 501 | | 508 | |
| ... | @@ -513,7 +520,9 @@ pub const DeclGen = struct { | ... | @@ -513,7 +520,9 @@ pub const DeclGen = struct { |
| 513 | var member_index: usize = 0; | 520 | var member_index: usize = 0; |
| 514 | for (struct_ty.fields.values(), 0..) |field, i| { | 521 | for (struct_ty.fields.values(), 0..) |field, i| { |
| 515 | if (field.is_comptime or !field.ty.hasRuntimeBits()) continue; | 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 | member_index += 1; | 526 | member_index += 1; |
| 518 | } | 527 | } |
| 519 | | 528 | |
| ... | @@ -521,16 +530,17 @@ pub const DeclGen = struct { | ... | @@ -521,16 +530,17 @@ pub const DeclGen = struct { |
| 521 | }; | 530 | }; |
| 522 | defer self.spv.gpa.free(constituents); | 531 | defer self.spv.gpa.free(constituents); |
| 523 | | 532 | |
| 524 | const result_id = self.spv.allocId(); | | |
| 525 | try section.emit(self.spv.gpa, .OpConstantComposite, .{ | 533 | try section.emit(self.spv.gpa, .OpConstantComposite, .{ |
| 526 | .id_result_type = result_ty_id, | 534 | .id_result_type = result_ty_id, |
| 527 | .id_result = result_id, | 535 | .id_result = result_id, |
| 528 | .constituents = constituents, | 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 | .Void => unreachable, | 543 | .Void => unreachable, |
| 533 | .Fn => unreachable, | | |
| 534 | else => return self.todo("constant generation of type {s}: {}", .{ @tagName(ty.zigTypeTag()), ty.fmtDebug() }), | 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,6 +589,7 @@ pub const DeclGen = struct { |
| 579 | | 589 | |
| 580 | /// Turn a Zig type into a SPIR-V Type, and return a reference to it. | 590 | /// Turn a Zig type into a SPIR-V Type, and return a reference to it. |
| 581 | fn resolveType(self: *DeclGen, ty: Type, repr: Repr) Error!SpvType.Ref { | 591 | fn resolveType(self: *DeclGen, ty: Type, repr: Repr) Error!SpvType.Ref { |
| | 592 | log.debug("resolveType: ty = {}", .{ty.fmtDebug()}); |
| 582 | const target = self.getTarget(); | 593 | const target = self.getTarget(); |
| 583 | switch (ty.zigTypeTag()) { | 594 | switch (ty.zigTypeTag()) { |
| 584 | .Void, .NoReturn => return try self.spv.resolveType(SpvType.initTag(.void)), | 595 | .Void, .NoReturn => return try self.spv.resolveType(SpvType.initTag(.void)), |
| ... | @@ -808,8 +819,7 @@ pub const DeclGen = struct { | ... | @@ -808,8 +819,7 @@ pub const DeclGen = struct { |
| 808 | .name = fqn, | 819 | .name = fqn, |
| 809 | }); | 820 | }); |
| 810 | } else { | 821 | } else { |
| 811 | // TODO | 822 | try self.genConstant(result_id, decl.ty, decl.val, .direct); |
| 812 | // return self.todo("generate decl type {}", .{decl.ty.zigTypeTag()}); | | |
| 813 | } | 823 | } |
| 814 | } | 824 | } |
| 815 | | 825 | |
| ... | @@ -1417,7 +1427,8 @@ pub const DeclGen = struct { | ... | @@ -1417,7 +1427,8 @@ pub const DeclGen = struct { |
| 1417 | .Packed => unreachable, // TODO | 1427 | .Packed => unreachable, // TODO |
| 1418 | else => { | 1428 | else => { |
| 1419 | const u32_ty_id = self.typeId(try self.intType(.unsigned, 32)); | 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 | const result_id = self.spv.allocId(); | 1432 | const result_id = self.spv.allocId(); |
| 1422 | const result_type_id = try self.resolveTypeId(result_ptr_ty); | 1433 | const result_type_id = try self.resolveTypeId(result_ptr_ty); |
| 1423 | const indexes = [_]IdRef{field_index_id}; | 1434 | const indexes = [_]IdRef{field_index_id}; |
| ... | @@ -1960,7 +1971,7 @@ pub const DeclGen = struct { | ... | @@ -1960,7 +1971,7 @@ pub const DeclGen = struct { |
| 1960 | return null; | 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 | _ = modifier; | 1975 | _ = modifier; |
| 1965 | | 1976 | |
| 1966 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 1977 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |