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.
3434 .code = code,
3535 .inst_table = std.AutoHashMap(*ir.Inst, Function.MCValue).init(code.allocator),
3636 .errors = std.ArrayList(ErrorMsg).init(code.allocator),
37 .constants = std.ArrayList(ir.TypedValue).init(code.allocator),
3837 };
3938 defer function.inst_table.deinit();
4039 defer function.errors.deinit();
......@@ -49,6 +48,7 @@ pub fn generateSymbol(typed_value: ir.TypedValue, module: ir.Module, code: *std.
4948 };
5049 try function.inst_table.putNoClobber(inst, new_inst);
5150 }
51
5252 return Symbol{ .errors = function.errors.toOwnedSlice() };
5353 },
5454 else => @panic("TODO implement generateSymbol for non-function types"),
......@@ -60,10 +60,6 @@ const Function = struct {
6060 mod_fn: *const ir.Module.Fn,
6161 code: *std.ArrayList(u8),
6262 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),
6763 errors: std.ArrayList(ErrorMsg),
6864
6965 const MCValue = union(enum) {
......@@ -71,8 +67,8 @@ const Function = struct {
7167 unreach,
7268 /// A pointer-sized integer that fits in a register.
7369 immediate: u64,
74 /// Refers to the index into `constants` field of `Function`.
75 local_const_ptr: usize,
70 /// The constant was emitted into the code, at this offset.
71 embedded_in_code: usize,
7672 };
7773
7874 fn genFuncInst(self: *Function, inst: *ir.Inst) !MCValue {
......@@ -88,13 +84,46 @@ const Function = struct {
8884 // TODO change this to call the panic function
8985 switch (self.module.target.cpu.arch) {
9086 .i386, .x86_64 => {
91 try self.code.append(0xcc); // x86 int3
87 try self.code.append(0xcc); // int3
9288 },
9389 else => return self.fail(src, "TODO implement panic for {}", .{self.module.target.cpu.arch}),
9490 }
9591 return .unreach;
9692 }
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
98127 fn genAsm(self: *Function, inst: *ir.Inst.Assembly) !MCValue {
99128 return self.fail(inst.base.src, "TODO machine code gen assembly", .{});
100129 }
......@@ -105,23 +134,51 @@ const Function = struct {
105134 }
106135
107136 fn resolveInst(self: *Function, inst: *ir.Inst) !MCValue {
137 if (self.inst_table.getValue(inst)) |mcv| {
138 return mcv;
139 }
108140 if (inst.cast(ir.Inst.Constant)) |const_inst| {
109 switch (inst.ty.zigTypeTag()) {
110 .Int => {
111 const info = inst.ty.intInfo(self.module.target);
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 }
141 const mcvalue = try self.genTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val });
142 try self.inst_table.putNoClobber(inst, mcvalue);
143 return mcvalue;
120144 } else {
121145 return self.inst_table.getValue(inst).?;
122146 }
123147 }
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
125182 fn fail(self: *Function, src: usize, comptime format: []const u8, args: var) error{ CodegenFail, OutOfMemory } {
126183 @setCold(true);
127184 const msg = try std.fmt.allocPrint(self.errors.allocator, format, args);