authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-09 17:15:00+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-09 17:21:21+01:00
log2082c275577163a3c3006ae15b0c8af51a414f7d
treefddfdf3e5970fc478d0b6cf66c12e8f3acc9034d
parente91dbab256354477fdac0849f43766f43a7df8f0

stage2+aarch64: clean up offset helper structs


2 files changed, 167 insertions(+), 147 deletions(-)

src/codegen.zig+4-6
...@@ -2736,7 +2736,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2736,7 +2736,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2736 // https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/using-the-stack-in-aarch64-implementing-push-and-pop)2736 // https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/using-the-stack-in-aarch64-implementing-push-and-pop)
2737 // str x28, [sp, #-16]2737 // str x28, [sp, #-16]
2738 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.str(.x28, Register.sp, .{2738 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.str(.x28, Register.sp, .{
2739 .offset = Instruction.Offset.imm_pre_index(-16),2739 .offset = Instruction.LoadStoreOffset.imm_pre_index(-16),
2740 }).toU32());2740 }).toU32());
2741 // adr x28, #82741 // adr x28, #8
2742 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.adr(.x28, 8).toU32());2742 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.adr(.x28, 8).toU32());
...@@ -2760,7 +2760,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2760,7 +2760,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2760 // ldr x28, [sp], #162760 // ldr x28, [sp], #16
2761 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(.x28, .{2761 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(.x28, .{
2762 .rn = Register.sp,2762 .rn = Register.sp,
2763 .offset = Instruction.Offset.imm_post_index(16),2763 .offset = Instruction.LoadStoreOffset.imm_post_index(16),
2764 }).toU32());2764 }).toU32());
2765 } else {2765 } else {
2766 // stp x0, x28, [sp, #-16]2766 // stp x0, x28, [sp, #-16]
...@@ -2768,8 +2768,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2768,8 +2768,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2768 .x0,2768 .x0,
2769 .x28,2769 .x28,
2770 Register.sp,2770 Register.sp,
2771 -16,2771 Instruction.LoadStorePairOffset.pre_index(-16),
2772 .PreIndex,
2773 ).toU32());2772 ).toU32());
2774 // adr x28, #82773 // adr x28, #8
2775 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.adr(.x28, 8).toU32());2774 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.adr(.x28, 8).toU32());
...@@ -2795,8 +2794,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2795,8 +2794,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2795 .x0,2794 .x0,
2796 .x28,2795 .x28,
2797 Register.sp,2796 Register.sp,
2798 16,2797 Instruction.LoadStorePairOffset.post_index(16),
2799 .PostIndex,
2800 ).toU32());2798 ).toU32());
2801 }2799 }
2802 } else {2800 } else {
src/codegen/aarch64.zig+163-141
...@@ -290,123 +290,6 @@ pub const Instruction = union(enum) {...@@ -290,123 +290,6 @@ pub const Instruction = union(enum) {
290 };290 };
291 }291 }
292292
293 /// Represents the offset operand of a load or store instruction.
294 /// Data can be loaded from memory with either an immediate offset
295 /// or an offset that is stored in some register.
296 pub const Offset = union(enum) {
297 Immediate: union(enum) {
298 PostIndex: i9,
299 PreIndex: i9,
300 Unsigned: u12,
301 },
302 Register: struct {
303 rm: u5,
304 shift: union(enum) {
305 Uxtw: u2,
306 Lsl: u2,
307 Sxtw: u2,
308 Sxtx: u2,
309 },
310 },
311
312 pub const none = Offset{
313 .Immediate = .{ .Unsigned = 0 },
314 };
315
316 pub fn toU12(self: Offset) u12 {
317 return switch (self) {
318 .Immediate => |imm_type| switch (imm_type) {
319 .PostIndex => |v| (@intCast(u12, @bitCast(u9, v)) << 2) + 1,
320 .PreIndex => |v| (@intCast(u12, @bitCast(u9, v)) << 2) + 3,
321 .Unsigned => |v| v,
322 },
323 .Register => |r| switch (r.shift) {
324 .Uxtw => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 16 + 2050,
325 .Lsl => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 24 + 2050,
326 .Sxtw => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 48 + 2050,
327 .Sxtx => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 56 + 2050,
328 },
329 };
330 }
331
332 pub fn imm(offset: u12) Offset {
333 return Offset{
334 .Immediate = .{ .Unsigned = offset },
335 };
336 }
337
338 pub fn imm_post_index(offset: i9) Offset {
339 return Offset{
340 .Immediate = .{ .PostIndex = offset },
341 };
342 }
343
344 pub fn imm_pre_index(offset: i9) Offset {
345 return Offset{
346 .Immediate = .{ .PreIndex = offset },
347 };
348 }
349
350 pub fn reg(rm: Register) Offset {
351 return Offset{
352 .Register = .{
353 .rm = rm.id(),
354 .shift = .{
355 .Lsl = 0,
356 },
357 },
358 };
359 }
360
361 pub fn reg_uxtw(rm: Register, shift: u2) Offset {
362 assert(rm.size() == 32 and (shift == 0 or shift == 2));
363 return Offset{
364 .Register = .{
365 .rm = rm.id(),
366 .shift = .{
367 .Uxtw = shift,
368 },
369 },
370 };
371 }
372
373 pub fn reg_lsl(rm: Register, shift: u2) Offset {
374 assert(rm.size() == 64 and (shift == 0 or shift == 3));
375 return Offset{
376 .Register = .{
377 .rm = rm.id(),
378 .shift = .{
379 .Lsl = shift,
380 },
381 },
382 };
383 }
384
385 pub fn reg_sxtw(rm: Register, shift: u2) Offset {
386 assert(rm.size() == 32 and (shift == 0 or shift == 2));
387 return Offset{
388 .Register = .{
389 .rm = rm.id(),
390 .shift = .{
391 .Sxtw = shift,
392 },
393 },
394 };
395 }
396
397 pub fn reg_sxtx(rm: Register, shift: u2) Offset {
398 assert(rm.size() == 64 and (shift == 0 or shift == 3));
399 return Offset{
400 .Register = .{
401 .rm = rm.id(),
402 .shift = .{
403 .Sxtx = shift,
404 },
405 },
406 };
407 }
408 };
409
410 pub const RegisterShift = struct {293 pub const RegisterShift = struct {
411 rn: u5,294 rn: u5,
412 imm6: u6,295 imm6: u6,
...@@ -514,7 +397,124 @@ pub const Instruction = union(enum) {...@@ -514,7 +397,124 @@ pub const Instruction = union(enum) {
514 };397 };
515 }398 }
516399
517 fn loadStoreRegister(rt: Register, rn: Register, offset: Offset, load: bool) Instruction {400 /// Represents the offset operand of a load or store instruction.
401 /// Data can be loaded from memory with either an immediate offset
402 /// or an offset that is stored in some register.
403 pub const LoadStoreOffset = union(enum) {
404 Immediate: union(enum) {
405 PostIndex: i9,
406 PreIndex: i9,
407 Unsigned: u12,
408 },
409 Register: struct {
410 rm: u5,
411 shift: union(enum) {
412 Uxtw: u2,
413 Lsl: u2,
414 Sxtw: u2,
415 Sxtx: u2,
416 },
417 },
418
419 pub const none = LoadStoreOffset{
420 .Immediate = .{ .Unsigned = 0 },
421 };
422
423 pub fn toU12(self: LoadStoreOffset) u12 {
424 return switch (self) {
425 .Immediate => |imm_type| switch (imm_type) {
426 .PostIndex => |v| (@intCast(u12, @bitCast(u9, v)) << 2) + 1,
427 .PreIndex => |v| (@intCast(u12, @bitCast(u9, v)) << 2) + 3,
428 .Unsigned => |v| v,
429 },
430 .Register => |r| switch (r.shift) {
431 .Uxtw => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 16 + 2050,
432 .Lsl => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 24 + 2050,
433 .Sxtw => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 48 + 2050,
434 .Sxtx => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 56 + 2050,
435 },
436 };
437 }
438
439 pub fn imm(offset: u12) LoadStoreOffset {
440 return .{
441 .Immediate = .{ .Unsigned = offset },
442 };
443 }
444
445 pub fn imm_post_index(offset: i9) LoadStoreOffset {
446 return .{
447 .Immediate = .{ .PostIndex = offset },
448 };
449 }
450
451 pub fn imm_pre_index(offset: i9) LoadStoreOffset {
452 return .{
453 .Immediate = .{ .PreIndex = offset },
454 };
455 }
456
457 pub fn reg(rm: Register) LoadStoreOffset {
458 return .{
459 .Register = .{
460 .rm = rm.id(),
461 .shift = .{
462 .Lsl = 0,
463 },
464 },
465 };
466 }
467
468 pub fn reg_uxtw(rm: Register, shift: u2) LoadStoreOffset {
469 assert(rm.size() == 32 and (shift == 0 or shift == 2));
470 return .{
471 .Register = .{
472 .rm = rm.id(),
473 .shift = .{
474 .Uxtw = shift,
475 },
476 },
477 };
478 }
479
480 pub fn reg_lsl(rm: Register, shift: u2) LoadStoreOffset {
481 assert(rm.size() == 64 and (shift == 0 or shift == 3));
482 return .{
483 .Register = .{
484 .rm = rm.id(),
485 .shift = .{
486 .Lsl = shift,
487 },
488 },
489 };
490 }
491
492 pub fn reg_sxtw(rm: Register, shift: u2) LoadStoreOffset {
493 assert(rm.size() == 32 and (shift == 0 or shift == 2));
494 return .{
495 .Register = .{
496 .rm = rm.id(),
497 .shift = .{
498 .Sxtw = shift,
499 },
500 },
501 };
502 }
503
504 pub fn reg_sxtx(rm: Register, shift: u2) LoadStoreOffset {
505 assert(rm.size() == 64 and (shift == 0 or shift == 3));
506 return .{
507 .Register = .{
508 .rm = rm.id(),
509 .shift = .{
510 .Sxtx = shift,
511 },
512 },
513 };
514 }
515 };
516
517 fn loadStoreRegister(rt: Register, rn: Register, offset: LoadStoreOffset, load: bool) Instruction {
518 const off = offset.toU12();518 const off = offset.toU12();
519 const op1: u2 = blk: {519 const op1: u2 = blk: {
520 switch (offset) {520 switch (offset) {
...@@ -709,9 +709,10 @@ pub const Instruction = union(enum) {...@@ -709,9 +709,10 @@ pub const Instruction = union(enum) {
709709
710 pub const LdrArgs = struct {710 pub const LdrArgs = struct {
711 rn: ?Register = null,711 rn: ?Register = null,
712 offset: Offset = Offset.none,712 offset: LoadStoreOffset = LoadStoreOffset.none,
713 literal: ?u19 = null,713 literal: ?u19 = null,
714 };714 };
715
715 pub fn ldr(rt: Register, args: LdrArgs) Instruction {716 pub fn ldr(rt: Register, args: LdrArgs) Instruction {
716 if (args.rn) |rn| {717 if (args.rn) |rn| {
717 return loadStoreRegister(rt, rn, args.offset, true);718 return loadStoreRegister(rt, rn, args.offset, true);
...@@ -721,29 +722,50 @@ pub const Instruction = union(enum) {...@@ -721,29 +722,50 @@ pub const Instruction = union(enum) {
721 }722 }
722723
723 pub const StrArgs = struct {724 pub const StrArgs = struct {
724 offset: Offset = Offset.none,725 offset: LoadStoreOffset = LoadStoreOffset.none,
725 };726 };
727
726 pub fn str(rt: Register, rn: Register, args: StrArgs) Instruction {728 pub fn str(rt: Register, rn: Register, args: StrArgs) Instruction {
727 return loadStoreRegister(rt, rn, args.offset, false);729 return loadStoreRegister(rt, rn, args.offset, false);
728 }730 }
729731
730 // Load or store pair of registers732 // Load or store pair of registers
731733
732 pub const LoadStorePairEncoding = enum(u2) {734 pub const LoadStorePairOffset = struct {
733 PostIndex = 0b01,735 encoding: enum(u2) {
734 SignedOffset = 0b10,736 PostIndex = 0b01,
735 PreIndex = 0b11,737 Signed = 0b10,
738 PreIndex = 0b11,
739 },
740 offset: i9,
741
742 pub fn none() LoadStorePairOffset {
743 return .{ .encoding = .Signed, .offset = 0 };
744 }
745
746 pub fn post_index(imm: i9) LoadStorePairOffset {
747 return .{ .encoding = .PostIndex, .offset = imm };
748 }
749
750 pub fn pre_index(imm: i9) LoadStorePairOffset {
751 return .{ .encoding = .PreIndex, .offset = imm };
752 }
753
754 pub fn signed(imm: i9) LoadStorePairOffset {
755 return .{ .encoding = .Signed, .offset = imm };
756 }
736 };757 };
737 pub fn ldp(rt1: Register, rt2: Register, rn: Register, offset: i9, encoding: LoadStorePairEncoding) Instruction {758
738 return loadStorePairOfRegisters(rt1, rt2, rn, offset, @enumToInt(encoding), true);759 pub fn ldp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction {
760 return loadStorePairOfRegisters(rt1, rt2, rn, offset.offset, @enumToInt(offset.encoding), true);
739 }761 }
740762
741 pub fn ldnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {763 pub fn ldnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {
742 return loadStorePairOfRegisters(rt1, rt2, rn, offset, 0, true);764 return loadStorePairOfRegisters(rt1, rt2, rn, offset, 0, true);
743 }765 }
744766
745 pub fn stp(rt1: Register, rt2: Register, rn: Register, offset: i9, encoding: LoadStorePairEncoding) Instruction {767 pub fn stp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction {
746 return loadStorePairOfRegisters(rt1, rt2, rn, offset, @enumToInt(encoding), false);768 return loadStorePairOfRegisters(rt1, rt2, rn, offset.offset, @enumToInt(offset.encoding), false);
747 }769 }
748770
749 pub fn stnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {771 pub fn stnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {
...@@ -867,15 +889,15 @@ test "serialize instructions" {...@@ -867,15 +889,15 @@ test "serialize instructions" {
867 .expected = 0b11_111_0_01_01_000000000000_00001_00010,889 .expected = 0b11_111_0_01_01_000000000000_00001_00010,
868 },890 },
869 .{ // ldr x2, [x1, #1]!891 .{ // ldr x2, [x1, #1]!
870 .inst = Instruction.ldr(.x2, .{ .rn = .x1, .offset = Instruction.Offset.imm_pre_index(1) }),892 .inst = Instruction.ldr(.x2, .{ .rn = .x1, .offset = Instruction.LoadStoreOffset.imm_pre_index(1) }),
871 .expected = 0b11_111_0_00_01_0_000000001_11_00001_00010,893 .expected = 0b11_111_0_00_01_0_000000001_11_00001_00010,
872 },894 },
873 .{ // ldr x2, [x1], #-1895 .{ // ldr x2, [x1], #-1
874 .inst = Instruction.ldr(.x2, .{ .rn = .x1, .offset = Instruction.Offset.imm_post_index(-1) }),896 .inst = Instruction.ldr(.x2, .{ .rn = .x1, .offset = Instruction.LoadStoreOffset.imm_post_index(-1) }),
875 .expected = 0b11_111_0_00_01_0_111111111_01_00001_00010,897 .expected = 0b11_111_0_00_01_0_111111111_01_00001_00010,
876 },898 },
877 .{ // ldr x2, [x1], (x3)899 .{ // ldr x2, [x1], (x3)
878 .inst = Instruction.ldr(.x2, .{ .rn = .x1, .offset = Instruction.Offset.reg(.x3) }),900 .inst = Instruction.ldr(.x2, .{ .rn = .x1, .offset = Instruction.LoadStoreOffset.reg(.x3) }),
879 .expected = 0b11_111_0_00_01_1_00011_011_0_10_00001_00010,901 .expected = 0b11_111_0_00_01_1_00011_011_0_10_00001_00010,
880 },902 },
881 .{ // ldr x2, label903 .{ // ldr x2, label
...@@ -887,7 +909,7 @@ test "serialize instructions" {...@@ -887,7 +909,7 @@ test "serialize instructions" {
887 .expected = 0b11_111_0_01_00_000000000000_00001_00010,909 .expected = 0b11_111_0_01_00_000000000000_00001_00010,
888 },910 },
889 .{ // str x2, [x1], (x3)911 .{ // str x2, [x1], (x3)
890 .inst = Instruction.str(.x2, .x1, .{ .offset = Instruction.Offset.reg(.x3) }),912 .inst = Instruction.str(.x2, .x1, .{ .offset = Instruction.LoadStoreOffset.reg(.x3) }),
891 .expected = 0b11_111_0_00_00_1_00011_011_0_10_00001_00010,913 .expected = 0b11_111_0_00_00_1_00011_011_0_10_00001_00010,
892 },914 },
893 .{ // adr x2, #0x8915 .{ // adr x2, #0x8
...@@ -907,20 +929,20 @@ test "serialize instructions" {...@@ -907,20 +929,20 @@ test "serialize instructions" {
907 .expected = 0b1_00_10000_1111111111111111110_00010,929 .expected = 0b1_00_10000_1111111111111111110_00010,
908 },930 },
909 .{ // stp x1, x2, [sp, #8]931 .{ // stp x1, x2, [sp, #8]
910 .inst = Instruction.stp(.x1, .x2, Register.sp, 8, .SignedOffset),932 .inst = Instruction.stp(.x1, .x2, Register.sp, Instruction.LoadStorePairOffset.signed(8)),
911 .expected = 0b10_101_0_010_0_0000001_00010_11111_00001,933 .expected = 0b10_101_0_010_0_0000001_00010_11111_00001,
912 },934 },
913 .{ // stp x1, x2, [sp, #-16]
914 .inst = Instruction.stp(.x1, .x2, Register.sp, -16, .SignedOffset),
915 .expected = 0b10_101_0_010_0_1111110_00010_11111_00001,
916 },
917 .{ // ldp x1, x2, [sp, #8]935 .{ // ldp x1, x2, [sp, #8]
918 .inst = Instruction.ldp(.x1, .x2, Register.sp, 8, .SignedOffset),936 .inst = Instruction.ldp(.x1, .x2, Register.sp, Instruction.LoadStorePairOffset.signed(8)),
919 .expected = 0b10_101_0_010_1_0000001_00010_11111_00001,937 .expected = 0b10_101_0_010_1_0000001_00010_11111_00001,
920 },938 },
921 .{ // ldp x1, x2, [sp, #16]939 .{ // stp x1, x2, [sp, #-16]!
922 .inst = Instruction.ldp(.x1, .x2, Register.sp, 16, .SignedOffset),940 .inst = Instruction.stp(.x1, .x2, Register.sp, Instruction.LoadStorePairOffset.pre_index(-16)),
923 .expected = 0b10_101_0_010_1_0000010_00010_11111_00001,941 .expected = 0b10_101_0_011_0_1111110_00010_11111_00001,
942 },
943 .{ // ldp x1, x2, [sp], #16
944 .inst = Instruction.ldp(.x1, .x2, Register.sp, Instruction.LoadStorePairOffset.post_index(16)),
945 .expected = 0b10_101_0_001_1_0000010_00010_11111_00001,
924 },946 },
925 };947 };
926948