| ... | ... | @@ -20,7 +20,21 @@ const leb128 = std.debug.leb; |
| 20 | 20 | |
| 21 | 21 | /// The codegen-related data that is stored in `ir.Inst.Block` instructions. |
| 22 | 22 | pub const BlockData = struct { |
| 23 | | relocs: std.ArrayListUnmanaged(Reloc) = .{}, |
| 23 | relocs: std.ArrayListUnmanaged(Reloc) = undefined, |
| 24 | /// The first break instruction encounters `null` here and chooses a |
| 25 | /// machine code value for the block result, populating this field. |
| 26 | /// Following break instructions encounter that value and use it for |
| 27 | /// the location to store their block results. |
| 28 | mcv: AnyMCValue = undefined, |
| 29 | }; |
| 30 | |
| 31 | /// Architecture-independent MCValue. Here, we have a type that is the same size as |
| 32 | /// the architecture-specific MCValue. Next to the declaration of MCValue is a |
| 33 | /// comptime assert that makes sure we guessed correctly about the size. This only |
| 34 | /// exists so that we can bitcast an arch-independent field to and from the real MCValue. |
| 35 | pub const AnyMCValue = extern struct { |
| 36 | a: u64, |
| 37 | b: u64, |
| 24 | 38 | }; |
| 25 | 39 | |
| 26 | 40 | pub const Reloc = union(enum) { |
| ... | ... | @@ -1387,16 +1401,23 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1387 | 1401 | } |
| 1388 | 1402 | |
| 1389 | 1403 | fn genBlock(self: *Self, inst: *ir.Inst.Block) !MCValue { |
| 1390 | | if (inst.base.ty.hasCodeGenBits()) { |
| 1391 | | return self.fail(inst.base.src, "TODO codegen Block with non-void type", .{}); |
| 1392 | | } |
| 1393 | | // A block is a setup to be able to jump to the end. |
| 1404 | inst.codegen = .{ |
| 1405 | // A block is a setup to be able to jump to the end. |
| 1406 | .relocs = .{}, |
| 1407 | // It also acts as a receptical for break operands. |
| 1408 | // Here we use `MCValue.none` to represent a null value so that the first |
| 1409 | // break instruction will choose a MCValue for the block result and overwrite |
| 1410 | // this field. Following break instructions will use that MCValue to put their |
| 1411 | // block results. |
| 1412 | .mcv = @bitCast(AnyMCValue, MCValue { .none = {} }), |
| 1413 | }; |
| 1394 | 1414 | defer inst.codegen.relocs.deinit(self.gpa); |
| 1415 | |
| 1395 | 1416 | try self.genBody(inst.body); |
| 1396 | 1417 | |
| 1397 | 1418 | for (inst.codegen.relocs.items) |reloc| try self.performReloc(inst.base.src, reloc); |
| 1398 | 1419 | |
| 1399 | | return MCValue.none; |
| 1420 | return @bitCast(MCValue, inst.codegen.mcv); |
| 1400 | 1421 | } |
| 1401 | 1422 | |
| 1402 | 1423 | fn performReloc(self: *Self, src: usize, reloc: Reloc) !void { |
| ... | ... | @@ -1416,13 +1437,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1416 | 1437 | } |
| 1417 | 1438 | |
| 1418 | 1439 | fn genBr(self: *Self, inst: *ir.Inst.Br) !MCValue { |
| 1419 | | if (!inst.operand.ty.hasCodeGenBits()) |
| 1420 | | return self.brVoid(inst.base.src, inst.block); |
| 1421 | | |
| 1422 | | const operand = try self.resolveInst(inst.operand); |
| 1423 | | switch (arch) { |
| 1424 | | else => return self.fail(inst.base.src, "TODO implement br for {}", .{self.target.cpu.arch}), |
| 1440 | if (inst.operand.ty.hasCodeGenBits()) { |
| 1441 | const operand = try self.resolveInst(inst.operand); |
| 1442 | const block_mcv = @bitCast(MCValue, inst.block.codegen.mcv); |
| 1443 | if (block_mcv == .none) { |
| 1444 | inst.block.codegen.mcv = @bitCast(AnyMCValue, operand); |
| 1445 | } else { |
| 1446 | try self.setRegOrMem(inst.base.src, inst.block.base.ty, block_mcv, operand); |
| 1447 | } |
| 1425 | 1448 | } |
| 1449 | return self.brVoid(inst.base.src, inst.block); |
| 1426 | 1450 | } |
| 1427 | 1451 | |
| 1428 | 1452 | fn genBrVoid(self: *Self, inst: *ir.Inst.BrVoid) !MCValue { |