x86_64: some encodings

This commit is contained in:
David Gonzalez Martin 2023-11-10 12:38:14 -06:00
parent 9dc5f795b2
commit 73769beb32

View File

@ -3765,12 +3765,31 @@ pub const MIR = struct {
const gp_register_encoding: Encoding.GP64 = switch (physical_register) { const gp_register_encoding: Encoding.GP64 = switch (physical_register) {
.rax => .a, .rax => .a,
.rdi => .di, .rdi => .di,
.rsi => .si,
.rdx => .d,
.rcx => .c,
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}; };
return gp_register_encoding; return gp_register_encoding;
} }
fn computeStackSize(stack_objects: []const StackObject) u32 {
var result: u32 = 0;
for (stack_objects) |stack_object| {
result += @intCast(stack_object.size);
result = std.mem.alignForward(u32, result, stack_object.alignment);
}
return result;
}
fn computeStackOffset(stack_objects: []const StackObject) i32 {
const stack_size = computeStackSize(stack_objects);
return -@as(i32, @intCast(stack_size));
}
pub fn encode(mir: *MIR) !*emit.Result { pub fn encode(mir: *MIR) !*emit.Result {
const image = try mir.allocator.create(emit.Result); const image = try mir.allocator.create(emit.Result);
image.* = try emit.Result.create(mir.allocator, mir.target, mir.entry_point); image.* = try emit.Result.create(mir.allocator, mir.target, mir.entry_point);
@ -3790,16 +3809,7 @@ pub const MIR = struct {
function_offsets.putAssumeCapacityNoClobber(function_index, function_offset); function_offsets.putAssumeCapacityNoClobber(function_index, function_offset);
image.sections.items[0].symbol_table.putAssumeCapacityNoClobber(function.name, function_offset); image.sections.items[0].symbol_table.putAssumeCapacityNoClobber(function.name, function_offset);
const stack_size = blk: { const stack_size = std.mem.alignForward(u32, computeStackSize(function.instruction_selection.stack_objects.items), 0x10);
var result: u32 = 0;
for (function.instruction_selection.stack_objects.items) |stack_object| {
assert(std.mem.isAligned(result, stack_object.alignment));
result += @intCast(stack_object.size);
}
break :blk result;
};
if (stack_size != 0) { if (stack_size != 0) {
image.appendCodeByte(0x55); // push rbp image.appendCodeByte(0x55); // push rbp
@ -3859,15 +3869,46 @@ pub const MIR = struct {
switch (memory.addressing_mode.base) { switch (memory.addressing_mode.base) {
.frame_index => |frame_index| { .frame_index => |frame_index| {
const stack_offset = blk: { const stack_offset = computeStackOffset(function.instruction_selection.stack_objects.items[0 .. frame_index + 1]);
var computed_stack_offset: usize = 0; const displacement_bytes: u3 = if (std.math.cast(i8, stack_offset)) |_| @sizeOf(i8) else if (std.math.cast(i32, stack_offset)) |_| @sizeOf(i32) else unreachable;
for (function.instruction_selection.stack_objects.items[0 .. frame_index + 1]) |stack_object| {
assert(std.mem.isAligned(computed_stack_offset, stack_object.alignment));
computed_stack_offset += stack_object.size;
}
break :blk -@as(i64, @intCast(computed_stack_offset)); const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes];
}; image.appendCode(stack_bytes);
},
else => |t| @panic(@tagName(t)),
}
},
.mov64mr => {
assert(instruction.operands.items.len == 2);
const rex = Rex{
.b = false,
.x = false,
.r = false,
.w = true,
};
image.appendCodeByte(@bitCast(rex));
const source_operand = mir.operands.get(instruction.operands.items[1]);
const source_gp64 = getGP64Encoding(source_operand.*);
const destination_operand = mir.operands.get(instruction.operands.items[0]);
assert(destination_operand.u == .memory);
const memory = destination_operand.u.memory;
const instruction_descriptor = instruction_descriptors.get(instruction.id);
const opcode: u8 = @intCast(instruction_descriptor.opcode);
image.appendCodeByte(opcode);
const modrm = ModRm{
.rm = @intFromEnum(Encoding.GP64.bp),
.reg = @intCast(@intFromEnum(source_gp64)),
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true),
};
image.appendCodeByte(@bitCast(modrm));
switch (memory.addressing_mode.base) {
.frame_index => |frame_index| {
const stack_offset = computeStackOffset(function.instruction_selection.stack_objects.items[0 .. frame_index + 1]);
const displacement_bytes: u3 = if (std.math.cast(i8, stack_offset)) |_| @sizeOf(i8) else if (std.math.cast(i32, stack_offset)) |_| @sizeOf(i32) else unreachable; const displacement_bytes: u3 = if (std.math.cast(i8, stack_offset)) |_| @sizeOf(i8) else if (std.math.cast(i32, stack_offset)) |_| @sizeOf(i32) else unreachable;
const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes]; const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes];
@ -3899,15 +3940,7 @@ pub const MIR = struct {
switch (source_memory.addressing_mode.base) { switch (source_memory.addressing_mode.base) {
.frame_index => |frame_index| { .frame_index => |frame_index| {
const stack_offset = blk: { const stack_offset = computeStackOffset(function.instruction_selection.stack_objects.items[0 .. frame_index + 1]);
var computed_stack_offset: usize = 0;
for (function.instruction_selection.stack_objects.items[0 .. frame_index + 1]) |stack_object| {
assert(std.mem.isAligned(computed_stack_offset, stack_object.alignment));
computed_stack_offset += stack_object.size;
}
break :blk -@as(i64, @intCast(computed_stack_offset));
};
const displacement_bytes: u3 = if (std.math.cast(i8, stack_offset)) |_| @sizeOf(i8) else if (std.math.cast(i32, stack_offset)) |_| @sizeOf(i32) else unreachable; const displacement_bytes: u3 = if (std.math.cast(i8, stack_offset)) |_| @sizeOf(i8) else if (std.math.cast(i32, stack_offset)) |_| @sizeOf(i32) else unreachable;
const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes]; const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes];
@ -3916,6 +3949,60 @@ pub const MIR = struct {
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
}, },
.mov64rm => {
assert(instruction.operands.items.len == 2);
const rex = Rex{
.b = false,
.x = false,
.r = false,
.w = true,
};
image.appendCodeByte(@bitCast(rex));
const instruction_descriptor = instruction_descriptors.get(instruction.id);
const opcode: u8 = @intCast(instruction_descriptor.opcode);
image.appendCodeByte(opcode);
const destination_operand = mir.operands.get(instruction.operands.items[0]);
const destination_gp64 = getGP64Encoding(destination_operand.*);
const source_operand = mir.operands.get(instruction.operands.items[1]);
assert(source_operand.u == .memory);
const source_memory = source_operand.u.memory;
const modrm = ModRm{
.rm = @intFromEnum(Encoding.GP64.bp),
.reg = @intCast(@intFromEnum(destination_gp64)),
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true),
};
image.appendCodeByte(@bitCast(modrm));
switch (source_memory.addressing_mode.base) {
.frame_index => |frame_index| {
const stack_offset = computeStackOffset(function.instruction_selection.stack_objects.items[0 .. frame_index + 1]);
const displacement_bytes: u3 = if (std.math.cast(i8, stack_offset)) |_| @sizeOf(i8) else if (std.math.cast(i32, stack_offset)) |_| @sizeOf(i32) else unreachable;
const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes];
image.appendCode(stack_bytes);
},
else => |t| @panic(@tagName(t)),
}
},
.mov32ri => {
assert(instruction.operands.items.len == 2);
const source_operand = mir.operands.get(instruction.operands.items[1]);
const source_immediate: u32 = @intCast(source_operand.u.immediate);
const destination_operand = mir.operands.get(instruction.operands.items[0]);
const destination_gp32 = getGP32Encoding(destination_operand.*);
const opcode = @as(u8, 0xb8) | @as(u3, @intCast(@intFromEnum(destination_gp32)));
image.appendCodeByte(opcode);
image.appendCode(std.mem.asBytes(&source_immediate));
},
.mov32ri64 => { .mov32ri64 => {
assert(instruction.operands.items.len == 2); assert(instruction.operands.items.len == 2);
const source_operand = mir.operands.get(instruction.operands.items[1]); const source_operand = mir.operands.get(instruction.operands.items[1]);
@ -3962,15 +4049,7 @@ pub const MIR = struct {
switch (source_memory.addressing_mode.base) { switch (source_memory.addressing_mode.base) {
.frame_index => |frame_index| { .frame_index => |frame_index| {
const stack_offset = blk: { const stack_offset = computeStackOffset(function.instruction_selection.stack_objects.items[0 .. frame_index + 1]);
var computed_stack_offset: usize = 0;
for (function.instruction_selection.stack_objects.items[0 .. frame_index + 1]) |stack_object| {
assert(std.mem.isAligned(computed_stack_offset, stack_object.alignment));
computed_stack_offset += stack_object.size;
}
break :blk -@as(i64, @intCast(computed_stack_offset));
};
const displacement_bytes: u3 = if (std.math.cast(i8, stack_offset)) |_| @sizeOf(i8) else if (std.math.cast(i32, stack_offset)) |_| @sizeOf(i32) else unreachable; const displacement_bytes: u3 = if (std.math.cast(i8, stack_offset)) |_| @sizeOf(i8) else if (std.math.cast(i32, stack_offset)) |_| @sizeOf(i32) else unreachable;
const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes]; const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes];
@ -4016,9 +4095,6 @@ pub const MIR = struct {
const source_operand = mir.operands.get(instruction.operands.items[1]); const source_operand = mir.operands.get(instruction.operands.items[1]);
assert(destination_operand.id == source_operand.id); assert(destination_operand.id == source_operand.id);
// const destination_physical_register = destination_operand.u.register.index.physical;
// _ = destination_physical_register;
// const source_physical_register = source_operand.u.register.index.physical;
switch (destination_operand.id) { switch (destination_operand.id) {
.gp32 => { .gp32 => {
image.appendCodeByte(0x89); image.appendCodeByte(0x89);
@ -4032,9 +4108,69 @@ pub const MIR = struct {
}; };
image.appendCodeByte(@bitCast(modrm)); image.appendCodeByte(@bitCast(modrm));
}, },
.gp64 => {
const rex = Rex{
.b = false,
.x = false,
.r = false,
.w = true,
};
image.appendCodeByte(@bitCast(rex));
image.appendCodeByte(0x89);
const destination_register = getGP64Encoding(destination_operand.*);
const source_register = getGP64Encoding(source_operand.*);
const modrm = ModRm{
.rm = @intCast(@intFromEnum(destination_register)),
.reg = @intCast(@intFromEnum(source_register)),
.mod = @as(u2, @intFromBool(true)) << 1 | @intFromBool(true),
};
image.appendCodeByte(@bitCast(modrm));
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
}, },
.lea64r => {
assert(instruction.operands.items.len == 2);
const rex = Rex{
.b = false,
.x = false,
.r = false,
.w = true,
};
image.appendCodeByte(@bitCast(rex));
const instruction_descriptor = instruction_descriptors.get(instruction.id);
const opcode: u8 = @intCast(instruction_descriptor.opcode);
image.appendCodeByte(opcode);
const destination_operand = mir.operands.get(instruction.operands.items[0]);
const destination_register = getGP64Encoding(destination_operand.*);
// const source_operand = mir.operands.get(instruction.operands.items[1]);
const modrm = ModRm{
.rm = @intFromEnum(Encoding.GP64.bp),
.reg = @intCast(@intFromEnum(destination_register)),
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(false),
};
image.appendCodeByte(@bitCast(modrm));
const source_operand = mir.operands.get(instruction.operands.items[1]);
switch (source_operand.u) {
.lea64mem => |lea64mem| {
assert(lea64mem.gp64 == null);
assert(lea64mem.scale == 1);
assert(lea64mem.scale_reg == null);
switch (lea64mem.displacement) {
.string_literal => unreachable,
else => unreachable,
}
},
else => |t| @panic(@tagName(t)),
}
unreachable;
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }