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 {
27362736 // https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/using-the-stack-in-aarch64-implementing-push-and-pop)
27372737 // str x28, [sp, #-16]
27382738 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),
27402740 }).toU32());
27412741 // adr x28, #8
27422742 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 {
27602760 // ldr x28, [sp], #16
27612761 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(.x28, .{
27622762 .rn = Register.sp,
2763 .offset = Instruction.Offset.imm_post_index(16),
2763 .offset = Instruction.LoadStoreOffset.imm_post_index(16),
27642764 }).toU32());
27652765 } else {
27662766 // stp x0, x28, [sp, #-16]
......@@ -2768,8 +2768,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
27682768 .x0,
27692769 .x28,
27702770 Register.sp,
2771 -16,
2772 .PreIndex,
2771 Instruction.LoadStorePairOffset.pre_index(-16),
27732772 ).toU32());
27742773 // adr x28, #8
27752774 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 {
27952794 .x0,
27962795 .x28,
27972796 Register.sp,
2798 16,
2799 .PostIndex,
2797 Instruction.LoadStorePairOffset.post_index(16),
28002798 ).toU32());
28012799 }
28022800 } else {
src/codegen/aarch64.zig+163-141
......@@ -290,123 +290,6 @@ pub const Instruction = union(enum) {
290290 };
291291 }
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
410293 pub const RegisterShift = struct {
411294 rn: u5,
412295 imm6: u6,
......@@ -514,7 +397,124 @@ pub const Instruction = union(enum) {
514397 };
515398 }
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 {
518518 const off = offset.toU12();
519519 const op1: u2 = blk: {
520520 switch (offset) {
......@@ -709,9 +709,10 @@ pub const Instruction = union(enum) {
709709
710710 pub const LdrArgs = struct {
711711 rn: ?Register = null,
712 offset: Offset = Offset.none,
712 offset: LoadStoreOffset = LoadStoreOffset.none,
713713 literal: ?u19 = null,
714714 };
715
715716 pub fn ldr(rt: Register, args: LdrArgs) Instruction {
716717 if (args.rn) |rn| {
717718 return loadStoreRegister(rt, rn, args.offset, true);
......@@ -721,29 +722,50 @@ pub const Instruction = union(enum) {
721722 }
722723
723724 pub const StrArgs = struct {
724 offset: Offset = Offset.none,
725 offset: LoadStoreOffset = LoadStoreOffset.none,
725726 };
727
726728 pub fn str(rt: Register, rn: Register, args: StrArgs) Instruction {
727729 return loadStoreRegister(rt, rn, args.offset, false);
728730 }
729731
730732 // Load or store pair of registers
731733
732 pub const LoadStorePairEncoding = enum(u2) {
733 PostIndex = 0b01,
734 SignedOffset = 0b10,
735 PreIndex = 0b11,
734 pub const LoadStorePairOffset = struct {
735 encoding: enum(u2) {
736 PostIndex = 0b01,
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 }
736757 };
737 pub fn ldp(rt1: Register, rt2: Register, rn: Register, offset: i9, encoding: LoadStorePairEncoding) Instruction {
738 return loadStorePairOfRegisters(rt1, rt2, rn, offset, @enumToInt(encoding), true);
758
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);
739761 }
740762
741763 pub fn ldnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {
742764 return loadStorePairOfRegisters(rt1, rt2, rn, offset, 0, true);
743765 }
744766
745 pub fn stp(rt1: Register, rt2: Register, rn: Register, offset: i9, encoding: LoadStorePairEncoding) Instruction {
746 return loadStorePairOfRegisters(rt1, rt2, rn, offset, @enumToInt(encoding), false);
767 pub fn stp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction {
768 return loadStorePairOfRegisters(rt1, rt2, rn, offset.offset, @enumToInt(offset.encoding), false);
747769 }
748770
749771 pub fn stnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {
......@@ -867,15 +889,15 @@ test "serialize instructions" {
867889 .expected = 0b11_111_0_01_01_000000000000_00001_00010,
868890 },
869891 .{ // 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) }),
871893 .expected = 0b11_111_0_00_01_0_000000001_11_00001_00010,
872894 },
873895 .{ // 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) }),
875897 .expected = 0b11_111_0_00_01_0_111111111_01_00001_00010,
876898 },
877899 .{ // 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) }),
879901 .expected = 0b11_111_0_00_01_1_00011_011_0_10_00001_00010,
880902 },
881903 .{ // ldr x2, label
......@@ -887,7 +909,7 @@ test "serialize instructions" {
887909 .expected = 0b11_111_0_01_00_000000000000_00001_00010,
888910 },
889911 .{ // 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) }),
891913 .expected = 0b11_111_0_00_00_1_00011_011_0_10_00001_00010,
892914 },
893915 .{ // adr x2, #0x8
......@@ -907,20 +929,20 @@ test "serialize instructions" {
907929 .expected = 0b1_00_10000_1111111111111111110_00010,
908930 },
909931 .{ // 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)),
911933 .expected = 0b10_101_0_010_0_0000001_00010_11111_00001,
912934 },
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 },
917935 .{ // 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)),
919937 .expected = 0b10_101_0_010_1_0000001_00010_11111_00001,
920938 },
921 .{ // ldp x1, x2, [sp, #16]
922 .inst = Instruction.ldp(.x1, .x2, Register.sp, 16, .SignedOffset),
923 .expected = 0b10_101_0_010_1_0000010_00010_11111_00001,
939 .{ // stp x1, x2, [sp, #-16]!
940 .inst = Instruction.stp(.x1, .x2, Register.sp, Instruction.LoadStorePairOffset.pre_index(-16)),
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,
924946 },
925947 };
926948