codegen for inline assembly
This commit is contained in:
parent
99ec614b71
commit
63b54bcf51
@ -4,6 +4,7 @@ const assert = std.debug.assert;
|
||||
const ir = @import("ir.zig");
|
||||
const Type = @import("type.zig").Type;
|
||||
const Value = @import("value.zig").Value;
|
||||
const Target = std.Target;
|
||||
|
||||
pub const ErrorMsg = struct {
|
||||
byte_offset: usize,
|
||||
@ -69,6 +70,9 @@ const Function = struct {
|
||||
immediate: u64,
|
||||
/// The constant was emitted into the code, at this offset.
|
||||
embedded_in_code: usize,
|
||||
/// The value is in a target-specific register. The value can
|
||||
/// be @intToEnum casted to the respective Reg enum.
|
||||
register: usize,
|
||||
};
|
||||
|
||||
fn genFuncInst(self: *Function, inst: *ir.Inst) !MCValue {
|
||||
@ -108,14 +112,9 @@ const Function = struct {
|
||||
try self.code.resize(self.code.items.len + 2);
|
||||
self.code.items[self.code.items.len - 2] = 0xeb;
|
||||
self.code.items[self.code.items.len - 1] = @intCast(u8, amount);
|
||||
} else if (amount <= std.math.maxInt(u16)) {
|
||||
try self.code.resize(self.code.items.len + 3);
|
||||
self.code.items[self.code.items.len - 3] = 0xe9; // jmp rel16
|
||||
const imm_ptr = self.code.items[self.code.items.len - 2 ..][0..2];
|
||||
mem.writeIntLittle(u16, imm_ptr, @intCast(u16, amount));
|
||||
} else {
|
||||
try self.code.resize(self.code.items.len + 5);
|
||||
self.code.items[self.code.items.len - 5] = 0xea; // jmp rel32
|
||||
self.code.items[self.code.items.len - 5] = 0xe9; // jmp rel32
|
||||
const imm_ptr = self.code.items[self.code.items.len - 4 ..][0..4];
|
||||
mem.writeIntLittle(u32, imm_ptr, amount);
|
||||
}
|
||||
@ -125,7 +124,104 @@ const Function = struct {
|
||||
}
|
||||
|
||||
fn genAsm(self: *Function, inst: *ir.Inst.Assembly) !MCValue {
|
||||
return self.fail(inst.base.src, "TODO machine code gen assembly", .{});
|
||||
// TODO convert to inline function
|
||||
switch (self.module.target.cpu.arch) {
|
||||
.arm => return self.genAsmArch(.arm, inst),
|
||||
.armeb => return self.genAsmArch(.armeb, inst),
|
||||
.aarch64 => return self.genAsmArch(.aarch64, inst),
|
||||
.aarch64_be => return self.genAsmArch(.aarch64_be, inst),
|
||||
.aarch64_32 => return self.genAsmArch(.aarch64_32, inst),
|
||||
.arc => return self.genAsmArch(.arc, inst),
|
||||
.avr => return self.genAsmArch(.avr, inst),
|
||||
.bpfel => return self.genAsmArch(.bpfel, inst),
|
||||
.bpfeb => return self.genAsmArch(.bpfeb, inst),
|
||||
.hexagon => return self.genAsmArch(.hexagon, inst),
|
||||
.mips => return self.genAsmArch(.mips, inst),
|
||||
.mipsel => return self.genAsmArch(.mipsel, inst),
|
||||
.mips64 => return self.genAsmArch(.mips64, inst),
|
||||
.mips64el => return self.genAsmArch(.mips64el, inst),
|
||||
.msp430 => return self.genAsmArch(.msp430, inst),
|
||||
.powerpc => return self.genAsmArch(.powerpc, inst),
|
||||
.powerpc64 => return self.genAsmArch(.powerpc64, inst),
|
||||
.powerpc64le => return self.genAsmArch(.powerpc64le, inst),
|
||||
.r600 => return self.genAsmArch(.r600, inst),
|
||||
.amdgcn => return self.genAsmArch(.amdgcn, inst),
|
||||
.riscv32 => return self.genAsmArch(.riscv32, inst),
|
||||
.riscv64 => return self.genAsmArch(.riscv64, inst),
|
||||
.sparc => return self.genAsmArch(.sparc, inst),
|
||||
.sparcv9 => return self.genAsmArch(.sparcv9, inst),
|
||||
.sparcel => return self.genAsmArch(.sparcel, inst),
|
||||
.s390x => return self.genAsmArch(.s390x, inst),
|
||||
.tce => return self.genAsmArch(.tce, inst),
|
||||
.tcele => return self.genAsmArch(.tcele, inst),
|
||||
.thumb => return self.genAsmArch(.thumb, inst),
|
||||
.thumbeb => return self.genAsmArch(.thumbeb, inst),
|
||||
.i386 => return self.genAsmArch(.i386, inst),
|
||||
.x86_64 => return self.genAsmArch(.x86_64, inst),
|
||||
.xcore => return self.genAsmArch(.xcore, inst),
|
||||
.nvptx => return self.genAsmArch(.nvptx, inst),
|
||||
.nvptx64 => return self.genAsmArch(.nvptx64, inst),
|
||||
.le32 => return self.genAsmArch(.le32, inst),
|
||||
.le64 => return self.genAsmArch(.le64, inst),
|
||||
.amdil => return self.genAsmArch(.amdil, inst),
|
||||
.amdil64 => return self.genAsmArch(.amdil64, inst),
|
||||
.hsail => return self.genAsmArch(.hsail, inst),
|
||||
.hsail64 => return self.genAsmArch(.hsail64, inst),
|
||||
.spir => return self.genAsmArch(.spir, inst),
|
||||
.spir64 => return self.genAsmArch(.spir64, inst),
|
||||
.kalimba => return self.genAsmArch(.kalimba, inst),
|
||||
.shave => return self.genAsmArch(.shave, inst),
|
||||
.lanai => return self.genAsmArch(.lanai, inst),
|
||||
.wasm32 => return self.genAsmArch(.wasm32, inst),
|
||||
.wasm64 => return self.genAsmArch(.wasm64, inst),
|
||||
.renderscript32 => return self.genAsmArch(.renderscript32, inst),
|
||||
.renderscript64 => return self.genAsmArch(.renderscript64, inst),
|
||||
.ve => return self.genAsmArch(.ve, inst),
|
||||
}
|
||||
}
|
||||
|
||||
fn genAsmArch(self: *Function, comptime arch: Target.Cpu.Arch, inst: *ir.Inst.Assembly) !MCValue {
|
||||
if (arch != .x86_64 and arch != .i386) {
|
||||
return self.fail(inst.base.src, "TODO implement inline asm support for more architectures", .{});
|
||||
}
|
||||
if (!mem.eql(u8, inst.args.asm_source, "syscall")) {
|
||||
return self.fail(inst.base.src, "TODO implement support for more x86 assembly instructions", .{});
|
||||
}
|
||||
for (inst.args.inputs) |input, i| {
|
||||
if (input.len < 3 or input[0] != '{' or input[input.len - 1] != '}') {
|
||||
return self.fail(inst.base.src, "unrecognized asm input constraint: '{}'", .{input});
|
||||
}
|
||||
const reg_name = input[1 .. input.len - 1];
|
||||
const reg = parseRegName(arch, reg_name) orelse
|
||||
return self.fail(inst.base.src, "unrecognized register: '{}'", .{reg_name});
|
||||
const arg = try self.resolveInst(inst.args.args[i]);
|
||||
try self.genSetReg(inst.base.src, arch, reg, arg);
|
||||
}
|
||||
|
||||
if (inst.args.output) |output| {
|
||||
if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') {
|
||||
return self.fail(inst.base.src, "unrecognized asm output constraint: '{}'", .{output});
|
||||
}
|
||||
const reg_name = output[2 .. output.len - 1];
|
||||
const reg = parseRegName(arch, reg_name) orelse
|
||||
return self.fail(inst.base.src, "unrecognized register: '{}'", .{reg_name});
|
||||
return MCValue{ .register = @enumToInt(reg) };
|
||||
} else {
|
||||
return MCValue.none;
|
||||
}
|
||||
}
|
||||
|
||||
fn genSetReg(self: *Function, src: usize, comptime arch: Target.Cpu.Arch, reg: Reg(arch), mcv: MCValue) !void {
|
||||
switch (arch) {
|
||||
.x86_64 => switch (reg) {
|
||||
.rax => return self.fail(src, "TODO implement genSetReg for x86_64 'rax'", .{}),
|
||||
.rdi => return self.fail(src, "TODO implement genSetReg for x86_64 'rdi'", .{}),
|
||||
.rsi => return self.fail(src, "TODO implement genSetReg for x86_64 'rsi'", .{}),
|
||||
.rdx => return self.fail(src, "TODO implement genSetReg for x86_64 'rdx'", .{}),
|
||||
else => return self.fail(src, "TODO implement genSetReg for x86_64 '{}'", .{@tagName(reg)}),
|
||||
},
|
||||
else => return self.fail(src, "TODO implement genSetReg for more architectures", .{}),
|
||||
}
|
||||
}
|
||||
|
||||
fn genPtrToInt(self: *Function, inst: *ir.Inst.PtrToInt) !MCValue {
|
||||
@ -192,3 +288,112 @@ const Function = struct {
|
||||
return error.CodegenFail;
|
||||
}
|
||||
};
|
||||
|
||||
fn Reg(comptime arch: Target.Cpu.Arch) type {
|
||||
return switch (arch) {
|
||||
.i386 => enum {
|
||||
eax,
|
||||
ebx,
|
||||
ecx,
|
||||
edx,
|
||||
ebp,
|
||||
esp,
|
||||
esi,
|
||||
edi,
|
||||
|
||||
ax,
|
||||
bx,
|
||||
cx,
|
||||
dx,
|
||||
bp,
|
||||
sp,
|
||||
si,
|
||||
di,
|
||||
|
||||
ah,
|
||||
bh,
|
||||
ch,
|
||||
dh,
|
||||
|
||||
al,
|
||||
bl,
|
||||
cl,
|
||||
dl,
|
||||
},
|
||||
.x86_64 => enum {
|
||||
rax,
|
||||
rbx,
|
||||
rcx,
|
||||
rdx,
|
||||
rbp,
|
||||
rsp,
|
||||
rsi,
|
||||
rdi,
|
||||
r8,
|
||||
r9,
|
||||
r10,
|
||||
r11,
|
||||
r12,
|
||||
r13,
|
||||
r14,
|
||||
r15,
|
||||
|
||||
eax,
|
||||
ebx,
|
||||
ecx,
|
||||
edx,
|
||||
ebp,
|
||||
esp,
|
||||
esi,
|
||||
edi,
|
||||
r8d,
|
||||
r9d,
|
||||
r10d,
|
||||
r11d,
|
||||
r12d,
|
||||
r13d,
|
||||
r14d,
|
||||
r15d,
|
||||
|
||||
ax,
|
||||
bx,
|
||||
cx,
|
||||
dx,
|
||||
bp,
|
||||
sp,
|
||||
si,
|
||||
di,
|
||||
r8w,
|
||||
r9w,
|
||||
r10w,
|
||||
r11w,
|
||||
r12w,
|
||||
r13w,
|
||||
r14w,
|
||||
r15w,
|
||||
|
||||
ah,
|
||||
bh,
|
||||
ch,
|
||||
dh,
|
||||
|
||||
al,
|
||||
bl,
|
||||
cl,
|
||||
dl,
|
||||
r8b,
|
||||
r9b,
|
||||
r10b,
|
||||
r11b,
|
||||
r12b,
|
||||
r13b,
|
||||
r14b,
|
||||
r15b,
|
||||
},
|
||||
else => @compileError("TODO add more register enums"),
|
||||
};
|
||||
}
|
||||
|
||||
fn parseRegName(comptime arch: Target.Cpu.Arch, name: []const u8) ?Reg(arch) {
|
||||
return std.meta.stringToEnum(Reg(arch), name);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user