authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-04-16 23:03:11+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-04-19 22:40:48+02:00
logd9d9fea6aee7fd0f4dadb53e41f9884330229051
treeeb8197c3f6551a0dec931bcffb7fa3dad4a52aef
parentf95a8ddafa53d4cee591c82bd5ed3eb0eac4a51b
signaturelock-open Commit is signed but in an unrecognized format.

stage2 AArch64: Add ldrsb, ldrsh instructions


6 files changed, 119 insertions(+), 125 deletions(-)

src/arch/aarch64/CodeGen.zig+41-97
......@@ -2056,7 +2056,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
20562056 .undef => unreachable,
20572057 .compare_flags_signed, .compare_flags_unsigned => unreachable,
20582058 .register => |dst_reg| {
2059 try self.genLdrRegister(dst_reg, addr_reg, elem_size);
2059 try self.genLdrRegister(dst_reg, addr_reg, elem_ty);
20602060 },
20612061 .stack_offset => |off| {
20622062 if (elem_size <= 8) {
......@@ -2210,98 +2210,47 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
22102210 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
22112211}
22122212
2213fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, abi_size: u64) !void {
2214 switch (abi_size) {
2215 1 => {
2216 _ = try self.addInst(.{
2217 .tag = .ldrb_immediate,
2218 .data = .{ .load_store_register_immediate = .{
2219 .rt = value_reg.to32(),
2220 .rn = addr_reg,
2221 .offset = Instruction.LoadStoreOffset.none.immediate,
2222 } },
2223 });
2224 },
2225 2 => {
2226 _ = try self.addInst(.{
2227 .tag = .ldrh_immediate,
2228 .data = .{ .load_store_register_immediate = .{
2229 .rt = value_reg.to32(),
2230 .rn = addr_reg,
2231 .offset = Instruction.LoadStoreOffset.none.immediate,
2232 } },
2233 });
2234 },
2235 4 => {
2236 _ = try self.addInst(.{
2237 .tag = .ldr_immediate,
2238 .data = .{ .load_store_register_immediate = .{
2239 .rt = value_reg.to32(),
2240 .rn = addr_reg,
2241 .offset = Instruction.LoadStoreOffset.none.immediate,
2242 } },
2243 });
2244 },
2245 8 => {
2246 _ = try self.addInst(.{
2247 .tag = .ldr_immediate,
2248 .data = .{ .load_store_register_immediate = .{
2249 .rt = value_reg.to64(),
2250 .rn = addr_reg,
2251 .offset = Instruction.LoadStoreOffset.none.immediate,
2252 } },
2253 });
2254 },
2213fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type) !void {
2214 const abi_size = ty.abiSize(self.target.*);
2215
2216 const tag: Mir.Inst.Tag = switch (abi_size) {
2217 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_immediate else .ldrb_immediate,
2218 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_immediate else .ldrh_immediate,
2219 4 => .ldr_immediate,
2220 8 => .ldr_immediate,
22552221 3, 5, 6, 7 => return self.fail("TODO: genLdrRegister for more abi_sizes", .{}),
22562222 else => unreachable,
2257 }
2223 };
2224
2225 _ = try self.addInst(.{
2226 .tag = tag,
2227 .data = .{ .load_store_register_immediate = .{
2228 .rt = value_reg,
2229 .rn = addr_reg,
2230 .offset = Instruction.LoadStoreOffset.none.immediate,
2231 } },
2232 });
22582233}
22592234
2260fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, abi_size: u64) !void {
2261 switch (abi_size) {
2262 1 => {
2263 _ = try self.addInst(.{
2264 .tag = .strb_immediate,
2265 .data = .{ .load_store_register_immediate = .{
2266 .rt = value_reg.to32(),
2267 .rn = addr_reg,
2268 .offset = Instruction.LoadStoreOffset.none.immediate,
2269 } },
2270 });
2271 },
2272 2 => {
2273 _ = try self.addInst(.{
2274 .tag = .strh_immediate,
2275 .data = .{ .load_store_register_immediate = .{
2276 .rt = value_reg.to32(),
2277 .rn = addr_reg,
2278 .offset = Instruction.LoadStoreOffset.none.immediate,
2279 } },
2280 });
2281 },
2282 4 => {
2283 _ = try self.addInst(.{
2284 .tag = .str_immediate,
2285 .data = .{ .load_store_register_immediate = .{
2286 .rt = value_reg.to32(),
2287 .rn = addr_reg,
2288 .offset = Instruction.LoadStoreOffset.none.immediate,
2289 } },
2290 });
2291 },
2292 8 => {
2293 _ = try self.addInst(.{
2294 .tag = .str_immediate,
2295 .data = .{ .load_store_register_immediate = .{
2296 .rt = value_reg.to64(),
2297 .rn = addr_reg,
2298 .offset = Instruction.LoadStoreOffset.none.immediate,
2299 } },
2300 });
2301 },
2235fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type) !void {
2236 const abi_size = ty.abiSize(self.target.*);
2237
2238 const tag: Mir.Inst.Tag = switch (abi_size) {
2239 1 => .strb_immediate,
2240 2 => .strh_immediate,
2241 4, 8 => .str_immediate,
23022242 3, 5, 6, 7 => return self.fail("TODO: genStrRegister for more abi_sizes", .{}),
23032243 else => unreachable,
2304 }
2244 };
2245
2246 _ = try self.addInst(.{
2247 .tag = tag,
2248 .data = .{ .load_store_register_immediate = .{
2249 .rt = value_reg,
2250 .rn = addr_reg,
2251 .offset = Instruction.LoadStoreOffset.none.immediate,
2252 } },
2253 });
23052254}
23062255
23072256fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void {
......@@ -2326,7 +2275,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
23262275
23272276 switch (value) {
23282277 .register => |value_reg| {
2329 try self.genStrRegister(value_reg, addr_reg, abi_size);
2278 try self.genStrRegister(value_reg, addr_reg, value_ty);
23302279 },
23312280 else => {
23322281 if (abi_size <= 8) {
......@@ -3624,7 +3573,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
36243573 // The value is in memory at a hard-coded address.
36253574 // If the type is a pointer, it means the pointer address is at this memory location.
36263575 try self.genSetReg(ty, reg.to64(), .{ .immediate = addr });
3627 try self.genLdrRegister(reg, reg.to64(), ty.abiSize(self.target.*));
3576 try self.genLdrRegister(reg, reg.to64(), ty);
36283577 },
36293578 .stack_offset => |off| {
36303579 const abi_size = ty.abiSize(self.target.*);
......@@ -3632,21 +3581,16 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
36323581 switch (abi_size) {
36333582 1, 2, 4, 8 => {
36343583 const tag: Mir.Inst.Tag = switch (abi_size) {
3635 1 => .ldrb_stack,
3636 2 => .ldrh_stack,
3584 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_stack else .ldrb_stack,
3585 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_stack else .ldrh_stack,
36373586 4, 8 => .ldr_stack,
36383587 else => unreachable, // unexpected abi size
36393588 };
3640 const rt: Register = switch (abi_size) {
3641 1, 2, 4 => reg.to32(),
3642 8 => reg.to64(),
3643 else => unreachable, // unexpected abi size
3644 };
36453589
36463590 _ = try self.addInst(.{
36473591 .tag = tag,
36483592 .data = .{ .load_store_stack = .{
3649 .rt = rt,
3593 .rt = reg,
36503594 .offset = @intCast(u32, off),
36513595 } },
36523596 });
src/arch/aarch64/Emit.zig+12-2
......@@ -131,6 +131,8 @@ pub fn emitMir(
131131 .ldr_stack => try emit.mirLoadStoreStack(inst),
132132 .ldrb_stack => try emit.mirLoadStoreStack(inst),
133133 .ldrh_stack => try emit.mirLoadStoreStack(inst),
134 .ldrsb_stack => try emit.mirLoadStoreStack(inst),
135 .ldrsh_stack => try emit.mirLoadStoreStack(inst),
134136 .str_stack => try emit.mirLoadStoreStack(inst),
135137 .strb_stack => try emit.mirLoadStoreStack(inst),
136138 .strh_stack => try emit.mirLoadStoreStack(inst),
......@@ -145,6 +147,9 @@ pub fn emitMir(
145147 .ldr_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
146148 .ldrb_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
147149 .ldrh_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
150 .ldrsb_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
151 .ldrsh_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
152 .ldrsw_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
148153 .str_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
149154 .strb_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
150155 .strh_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
......@@ -847,14 +852,14 @@ fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void {
847852
848853 const raw_offset = emit.stack_size - load_store_stack.offset;
849854 const offset = switch (tag) {
850 .ldrb_stack, .strb_stack => blk: {
855 .ldrb_stack, .ldrsb_stack, .strb_stack => blk: {
851856 if (math.cast(u12, raw_offset)) |imm| {
852857 break :blk Instruction.LoadStoreOffset.imm(imm);
853858 } else |_| {
854859 return emit.fail("TODO load/store stack byte with larger offset", .{});
855860 }
856861 },
857 .ldrh_stack, .strh_stack => blk: {
862 .ldrh_stack, .ldrsh_stack, .strh_stack => blk: {
858863 assert(std.mem.isAlignedGeneric(u32, raw_offset, 2)); // misaligned stack entry
859864 if (math.cast(u12, @divExact(raw_offset, 2))) |imm| {
860865 break :blk Instruction.LoadStoreOffset.imm(imm);
......@@ -883,6 +888,8 @@ fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void {
883888 .ldr_stack => try emit.writeInstruction(Instruction.ldr(rt, .sp, offset)),
884889 .ldrb_stack => try emit.writeInstruction(Instruction.ldrb(rt, .sp, offset)),
885890 .ldrh_stack => try emit.writeInstruction(Instruction.ldrh(rt, .sp, offset)),
891 .ldrsb_stack => try emit.writeInstruction(Instruction.ldrsb(rt, .sp, offset)),
892 .ldrsh_stack => try emit.writeInstruction(Instruction.ldrsh(rt, .sp, offset)),
886893 .str_stack => try emit.writeInstruction(Instruction.str(rt, .sp, offset)),
887894 .strb_stack => try emit.writeInstruction(Instruction.strb(rt, .sp, offset)),
888895 .strh_stack => try emit.writeInstruction(Instruction.strh(rt, .sp, offset)),
......@@ -901,6 +908,9 @@ fn mirLoadStoreRegisterImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
901908 .ldr_immediate => try emit.writeInstruction(Instruction.ldr(rt, rn, offset)),
902909 .ldrb_immediate => try emit.writeInstruction(Instruction.ldrb(rt, rn, offset)),
903910 .ldrh_immediate => try emit.writeInstruction(Instruction.ldrh(rt, rn, offset)),
911 .ldrsb_immediate => try emit.writeInstruction(Instruction.ldrsb(rt, rn, offset)),
912 .ldrsh_immediate => try emit.writeInstruction(Instruction.ldrsh(rt, rn, offset)),
913 .ldrsw_immediate => try emit.writeInstruction(Instruction.ldrsw(rt, rn, offset)),
904914 .str_immediate => try emit.writeInstruction(Instruction.str(rt, rn, offset)),
905915 .strb_immediate => try emit.writeInstruction(Instruction.strb(rt, rn, offset)),
906916 .strh_immediate => try emit.writeInstruction(Instruction.strh(rt, rn, offset)),
src/arch/aarch64/Mir.zig+10
......@@ -100,6 +100,16 @@ pub const Inst = struct {
100100 ldrh_immediate,
101101 /// Load Register Halfword (register)
102102 ldrh_register,
103 /// Load Register Signed Byte (immediate)
104 ldrsb_immediate,
105 /// Pseudo-instruction: Load signed byte from stack
106 ldrsb_stack,
107 /// Load Register Signed Halfword (immediate)
108 ldrsh_immediate,
109 /// Pseudo-instruction: Load signed halfword from stack
110 ldrsh_stack,
111 /// Load Register Signed Word (immediate)
112 ldrsw_immediate,
103113 /// Logical Shift Left (immediate)
104114 lsl_immediate,
105115 /// Logical Shift Left (register)
src/arch/aarch64/bits.zig+56-22
......@@ -665,18 +665,24 @@ pub const Instruction = union(enum) {
665665
666666 /// Which kind of load/store to perform
667667 const LoadStoreVariant = enum {
668 /// 32-bit or 64-bit
668 /// 32 bits or 64 bits
669669 str,
670 /// 16-bit, zero-extended
671 strh,
672 /// 8-bit, zero-extended
670 /// 8 bits, zero-extended
673671 strb,
674 /// 32-bit or 64-bit
672 /// 16 bits, zero-extended
673 strh,
674 /// 32 bits or 64 bits
675675 ldr,
676 /// 16-bit, zero-extended
677 ldrh,
678 /// 8-bit, zero-extended
676 /// 8 bits, zero-extended
679677 ldrb,
678 /// 16 bits, zero-extended
679 ldrh,
680 /// 8 bits, sign extended
681 ldrsb,
682 /// 16 bits, sign extended
683 ldrsh,
684 /// 32 bits, sign extended
685 ldrsw,
680686 };
681687
682688 fn loadStoreRegister(
......@@ -689,6 +695,7 @@ pub const Instruction = union(enum) {
689695 assert(rn.id() != Register.xzr.id());
690696
691697 const off = offset.toU12();
698
692699 const op1: u2 = blk: {
693700 switch (offset) {
694701 .immediate => |imm| switch (imm) {
......@@ -699,10 +706,35 @@ pub const Instruction = union(enum) {
699706 }
700707 break :blk 0b00;
701708 };
702 const opc: u2 = switch (variant) {
703 .ldr, .ldrh, .ldrb => 0b01,
704 .str, .strh, .strb => 0b00,
709
710 const opc: u2 = blk: {
711 switch (variant) {
712 .ldr, .ldrh, .ldrb => break :blk 0b01,
713 .str, .strh, .strb => break :blk 0b00,
714 .ldrsb,
715 .ldrsh,
716 => switch (rt.size()) {
717 32 => break :blk 0b11,
718 64 => break :blk 0b10,
719 else => unreachable, // unexpected register size
720 },
721 .ldrsw => break :blk 0b10,
722 }
723 };
724
725 const size: u2 = blk: {
726 switch (variant) {
727 .ldr, .str => switch (rt.size()) {
728 32 => break :blk 0b10,
729 64 => break :blk 0b11,
730 else => unreachable, // unexpected register size
731 },
732 .ldrsw => break :blk 0b10,
733 .ldrh, .ldrsh, .strh => break :blk 0b01,
734 .ldrb, .ldrsb, .strb => break :blk 0b00,
735 }
705736 };
737
706738 return Instruction{
707739 .load_store_register = .{
708740 .rt = rt.enc(),
......@@ -711,17 +743,7 @@ pub const Instruction = union(enum) {
711743 .opc = opc,
712744 .op1 = op1,
713745 .v = 0,
714 .size = blk: {
715 switch (variant) {
716 .ldr, .str => switch (rt.size()) {
717 32 => break :blk 0b10,
718 64 => break :blk 0b11,
719 else => unreachable, // unexpected register size
720 },
721 .ldrh, .strh => break :blk 0b01,
722 .ldrb, .strb => break :blk 0b00,
723 }
724 },
746 .size = size,
725747 },
726748 };
727749 }
......@@ -1150,6 +1172,18 @@ pub const Instruction = union(enum) {
11501172 return loadStoreRegister(rt, rn, offset, .ldrb);
11511173 }
11521174
1175 pub fn ldrsb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1176 return loadStoreRegister(rt, rn, offset, .ldrsb);
1177 }
1178
1179 pub fn ldrsh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1180 return loadStoreRegister(rt, rn, offset, .ldrsh);
1181 }
1182
1183 pub fn ldrsw(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1184 return loadStoreRegister(rt, rn, offset, .ldrsw);
1185 }
1186
11531187 pub fn str(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
11541188 return loadStoreRegister(rt, rn, offset, .str);
11551189 }
test/behavior/basic.zig-2
......@@ -23,8 +23,6 @@ fn testTruncate(x: u32) u8 {
2323}
2424
2525test "truncate to non-power-of-two integers" {
26 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
27
2826 try testTrunc(u32, u1, 0b10101, 0b1);
2927 try testTrunc(u32, u1, 0b10110, 0b0);
3028 try testTrunc(u32, u2, 0b10101, 0b01);
test/behavior/truncate.zig-2
......@@ -49,8 +49,6 @@ test "truncate.i0.var" {
4949}
5050
5151test "truncate on comptime integer" {
52 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
53
5452 var x = @truncate(u16, 9999);
5553 try expect(x == 9999);
5654 var y = @truncate(u16, -21555);