authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-22 01:30:49-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-02-22 01:30:49-05:00
log6dc5ce931cbd208221be8588115e6d5e2fcb6eae
tree7176ce4247ac44aad5e5b0e37dbc058e1e2723f2
parent74303a3d9591f188fb4dda96bf689c00ebbd24ca
parent25f73224f7f9921633e67d4b5ef12c6ec10406eb
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10959 from joachimschmidt557/stage2-aarch64

stage2 AArch64: misc improvements

12 files changed, 331 insertions(+), 184 deletions(-)

src/arch/aarch64/CodeGen.zig+241-114
......@@ -372,7 +372,7 @@ fn gen(self: *Self) !void {
372372 .data = .{ .load_store_register_pair = .{
373373 .rt = .x29,
374374 .rt2 = .x30,
375 .rn = Register.sp,
375 .rn = .sp,
376376 .offset = Instruction.LoadStorePairOffset.pre_index(-16),
377377 } },
378378 });
......@@ -407,7 +407,7 @@ fn gen(self: *Self) !void {
407407 self.saved_regs_stack_space = 16;
408408 inline for (callee_preserved_regs) |reg| {
409409 if (self.register_manager.isRegAllocated(reg)) {
410 saved_regs |= @as(u32, 1) << reg.id();
410 saved_regs |= @as(u32, 1) << @intCast(u5, reg.id());
411411 self.saved_regs_stack_space += 8;
412412 }
413413 }
......@@ -449,7 +449,7 @@ fn gen(self: *Self) !void {
449449 // the code. Therefore, we can just delete
450450 // the space initially reserved for the
451451 // jump
452 self.mir_instructions.len -= 1;
452 self.mir_instructions.orderedRemove(self.exitlude_jump_relocs.items[0]);
453453 } else for (self.exitlude_jump_relocs.items) |jmp_reloc| {
454454 self.mir_instructions.set(jmp_reloc, .{
455455 .tag = .b,
......@@ -475,7 +475,7 @@ fn gen(self: *Self) !void {
475475 .data = .{ .load_store_register_pair = .{
476476 .rt = .x29,
477477 .rt2 = .x30,
478 .rn = Register.sp,
478 .rn = .sp,
479479 .offset = Instruction.LoadStorePairOffset.post_index(16),
480480 } },
481481 });
......@@ -1041,6 +1041,7 @@ fn binOpRegister(
10411041 const mir_tag: Mir.Inst.Tag = switch (tag) {
10421042 .add, .ptr_add => .add_shifted_register,
10431043 .sub, .ptr_sub => .sub_shifted_register,
1044 .mul => .mul,
10441045 .xor => .eor_shifted_register,
10451046 else => unreachable,
10461047 };
......@@ -1056,6 +1057,11 @@ fn binOpRegister(
10561057 .imm6 = 0,
10571058 .shift = .lsl,
10581059 } },
1060 .mul => .{ .rrr = .{
1061 .rd = dest_reg,
1062 .rn = lhs_reg,
1063 .rm = rhs_reg,
1064 } },
10591065 .xor => .{ .rrr_imm6_logical_shift = .{
10601066 .rd = dest_reg,
10611067 .rn = lhs_reg,
......@@ -1222,6 +1228,24 @@ fn binOp(
12221228 else => unreachable,
12231229 }
12241230 },
1231 .mul => {
1232 switch (lhs_ty.zigTypeTag()) {
1233 .Vector => return self.fail("TODO binary operations on vectors", .{}),
1234 .Int => {
1235 assert(lhs_ty.eql(rhs_ty));
1236 const int_info = lhs_ty.intInfo(self.target.*);
1237 if (int_info.bits <= 64) {
1238 // TODO add optimisations for multiplication
1239 // with immediates, for example a * 2 can be
1240 // lowered to a << 1
1241 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1242 } else {
1243 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
1244 }
1245 },
1246 else => unreachable,
1247 }
1248 },
12251249 // Bitwise operations on integers
12261250 .xor => {
12271251 switch (lhs_ty.zigTypeTag()) {
......@@ -1551,88 +1575,37 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
15511575 };
15521576 self.register_manager.freezeRegs(&.{base_mcv.register});
15531577
1554 // TODO implement optimized ldr for airSliceElemVal
1555 const dst_mcv = try self.allocRegOrMem(inst, true);
1556
1557 const offset_mcv = try self.genMulConstant(bin_op.rhs, @intCast(u32, elem_size));
1558 assert(offset_mcv == .register); // result of multiplication should always be register
1559 self.register_manager.freezeRegs(&.{offset_mcv.register});
1578 switch (elem_size) {
1579 else => {
1580 const dst_mcv = try self.allocRegOrMem(inst, true);
15601581
1561 const addr_reg = try self.register_manager.allocReg(null);
1562 self.register_manager.freezeRegs(&.{addr_reg});
1563 defer self.register_manager.unfreezeRegs(&.{addr_reg});
1582 const offset_mcv = try self.binOp(
1583 .mul,
1584 null,
1585 index_mcv,
1586 .{ .immediate = elem_size },
1587 Type.usize,
1588 Type.usize,
1589 );
1590 assert(offset_mcv == .register); // result of multiplication should always be register
1591 self.register_manager.freezeRegs(&.{offset_mcv.register});
15641592
1565 _ = try self.addInst(.{
1566 .tag = .add_shifted_register,
1567 .data = .{ .rrr_imm6_shift = .{
1568 .rd = addr_reg,
1569 .rn = base_mcv.register,
1570 .rm = offset_mcv.register,
1571 .imm6 = 0,
1572 .shift = .lsl,
1573 } },
1574 });
1593 const addr_mcv = try self.binOp(.add, null, base_mcv, offset_mcv, Type.usize, Type.usize);
15751594
1576 // At this point in time, neither the base register
1577 // nor the offset register contains any valuable data
1578 // anymore.
1579 self.register_manager.unfreezeRegs(&.{ base_mcv.register, offset_mcv.register });
1595 // At this point in time, neither the base register
1596 // nor the offset register contains any valuable data
1597 // anymore.
1598 self.register_manager.unfreezeRegs(&.{ base_mcv.register, offset_mcv.register });
15801599
1581 try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type);
1600 try self.load(dst_mcv, addr_mcv, slice_ptr_field_type);
15821601
1583 break :result dst_mcv;
1602 break :result dst_mcv;
1603 },
1604 }
15841605 };
15851606 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
15861607}
15871608
1588fn genMulConstant(self: *Self, op: Air.Inst.Ref, imm: u32) !MCValue {
1589 const lhs = try self.resolveInst(op);
1590 const rhs = MCValue{ .immediate = imm };
1591
1592 const lhs_is_register = lhs == .register;
1593
1594 if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register});
1595 defer if (lhs_is_register) self.register_manager.unfreezeRegs(&.{lhs.register});
1596
1597 // Destination must be a register
1598 // LHS must be a register
1599 // RHS must be a register
1600 var dst_mcv: MCValue = undefined;
1601 var lhs_mcv: MCValue = lhs;
1602 var rhs_mcv: MCValue = rhs;
1603
1604 // Allocate registers for operands and/or destination
1605 // Allocate 1 or 2 registers
1606 if (lhs_is_register) {
1607 // Move RHS to register
1608 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(null) };
1609 rhs_mcv = dst_mcv;
1610 } else {
1611 // Move LHS and RHS to register
1612 const regs = try self.register_manager.allocRegs(2, .{ null, null });
1613 lhs_mcv = MCValue{ .register = regs[0] };
1614 rhs_mcv = MCValue{ .register = regs[1] };
1615 dst_mcv = lhs_mcv;
1616 }
1617
1618 // Move the operands to the newly allocated registers
1619 if (!lhs_is_register) {
1620 try self.genSetReg(self.air.typeOf(op), lhs_mcv.register, lhs);
1621 }
1622 try self.genSetReg(Type.initTag(.usize), rhs_mcv.register, rhs);
1623
1624 _ = try self.addInst(.{
1625 .tag = .mul,
1626 .data = .{ .rrr = .{
1627 .rd = dst_mcv.register,
1628 .rn = lhs_mcv.register,
1629 .rm = rhs_mcv.register,
1630 } },
1631 });
1632
1633 return dst_mcv;
1634}
1635
16361609fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
16371610 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
16381611 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
......@@ -1763,23 +1736,17 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
17631736 self.register_manager.freezeRegs(&.{addr_reg});
17641737 defer self.register_manager.unfreezeRegs(&.{addr_reg});
17651738
1739 const abi_size = elem_ty.abiSize(self.target.*);
17661740 switch (dst_mcv) {
17671741 .dead => unreachable,
17681742 .undef => unreachable,
17691743 .compare_flags_signed, .compare_flags_unsigned => unreachable,
17701744 .embedded_in_code => unreachable,
17711745 .register => |dst_reg| {
1772 _ = try self.addInst(.{
1773 .tag = .ldr_immediate,
1774 .data = .{ .load_store_register_immediate = .{
1775 .rt = dst_reg,
1776 .rn = addr_reg,
1777 .offset = Instruction.LoadStoreOffset.none.immediate,
1778 } },
1779 });
1746 try self.genLdrRegister(dst_reg, addr_reg, abi_size);
17801747 },
17811748 .stack_offset => |off| {
1782 if (elem_ty.abiSize(self.target.*) <= 8) {
1749 if (abi_size <= 8) {
17831750 const tmp_reg = try self.register_manager.allocReg(null);
17841751 self.register_manager.freezeRegs(&.{tmp_reg});
17851752 defer self.register_manager.unfreezeRegs(&.{tmp_reg});
......@@ -1940,6 +1907,100 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
19401907 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
19411908}
19421909
1910fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, abi_size: u64) !void {
1911 switch (abi_size) {
1912 1 => {
1913 _ = try self.addInst(.{
1914 .tag = .ldrb_immediate,
1915 .data = .{ .load_store_register_immediate = .{
1916 .rt = value_reg.to32(),
1917 .rn = addr_reg,
1918 .offset = Instruction.LoadStoreOffset.none.immediate,
1919 } },
1920 });
1921 },
1922 2 => {
1923 _ = try self.addInst(.{
1924 .tag = .ldrh_immediate,
1925 .data = .{ .load_store_register_immediate = .{
1926 .rt = value_reg.to32(),
1927 .rn = addr_reg,
1928 .offset = Instruction.LoadStoreOffset.none.immediate,
1929 } },
1930 });
1931 },
1932 4 => {
1933 _ = try self.addInst(.{
1934 .tag = .ldr_immediate,
1935 .data = .{ .load_store_register_immediate = .{
1936 .rt = value_reg.to32(),
1937 .rn = addr_reg,
1938 .offset = Instruction.LoadStoreOffset.none.immediate,
1939 } },
1940 });
1941 },
1942 8 => {
1943 _ = try self.addInst(.{
1944 .tag = .ldr_immediate,
1945 .data = .{ .load_store_register_immediate = .{
1946 .rt = value_reg.to64(),
1947 .rn = addr_reg,
1948 .offset = Instruction.LoadStoreOffset.none.immediate,
1949 } },
1950 });
1951 },
1952 3, 5, 6, 7 => return self.fail("TODO: genLdrRegister for more abi_sizes", .{}),
1953 else => unreachable,
1954 }
1955}
1956
1957fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, abi_size: u64) !void {
1958 switch (abi_size) {
1959 1 => {
1960 _ = try self.addInst(.{
1961 .tag = .strb_immediate,
1962 .data = .{ .load_store_register_immediate = .{
1963 .rt = value_reg.to32(),
1964 .rn = addr_reg,
1965 .offset = Instruction.LoadStoreOffset.none.immediate,
1966 } },
1967 });
1968 },
1969 2 => {
1970 _ = try self.addInst(.{
1971 .tag = .strh_immediate,
1972 .data = .{ .load_store_register_immediate = .{
1973 .rt = value_reg.to32(),
1974 .rn = addr_reg,
1975 .offset = Instruction.LoadStoreOffset.none.immediate,
1976 } },
1977 });
1978 },
1979 4 => {
1980 _ = try self.addInst(.{
1981 .tag = .str_immediate,
1982 .data = .{ .load_store_register_immediate = .{
1983 .rt = value_reg.to32(),
1984 .rn = addr_reg,
1985 .offset = Instruction.LoadStoreOffset.none.immediate,
1986 } },
1987 });
1988 },
1989 8 => {
1990 _ = try self.addInst(.{
1991 .tag = .str_immediate,
1992 .data = .{ .load_store_register_immediate = .{
1993 .rt = value_reg.to64(),
1994 .rn = addr_reg,
1995 .offset = Instruction.LoadStoreOffset.none.immediate,
1996 } },
1997 });
1998 },
1999 3, 5, 6, 7 => return self.fail("TODO: genStrRegister for more abi_sizes", .{}),
2000 else => unreachable,
2001 }
2002}
2003
19432004fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void {
19442005 switch (ptr) {
19452006 .none => unreachable,
......@@ -1960,8 +2021,28 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
19602021 .embedded_in_code => {
19612022 return self.fail("TODO implement storing to MCValue.embedded_in_code", .{});
19622023 },
1963 .register => {
1964 return self.fail("TODO implement storing to MCValue.register", .{});
2024 .register => |addr_reg| {
2025 self.register_manager.freezeRegs(&.{addr_reg});
2026 defer self.register_manager.unfreezeRegs(&.{addr_reg});
2027
2028 const abi_size = value_ty.abiSize(self.target.*);
2029 switch (value) {
2030 .register => |value_reg| {
2031 try self.genStrRegister(value_reg, addr_reg, abi_size);
2032 },
2033 else => {
2034 if (abi_size <= 8) {
2035 const tmp_reg = try self.register_manager.allocReg(null);
2036 self.register_manager.freezeRegs(&.{tmp_reg});
2037 defer self.register_manager.unfreezeRegs(&.{tmp_reg});
2038
2039 try self.genSetReg(value_ty, tmp_reg, value);
2040 try self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
2041 } else {
2042 return self.fail("TODO implement memcpy", .{});
2043 }
2044 },
2045 }
19652046 },
19662047 .memory,
19672048 .stack_offset,
......@@ -2005,7 +2086,8 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {
20052086fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue {
20062087 return if (self.liveness.isUnused(inst)) .dead else result: {
20072088 const mcv = try self.resolveInst(operand);
2008 const struct_ty = self.air.typeOf(operand).childType();
2089 const ptr_ty = self.air.typeOf(operand);
2090 const struct_ty = ptr_ty.childType();
20092091 const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*));
20102092 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));
20112093 const struct_field_ty = struct_ty.structFieldType(index);
......@@ -2014,7 +2096,28 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
20142096 .ptr_stack_offset => |off| {
20152097 break :result MCValue{ .ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size };
20162098 },
2017 else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}),
2099 else => {
2100 const offset_reg = try self.copyToTmpRegister(ptr_ty, .{
2101 .immediate = struct_field_offset,
2102 });
2103 self.register_manager.freezeRegs(&.{offset_reg});
2104 defer self.register_manager.unfreezeRegs(&.{offset_reg});
2105
2106 const addr_reg = try self.copyToTmpRegister(ptr_ty, mcv);
2107 self.register_manager.freezeRegs(&.{addr_reg});
2108 defer self.register_manager.unfreezeRegs(&.{addr_reg});
2109
2110 const dest = try self.binOp(
2111 .add,
2112 null,
2113 .{ .register = addr_reg },
2114 .{ .register = offset_reg },
2115 Type.usize,
2116 Type.usize,
2117 );
2118
2119 break :result dest;
2120 },
20182121 }
20192122 };
20202123}
......@@ -2983,8 +3086,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
29833086 const abi_size = ty.abiSize(self.target.*);
29843087 switch (mcv) {
29853088 .dead => unreachable,
2986 .ptr_stack_offset => unreachable,
2987 .ptr_embedded_in_code => unreachable,
29883089 .unreach, .none => return, // Nothing to do.
29893090 .undef => {
29903091 if (!self.wantSafety())
......@@ -3001,6 +3102,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
30013102 .compare_flags_unsigned,
30023103 .compare_flags_signed,
30033104 .immediate,
3105 .ptr_stack_offset,
3106 .ptr_embedded_in_code,
30043107 => {
30053108 const reg = try self.copyToTmpRegister(ty, mcv);
30063109 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
......@@ -3043,17 +3146,18 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
30433146 _ = sym_index;
30443147 return self.fail("TODO implement set stack variable from {}", .{mcv});
30453148 },
3046 .memory => |vaddr| {
3047 _ = vaddr;
3048 return self.fail("TODO implement set stack variable from memory vaddr", .{});
3049 },
3050 .stack_offset => |off| {
3051 if (stack_offset == off)
3052 return; // Copy stack variable to itself; nothing to do.
3149 .memory,
3150 .stack_offset,
3151 => {
3152 switch (mcv) {
3153 .stack_offset => |off| {
3154 if (stack_offset == off)
3155 return; // Copy stack variable to itself; nothing to do.
3156 },
3157 else => {},
3158 }
30533159
3054 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
3055 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
3056 if (abi_size <= ptr_bytes) {
3160 if (abi_size <= 8) {
30573161 const reg = try self.copyToTmpRegister(ty, mcv);
30583162 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
30593163 } else {
......@@ -3068,17 +3172,23 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
30683172 const count_reg = regs[3];
30693173 const tmp_reg = regs[4];
30703174
3071 // sub src_reg, fp, #off
3072 const adj_src_offset = off + abi_size;
3073 const src_offset = math.cast(u12, adj_src_offset) catch return self.fail("TODO load: larger stack offsets", .{});
3074 _ = try self.addInst(.{
3075 .tag = .sub_immediate,
3076 .data = .{ .rr_imm12_sh = .{
3077 .rd = src_reg,
3078 .rn = .x29,
3079 .imm12 = src_offset,
3080 } },
3081 });
3175 switch (mcv) {
3176 .stack_offset => |off| {
3177 // sub src_reg, fp, #off
3178 const adj_src_offset = off + abi_size;
3179 const src_offset = math.cast(u12, adj_src_offset) catch return self.fail("TODO load: larger stack offsets", .{});
3180 _ = try self.addInst(.{
3181 .tag = .sub_immediate,
3182 .data = .{ .rr_imm12_sh = .{
3183 .rd = src_reg,
3184 .rn = .x29,
3185 .imm12 = src_offset,
3186 } },
3187 });
3188 },
3189 .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = addr }),
3190 else => unreachable,
3191 }
30823192
30833193 // sub dst_reg, fp, #stack_offset
30843194 const adj_dst_off = stack_offset + abi_size;
......@@ -3105,7 +3215,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
31053215fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
31063216 switch (mcv) {
31073217 .dead => unreachable,
3108 .ptr_stack_offset => unreachable,
31093218 .ptr_embedded_in_code => unreachable,
31103219 .unreach, .none => return, // Nothing to do.
31113220 .undef => {
......@@ -3118,6 +3227,24 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
31183227 else => unreachable, // unexpected register size
31193228 }
31203229 },
3230 .ptr_stack_offset => |unadjusted_off| {
3231 // TODO: maybe addressing from sp instead of fp
3232 const elem_ty = ty.childType();
3233 const abi_size = elem_ty.abiSize(self.target.*);
3234 const adj_off = unadjusted_off + abi_size;
3235
3236 const imm12 = math.cast(u12, adj_off) catch
3237 return self.fail("TODO larger stack offsets", .{});
3238
3239 _ = try self.addInst(.{
3240 .tag = .sub_immediate,
3241 .data = .{ .rr_imm12_sh = .{
3242 .rd = reg,
3243 .rn = .x29,
3244 .imm12 = imm12,
3245 } },
3246 });
3247 },
31213248 .compare_flags_unsigned,
31223249 .compare_flags_signed,
31233250 => |op| {
src/arch/aarch64/Emit.zig+2-2
......@@ -909,7 +909,7 @@ fn mirPushPopRegs(emit: *Emit, inst: Mir.Inst.Index) !void {
909909 var other_reg: Register = undefined;
910910 while (i > 0) : (i -= 1) {
911911 const reg = @intToEnum(Register, i - 1);
912 if (reg_list & @as(u32, 1) << reg.id() != 0) {
912 if (reg_list & @as(u32, 1) << @intCast(u5, reg.id()) != 0) {
913913 if (count % 2 == 0) {
914914 if (count == number_of_regs - 1) {
915915 try emit.writeInstruction(Instruction.ldr(
......@@ -939,7 +939,7 @@ fn mirPushPopRegs(emit: *Emit, inst: Mir.Inst.Index) !void {
939939 var other_reg: Register = undefined;
940940 while (i < 32) : (i += 1) {
941941 const reg = @intToEnum(Register, i);
942 if (reg_list & @as(u32, 1) << reg.id() != 0) {
942 if (reg_list & @as(u32, 1) << @intCast(u5, reg.id()) != 0) {
943943 if (count % 2 == 0) {
944944 if (count == number_of_regs - 1) {
945945 try emit.writeInstruction(Instruction.str(
src/arch/aarch64/bits.zig+79-51
......@@ -7,7 +7,7 @@ const testing = std.testing;
77// zig fmt: off
88
99/// General purpose registers in the AArch64 instruction set
10pub const Register = enum(u6) {
10pub const Register = enum(u7) {
1111 // 64-bit registers
1212 x0, x1, x2, x3, x4, x5, x6, x7,
1313 x8, x9, x10, x11, x12, x13, x14, x15,
......@@ -20,10 +20,23 @@ pub const Register = enum(u6) {
2020 w16, w17, w18, w19, w20, w21, w22, w23,
2121 w24, w25, w26, w27, w28, w29, w30, wzr,
2222
23 pub const sp = Register.xzr;
23 // Stack pointer
24 sp, wsp,
2425
25 pub fn id(self: Register) u5 {
26 return @truncate(u5, @enumToInt(self));
26 pub fn id(self: Register) u6 {
27 return switch (@enumToInt(self)) {
28 0...63 => return @as(u6, @truncate(u5, @enumToInt(self))),
29 64...65 => 32,
30 else => unreachable,
31 };
32 }
33
34 pub fn enc(self: Register) u5 {
35 return switch (@enumToInt(self)) {
36 0...63 => return @truncate(u5, @enumToInt(self)),
37 64...65 => 31,
38 else => unreachable,
39 };
2740 }
2841
2942 /// Returns the bit-width of the register.
......@@ -31,17 +44,32 @@ pub const Register = enum(u6) {
3144 return switch (@enumToInt(self)) {
3245 0...31 => 64,
3346 32...63 => 32,
47 64 => 64,
48 65 => 32,
49 else => unreachable,
3450 };
3551 }
3652
3753 /// Convert from any register to its 64 bit alias.
3854 pub fn to64(self: Register) Register {
39 return @intToEnum(Register, self.id());
55 return switch (@enumToInt(self)) {
56 0...31 => self,
57 32...63 => @intToEnum(Register, @enumToInt(self) - 32),
58 64 => .sp,
59 65 => .sp,
60 else => unreachable,
61 };
4062 }
4163
4264 /// Convert from any register to its 32 bit alias.
4365 pub fn to32(self: Register) Register {
44 return @intToEnum(Register, @as(u6, self.id()) + 32);
66 return switch (@enumToInt(self)) {
67 0...31 => @intToEnum(Register, @enumToInt(self) + 32),
68 32...63 => self,
69 64 => .wsp,
70 65 => .wsp,
71 else => unreachable,
72 };
4573 }
4674
4775 /// Returns the index into `callee_preserved_regs`.
......@@ -53,7 +81,7 @@ pub const Register = enum(u6) {
5381 }
5482
5583 pub fn dwarfLocOp(self: Register) u8 {
56 return @as(u8, self.id()) + DW.OP.reg0;
84 return @as(u8, self.enc()) + DW.OP.reg0;
5785 }
5886};
5987
......@@ -76,15 +104,15 @@ pub const callee_preserved_regs = callee_preserved_regs_impl.callee_preserved_re
76104pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
77105pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
78106
79test "Register.id" {
80 try testing.expectEqual(@as(u5, 0), Register.x0.id());
81 try testing.expectEqual(@as(u5, 0), Register.w0.id());
107test "Register.enc" {
108 try testing.expectEqual(@as(u5, 0), Register.x0.enc());
109 try testing.expectEqual(@as(u5, 0), Register.w0.enc());
82110
83 try testing.expectEqual(@as(u5, 31), Register.xzr.id());
84 try testing.expectEqual(@as(u5, 31), Register.wzr.id());
111 try testing.expectEqual(@as(u5, 31), Register.xzr.enc());
112 try testing.expectEqual(@as(u5, 31), Register.wzr.enc());
85113
86 try testing.expectEqual(@as(u5, 31), Register.sp.id());
87 try testing.expectEqual(@as(u5, 31), Register.sp.id());
114 try testing.expectEqual(@as(u5, 31), Register.sp.enc());
115 try testing.expectEqual(@as(u5, 31), Register.sp.enc());
88116}
89117
90118test "Register.size" {
......@@ -479,7 +507,7 @@ pub const Instruction = union(enum) {
479507 assert(shift % 16 == 0 and shift <= 16);
480508 return Instruction{
481509 .move_wide_immediate = .{
482 .rd = rd.id(),
510 .rd = rd.enc(),
483511 .imm16 = imm16,
484512 .hw = @intCast(u2, shift / 16),
485513 .opc = opc,
......@@ -491,7 +519,7 @@ pub const Instruction = union(enum) {
491519 assert(shift % 16 == 0 and shift <= 48);
492520 return Instruction{
493521 .move_wide_immediate = .{
494 .rd = rd.id(),
522 .rd = rd.enc(),
495523 .imm16 = imm16,
496524 .hw = @intCast(u2, shift / 16),
497525 .opc = opc,
......@@ -508,7 +536,7 @@ pub const Instruction = union(enum) {
508536 const imm21_u = @bitCast(u21, imm21);
509537 return Instruction{
510538 .pc_relative_address = .{
511 .rd = rd.id(),
539 .rd = rd.enc(),
512540 .immlo = @truncate(u2, imm21_u),
513541 .immhi = @truncate(u19, imm21_u >> 2),
514542 .op = op,
......@@ -580,7 +608,7 @@ pub const Instruction = union(enum) {
580608 pub fn reg(rm: Register) LoadStoreOffset {
581609 return .{
582610 .register = .{
583 .rm = rm.id(),
611 .rm = rm.enc(),
584612 .shift = .{
585613 .lsl = 0,
586614 },
......@@ -592,7 +620,7 @@ pub const Instruction = union(enum) {
592620 assert(rm.size() == 32 and (shift == 0 or shift == 2));
593621 return .{
594622 .register = .{
595 .rm = rm.id(),
623 .rm = rm.enc(),
596624 .shift = .{
597625 .uxtw = shift,
598626 },
......@@ -604,7 +632,7 @@ pub const Instruction = union(enum) {
604632 assert(rm.size() == 64 and (shift == 0 or shift == 3));
605633 return .{
606634 .register = .{
607 .rm = rm.id(),
635 .rm = rm.enc(),
608636 .shift = .{
609637 .lsl = shift,
610638 },
......@@ -616,7 +644,7 @@ pub const Instruction = union(enum) {
616644 assert(rm.size() == 32 and (shift == 0 or shift == 2));
617645 return .{
618646 .register = .{
619 .rm = rm.id(),
647 .rm = rm.enc(),
620648 .shift = .{
621649 .sxtw = shift,
622650 },
......@@ -628,7 +656,7 @@ pub const Instruction = union(enum) {
628656 assert(rm.size() == 64 and (shift == 0 or shift == 3));
629657 return .{
630658 .register = .{
631 .rm = rm.id(),
659 .rm = rm.enc(),
632660 .shift = .{
633661 .sxtx = shift,
634662 },
......@@ -676,8 +704,8 @@ pub const Instruction = union(enum) {
676704 };
677705 return Instruction{
678706 .load_store_register = .{
679 .rt = rt.id(),
680 .rn = rn.id(),
707 .rt = rt.enc(),
708 .rn = rn.enc(),
681709 .offset = off,
682710 .opc = opc,
683711 .op1 = op1,
......@@ -711,9 +739,9 @@ pub const Instruction = union(enum) {
711739 const imm7 = @truncate(u7, @bitCast(u9, offset >> 2));
712740 return Instruction{
713741 .load_store_register_pair = .{
714 .rt1 = rt1.id(),
715 .rn = rn.id(),
716 .rt2 = rt2.id(),
742 .rt1 = rt1.enc(),
743 .rn = rn.enc(),
744 .rt2 = rt2.enc(),
717745 .imm7 = imm7,
718746 .load = @boolToInt(load),
719747 .encoding = encoding,
......@@ -726,9 +754,9 @@ pub const Instruction = union(enum) {
726754 const imm7 = @truncate(u7, @bitCast(u9, offset >> 3));
727755 return Instruction{
728756 .load_store_register_pair = .{
729 .rt1 = rt1.id(),
730 .rn = rn.id(),
731 .rt2 = rt2.id(),
757 .rt1 = rt1.enc(),
758 .rn = rn.enc(),
759 .rt2 = rt2.enc(),
732760 .imm7 = imm7,
733761 .load = @boolToInt(load),
734762 .encoding = encoding,
......@@ -743,7 +771,7 @@ pub const Instruction = union(enum) {
743771 fn loadLiteral(rt: Register, imm19: u19) Instruction {
744772 return Instruction{
745773 .load_literal = .{
746 .rt = rt.id(),
774 .rt = rt.enc(),
747775 .imm19 = imm19,
748776 .opc = switch (rt.size()) {
749777 32 => 0b00,
......@@ -782,7 +810,7 @@ pub const Instruction = union(enum) {
782810 return Instruction{
783811 .unconditional_branch_register = .{
784812 .op4 = op4,
785 .rn = rn.id(),
813 .rn = rn.enc(),
786814 .op3 = op3,
787815 .op2 = op2,
788816 .opc = opc,
......@@ -818,10 +846,10 @@ pub const Instruction = union(enum) {
818846 assert(amount < 32);
819847 return Instruction{
820848 .logical_shifted_register = .{
821 .rd = rd.id(),
822 .rn = rn.id(),
849 .rd = rd.enc(),
850 .rn = rn.enc(),
823851 .imm6 = amount,
824 .rm = rm.id(),
852 .rm = rm.enc(),
825853 .n = n,
826854 .shift = @enumToInt(shift),
827855 .opc = opc,
......@@ -832,10 +860,10 @@ pub const Instruction = union(enum) {
832860 64 => {
833861 return Instruction{
834862 .logical_shifted_register = .{
835 .rd = rd.id(),
836 .rn = rn.id(),
863 .rd = rd.enc(),
864 .rn = rn.enc(),
837865 .imm6 = amount,
838 .rm = rm.id(),
866 .rm = rm.enc(),
839867 .n = n,
840868 .shift = @enumToInt(shift),
841869 .opc = opc,
......@@ -857,8 +885,8 @@ pub const Instruction = union(enum) {
857885 ) Instruction {
858886 return Instruction{
859887 .add_subtract_immediate = .{
860 .rd = rd.id(),
861 .rn = rn.id(),
888 .rd = rd.enc(),
889 .rn = rn.enc(),
862890 .imm12 = imm12,
863891 .sh = @boolToInt(shift),
864892 .s = s,
......@@ -885,10 +913,10 @@ pub const Instruction = union(enum) {
885913 ) Instruction {
886914 return Instruction{
887915 .add_subtract_shifted_register = .{
888 .rd = rd.id(),
889 .rn = rn.id(),
916 .rd = rd.enc(),
917 .rn = rn.enc(),
890918 .imm6 = imm6,
891 .rm = rm.id(),
919 .rm = rm.enc(),
892920 .shift = @enumToInt(shift),
893921 .s = s,
894922 .op = op,
......@@ -926,7 +954,7 @@ pub const Instruction = union(enum) {
926954 assert(offset & 0b11 == 0b00);
927955 return Instruction{
928956 .compare_and_branch = .{
929 .rt = rt.id(),
957 .rt = rt.enc(),
930958 .imm19 = @bitCast(u19, @intCast(i19, offset >> 2)),
931959 .op = op,
932960 .sf = switch (rt.size()) {
......@@ -949,11 +977,11 @@ pub const Instruction = union(enum) {
949977 ) Instruction {
950978 return Instruction{
951979 .conditional_select = .{
952 .rd = rd.id(),
953 .rn = rn.id(),
980 .rd = rd.enc(),
981 .rn = rn.enc(),
954982 .op2 = op2,
955983 .cond = @enumToInt(cond),
956 .rm = rm.id(),
984 .rm = rm.enc(),
957985 .s = s,
958986 .op = op,
959987 .sf = switch (rd.size()) {
......@@ -976,11 +1004,11 @@ pub const Instruction = union(enum) {
9761004 ) Instruction {
9771005 return Instruction{
9781006 .data_processing_3_source = .{
979 .rd = rd.id(),
980 .rn = rn.id(),
981 .ra = ra.id(),
1007 .rd = rd.enc(),
1008 .rn = rn.enc(),
1009 .ra = ra.enc(),
9821010 .o0 = o0,
983 .rm = rm.id(),
1011 .rm = rm.enc(),
9841012 .op31 = op31,
9851013 .op54 = op54,
9861014 .sf = switch (rd.size()) {
test/behavior/align.zig+1-3
......@@ -27,7 +27,6 @@ test "default alignment allows unspecified in type syntax" {
2727}
2828
2929test "implicitly decreasing pointer alignment" {
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3130 const a: u32 align(4) = 3;
3231 const b: u32 align(8) = 4;
3332 try expect(addUnaligned(&a, &b) == 7);
......@@ -38,7 +37,6 @@ fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 {
3837}
3938
4039test "@alignCast pointers" {
41 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4240 var x: u32 align(4) = 1;
4341 expectsOnly1(&x);
4442 try expect(x == 2);
......@@ -313,7 +311,7 @@ fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) !void {
313311}
314312
315313test "alignment of function with c calling convention" {
316 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
314 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
317315 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
318316
319317 var runtime_nothing = &nothing;
test/behavior/basic.zig+3-4
......@@ -48,7 +48,7 @@ const g1: i32 = 1233 + 1;
4848var g2: i32 = 0;
4949
5050test "global variables" {
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
51 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
5252 try expect(g2 == 0);
5353 g2 = g1;
5454 try expect(g2 == 1234);
......@@ -327,7 +327,6 @@ const FnPtrWrapper = struct {
327327};
328328
329329test "const ptr from var variable" {
330 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
331330 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
332331
333332 var x: u64 = undefined;
......@@ -611,7 +610,7 @@ test "comptime cast fn to ptr" {
611610}
612611
613612test "equality compare fn ptrs" {
614 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
613 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
615614 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
616615
617616 var a = &emptyFn;
......@@ -619,7 +618,7 @@ test "equality compare fn ptrs" {
619618}
620619
621620test "self reference through fn ptr field" {
622 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
621 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
623622 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
624623 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
625624
test/behavior/bitreverse.zig-1
......@@ -8,7 +8,6 @@ test "@bitReverse large exotic integer" {
88 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
99 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1010 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1211 // Currently failing on stage1 for big-endian targets
1312 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1413
test/behavior/bugs/1486.zig+1-1
......@@ -6,7 +6,7 @@ const ptr = &global;
66var global: usize = 123;
77
88test "constant pointer to global variable causes runtime load" {
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
1010 global = 1234;
1111 try expect(&global == ptr);
1212 try expect(ptr.* == 1234);
test/behavior/bugs/2006.zig+1-1
......@@ -6,7 +6,7 @@ const S = struct {
66 p: *S,
77};
88test "bug 2006" {
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
1010 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1111 var a: S = undefined;
1212 a = S{ .p = undefined };
test/behavior/cast.zig+1-2
......@@ -211,7 +211,6 @@ test "implicit cast from *[N]T to [*c]T" {
211211}
212212
213213test "*usize to *void" {
214 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
215214 var i = @as(usize, 0);
216215 var v = @ptrCast(*void, &i);
217216 v.* = {};
......@@ -1014,7 +1013,7 @@ test "cast from array reference to fn: comptime fn ptr" {
10141013 try expect(@ptrToInt(f) == @ptrToInt(&global_array));
10151014}
10161015test "cast from array reference to fn: runtime fn ptr" {
1017 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1016 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
10181017 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
10191018 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10201019 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
test/behavior/optional.zig-1
......@@ -36,7 +36,6 @@ test "optional pointer to size zero struct" {
3636}
3737
3838test "equality compare optional pointers" {
39 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4039 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4140 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
4241
test/behavior/slice.zig+1-1
......@@ -81,7 +81,7 @@ fn assertLenIsZero(msg: []const u8) !void {
8181}
8282
8383test "access len index of sentinel-terminated slice" {
84 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
84 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
8585 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
8686
8787 const S = struct {
test/behavior/struct.zig+1-3
......@@ -43,7 +43,6 @@ const StructWithFields = struct {
4343};
4444
4545test "non-packed struct has fields padded out to the required alignment" {
46 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4746 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
4847
4948 const foo = StructWithFields{ .a = 5, .b = 1, .c = 10, .d = 2 };
......@@ -67,7 +66,7 @@ const SmallStruct = struct {
6766};
6867
6968test "lower unnamed constants" {
70 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
69 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
7170 var foo = SmallStruct{ .a = 1, .b = 255 };
7271 try expect(foo.first() == 1);
7372 try expect(foo.second() == 255);
......@@ -186,7 +185,6 @@ test "store member function in variable" {
186185}
187186
188187test "member functions" {
189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
190188 const r = MemberFnRand{ .seed = 1234 };
191189 try expect(r.getSeed() == 1234);
192190}