authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-23 19:40:17-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-23 19:40:17-04:00
log0ac502f37257c607fc835840d02f0401c5e59442
treec97370a4c01bc7116984fb450c31c20f31993bfb
parent63b54bcf5173931270724c284696b747c5c6761a

codegen for setting rax and rdi registers


1 files changed, 80 insertions(+), 7 deletions(-)

src-self-hosted/codegen.zig+80-7
...@@ -184,9 +184,6 @@ const Function = struct {...@@ -184,9 +184,6 @@ const Function = struct {
184 if (arch != .x86_64 and arch != .i386) {184 if (arch != .x86_64 and arch != .i386) {
185 return self.fail(inst.base.src, "TODO implement inline asm support for more architectures", .{});185 return self.fail(inst.base.src, "TODO implement inline asm support for more architectures", .{});
186 }186 }
187 if (!mem.eql(u8, inst.args.asm_source, "syscall")) {
188 return self.fail(inst.base.src, "TODO implement support for more x86 assembly instructions", .{});
189 }
190 for (inst.args.inputs) |input, i| {187 for (inst.args.inputs) |input, i| {
191 if (input.len < 3 or input[0] != '{' or input[input.len - 1] != '}') {188 if (input.len < 3 or input[0] != '{' or input[input.len - 1] != '}') {
192 return self.fail(inst.base.src, "unrecognized asm input constraint: '{}'", .{input});189 return self.fail(inst.base.src, "unrecognized asm input constraint: '{}'", .{input});
...@@ -198,6 +195,12 @@ const Function = struct {...@@ -198,6 +195,12 @@ const Function = struct {
198 try self.genSetReg(inst.base.src, arch, reg, arg);195 try self.genSetReg(inst.base.src, arch, reg, arg);
199 }196 }
200197
198 if (mem.eql(u8, inst.args.asm_source, "syscall")) {
199 try self.code.appendSlice(&[_]u8{ 0x0f, 0x05 });
200 } else {
201 return self.fail(inst.base.src, "TODO implement support for more x86 assembly instructions", .{});
202 }
203
201 if (inst.args.output) |output| {204 if (inst.args.output) |output| {
202 if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') {205 if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') {
203 return self.fail(inst.base.src, "unrecognized asm output constraint: '{}'", .{output});206 return self.fail(inst.base.src, "unrecognized asm output constraint: '{}'", .{output});
...@@ -214,10 +217,80 @@ const Function = struct {...@@ -214,10 +217,80 @@ const Function = struct {
214 fn genSetReg(self: *Function, src: usize, comptime arch: Target.Cpu.Arch, reg: Reg(arch), mcv: MCValue) !void {217 fn genSetReg(self: *Function, src: usize, comptime arch: Target.Cpu.Arch, reg: Reg(arch), mcv: MCValue) !void {
215 switch (arch) {218 switch (arch) {
216 .x86_64 => switch (reg) {219 .x86_64 => switch (reg) {
217 .rax => return self.fail(src, "TODO implement genSetReg for x86_64 'rax'", .{}),220 .rax => switch (mcv) {
218 .rdi => return self.fail(src, "TODO implement genSetReg for x86_64 'rdi'", .{}),221 .none, .unreach => unreachable,
219 .rsi => return self.fail(src, "TODO implement genSetReg for x86_64 'rsi'", .{}),222 .immediate => |x| {
220 .rdx => return self.fail(src, "TODO implement genSetReg for x86_64 'rdx'", .{}),223 // Setting the eax register zeroes the upper part of rax, so if the number is small
224 // enough, that is preferable.
225 // Best case: zero
226 // 31 c0 xor eax,eax
227 if (x == 0) {
228 return self.code.appendSlice(&[_]u8{ 0x31, 0xc0 });
229 }
230 // Next best case: set eax with 4 bytes
231 // b8 04 03 02 01 mov eax,0x01020304
232 if (x <= std.math.maxInt(u32)) {
233 try self.code.resize(self.code.items.len + 5);
234 self.code.items[self.code.items.len - 5] = 0xb8;
235 const imm_ptr = self.code.items[self.code.items.len - 4 ..][0..4];
236 mem.writeIntLittle(u32, imm_ptr, @intCast(u32, x));
237 return;
238 }
239 // Worst case: set rax with 8 bytes
240 // 48 b8 08 07 06 05 04 03 02 01 movabs rax,0x0102030405060708
241 try self.code.resize(self.code.items.len + 10);
242 self.code.items[self.code.items.len - 10] = 0x48;
243 self.code.items[self.code.items.len - 9] = 0xb8;
244 const imm_ptr = self.code.items[self.code.items.len - 8 ..][0..8];
245 mem.writeIntLittle(u64, imm_ptr, x);
246 return;
247 },
248 .embedded_in_code => return self.fail(src, "TODO implement x86_64 genSetReg %rax = embedded_in_code", .{}),
249 .register => return self.fail(src, "TODO implement x86_64 genSetReg %rax = register", .{}),
250 },
251 .rdi => switch (mcv) {
252 .none, .unreach => unreachable,
253 .immediate => |x| {
254 // Setting the edi register zeroes the upper part of rdi, so if the number is small
255 // enough, that is preferable.
256 // Best case: zero
257 // 31 ff xor edi,edi
258 if (x == 0) {
259 return self.code.appendSlice(&[_]u8{ 0x31, 0xff });
260 }
261 // Next best case: set edi with 4 bytes
262 // bf 04 03 02 01 mov edi,0x1020304
263 if (x <= std.math.maxInt(u32)) {
264 try self.code.resize(self.code.items.len + 5);
265 self.code.items[self.code.items.len - 5] = 0xbf;
266 const imm_ptr = self.code.items[self.code.items.len - 4 ..][0..4];
267 mem.writeIntLittle(u32, imm_ptr, @intCast(u32, x));
268 return;
269 }
270 // Worst case: set rdi with 8 bytes
271 // 48 bf 08 07 06 05 04 03 02 01 movabs rax,0x0102030405060708
272 try self.code.resize(self.code.items.len + 10);
273 self.code.items[self.code.items.len - 10] = 0x48;
274 self.code.items[self.code.items.len - 9] = 0xbf;
275 const imm_ptr = self.code.items[self.code.items.len - 8 ..][0..8];
276 mem.writeIntLittle(u64, imm_ptr, x);
277 return;
278 },
279 .embedded_in_code => return self.fail(src, "TODO implement x86_64 genSetReg %rdi = embedded_in_code", .{}),
280 .register => return self.fail(src, "TODO implement x86_64 genSetReg %rdi = register", .{}),
281 },
282 .rsi => switch (mcv) {
283 .none, .unreach => unreachable,
284 .immediate => return self.fail(src, "TODO implement x86_64 genSetReg %rsi = immediate", .{}),
285 .embedded_in_code => return self.fail(src, "TODO implement x86_64 genSetReg %rsi = embedded_in_code", .{}),
286 .register => return self.fail(src, "TODO implement x86_64 genSetReg %rsi = register", .{}),
287 },
288 .rdx => switch (mcv) {
289 .none, .unreach => unreachable,
290 .immediate => return self.fail(src, "TODO implement x86_64 genSetReg %rdx = immediate", .{}),
291 .embedded_in_code => return self.fail(src, "TODO implement x86_64 genSetReg %rdx = embedded_in_code", .{}),
292 .register => return self.fail(src, "TODO implement x86_64 genSetReg %rdx = register", .{}),
293 },
221 else => return self.fail(src, "TODO implement genSetReg for x86_64 '{}'", .{@tagName(reg)}),294 else => return self.fail(src, "TODO implement genSetReg for x86_64 '{}'", .{@tagName(reg)}),
222 },295 },
223 else => return self.fail(src, "TODO implement genSetReg for more architectures", .{}),296 else => return self.fail(src, "TODO implement genSetReg for more architectures", .{}),