authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2021-05-09 15:20:08+08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-22 21:15:25-04:00
loge8236551abdb7bb74811e5e9dc9890cb2abbd269
treea7cdaddfb3e7b5cd3f760b682e6ded775a68bfc5
parent1c636e2564e2fc2e8e4b6b1edbc782592ee3d2d7

stage2: Move BlockData out of ir.Inst.Block


5 files changed, 62 insertions(+), 63 deletions(-)

src/air.zig-2
......@@ -395,8 +395,6 @@ pub const Inst = struct {
395395
396396 base: Inst,
397397 body: Body,
398 /// This memory is reserved for codegen code to do whatever it needs to here.
399 codegen: codegen.BlockData = .{},
400398
401399 pub fn operandCount(self: *const Block) usize {
402400 return 0;
src/codegen.zig+40-42
......@@ -22,37 +22,6 @@ const RegisterManager = @import("register_manager.zig").RegisterManager;
2222
2323const X8664Encoder = @import("codegen/x86_64.zig").Encoder;
2424
25/// The codegen-related data that is stored in `ir.Inst.Block` instructions.
26pub const BlockData = struct {
27 relocs: std.ArrayListUnmanaged(Reloc) = undefined,
28 /// The first break instruction encounters `null` here and chooses a
29 /// machine code value for the block result, populating this field.
30 /// Following break instructions encounter that value and use it for
31 /// the location to store their block results.
32 mcv: AnyMCValue = undefined,
33};
34
35/// Architecture-independent MCValue. Here, we have a type that is the same size as
36/// the architecture-specific MCValue. Next to the declaration of MCValue is a
37/// comptime assert that makes sure we guessed correctly about the size. This only
38/// exists so that we can bitcast an arch-independent field to and from the real MCValue.
39pub const AnyMCValue = extern struct {
40 a: usize,
41 b: u64,
42};
43
44pub const Reloc = union(enum) {
45 /// The value is an offset into the `Function` `code` from the beginning.
46 /// To perform the reloc, write 32-bit signed little-endian integer
47 /// which is a relative jump, based on the address following the reloc.
48 rel32: usize,
49 /// A branch in the ARM instruction set
50 arm_branch: struct {
51 pos: usize,
52 cond: @import("codegen/arm.zig").Condition,
53 },
54};
55
5625pub const Result = union(enum) {
5726 /// The `code` parameter passed to `generateSymbol` has the value appended.
5827 appended: void,
......@@ -317,6 +286,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
317286 /// across each runtime branch upon joining.
318287 branch_stack: *std.ArrayList(Branch),
319288
289 blocks: std.AutoHashMapUnmanaged(*ir.Inst.Block, BlockData) = .{},
290
320291 register_manager: RegisterManager(Self, Register, &callee_preserved_regs) = .{},
321292 /// Maps offset to what is stored there.
322293 stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
......@@ -415,6 +386,27 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
415386 size: u32,
416387 };
417388
389 const BlockData = struct {
390 relocs: std.ArrayListUnmanaged(Reloc),
391 /// The first break instruction encounters `null` here and chooses a
392 /// machine code value for the block result, populating this field.
393 /// Following break instructions encounter that value and use it for
394 /// the location to store their block results.
395 mcv: MCValue,
396 };
397
398 const Reloc = union(enum) {
399 /// The value is an offset into the `Function` `code` from the beginning.
400 /// To perform the reloc, write 32-bit signed little-endian integer
401 /// which is a relative jump, based on the address following the reloc.
402 rel32: usize,
403 /// A branch in the ARM instruction set
404 arm_branch: struct {
405 pos: usize,
406 cond: @import("codegen/arm.zig").Condition,
407 },
408 };
409
418410 const Self = @This();
419411
420412 fn generateSymbol(
......@@ -463,6 +455,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
463455 .end_di_column = module_fn.rbrace_column,
464456 };
465457 defer function.stack.deinit(bin_file.allocator);
458 defer function.blocks.deinit(bin_file.allocator);
466459 defer function.exitlude_jump_relocs.deinit(bin_file.allocator);
467460
468461 var call_info = function.resolveCallingConventionValues(src_loc.lazy, fn_type) catch |err| switch (err) {
......@@ -3025,7 +3018,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
30253018 }
30263019
30273020 fn genBlock(self: *Self, inst: *ir.Inst.Block) !MCValue {
3028 inst.codegen = .{
3021 try self.blocks.putNoClobber(self.gpa, inst, .{
30293022 // A block is a setup to be able to jump to the end.
30303023 .relocs = .{},
30313024 // It also acts as a receptical for break operands.
......@@ -3033,15 +3026,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
30333026 // break instruction will choose a MCValue for the block result and overwrite
30343027 // this field. Following break instructions will use that MCValue to put their
30353028 // block results.
3036 .mcv = @bitCast(AnyMCValue, MCValue{ .none = {} }),
3037 };
3038 defer inst.codegen.relocs.deinit(self.gpa);
3029 .mcv = MCValue{ .none = {} },
3030 });
3031 const block_data = &self.blocks.getEntry(inst).?.value;
3032 defer block_data.relocs.deinit(self.gpa);
30393033
30403034 try self.genBody(inst.body);
30413035
3042 for (inst.codegen.relocs.items) |reloc| try self.performReloc(inst.base.src, reloc);
3036 for (block_data.relocs.items) |reloc| try self.performReloc(inst.base.src, reloc);
30433037
3044 return @bitCast(MCValue, inst.codegen.mcv);
3038 return @bitCast(MCValue, block_data.mcv);
30453039 }
30463040
30473041 fn genSwitch(self: *Self, inst: *ir.Inst.SwitchBr) !MCValue {
......@@ -3115,11 +3109,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
31153109 }
31163110
31173111 fn br(self: *Self, src: LazySrcLoc, block: *ir.Inst.Block, operand: *ir.Inst) !MCValue {
3112 const block_data = &self.blocks.getEntry(block).?.value;
3113
31183114 if (operand.ty.hasCodeGenBits()) {
31193115 const operand_mcv = try self.resolveInst(operand);
3120 const block_mcv = @bitCast(MCValue, block.codegen.mcv);
3116 const block_mcv = block_data.mcv;
31213117 if (block_mcv == .none) {
3122 block.codegen.mcv = @bitCast(AnyMCValue, operand_mcv);
3118 block_data.mcv = operand_mcv;
31233119 } else {
31243120 try self.setRegOrMem(src, block.base.ty, block_mcv, operand_mcv);
31253121 }
......@@ -3128,8 +3124,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
31283124 }
31293125
31303126 fn brVoid(self: *Self, src: LazySrcLoc, block: *ir.Inst.Block) !MCValue {
3127 const block_data = &self.blocks.getEntry(block).?.value;
3128
31313129 // Emit a jump with a relocation. It will be patched up after the block ends.
3132 try block.codegen.relocs.ensureCapacity(self.gpa, block.codegen.relocs.items.len + 1);
3130 try block_data.relocs.ensureCapacity(self.gpa, block_data.relocs.items.len + 1);
31333131
31343132 switch (arch) {
31353133 .i386, .x86_64 => {
......@@ -3138,11 +3136,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
31383136 try self.code.resize(self.code.items.len + 5);
31393137 self.code.items[self.code.items.len - 5] = 0xe9; // jmp rel32
31403138 // Leave the jump offset undefined
3141 block.codegen.relocs.appendAssumeCapacity(.{ .rel32 = self.code.items.len - 4 });
3139 block_data.relocs.appendAssumeCapacity(.{ .rel32 = self.code.items.len - 4 });
31423140 },
31433141 .arm, .armeb => {
31443142 try self.code.resize(self.code.items.len + 4);
3145 block.codegen.relocs.appendAssumeCapacity(.{
3143 block_data.relocs.appendAssumeCapacity(.{
31463144 .arm_branch = .{
31473145 .pos = self.code.items.len - 4,
31483146 .cond = .al,
src/codegen/c.zig+13-5
......@@ -33,6 +33,11 @@ pub const CValue = union(enum) {
3333 decl_ref: *Decl,
3434};
3535
36const BlockData = struct {
37 block_id: usize,
38 result: CValue,
39};
40
3641pub const CValueMap = std.AutoHashMap(*Inst, CValue);
3742pub const TypedefMap = std.HashMap(Type, struct { name: []const u8, rendered: []u8 }, Type.hash, Type.eql, std.hash_map.default_max_load_percentage);
3843
......@@ -83,6 +88,7 @@ pub const Object = struct {
8388 gpa: *mem.Allocator,
8489 code: std.ArrayList(u8),
8590 value_map: CValueMap,
91 blocks: std.AutoHashMapUnmanaged(*ir.Inst.Block, BlockData) = .{},
8692 next_arg_index: usize = 0,
8793 next_local_index: usize = 0,
8894 next_block_index: usize = 0,
......@@ -939,8 +945,6 @@ fn genBlock(o: *Object, inst: *Inst.Block) !CValue {
939945 o.next_block_index += 1;
940946 const writer = o.writer();
941947
942 // store the block id in relocs.capacity as it is not used for anything else in the C backend.
943 inst.codegen.relocs.capacity = block_id;
944948 const result = if (inst.base.ty.tag() != .void and !inst.base.isUnused()) blk: {
945949 // allocate a location for the result
946950 const local = try o.allocLocal(inst.base.ty, .Mut);
......@@ -948,7 +952,11 @@ fn genBlock(o: *Object, inst: *Inst.Block) !CValue {
948952 break :blk local;
949953 } else CValue{ .none = {} };
950954
951 inst.codegen.mcv = @bitCast(@import("../codegen.zig").AnyMCValue, result);
955 try o.blocks.putNoClobber(o.gpa, inst, .{
956 .block_id = block_id,
957 .result = result,
958 });
959
952960 try genBody(o, inst.body);
953961 try o.indent_writer.insertNewline();
954962 // label must be followed by an expression, add an empty one.
......@@ -957,7 +965,7 @@ fn genBlock(o: *Object, inst: *Inst.Block) !CValue {
957965}
958966
959967fn genBr(o: *Object, inst: *Inst.Br) !CValue {
960 const result = @bitCast(CValue, inst.block.codegen.mcv);
968 const result = o.blocks.get(inst.block).?.result;
961969 const writer = o.writer();
962970
963971 // If result is .none then the value of the block is unused.
......@@ -973,7 +981,7 @@ fn genBr(o: *Object, inst: *Inst.Br) !CValue {
973981}
974982
975983fn genBrVoid(o: *Object, block: *Inst.Block) !CValue {
976 try o.writer().print("goto zig_block_{d};\n", .{block.codegen.relocs.capacity});
984 try o.writer().print("goto zig_block_{d};\n", .{o.blocks.get(block).?.block_id});
977985 return CValue.none;
978986}
979987
src/codegen/wasm.zig+8-14
......@@ -14,7 +14,6 @@ const Inst = ir.Inst;
1414const Type = @import("../type.zig").Type;
1515const Value = @import("../value.zig").Value;
1616const Compilation = @import("../Compilation.zig");
17const AnyMCValue = @import("../codegen.zig").AnyMCValue;
1817const LazySrcLoc = Module.LazySrcLoc;
1918const link = @import("../link.zig");
2019const TypedValue = @import("../TypedValue.zig");
......@@ -29,8 +28,6 @@ const WValue = union(enum) {
2928 constant: *Inst,
3029 /// Offset position in the list of bytecode instructions
3130 code_offset: usize,
32 /// The label of the block, used by breaks to find its relative distance
33 block_idx: u32,
3431 /// Used for variables that create multiple locals on the stack when allocated
3532 /// such as structs and optionals.
3633 multi_value: u32,
......@@ -492,6 +489,8 @@ pub const Context = struct {
492489 gpa: *mem.Allocator,
493490 /// Table to save `WValue`'s generated by an `Inst`
494491 values: ValueTable,
492 /// Mapping from *Inst.Block to block ids
493 blocks: std.AutoArrayHashMapUnmanaged(*Inst.Block, u32) = .{},
495494 /// `bytes` contains the wasm bytecode belonging to the 'code' section.
496495 code: ArrayList(u8),
497496 /// Contains the generated function type bytecode for the current function
......@@ -521,6 +520,7 @@ pub const Context = struct {
521520
522521 pub fn deinit(self: *Context) void {
523522 self.values.deinit(self.gpa);
523 self.blocks.deinit(self.gpa);
524524 self.locals.deinit(self.gpa);
525525 self.* = undefined;
526526 }
......@@ -590,7 +590,6 @@ pub const Context = struct {
590590 fn emitWValue(self: *Context, val: WValue) InnerError!void {
591591 const writer = self.code.writer();
592592 switch (val) {
593 .block_idx => unreachable, // block_idx cannot be referenced
594593 .multi_value => unreachable, // multi_value can never be written directly, and must be accessed individually
595594 .none, .code_offset => {}, // no-op
596595 .local => |idx| {
......@@ -968,13 +967,9 @@ pub const Context = struct {
968967 const block_ty = try self.genBlockType(block.base.src, block.base.ty);
969968
970969 try self.startBlock(.block, block_ty, null);
971 block.codegen = .{
972 // we don't use relocs, so using `relocs` is illegal behaviour.
973 .relocs = undefined,
974 // Here we set the current block idx, so breaks know the depth to jump
975 // to when breaking out.
976 .mcv = @bitCast(AnyMCValue, WValue{ .block_idx = self.block_depth }),
977 };
970 // Here we set the current block idx, so breaks know the depth to jump
971 // to when breaking out.
972 try self.blocks.putNoClobber(self.gpa, block, self.block_depth);
978973 try self.genBody(block.body);
979974 try self.endBlock();
980975
......@@ -1091,10 +1086,9 @@ pub const Context = struct {
10911086 try self.emitWValue(operand);
10921087 }
10931088
1094 // every block contains a `WValue` with its block index.
1089 // We map every block to its block index.
10951090 // We then determine how far we have to jump to it by substracting it from current block depth
1096 const wvalue = @bitCast(WValue, br.block.codegen.mcv);
1097 const idx: u32 = self.block_depth - wvalue.block_idx;
1091 const idx: u32 = self.block_depth - self.blocks.get(br.block).?;
10981092 const writer = self.code.writer();
10991093 try writer.writeByte(wasm.opcode(.br));
11001094 try leb.writeULEB128(writer, idx);
src/link/C.zig+1
......@@ -125,6 +125,7 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
125125 object.indent_writer = .{ .underlying_writer = object.code.writer() };
126126 defer {
127127 object.value_map.deinit();
128 object.blocks.deinit(module.gpa);
128129 object.code.deinit();
129130 object.dg.fwd_decl.deinit();
130131 var it = object.dg.typedefs.iterator();