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 {...@@ -2415,19 +2415,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2415 try self.genSetReg(inst.base.src, reg, arg);2415 try self.genSetReg(inst.base.src, reg, arg);
2416 }2416 }
24172417
2418 // TODO move this to lib/std/{elf, macho}.zig, etc.2418 if (mem.eql(u8, inst.asm_source, "svc #0")) {
2419 const is_syscall_inst = switch (self.bin_file.tag) {2419 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.svc(0x0).toU32());
2420 .macho => mem.eql(u8, inst.asm_source, "svc #0x80"),2420 } else if (mem.eql(u8, inst.asm_source, "svc #0x80")) {
2421 .elf => mem.eql(u8, inst.asm_source, "svc #0"),2421 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.svc(0x80).toU32());
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());
2431 } else {2422 } else {
2432 return self.fail(inst.base.src, "TODO implement support for more aarch64 assembly instructions", .{});2423 return self.fail(inst.base.src, "TODO implement support for more aarch64 assembly instructions", .{});
2433 }2424 }
...@@ -2876,8 +2867,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2876,8 +2867,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2876 // mov r, x02867 // mov r, x0
2877 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(2868 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(
2878 reg,2869 reg,
2870 .xzr,
2879 .x0,2871 .x0,
2880 Instruction.RegisterShift.none(),2872 Instruction.Shift.none,
2881 ).toU32());2873 ).toU32());
2882 // ldr x28, [sp], #162874 // ldr x28, [sp], #16
2883 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(.x28, .{2875 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(.x28, .{
...@@ -2908,8 +2900,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2908,8 +2900,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2908 // mov r, x02900 // mov r, x0
2909 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(2901 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(
2910 reg,2902 reg,
2903 .xzr,
2911 .x0,2904 .x0,
2912 Instruction.RegisterShift.none(),2905 Instruction.Shift.none,
2913 ).toU32());2906 ).toU32());
2914 // ldp x0, x28, [sp, #16]2907 // ldp x0, x28, [sp, #16]
2915 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldp(2908 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldp(
src/codegen/aarch64.zig+117-83
...@@ -200,17 +200,6 @@ test "FloatingPointRegister.toX" {...@@ -200,17 +200,6 @@ test "FloatingPointRegister.toX" {
200200
201/// Represents an instruction in the AArch64 instruction set201/// Represents an instruction in the AArch64 instruction set
202pub const Instruction = union(enum) {202pub 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 },
214 MoveWideImmediate: packed struct {203 MoveWideImmediate: packed struct {
215 rd: u5,204 rd: u5,
216 imm16: u16,205 imm16: u16,
...@@ -274,10 +263,37 @@ pub const Instruction = union(enum) {...@@ -274,10 +263,37 @@ pub const Instruction = union(enum) {
274 NoOperation: packed struct {263 NoOperation: packed struct {
275 fixed: u32 = 0b1101010100_0_00_011_0010_0000_000_11111,264 fixed: u32 = 0b1101010100_0_00_011_0010_0000_000_11111,
276 },265 },
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
278 pub fn toU32(self: Instruction) u32 {295 pub fn toU32(self: Instruction) u32 {
279 return switch (self) {296 return switch (self) {
280 .OrShiftedRegister => |v| @bitCast(u32, v),
281 .MoveWideImmediate => |v| @bitCast(u32, v),297 .MoveWideImmediate => |v| @bitCast(u32, v),
282 .PCRelativeAddress => |v| @bitCast(u32, v),298 .PCRelativeAddress => |v| @bitCast(u32, v),
283 .LoadStoreRegister => |v| @bitCast(u32, v),299 .LoadStoreRegister => |v| @bitCast(u32, v),
...@@ -287,68 +303,10 @@ pub const Instruction = union(enum) {...@@ -287,68 +303,10 @@ pub const Instruction = union(enum) {
287 .UnconditionalBranchRegister => |v| @bitCast(u32, v),303 .UnconditionalBranchRegister => |v| @bitCast(u32, v),
288 .UnconditionalBranchImmediate => |v| @bitCast(u32, v),304 .UnconditionalBranchImmediate => |v| @bitCast(u32, v),
289 .NoOperation => |v| @bitCast(u32, v),305 .NoOperation => |v| @bitCast(u32, v),
306 .LogicalShiftedRegister => |v| @bitCast(u32, v),
290 };307 };
291 }308 }
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
352 fn moveWideImmediate(310 fn moveWideImmediate(
353 opc: u2,311 opc: u2,
354 rd: Register,312 rd: Register,
...@@ -671,15 +629,49 @@ pub const Instruction = union(enum) {...@@ -671,15 +629,49 @@ pub const Instruction = union(enum) {
671 };629 };
672 }630 }
673631
674 // Bitwise (inclusive) OR of a register value632 fn logicalShiftedRegister(
675633 opc: u2,
676 pub fn orr(rd: Register, rm: Register, shift: RegisterShift) Instruction {634 n: u1,
677 return orShiftedRegister(rd, rm, shift, false);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 }
678 }672 }
679673
680 pub fn orn(rd: Register, rm: Register, shift: RegisterShift) Instruction {674 // Helper functions for assembly syntax functions
681 return orShiftedRegister(rd, rm, shift, true);
682 }
683675
684 // Move wide (immediate)676 // Move wide (immediate)
685677
...@@ -823,6 +815,40 @@ pub const Instruction = union(enum) {...@@ -823,6 +815,40 @@ pub const Instruction = union(enum) {
823 pub fn nop() Instruction {815 pub fn nop() Instruction {
824 return Instruction{ .NoOperation = {} };816 return Instruction{ .NoOperation = {} };
825 }817 }
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 }
826};852};
827853
828test "" {854test "" {
...@@ -836,15 +862,15 @@ test "serialize instructions" {...@@ -836,15 +862,15 @@ test "serialize instructions" {
836 };862 };
837863
838 const testcases = [_]Testcase{864 const testcases = [_]Testcase{
839 .{ // orr x0 x1865 .{ // orr x0, xzr, x1
840 .inst = Instruction.orr(.x0, .x1, Instruction.RegisterShift.none()),866 .inst = Instruction.orr(.x0, .xzr, .x1, Instruction.Shift.none),
841 .expected = 0b1_01_01010_00_0_00001_000000_11111_00000,867 .expected = 0b1_01_01010_00_0_00001_000000_11111_00000,
842 },868 },
843 .{ // orn x0 x1869 .{ // orn x0, xzr, x1
844 .inst = Instruction.orn(.x0, .x1, Instruction.RegisterShift.none()),870 .inst = Instruction.orn(.x0, .xzr, .x1, Instruction.Shift.none),
845 .expected = 0b1_01_01010_00_1_00001_000000_11111_00000,871 .expected = 0b1_01_01010_00_1_00001_000000_11111_00000,
846 },872 },
847 .{ // movz x1 #4873 .{ // movz x1, #4
848 .inst = Instruction.movz(.x1, 4, 0),874 .inst = Instruction.movz(.x1, 4, 0),
849 .expected = 0b1_10_100101_00_0000000000000100_00001,875 .expected = 0b1_10_100101_00_0000000000000100_00001,
850 },876 },
...@@ -944,6 +970,14 @@ test "serialize instructions" {...@@ -944,6 +970,14 @@ test "serialize instructions" {
944 .inst = Instruction.ldp(.x1, .x2, Register.sp, Instruction.LoadStorePairOffset.post_index(16)),970 .inst = Instruction.ldp(.x1, .x2, Register.sp, Instruction.LoadStorePairOffset.post_index(16)),
945 .expected = 0b10_101_0_001_1_0000010_00010_11111_00001,971 .expected = 0b10_101_0_001_1_0000010_00010_11111_00001,
946 },972 },
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 },
947 };981 };
948982
949 for (testcases) |case| {983 for (testcases) |case| {