| ... | @@ -4,6 +4,7 @@ const assert = std.debug.assert; | ... | @@ -4,6 +4,7 @@ const assert = std.debug.assert; |
| 4 | const ir = @import("ir.zig"); | 4 | const ir = @import("ir.zig"); |
| 5 | const Type = @import("type.zig").Type; | 5 | const Type = @import("type.zig").Type; |
| 6 | const Value = @import("value.zig").Value; | 6 | const Value = @import("value.zig").Value; |
| | 7 | const Target = std.Target; |
| 7 | | 8 | |
| 8 | pub const ErrorMsg = struct { | 9 | pub const ErrorMsg = struct { |
| 9 | byte_offset: usize, | 10 | byte_offset: usize, |
| ... | @@ -69,6 +70,9 @@ const Function = struct { | ... | @@ -69,6 +70,9 @@ const Function = struct { |
| 69 | immediate: u64, | 70 | immediate: u64, |
| 70 | /// The constant was emitted into the code, at this offset. | 71 | /// The constant was emitted into the code, at this offset. |
| 71 | embedded_in_code: usize, | 72 | 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, |
| 72 | }; | 76 | }; |
| 73 | | 77 | |
| 74 | fn genFuncInst(self: *Function, inst: *ir.Inst) !MCValue { | 78 | fn genFuncInst(self: *Function, inst: *ir.Inst) !MCValue { |
| ... | @@ -108,14 +112,9 @@ const Function = struct { | ... | @@ -108,14 +112,9 @@ const Function = struct { |
| 108 | try self.code.resize(self.code.items.len + 2); | 112 | try self.code.resize(self.code.items.len + 2); |
| 109 | self.code.items[self.code.items.len - 2] = 0xeb; | 113 | self.code.items[self.code.items.len - 2] = 0xeb; |
| 110 | self.code.items[self.code.items.len - 1] = @intCast(u8, amount); | 114 | 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 { | 115 | } else { |
| 117 | try self.code.resize(self.code.items.len + 5); | 116 | 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 |
| 119 | const imm_ptr = self.code.items[self.code.items.len - 4 ..][0..4]; | 118 | const imm_ptr = self.code.items[self.code.items.len - 4 ..][0..4]; |
| 120 | mem.writeIntLittle(u32, imm_ptr, amount); | 119 | mem.writeIntLittle(u32, imm_ptr, amount); |
| 121 | } | 120 | } |
| ... | @@ -125,7 +124,104 @@ const Function = struct { | ... | @@ -125,7 +124,104 @@ const Function = struct { |
| 125 | } | 124 | } |
| 126 | | 125 | |
| 127 | fn genAsm(self: *Function, inst: *ir.Inst.Assembly) !MCValue { | 126 | 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 | } |
| 129 | } | 225 | } |
| 130 | | 226 | |
| 131 | fn genPtrToInt(self: *Function, inst: *ir.Inst.PtrToInt) !MCValue { | 227 | fn genPtrToInt(self: *Function, inst: *ir.Inst.PtrToInt) !MCValue { |
| ... | @@ -192,3 +288,112 @@ const Function = struct { | ... | @@ -192,3 +288,112 @@ const Function = struct { |
| 192 | return error.CodegenFail; | 288 | return error.CodegenFail; |
| 193 | } | 289 | } |
| 194 | }; | 290 | }; |
| | 291 | |
| | 292 | fn 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 | |
| | 397 | fn parseRegName(comptime arch: Target.Cpu.Arch, name: []const u8) ?Reg(arch) { |
| | 398 | return std.meta.stringToEnum(Reg(arch), name); |
| | 399 | } |