authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-23 17:46:01-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-23 17:46:01-04:00
log99ec614b717d2e36d4dc712ac479be1df5ac62b2
tree91e88526534b54a78da900263c3ac008c3f62ffb
parent24a01eed90b60a1e57172ae5a5305bc437bfeaba

codegen for const ints and string literals


1 files changed, 76 insertions(+), 19 deletions(-)

src-self-hosted/codegen.zig+76-19
...@@ -34,7 +34,6 @@ pub fn generateSymbol(typed_value: ir.TypedValue, module: ir.Module, code: *std....@@ -34,7 +34,6 @@ pub fn generateSymbol(typed_value: ir.TypedValue, module: ir.Module, code: *std.
34 .code = code,34 .code = code,
35 .inst_table = std.AutoHashMap(*ir.Inst, Function.MCValue).init(code.allocator),35 .inst_table = std.AutoHashMap(*ir.Inst, Function.MCValue).init(code.allocator),
36 .errors = std.ArrayList(ErrorMsg).init(code.allocator),36 .errors = std.ArrayList(ErrorMsg).init(code.allocator),
37 .constants = std.ArrayList(ir.TypedValue).init(code.allocator),
38 };37 };
39 defer function.inst_table.deinit();38 defer function.inst_table.deinit();
40 defer function.errors.deinit();39 defer function.errors.deinit();
...@@ -49,6 +48,7 @@ pub fn generateSymbol(typed_value: ir.TypedValue, module: ir.Module, code: *std....@@ -49,6 +48,7 @@ pub fn generateSymbol(typed_value: ir.TypedValue, module: ir.Module, code: *std.
49 };48 };
50 try function.inst_table.putNoClobber(inst, new_inst);49 try function.inst_table.putNoClobber(inst, new_inst);
51 }50 }
51
52 return Symbol{ .errors = function.errors.toOwnedSlice() };52 return Symbol{ .errors = function.errors.toOwnedSlice() };
53 },53 },
54 else => @panic("TODO implement generateSymbol for non-function types"),54 else => @panic("TODO implement generateSymbol for non-function types"),
...@@ -60,10 +60,6 @@ const Function = struct {...@@ -60,10 +60,6 @@ const Function = struct {
60 mod_fn: *const ir.Module.Fn,60 mod_fn: *const ir.Module.Fn,
61 code: *std.ArrayList(u8),61 code: *std.ArrayList(u8),
62 inst_table: std.AutoHashMap(*ir.Inst, MCValue),62 inst_table: std.AutoHashMap(*ir.Inst, MCValue),
63 /// Constants are embedded within functions (at the end, after `ret`)
64 /// so that they are independently updateable.
65 /// This is a list of constants that must be appended to the symbol after `ret`.
66 constants: std.ArrayList(ir.TypedValue),
67 errors: std.ArrayList(ErrorMsg),63 errors: std.ArrayList(ErrorMsg),
6864
69 const MCValue = union(enum) {65 const MCValue = union(enum) {
...@@ -71,8 +67,8 @@ const Function = struct {...@@ -71,8 +67,8 @@ const Function = struct {
71 unreach,67 unreach,
72 /// A pointer-sized integer that fits in a register.68 /// A pointer-sized integer that fits in a register.
73 immediate: u64,69 immediate: u64,
74 /// Refers to the index into `constants` field of `Function`.70 /// The constant was emitted into the code, at this offset.
75 local_const_ptr: usize,71 embedded_in_code: usize,
76 };72 };
7773
78 fn genFuncInst(self: *Function, inst: *ir.Inst) !MCValue {74 fn genFuncInst(self: *Function, inst: *ir.Inst) !MCValue {
...@@ -88,13 +84,46 @@ const Function = struct {...@@ -88,13 +84,46 @@ const Function = struct {
88 // TODO change this to call the panic function84 // TODO change this to call the panic function
89 switch (self.module.target.cpu.arch) {85 switch (self.module.target.cpu.arch) {
90 .i386, .x86_64 => {86 .i386, .x86_64 => {
91 try self.code.append(0xcc); // x86 int387 try self.code.append(0xcc); // int3
92 },88 },
93 else => return self.fail(src, "TODO implement panic for {}", .{self.module.target.cpu.arch}),89 else => return self.fail(src, "TODO implement panic for {}", .{self.module.target.cpu.arch}),
94 }90 }
95 return .unreach;91 return .unreach;
96 }92 }
9793
94 fn genRet(self: *Function, src: usize) !void {
95 // TODO change this to call the panic function
96 switch (self.module.target.cpu.arch) {
97 .i386, .x86_64 => {
98 try self.code.append(0xc3); // ret
99 },
100 else => return self.fail(src, "TODO implement ret for {}", .{self.module.target.cpu.arch}),
101 }
102 }
103
104 fn genRelativeFwdJump(self: *Function, src: usize, amount: u32) !void {
105 switch (self.module.target.cpu.arch) {
106 .i386, .x86_64 => {
107 if (amount <= std.math.maxInt(u8)) {
108 try self.code.resize(self.code.items.len + 2);
109 self.code.items[self.code.items.len - 2] = 0xeb;
110 self.code.items[self.code.items.len - 1] = @intCast(u8, amount);
111 } else if (amount <= std.math.maxInt(u16)) {
112 try self.code.resize(self.code.items.len + 3);
113 self.code.items[self.code.items.len - 3] = 0xe9; // jmp rel16
114 const imm_ptr = self.code.items[self.code.items.len - 2 ..][0..2];
115 mem.writeIntLittle(u16, imm_ptr, @intCast(u16, amount));
116 } else {
117 try self.code.resize(self.code.items.len + 5);
118 self.code.items[self.code.items.len - 5] = 0xea; // jmp rel32
119 const imm_ptr = self.code.items[self.code.items.len - 4 ..][0..4];
120 mem.writeIntLittle(u32, imm_ptr, amount);
121 }
122 },
123 else => return self.fail(src, "TODO implement relative forward jump for {}", .{self.module.target.cpu.arch}),
124 }
125 }
126
98 fn genAsm(self: *Function, inst: *ir.Inst.Assembly) !MCValue {127 fn genAsm(self: *Function, inst: *ir.Inst.Assembly) !MCValue {
99 return self.fail(inst.base.src, "TODO machine code gen assembly", .{});128 return self.fail(inst.base.src, "TODO machine code gen assembly", .{});
100 }129 }
...@@ -105,23 +134,51 @@ const Function = struct {...@@ -105,23 +134,51 @@ const Function = struct {
105 }134 }
106135
107 fn resolveInst(self: *Function, inst: *ir.Inst) !MCValue {136 fn resolveInst(self: *Function, inst: *ir.Inst) !MCValue {
137 if (self.inst_table.getValue(inst)) |mcv| {
138 return mcv;
139 }
108 if (inst.cast(ir.Inst.Constant)) |const_inst| {140 if (inst.cast(ir.Inst.Constant)) |const_inst| {
109 switch (inst.ty.zigTypeTag()) {141 const mcvalue = try self.genTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val });
110 .Int => {142 try self.inst_table.putNoClobber(inst, mcvalue);
111 const info = inst.ty.intInfo(self.module.target);143 return mcvalue;
112 const ptr_bits = self.module.target.cpu.arch.ptrBitWidth();
113 if (info.bits > ptr_bits or info.signed) {
114 return self.fail(inst.src, "TODO const int bigger than ptr and signed int", .{});
115 }
116 return MCValue{ .immediate = const_inst.val.toUnsignedInt() };
117 },
118 else => return self.fail(inst.src, "TODO implement const of type '{}'", .{inst.ty}),
119 }
120 } else {144 } else {
121 return self.inst_table.getValue(inst).?;145 return self.inst_table.getValue(inst).?;
122 }146 }
123 }147 }
124148
149 fn genTypedValue(self: *Function, src: usize, typed_value: ir.TypedValue) !MCValue {
150 switch (typed_value.ty.zigTypeTag()) {
151 .Pointer => {
152 const ptr_elem_type = typed_value.ty.elemType();
153 switch (ptr_elem_type.zigTypeTag()) {
154 .Array => {
155 // TODO more checks to make sure this can be emitted as a string literal
156 const bytes = try typed_value.val.toAllocatedBytes(self.code.allocator);
157 defer self.code.allocator.free(bytes);
158 const smaller_len = std.math.cast(u32, bytes.len) catch
159 return self.fail(src, "TODO handle a larger string constant", .{});
160
161 // Emit the string literal directly into the code; jump over it.
162 const offset = self.code.items.len;
163 try self.genRelativeFwdJump(src, smaller_len);
164 try self.code.appendSlice(bytes);
165 return MCValue{ .embedded_in_code = offset };
166 },
167 else => |t| return self.fail(src, "TODO implement emitTypedValue for pointer to '{}'", .{@tagName(t)}),
168 }
169 },
170 .Int => {
171 const info = typed_value.ty.intInfo(self.module.target);
172 const ptr_bits = self.module.target.cpu.arch.ptrBitWidth();
173 if (info.bits > ptr_bits or info.signed) {
174 return self.fail(src, "TODO const int bigger than ptr and signed int", .{});
175 }
176 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
177 },
178 else => return self.fail(src, "TODO implement const of type '{}'", .{typed_value.ty}),
179 }
180 }
181
125 fn fail(self: *Function, src: usize, comptime format: []const u8, args: var) error{ CodegenFail, OutOfMemory } {182 fn fail(self: *Function, src: usize, comptime format: []const u8, args: var) error{ CodegenFail, OutOfMemory } {
126 @setCold(true);183 @setCold(true);
127 const msg = try std.fmt.allocPrint(self.errors.allocator, format, args);184 const msg = try std.fmt.allocPrint(self.errors.allocator, format, args);