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 {...@@ -395,8 +395,6 @@ pub const Inst = struct {
395395
396 base: Inst,396 base: Inst,
397 body: Body,397 body: Body,
398 /// This memory is reserved for codegen code to do whatever it needs to here.
399 codegen: codegen.BlockData = .{},
400398
401 pub fn operandCount(self: *const Block) usize {399 pub fn operandCount(self: *const Block) usize {
402 return 0;400 return 0;
src/codegen.zig+40-42
...@@ -22,37 +22,6 @@ const RegisterManager = @import("register_manager.zig").RegisterManager;...@@ -22,37 +22,6 @@ const RegisterManager = @import("register_manager.zig").RegisterManager;
2222
23const X8664Encoder = @import("codegen/x86_64.zig").Encoder;23const 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
56pub const Result = union(enum) {25pub const Result = union(enum) {
57 /// The `code` parameter passed to `generateSymbol` has the value appended.26 /// The `code` parameter passed to `generateSymbol` has the value appended.
58 appended: void,27 appended: void,
...@@ -317,6 +286,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -317,6 +286,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
317 /// across each runtime branch upon joining.286 /// across each runtime branch upon joining.
318 branch_stack: *std.ArrayList(Branch),287 branch_stack: *std.ArrayList(Branch),
319288
289 blocks: std.AutoHashMapUnmanaged(*ir.Inst.Block, BlockData) = .{},
290
320 register_manager: RegisterManager(Self, Register, &callee_preserved_regs) = .{},291 register_manager: RegisterManager(Self, Register, &callee_preserved_regs) = .{},
321 /// Maps offset to what is stored there.292 /// Maps offset to what is stored there.
322 stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},293 stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
...@@ -415,6 +386,27 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -415,6 +386,27 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
415 size: u32,386 size: u32,
416 };387 };
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
418 const Self = @This();410 const Self = @This();
419411
420 fn generateSymbol(412 fn generateSymbol(
...@@ -463,6 +455,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -463,6 +455,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
463 .end_di_column = module_fn.rbrace_column,455 .end_di_column = module_fn.rbrace_column,
464 };456 };
465 defer function.stack.deinit(bin_file.allocator);457 defer function.stack.deinit(bin_file.allocator);
458 defer function.blocks.deinit(bin_file.allocator);
466 defer function.exitlude_jump_relocs.deinit(bin_file.allocator);459 defer function.exitlude_jump_relocs.deinit(bin_file.allocator);
467460
468 var call_info = function.resolveCallingConventionValues(src_loc.lazy, fn_type) catch |err| switch (err) {461 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 {...@@ -3025,7 +3018,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3025 }3018 }
30263019
3027 fn genBlock(self: *Self, inst: *ir.Inst.Block) !MCValue {3020 fn genBlock(self: *Self, inst: *ir.Inst.Block) !MCValue {
3028 inst.codegen = .{3021 try self.blocks.putNoClobber(self.gpa, inst, .{
3029 // A block is a setup to be able to jump to the end.3022 // A block is a setup to be able to jump to the end.
3030 .relocs = .{},3023 .relocs = .{},
3031 // It also acts as a receptical for break operands.3024 // It also acts as a receptical for break operands.
...@@ -3033,15 +3026,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3033,15 +3026,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3033 // break instruction will choose a MCValue for the block result and overwrite3026 // break instruction will choose a MCValue for the block result and overwrite
3034 // this field. Following break instructions will use that MCValue to put their3027 // this field. Following break instructions will use that MCValue to put their
3035 // block results.3028 // block results.
3036 .mcv = @bitCast(AnyMCValue, MCValue{ .none = {} }),3029 .mcv = MCValue{ .none = {} },
3037 };3030 });
3038 defer inst.codegen.relocs.deinit(self.gpa);3031 const block_data = &self.blocks.getEntry(inst).?.value;
3032 defer block_data.relocs.deinit(self.gpa);
30393033
3040 try self.genBody(inst.body);3034 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);
3045 }3039 }
30463040
3047 fn genSwitch(self: *Self, inst: *ir.Inst.SwitchBr) !MCValue {3041 fn genSwitch(self: *Self, inst: *ir.Inst.SwitchBr) !MCValue {
...@@ -3115,11 +3109,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3115,11 +3109,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3115 }3109 }
31163110
3117 fn br(self: *Self, src: LazySrcLoc, block: *ir.Inst.Block, operand: *ir.Inst) !MCValue {3111 fn br(self: *Self, src: LazySrcLoc, block: *ir.Inst.Block, operand: *ir.Inst) !MCValue {
3112 const block_data = &self.blocks.getEntry(block).?.value;
3113
3118 if (operand.ty.hasCodeGenBits()) {3114 if (operand.ty.hasCodeGenBits()) {
3119 const operand_mcv = try self.resolveInst(operand);3115 const operand_mcv = try self.resolveInst(operand);
3120 const block_mcv = @bitCast(MCValue, block.codegen.mcv);3116 const block_mcv = block_data.mcv;
3121 if (block_mcv == .none) {3117 if (block_mcv == .none) {
3122 block.codegen.mcv = @bitCast(AnyMCValue, operand_mcv);3118 block_data.mcv = operand_mcv;
3123 } else {3119 } else {
3124 try self.setRegOrMem(src, block.base.ty, block_mcv, operand_mcv);3120 try self.setRegOrMem(src, block.base.ty, block_mcv, operand_mcv);
3125 }3121 }
...@@ -3128,8 +3124,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3128,8 +3124,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3128 }3124 }
31293125
3130 fn brVoid(self: *Self, src: LazySrcLoc, block: *ir.Inst.Block) !MCValue {3126 fn brVoid(self: *Self, src: LazySrcLoc, block: *ir.Inst.Block) !MCValue {
3127 const block_data = &self.blocks.getEntry(block).?.value;
3128
3131 // Emit a jump with a relocation. It will be patched up after the block ends.3129 // 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
3134 switch (arch) {3132 switch (arch) {
3135 .i386, .x86_64 => {3133 .i386, .x86_64 => {
...@@ -3138,11 +3136,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3138,11 +3136,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3138 try self.code.resize(self.code.items.len + 5);3136 try self.code.resize(self.code.items.len + 5);
3139 self.code.items[self.code.items.len - 5] = 0xe9; // jmp rel323137 self.code.items[self.code.items.len - 5] = 0xe9; // jmp rel32
3140 // Leave the jump offset undefined3138 // 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 });
3142 },3140 },
3143 .arm, .armeb => {3141 .arm, .armeb => {
3144 try self.code.resize(self.code.items.len + 4);3142 try self.code.resize(self.code.items.len + 4);
3145 block.codegen.relocs.appendAssumeCapacity(.{3143 block_data.relocs.appendAssumeCapacity(.{
3146 .arm_branch = .{3144 .arm_branch = .{
3147 .pos = self.code.items.len - 4,3145 .pos = self.code.items.len - 4,
3148 .cond = .al,3146 .cond = .al,
src/codegen/c.zig+13-5
...@@ -33,6 +33,11 @@ pub const CValue = union(enum) {...@@ -33,6 +33,11 @@ pub const CValue = union(enum) {
33 decl_ref: *Decl,33 decl_ref: *Decl,
34};34};
3535
36const BlockData = struct {
37 block_id: usize,
38 result: CValue,
39};
40
36pub const CValueMap = std.AutoHashMap(*Inst, CValue);41pub const CValueMap = std.AutoHashMap(*Inst, CValue);
37pub const TypedefMap = std.HashMap(Type, struct { name: []const u8, rendered: []u8 }, Type.hash, Type.eql, std.hash_map.default_max_load_percentage);42pub 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 {...@@ -83,6 +88,7 @@ pub const Object = struct {
83 gpa: *mem.Allocator,88 gpa: *mem.Allocator,
84 code: std.ArrayList(u8),89 code: std.ArrayList(u8),
85 value_map: CValueMap,90 value_map: CValueMap,
91 blocks: std.AutoHashMapUnmanaged(*ir.Inst.Block, BlockData) = .{},
86 next_arg_index: usize = 0,92 next_arg_index: usize = 0,
87 next_local_index: usize = 0,93 next_local_index: usize = 0,
88 next_block_index: usize = 0,94 next_block_index: usize = 0,
...@@ -939,8 +945,6 @@ fn genBlock(o: *Object, inst: *Inst.Block) !CValue {...@@ -939,8 +945,6 @@ fn genBlock(o: *Object, inst: *Inst.Block) !CValue {
939 o.next_block_index += 1;945 o.next_block_index += 1;
940 const writer = o.writer();946 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;
944 const result = if (inst.base.ty.tag() != .void and !inst.base.isUnused()) blk: {948 const result = if (inst.base.ty.tag() != .void and !inst.base.isUnused()) blk: {
945 // allocate a location for the result949 // allocate a location for the result
946 const local = try o.allocLocal(inst.base.ty, .Mut);950 const local = try o.allocLocal(inst.base.ty, .Mut);
...@@ -948,7 +952,11 @@ fn genBlock(o: *Object, inst: *Inst.Block) !CValue {...@@ -948,7 +952,11 @@ fn genBlock(o: *Object, inst: *Inst.Block) !CValue {
948 break :blk local;952 break :blk local;
949 } else CValue{ .none = {} };953 } 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
952 try genBody(o, inst.body);960 try genBody(o, inst.body);
953 try o.indent_writer.insertNewline();961 try o.indent_writer.insertNewline();
954 // label must be followed by an expression, add an empty one.962 // label must be followed by an expression, add an empty one.
...@@ -957,7 +965,7 @@ fn genBlock(o: *Object, inst: *Inst.Block) !CValue {...@@ -957,7 +965,7 @@ fn genBlock(o: *Object, inst: *Inst.Block) !CValue {
957}965}
958966
959fn genBr(o: *Object, inst: *Inst.Br) !CValue {967fn 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;
961 const writer = o.writer();969 const writer = o.writer();
962970
963 // If result is .none then the value of the block is unused.971 // If result is .none then the value of the block is unused.
...@@ -973,7 +981,7 @@ fn genBr(o: *Object, inst: *Inst.Br) !CValue {...@@ -973,7 +981,7 @@ fn genBr(o: *Object, inst: *Inst.Br) !CValue {
973}981}
974982
975fn genBrVoid(o: *Object, block: *Inst.Block) !CValue {983fn 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});
977 return CValue.none;985 return CValue.none;
978}986}
979987
src/codegen/wasm.zig+8-14
...@@ -14,7 +14,6 @@ const Inst = ir.Inst;...@@ -14,7 +14,6 @@ const Inst = ir.Inst;
14const Type = @import("../type.zig").Type;14const Type = @import("../type.zig").Type;
15const Value = @import("../value.zig").Value;15const Value = @import("../value.zig").Value;
16const Compilation = @import("../Compilation.zig");16const Compilation = @import("../Compilation.zig");
17const AnyMCValue = @import("../codegen.zig").AnyMCValue;
18const LazySrcLoc = Module.LazySrcLoc;17const LazySrcLoc = Module.LazySrcLoc;
19const link = @import("../link.zig");18const link = @import("../link.zig");
20const TypedValue = @import("../TypedValue.zig");19const TypedValue = @import("../TypedValue.zig");
...@@ -29,8 +28,6 @@ const WValue = union(enum) {...@@ -29,8 +28,6 @@ const WValue = union(enum) {
29 constant: *Inst,28 constant: *Inst,
30 /// Offset position in the list of bytecode instructions29 /// Offset position in the list of bytecode instructions
31 code_offset: usize,30 code_offset: usize,
32 /// The label of the block, used by breaks to find its relative distance
33 block_idx: u32,
34 /// Used for variables that create multiple locals on the stack when allocated31 /// Used for variables that create multiple locals on the stack when allocated
35 /// such as structs and optionals.32 /// such as structs and optionals.
36 multi_value: u32,33 multi_value: u32,
...@@ -492,6 +489,8 @@ pub const Context = struct {...@@ -492,6 +489,8 @@ pub const Context = struct {
492 gpa: *mem.Allocator,489 gpa: *mem.Allocator,
493 /// Table to save `WValue`'s generated by an `Inst`490 /// Table to save `WValue`'s generated by an `Inst`
494 values: ValueTable,491 values: ValueTable,
492 /// Mapping from *Inst.Block to block ids
493 blocks: std.AutoArrayHashMapUnmanaged(*Inst.Block, u32) = .{},
495 /// `bytes` contains the wasm bytecode belonging to the 'code' section.494 /// `bytes` contains the wasm bytecode belonging to the 'code' section.
496 code: ArrayList(u8),495 code: ArrayList(u8),
497 /// Contains the generated function type bytecode for the current function496 /// Contains the generated function type bytecode for the current function
...@@ -521,6 +520,7 @@ pub const Context = struct {...@@ -521,6 +520,7 @@ pub const Context = struct {
521520
522 pub fn deinit(self: *Context) void {521 pub fn deinit(self: *Context) void {
523 self.values.deinit(self.gpa);522 self.values.deinit(self.gpa);
523 self.blocks.deinit(self.gpa);
524 self.locals.deinit(self.gpa);524 self.locals.deinit(self.gpa);
525 self.* = undefined;525 self.* = undefined;
526 }526 }
...@@ -590,7 +590,6 @@ pub const Context = struct {...@@ -590,7 +590,6 @@ pub const Context = struct {
590 fn emitWValue(self: *Context, val: WValue) InnerError!void {590 fn emitWValue(self: *Context, val: WValue) InnerError!void {
591 const writer = self.code.writer();591 const writer = self.code.writer();
592 switch (val) {592 switch (val) {
593 .block_idx => unreachable, // block_idx cannot be referenced
594 .multi_value => unreachable, // multi_value can never be written directly, and must be accessed individually593 .multi_value => unreachable, // multi_value can never be written directly, and must be accessed individually
595 .none, .code_offset => {}, // no-op594 .none, .code_offset => {}, // no-op
596 .local => |idx| {595 .local => |idx| {
...@@ -968,13 +967,9 @@ pub const Context = struct {...@@ -968,13 +967,9 @@ pub const Context = struct {
968 const block_ty = try self.genBlockType(block.base.src, block.base.ty);967 const block_ty = try self.genBlockType(block.base.src, block.base.ty);
969968
970 try self.startBlock(.block, block_ty, null);969 try self.startBlock(.block, block_ty, null);
971 block.codegen = .{970 // Here we set the current block idx, so breaks know the depth to jump
972 // we don't use relocs, so using `relocs` is illegal behaviour.971 // to when breaking out.
973 .relocs = undefined,972 try self.blocks.putNoClobber(self.gpa, block, self.block_depth);
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 };
978 try self.genBody(block.body);973 try self.genBody(block.body);
979 try self.endBlock();974 try self.endBlock();
980975
...@@ -1091,10 +1086,9 @@ pub const Context = struct {...@@ -1091,10 +1086,9 @@ pub const Context = struct {
1091 try self.emitWValue(operand);1086 try self.emitWValue(operand);
1092 }1087 }
10931088
1094 // every block contains a `WValue` with its block index.1089 // We map every block to its block index.
1095 // We then determine how far we have to jump to it by substracting it from current block depth1090 // 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);1091 const idx: u32 = self.block_depth - self.blocks.get(br.block).?;
1097 const idx: u32 = self.block_depth - wvalue.block_idx;
1098 const writer = self.code.writer();1092 const writer = self.code.writer();
1099 try writer.writeByte(wasm.opcode(.br));1093 try writer.writeByte(wasm.opcode(.br));
1100 try leb.writeULEB128(writer, idx);1094 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 {...@@ -125,6 +125,7 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
125 object.indent_writer = .{ .underlying_writer = object.code.writer() };125 object.indent_writer = .{ .underlying_writer = object.code.writer() };
126 defer {126 defer {
127 object.value_map.deinit();127 object.value_map.deinit();
128 object.blocks.deinit(module.gpa);
128 object.code.deinit();129 object.code.deinit();
129 object.dg.fwd_decl.deinit();130 object.dg.fwd_decl.deinit();
130 var it = object.dg.typedefs.iterator();131 var it = object.dg.typedefs.iterator();