Commit c5ec096b2f
Changed files (2)
src
codegen
src/codegen/aarch64.zig
@@ -200,17 +200,6 @@ test "FloatingPointRegister.toX" {
/// Represents an instruction in the AArch64 instruction set
pub const Instruction = union(enum) {
- OrShiftedRegister: packed struct {
- rd: u5,
- rn: u5,
- imm6: u6,
- rm: u5,
- n: u1,
- shift: u2,
- fixed: u5 = 0b01010,
- opc: u2 = 0b01,
- sf: u1,
- },
MoveWideImmediate: packed struct {
rd: u5,
imm16: u16,
@@ -274,10 +263,37 @@ pub const Instruction = union(enum) {
NoOperation: packed struct {
fixed: u32 = 0b1101010100_0_00_011_0010_0000_000_11111,
},
+ LogicalShiftedRegister: packed struct {
+ rd: u5,
+ rn: u5,
+ imm6: u6,
+ rm: u5,
+ n: u1,
+ shift: u2,
+ fixed: u5 = 0b01010,
+ opc: u2,
+ sf: u1,
+ },
+
+ pub const Shift = struct {
+ shift: Type = .lsl,
+ amount: u6 = 0,
+
+ pub const Type = enum(u2) {
+ lsl,
+ lsr,
+ asr,
+ ror,
+ };
+
+ pub const none = Shift{
+ .shift = .lsl,
+ .amount = 0,
+ };
+ };
pub fn toU32(self: Instruction) u32 {
return switch (self) {
- .OrShiftedRegister => |v| @bitCast(u32, v),
.MoveWideImmediate => |v| @bitCast(u32, v),
.PCRelativeAddress => |v| @bitCast(u32, v),
.LoadStoreRegister => |v| @bitCast(u32, v),
@@ -287,68 +303,10 @@ pub const Instruction = union(enum) {
.UnconditionalBranchRegister => |v| @bitCast(u32, v),
.UnconditionalBranchImmediate => |v| @bitCast(u32, v),
.NoOperation => |v| @bitCast(u32, v),
+ .LogicalShiftedRegister => |v| @bitCast(u32, v),
};
}
- pub const RegisterShift = struct {
- rn: u5,
- imm6: u6,
- shift: enum(u2) {
- Lsl = 0,
- Lsr = 1,
- Asr = 2,
- Ror = 3,
- },
-
- pub fn none() RegisterShift {
- return .{
- .rn = 0b11111,
- .imm6 = 0,
- .shift = .Lsl,
- };
- }
- };
-
- // Helper functions for assembly syntax functions
-
- fn orShiftedRegister(
- rd: Register,
- rm: Register,
- shift: RegisterShift,
- invert: bool,
- ) Instruction {
- const n: u1 = if (invert) 1 else 0;
- switch (rd.size()) {
- 32 => {
- return Instruction{
- .OrShiftedRegister = .{
- .rd = rd.id(),
- .rn = shift.rn,
- .imm6 = shift.imm6,
- .rm = rm.id(),
- .n = n,
- .shift = @enumToInt(shift.shift),
- .sf = 0,
- },
- };
- },
- 64 => {
- return Instruction{
- .OrShiftedRegister = .{
- .rd = rd.id(),
- .rn = shift.rn,
- .imm6 = shift.imm6,
- .rm = rm.id(),
- .n = n,
- .shift = @enumToInt(shift.shift),
- .sf = 1,
- },
- };
- },
- else => unreachable, // unexpected register size
- }
- }
-
fn moveWideImmediate(
opc: u2,
rd: Register,
@@ -671,15 +629,49 @@ pub const Instruction = union(enum) {
};
}
- // Bitwise (inclusive) OR of a register value
-
- pub fn orr(rd: Register, rm: Register, shift: RegisterShift) Instruction {
- return orShiftedRegister(rd, rm, shift, false);
+ fn logicalShiftedRegister(
+ opc: u2,
+ n: u1,
+ shift: Shift,
+ rd: Register,
+ rn: Register,
+ rm: Register,
+ ) Instruction {
+ switch (rd.size()) {
+ 32 => {
+ assert(shift.amount < 32);
+ return Instruction{
+ .LogicalShiftedRegister = .{
+ .rd = rd.id(),
+ .rn = rn.id(),
+ .imm6 = shift.amount,
+ .rm = rm.id(),
+ .n = n,
+ .shift = @enumToInt(shift.shift),
+ .opc = opc,
+ .sf = 0b0,
+ },
+ };
+ },
+ 64 => {
+ return Instruction{
+ .LogicalShiftedRegister = .{
+ .rd = rd.id(),
+ .rn = rn.id(),
+ .imm6 = shift.amount,
+ .rm = rm.id(),
+ .n = n,
+ .shift = @enumToInt(shift.shift),
+ .opc = opc,
+ .sf = 0b1,
+ },
+ };
+ },
+ else => unreachable, // unexpected register size
+ }
}
- pub fn orn(rd: Register, rm: Register, shift: RegisterShift) Instruction {
- return orShiftedRegister(rd, rm, shift, true);
- }
+ // Helper functions for assembly syntax functions
// Move wide (immediate)
@@ -823,6 +815,40 @@ pub const Instruction = union(enum) {
pub fn nop() Instruction {
return Instruction{ .NoOperation = {} };
}
+
+ // Logical (shifted register)
+
+ pub fn @"and"(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
+ return logicalShiftedRegister(0b00, 0b0, shift, rd, rn, rm);
+ }
+
+ pub fn bic(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
+ return logicalShiftedRegister(0b00, 0b1, shift, rd, rn, rm);
+ }
+
+ pub fn orr(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
+ return logicalShiftedRegister(0b01, 0b0, shift, rd, rn, rm);
+ }
+
+ pub fn orn(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
+ return logicalShiftedRegister(0b01, 0b1, shift, rd, rn, rm);
+ }
+
+ pub fn eor(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
+ return logicalShiftedRegister(0b10, 0b0, shift, rd, rn, rm);
+ }
+
+ pub fn eon(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
+ return logicalShiftedRegister(0b10, 0b1, shift, rd, rn, rm);
+ }
+
+ pub fn ands(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
+ return logicalShiftedRegister(0b11, 0b0, shift, rd, rn, rm);
+ }
+
+ pub fn bics(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
+ return logicalShiftedRegister(0b11, 0b1, shift, rd, rn, rm);
+ }
};
test "" {
@@ -836,15 +862,15 @@ test "serialize instructions" {
};
const testcases = [_]Testcase{
- .{ // orr x0 x1
- .inst = Instruction.orr(.x0, .x1, Instruction.RegisterShift.none()),
+ .{ // orr x0, xzr, x1
+ .inst = Instruction.orr(.x0, .xzr, .x1, Instruction.Shift.none),
.expected = 0b1_01_01010_00_0_00001_000000_11111_00000,
},
- .{ // orn x0 x1
- .inst = Instruction.orn(.x0, .x1, Instruction.RegisterShift.none()),
+ .{ // orn x0, xzr, x1
+ .inst = Instruction.orn(.x0, .xzr, .x1, Instruction.Shift.none),
.expected = 0b1_01_01010_00_1_00001_000000_11111_00000,
},
- .{ // movz x1 #4
+ .{ // movz x1, #4
.inst = Instruction.movz(.x1, 4, 0),
.expected = 0b1_10_100101_00_0000000000000100_00001,
},
@@ -944,6 +970,14 @@ test "serialize instructions" {
.inst = Instruction.ldp(.x1, .x2, Register.sp, Instruction.LoadStorePairOffset.post_index(16)),
.expected = 0b10_101_0_001_1_0000010_00010_11111_00001,
},
+ .{ // and x0, x4, x2
+ .inst = Instruction.@"and"(.x0, .x4, .x2, .{}),
+ .expected = 0b1_00_01010_00_0_00010_000000_00100_00000,
+ },
+ .{ // and x0, x4, x2, lsl #0x8
+ .inst = Instruction.@"and"(.x0, .x4, .x2, .{ .shift = .lsl, .amount = 0x8 }),
+ .expected = 0b1_00_01010_00_0_00010_001000_00100_00000,
+ },
};
for (testcases) |case| {
src/codegen.zig
@@ -2415,19 +2415,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
try self.genSetReg(inst.base.src, reg, arg);
}
- // TODO move this to lib/std/{elf, macho}.zig, etc.
- const is_syscall_inst = switch (self.bin_file.tag) {
- .macho => mem.eql(u8, inst.asm_source, "svc #0x80"),
- .elf => mem.eql(u8, inst.asm_source, "svc #0"),
- else => |tag| return self.fail(inst.base.src, "TODO implement aarch64 support for other syscall instructions for file format: '{}'", .{tag}),
- };
- if (is_syscall_inst) {
- const imm16: u16 = switch (self.bin_file.tag) {
- .macho => 0x80,
- .elf => 0,
- else => unreachable,
- };
- mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.svc(imm16).toU32());
+ if (mem.eql(u8, inst.asm_source, "svc #0")) {
+ mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.svc(0x0).toU32());
+ } else if (mem.eql(u8, inst.asm_source, "svc #0x80")) {
+ mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.svc(0x80).toU32());
} else {
return self.fail(inst.base.src, "TODO implement support for more aarch64 assembly instructions", .{});
}
@@ -2876,8 +2867,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
// mov r, x0
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(
reg,
+ .xzr,
.x0,
- Instruction.RegisterShift.none(),
+ Instruction.Shift.none,
).toU32());
// ldr x28, [sp], #16
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(.x28, .{
@@ -2908,8 +2900,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
// mov r, x0
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(
reg,
+ .xzr,
.x0,
- Instruction.RegisterShift.none(),
+ Instruction.Shift.none,
).toU32());
// ldp x0, x28, [sp, #16]
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldp(