authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-23 18:58:47-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-23 18:58:47-04:00
log63b54bcf5173931270724c284696b747c5c6761a
treeab520acbca9f4b33aa42e1b5363c5b8a8b30fb67
parent99ec614b717d2e36d4dc712ac479be1df5ac62b2

codegen for inline assembly


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

src-self-hosted/codegen.zig+212-7
......@@ -4,6 +4,7 @@ const assert = std.debug.assert;
44const ir = @import("ir.zig");
55const Type = @import("type.zig").Type;
66const Value = @import("value.zig").Value;
7const Target = std.Target;
78
89pub const ErrorMsg = struct {
910 byte_offset: usize,
......@@ -69,6 +70,9 @@ const Function = struct {
6970 immediate: u64,
7071 /// The constant was emitted into the code, at this offset.
7172 embedded_in_code: usize,
73 /// The value is in a target-specific register. The value can
74 /// be @intToEnum casted to the respective Reg enum.
75 register: usize,
7276 };
7377
7478 fn genFuncInst(self: *Function, inst: *ir.Inst) !MCValue {
......@@ -108,14 +112,9 @@ const Function = struct {
108112 try self.code.resize(self.code.items.len + 2);
109113 self.code.items[self.code.items.len - 2] = 0xeb;
110114 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));
116115 } else {
117116 try self.code.resize(self.code.items.len + 5);
118 self.code.items[self.code.items.len - 5] = 0xea; // jmp rel32
117 self.code.items[self.code.items.len - 5] = 0xe9; // jmp rel32
119118 const imm_ptr = self.code.items[self.code.items.len - 4 ..][0..4];
120119 mem.writeIntLittle(u32, imm_ptr, amount);
121120 }
......@@ -125,7 +124,104 @@ const Function = struct {
125124 }
126125
127126 fn genAsm(self: *Function, inst: *ir.Inst.Assembly) !MCValue {
128 return self.fail(inst.base.src, "TODO machine code gen assembly", .{});
127 // TODO convert to inline function
128 switch (self.module.target.cpu.arch) {
129 .arm => return self.genAsmArch(.arm, inst),
130 .armeb => return self.genAsmArch(.armeb, inst),
131 .aarch64 => return self.genAsmArch(.aarch64, inst),
132 .aarch64_be => return self.genAsmArch(.aarch64_be, inst),
133 .aarch64_32 => return self.genAsmArch(.aarch64_32, inst),
134 .arc => return self.genAsmArch(.arc, inst),
135 .avr => return self.genAsmArch(.avr, inst),
136 .bpfel => return self.genAsmArch(.bpfel, inst),
137 .bpfeb => return self.genAsmArch(.bpfeb, inst),
138 .hexagon => return self.genAsmArch(.hexagon, inst),
139 .mips => return self.genAsmArch(.mips, inst),
140 .mipsel => return self.genAsmArch(.mipsel, inst),
141 .mips64 => return self.genAsmArch(.mips64, inst),
142 .mips64el => return self.genAsmArch(.mips64el, inst),
143 .msp430 => return self.genAsmArch(.msp430, inst),
144 .powerpc => return self.genAsmArch(.powerpc, inst),
145 .powerpc64 => return self.genAsmArch(.powerpc64, inst),
146 .powerpc64le => return self.genAsmArch(.powerpc64le, inst),
147 .r600 => return self.genAsmArch(.r600, inst),
148 .amdgcn => return self.genAsmArch(.amdgcn, inst),
149 .riscv32 => return self.genAsmArch(.riscv32, inst),
150 .riscv64 => return self.genAsmArch(.riscv64, inst),
151 .sparc => return self.genAsmArch(.sparc, inst),
152 .sparcv9 => return self.genAsmArch(.sparcv9, inst),
153 .sparcel => return self.genAsmArch(.sparcel, inst),
154 .s390x => return self.genAsmArch(.s390x, inst),
155 .tce => return self.genAsmArch(.tce, inst),
156 .tcele => return self.genAsmArch(.tcele, inst),
157 .thumb => return self.genAsmArch(.thumb, inst),
158 .thumbeb => return self.genAsmArch(.thumbeb, inst),
159 .i386 => return self.genAsmArch(.i386, inst),
160 .x86_64 => return self.genAsmArch(.x86_64, inst),
161 .xcore => return self.genAsmArch(.xcore, inst),
162 .nvptx => return self.genAsmArch(.nvptx, inst),
163 .nvptx64 => return self.genAsmArch(.nvptx64, inst),
164 .le32 => return self.genAsmArch(.le32, inst),
165 .le64 => return self.genAsmArch(.le64, inst),
166 .amdil => return self.genAsmArch(.amdil, inst),
167 .amdil64 => return self.genAsmArch(.amdil64, inst),
168 .hsail => return self.genAsmArch(.hsail, inst),
169 .hsail64 => return self.genAsmArch(.hsail64, inst),
170 .spir => return self.genAsmArch(.spir, inst),
171 .spir64 => return self.genAsmArch(.spir64, inst),
172 .kalimba => return self.genAsmArch(.kalimba, inst),
173 .shave => return self.genAsmArch(.shave, inst),
174 .lanai => return self.genAsmArch(.lanai, inst),
175 .wasm32 => return self.genAsmArch(.wasm32, inst),
176 .wasm64 => return self.genAsmArch(.wasm64, inst),
177 .renderscript32 => return self.genAsmArch(.renderscript32, inst),
178 .renderscript64 => return self.genAsmArch(.renderscript64, inst),
179 .ve => return self.genAsmArch(.ve, inst),
180 }
181 }
182
183 fn genAsmArch(self: *Function, comptime arch: Target.Cpu.Arch, inst: *ir.Inst.Assembly) !MCValue {
184 if (arch != .x86_64 and arch != .i386) {
185 return self.fail(inst.base.src, "TODO implement inline asm support for more architectures", .{});
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| {
191 if (input.len < 3 or input[0] != '{' or input[input.len - 1] != '}') {
192 return self.fail(inst.base.src, "unrecognized asm input constraint: '{}'", .{input});
193 }
194 const reg_name = input[1 .. input.len - 1];
195 const reg = parseRegName(arch, reg_name) orelse
196 return self.fail(inst.base.src, "unrecognized register: '{}'", .{reg_name});
197 const arg = try self.resolveInst(inst.args.args[i]);
198 try self.genSetReg(inst.base.src, arch, reg, arg);
199 }
200
201 if (inst.args.output) |output| {
202 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});
204 }
205 const reg_name = output[2 .. output.len - 1];
206 const reg = parseRegName(arch, reg_name) orelse
207 return self.fail(inst.base.src, "unrecognized register: '{}'", .{reg_name});
208 return MCValue{ .register = @enumToInt(reg) };
209 } else {
210 return MCValue.none;
211 }
212 }
213
214 fn genSetReg(self: *Function, src: usize, comptime arch: Target.Cpu.Arch, reg: Reg(arch), mcv: MCValue) !void {
215 switch (arch) {
216 .x86_64 => switch (reg) {
217 .rax => return self.fail(src, "TODO implement genSetReg for x86_64 'rax'", .{}),
218 .rdi => return self.fail(src, "TODO implement genSetReg for x86_64 'rdi'", .{}),
219 .rsi => return self.fail(src, "TODO implement genSetReg for x86_64 'rsi'", .{}),
220 .rdx => return self.fail(src, "TODO implement genSetReg for x86_64 'rdx'", .{}),
221 else => return self.fail(src, "TODO implement genSetReg for x86_64 '{}'", .{@tagName(reg)}),
222 },
223 else => return self.fail(src, "TODO implement genSetReg for more architectures", .{}),
224 }
129225 }
130226
131227 fn genPtrToInt(self: *Function, inst: *ir.Inst.PtrToInt) !MCValue {
......@@ -192,3 +288,112 @@ const Function = struct {
192288 return error.CodegenFail;
193289 }
194290};
291
292fn Reg(comptime arch: Target.Cpu.Arch) type {
293 return switch (arch) {
294 .i386 => enum {
295 eax,
296 ebx,
297 ecx,
298 edx,
299 ebp,
300 esp,
301 esi,
302 edi,
303
304 ax,
305 bx,
306 cx,
307 dx,
308 bp,
309 sp,
310 si,
311 di,
312
313 ah,
314 bh,
315 ch,
316 dh,
317
318 al,
319 bl,
320 cl,
321 dl,
322 },
323 .x86_64 => enum {
324 rax,
325 rbx,
326 rcx,
327 rdx,
328 rbp,
329 rsp,
330 rsi,
331 rdi,
332 r8,
333 r9,
334 r10,
335 r11,
336 r12,
337 r13,
338 r14,
339 r15,
340
341 eax,
342 ebx,
343 ecx,
344 edx,
345 ebp,
346 esp,
347 esi,
348 edi,
349 r8d,
350 r9d,
351 r10d,
352 r11d,
353 r12d,
354 r13d,
355 r14d,
356 r15d,
357
358 ax,
359 bx,
360 cx,
361 dx,
362 bp,
363 sp,
364 si,
365 di,
366 r8w,
367 r9w,
368 r10w,
369 r11w,
370 r12w,
371 r13w,
372 r14w,
373 r15w,
374
375 ah,
376 bh,
377 ch,
378 dh,
379
380 al,
381 bl,
382 cl,
383 dl,
384 r8b,
385 r9b,
386 r10b,
387 r11b,
388 r12b,
389 r13b,
390 r14b,
391 r15b,
392 },
393 else => @compileError("TODO add more register enums"),
394 };
395}
396
397fn parseRegName(comptime arch: Target.Cpu.Arch, name: []const u8) ?Reg(arch) {
398 return std.meta.stringToEnum(Reg(arch), name);
399}