| ... | @@ -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 | } |
| 200 | | 197 | |
| | 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", .{}), |