authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2020-11-14 18:25:23+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-01 14:43:12-08:00
logc5ec096b2ffd42aff6385debe2a412a6db67868f
treeaafbecd676b2d2fb3c9d86fe55cc7fc0fb6fbd67
parent6c0c275b279cfe52758fb9577921e600dd85c436

stage2 AArch64: add logical (shifted register) instructions


2 files changed, 125 insertions(+), 98 deletions(-)

src/codegen.zig+8-15
......@@ -2415,19 +2415,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
24152415 try self.genSetReg(inst.base.src, reg, arg);
24162416 }
24172417
2418 // TODO move this to lib/std/{elf, macho}.zig, etc.
2419 const is_syscall_inst = switch (self.bin_file.tag) {
2420 .macho => mem.eql(u8, inst.asm_source, "svc #0x80"),
2421 .elf => mem.eql(u8, inst.asm_source, "svc #0"),
2422 else => |tag| return self.fail(inst.base.src, "TODO implement aarch64 support for other syscall instructions for file format: '{}'", .{tag}),
2423 };
2424 if (is_syscall_inst) {
2425 const imm16: u16 = switch (self.bin_file.tag) {
2426 .macho => 0x80,
2427 .elf => 0,
2428 else => unreachable,
2429 };
2430 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.svc(imm16).toU32());
2418 if (mem.eql(u8, inst.asm_source, "svc #0")) {
2419 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.svc(0x0).toU32());
2420 } else if (mem.eql(u8, inst.asm_source, "svc #0x80")) {
2421 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.svc(0x80).toU32());
24312422 } else {
24322423 return self.fail(inst.base.src, "TODO implement support for more aarch64 assembly instructions", .{});
24332424 }
......@@ -2876,8 +2867,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
28762867 // mov r, x0
28772868 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(
28782869 reg,
2870 .xzr,
28792871 .x0,
2880 Instruction.RegisterShift.none(),
2872 Instruction.Shift.none,
28812873 ).toU32());
28822874 // ldr x28, [sp], #16
28832875 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(.x28, .{
......@@ -2908,8 +2900,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
29082900 // mov r, x0
29092901 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(
29102902 reg,
2903 .xzr,
29112904 .x0,
2912 Instruction.RegisterShift.none(),
2905 Instruction.Shift.none,
29132906 ).toU32());
29142907 // ldp x0, x28, [sp, #16]
29152908 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldp(
src/codegen/aarch64.zig+117-83
......@@ -200,17 +200,6 @@ test "FloatingPointRegister.toX" {
200200
201201/// Represents an instruction in the AArch64 instruction set
202202pub const Instruction = union(enum) {
203 OrShiftedRegister: packed struct {
204 rd: u5,
205 rn: u5,
206 imm6: u6,
207 rm: u5,
208 n: u1,
209 shift: u2,
210 fixed: u5 = 0b01010,
211 opc: u2 = 0b01,
212 sf: u1,
213 },
214203 MoveWideImmediate: packed struct {
215204 rd: u5,
216205 imm16: u16,
......@@ -274,10 +263,37 @@ pub const Instruction = union(enum) {
274263 NoOperation: packed struct {
275264 fixed: u32 = 0b1101010100_0_00_011_0010_0000_000_11111,
276265 },
266 LogicalShiftedRegister: packed struct {
267 rd: u5,
268 rn: u5,
269 imm6: u6,
270 rm: u5,
271 n: u1,
272 shift: u2,
273 fixed: u5 = 0b01010,
274 opc: u2,
275 sf: u1,
276 },
277
278 pub const Shift = struct {
279 shift: Type = .lsl,
280 amount: u6 = 0,
281
282 pub const Type = enum(u2) {
283 lsl,
284 lsr,
285 asr,
286 ror,
287 };
288
289 pub const none = Shift{
290 .shift = .lsl,
291 .amount = 0,
292 };
293 };
277294
278295 pub fn toU32(self: Instruction) u32 {
279296 return switch (self) {
280 .OrShiftedRegister => |v| @bitCast(u32, v),
281297 .MoveWideImmediate => |v| @bitCast(u32, v),
282298 .PCRelativeAddress => |v| @bitCast(u32, v),
283299 .LoadStoreRegister => |v| @bitCast(u32, v),
......@@ -287,68 +303,10 @@ pub const Instruction = union(enum) {
287303 .UnconditionalBranchRegister => |v| @bitCast(u32, v),
288304 .UnconditionalBranchImmediate => |v| @bitCast(u32, v),
289305 .NoOperation => |v| @bitCast(u32, v),
306 .LogicalShiftedRegister => |v| @bitCast(u32, v),
290307 };
291308 }
292309
293 pub const RegisterShift = struct {
294 rn: u5,
295 imm6: u6,
296 shift: enum(u2) {
297 Lsl = 0,
298 Lsr = 1,
299 Asr = 2,
300 Ror = 3,
301 },
302
303 pub fn none() RegisterShift {
304 return .{
305 .rn = 0b11111,
306 .imm6 = 0,
307 .shift = .Lsl,
308 };
309 }
310 };
311
312 // Helper functions for assembly syntax functions
313
314 fn orShiftedRegister(
315 rd: Register,
316 rm: Register,
317 shift: RegisterShift,
318 invert: bool,
319 ) Instruction {
320 const n: u1 = if (invert) 1 else 0;
321 switch (rd.size()) {
322 32 => {
323 return Instruction{
324 .OrShiftedRegister = .{
325 .rd = rd.id(),
326 .rn = shift.rn,
327 .imm6 = shift.imm6,
328 .rm = rm.id(),
329 .n = n,
330 .shift = @enumToInt(shift.shift),
331 .sf = 0,
332 },
333 };
334 },
335 64 => {
336 return Instruction{
337 .OrShiftedRegister = .{
338 .rd = rd.id(),
339 .rn = shift.rn,
340 .imm6 = shift.imm6,
341 .rm = rm.id(),
342 .n = n,
343 .shift = @enumToInt(shift.shift),
344 .sf = 1,
345 },
346 };
347 },
348 else => unreachable, // unexpected register size
349 }
350 }
351
352310 fn moveWideImmediate(
353311 opc: u2,
354312 rd: Register,
......@@ -671,15 +629,49 @@ pub const Instruction = union(enum) {
671629 };
672630 }
673631
674 // Bitwise (inclusive) OR of a register value
675
676 pub fn orr(rd: Register, rm: Register, shift: RegisterShift) Instruction {
677 return orShiftedRegister(rd, rm, shift, false);
632 fn logicalShiftedRegister(
633 opc: u2,
634 n: u1,
635 shift: Shift,
636 rd: Register,
637 rn: Register,
638 rm: Register,
639 ) Instruction {
640 switch (rd.size()) {
641 32 => {
642 assert(shift.amount < 32);
643 return Instruction{
644 .LogicalShiftedRegister = .{
645 .rd = rd.id(),
646 .rn = rn.id(),
647 .imm6 = shift.amount,
648 .rm = rm.id(),
649 .n = n,
650 .shift = @enumToInt(shift.shift),
651 .opc = opc,
652 .sf = 0b0,
653 },
654 };
655 },
656 64 => {
657 return Instruction{
658 .LogicalShiftedRegister = .{
659 .rd = rd.id(),
660 .rn = rn.id(),
661 .imm6 = shift.amount,
662 .rm = rm.id(),
663 .n = n,
664 .shift = @enumToInt(shift.shift),
665 .opc = opc,
666 .sf = 0b1,
667 },
668 };
669 },
670 else => unreachable, // unexpected register size
671 }
678672 }
679673
680 pub fn orn(rd: Register, rm: Register, shift: RegisterShift) Instruction {
681 return orShiftedRegister(rd, rm, shift, true);
682 }
674 // Helper functions for assembly syntax functions
683675
684676 // Move wide (immediate)
685677
......@@ -823,6 +815,40 @@ pub const Instruction = union(enum) {
823815 pub fn nop() Instruction {
824816 return Instruction{ .NoOperation = {} };
825817 }
818
819 // Logical (shifted register)
820
821 pub fn @"and"(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
822 return logicalShiftedRegister(0b00, 0b0, shift, rd, rn, rm);
823 }
824
825 pub fn bic(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
826 return logicalShiftedRegister(0b00, 0b1, shift, rd, rn, rm);
827 }
828
829 pub fn orr(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
830 return logicalShiftedRegister(0b01, 0b0, shift, rd, rn, rm);
831 }
832
833 pub fn orn(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
834 return logicalShiftedRegister(0b01, 0b1, shift, rd, rn, rm);
835 }
836
837 pub fn eor(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
838 return logicalShiftedRegister(0b10, 0b0, shift, rd, rn, rm);
839 }
840
841 pub fn eon(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
842 return logicalShiftedRegister(0b10, 0b1, shift, rd, rn, rm);
843 }
844
845 pub fn ands(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
846 return logicalShiftedRegister(0b11, 0b0, shift, rd, rn, rm);
847 }
848
849 pub fn bics(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
850 return logicalShiftedRegister(0b11, 0b1, shift, rd, rn, rm);
851 }
826852};
827853
828854test "" {
......@@ -836,15 +862,15 @@ test "serialize instructions" {
836862 };
837863
838864 const testcases = [_]Testcase{
839 .{ // orr x0 x1
840 .inst = Instruction.orr(.x0, .x1, Instruction.RegisterShift.none()),
865 .{ // orr x0, xzr, x1
866 .inst = Instruction.orr(.x0, .xzr, .x1, Instruction.Shift.none),
841867 .expected = 0b1_01_01010_00_0_00001_000000_11111_00000,
842868 },
843 .{ // orn x0 x1
844 .inst = Instruction.orn(.x0, .x1, Instruction.RegisterShift.none()),
869 .{ // orn x0, xzr, x1
870 .inst = Instruction.orn(.x0, .xzr, .x1, Instruction.Shift.none),
845871 .expected = 0b1_01_01010_00_1_00001_000000_11111_00000,
846872 },
847 .{ // movz x1 #4
873 .{ // movz x1, #4
848874 .inst = Instruction.movz(.x1, 4, 0),
849875 .expected = 0b1_10_100101_00_0000000000000100_00001,
850876 },
......@@ -944,6 +970,14 @@ test "serialize instructions" {
944970 .inst = Instruction.ldp(.x1, .x2, Register.sp, Instruction.LoadStorePairOffset.post_index(16)),
945971 .expected = 0b10_101_0_001_1_0000010_00010_11111_00001,
946972 },
973 .{ // and x0, x4, x2
974 .inst = Instruction.@"and"(.x0, .x4, .x2, .{}),
975 .expected = 0b1_00_01010_00_0_00010_000000_00100_00000,
976 },
977 .{ // and x0, x4, x2, lsl #0x8
978 .inst = Instruction.@"and"(.x0, .x4, .x2, .{ .shift = .lsl, .amount = 0x8 }),
979 .expected = 0b1_00_01010_00_0_00010_001000_00100_00000,
980 },
947981 };
948982
949983 for (testcases) |case| {