authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-02-26 10:23:25+01:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-02-26 13:00:01+01:00
logf48f4baf676061742adb9674bc5e43e82c63f96a
tree046a8c7ce6342b6bb929f0b5655efcfcddc66a4f
parent8ef80cfaab2a74506d7b3a866dc066d9cd281f55
signaturelock-open Commit is signed but in an unrecognized format.

stage2 ARM: generate correct variants of ldr instruction

When loading an i16 for example, generate ldrsh instead of ldrh

6 files changed, 155 insertions(+), 124 deletions(-)

src/arch/arm/CodeGen.zig+110-105
...@@ -1575,7 +1575,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -1575,7 +1575,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
1575 .compare_flags_signed, .compare_flags_unsigned => unreachable,1575 .compare_flags_signed, .compare_flags_unsigned => unreachable,
1576 .embedded_in_code => unreachable,1576 .embedded_in_code => unreachable,
1577 .register => |dst_reg| {1577 .register => |dst_reg| {
1578 try self.genLdrRegister(dst_reg, reg, elem_size);1578 try self.genLdrRegister(dst_reg, reg, elem_ty);
1579 },1579 },
1580 .stack_offset => |off| {1580 .stack_offset => |off| {
1581 if (elem_size <= 4) {1581 if (elem_size <= 4) {
...@@ -1676,7 +1676,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -1676,7 +1676,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
16761676
1677 switch (value) {1677 switch (value) {
1678 .register => |value_reg| {1678 .register => |value_reg| {
1679 try self.genStrRegister(value_reg, addr_reg, @intCast(u32, value_ty.abiSize(self.target.*)));1679 try self.genStrRegister(value_reg, addr_reg, value_ty);
1680 },1680 },
1681 else => {1681 else => {
1682 if (value_ty.abiSize(self.target.*) <= 4) {1682 if (value_ty.abiSize(self.target.*) <= 4) {
...@@ -2241,68 +2241,71 @@ fn binOp(...@@ -2241,68 +2241,71 @@ fn binOp(
2241 }2241 }
2242}2242}
22432243
2244fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, abi_size: u32) !void {2244fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) !void {
2245 switch (abi_size) {2245 const abi_size = ty.abiSize(self.target.*);
2246 1, 3, 4 => {
2247 const tag: Mir.Inst.Tag = switch (abi_size) {
2248 1 => .ldrb,
2249 3, 4 => .ldr,
2250 else => unreachable,
2251 };
22522246
2253 _ = try self.addInst(.{2247 const tag: Mir.Inst.Tag = switch (abi_size) {
2254 .tag = tag,2248 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb else .ldrb,
2255 .data = .{ .rr_offset = .{2249 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh else .ldrh,
2256 .rt = dest_reg,2250 3, 4 => .ldr,
2257 .rn = addr_reg,2251 else => unreachable,
2258 .offset = .{ .offset = Instruction.Offset.none },2252 };
2259 } },2253
2260 });2254 const rr_offset: Mir.Inst.Data = .{ .rr_offset = .{
2261 },2255 .rt = dest_reg,
2262 2 => {2256 .rn = addr_reg,
2263 _ = try self.addInst(.{2257 .offset = .{ .offset = Instruction.Offset.none },
2264 .tag = .ldrh,2258 } };
2265 .data = .{ .rr_extra_offset = .{2259 const rr_extra_offset: Mir.Inst.Data = .{ .rr_extra_offset = .{
2266 .rt = dest_reg,2260 .rt = dest_reg,
2267 .rn = addr_reg,2261 .rn = addr_reg,
2268 .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },2262 .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },
2269 } },2263 } };
2270 });2264
2271 },2265 const data: Mir.Inst.Data = switch (abi_size) {
2272 else => unreachable, // invalid abi_size for a register2266 1 => if (ty.isSignedInt()) rr_extra_offset else rr_offset,
2273 }2267 2 => rr_extra_offset,
2268 3, 4 => rr_offset,
2269 else => unreachable,
2270 };
2271
2272 _ = try self.addInst(.{
2273 .tag = tag,
2274 .data = data,
2275 });
2274}2276}
22752277
2276fn genStrRegister(self: *Self, source_reg: Register, addr_reg: Register, abi_size: u32) !void {2278fn genStrRegister(self: *Self, source_reg: Register, addr_reg: Register, ty: Type) !void {
2277 switch (abi_size) {2279 const abi_size = ty.abiSize(self.target.*);
2278 1, 3, 4 => {
2279 const tag: Mir.Inst.Tag = switch (abi_size) {
2280 1 => .strb,
2281 3, 4 => .str,
2282 else => unreachable,
2283 };
22842280
2285 _ = try self.addInst(.{2281 const tag: Mir.Inst.Tag = switch (abi_size) {
2286 .tag = tag,2282 1 => .strb,
2287 .data = .{ .rr_offset = .{2283 2 => .strh,
2288 .rt = source_reg,2284 3, 4 => .str,
2289 .rn = addr_reg,2285 else => unreachable,
2290 .offset = .{ .offset = Instruction.Offset.none },2286 };
2291 } },2287
2292 });2288 const rr_offset: Mir.Inst.Data = .{ .rr_offset = .{
2293 },2289 .rt = source_reg,
2294 2 => {2290 .rn = addr_reg,
2295 _ = try self.addInst(.{2291 .offset = .{ .offset = Instruction.Offset.none },
2296 .tag = .strh,2292 } };
2297 .data = .{ .rr_extra_offset = .{2293 const rr_extra_offset: Mir.Inst.Data = .{ .rr_extra_offset = .{
2298 .rt = source_reg,2294 .rt = source_reg,
2299 .rn = addr_reg,2295 .rn = addr_reg,
2300 .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },2296 .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },
2301 } },2297 } };
2302 });2298
2303 },2299 const data: Mir.Inst.Data = switch (abi_size) {
2304 else => unreachable, // invalid abi_size for a register2300 1, 3, 4 => rr_offset,
2305 }2301 2 => rr_extra_offset,
2302 else => unreachable,
2303 };
2304
2305 _ = try self.addInst(.{
2306 .tag = tag,
2307 .data = data,
2308 });
2306}2309}
23072310
2308fn genInlineMemcpy(2311fn genInlineMemcpy(
...@@ -2895,8 +2898,6 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {...@@ -2895,8 +2898,6 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
2895}2898}
28962899
2897fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {2900fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
2898 _ = operand;
2899
2900 const error_type = ty.errorUnionSet();2901 const error_type = ty.errorUnionSet();
2901 const payload_type = ty.errorUnionPayload();2902 const payload_type = ty.errorUnionPayload();
29022903
...@@ -3630,55 +3631,59 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -3630,55 +3631,59 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
3630 // The value is in memory at a hard-coded address.3631 // The value is in memory at a hard-coded address.
3631 // If the type is a pointer, it means the pointer address is at this memory location.3632 // If the type is a pointer, it means the pointer address is at this memory location.
3632 try self.genSetReg(ty, reg, .{ .immediate = @intCast(u32, addr) });3633 try self.genSetReg(ty, reg, .{ .immediate = @intCast(u32, addr) });
3633 try self.genLdrRegister(reg, reg, @intCast(u32, ty.abiSize(self.target.*)));3634 try self.genLdrRegister(reg, reg, ty);
3634 },3635 },
3635 .stack_offset => |unadjusted_off| {3636 .stack_offset => |unadjusted_off| {
3636 // TODO: maybe addressing from sp instead of fp3637 // TODO: maybe addressing from sp instead of fp
3637 const abi_size = @intCast(u32, ty.abiSize(self.target.*));3638 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
3638 const adj_off = unadjusted_off + abi_size;3639 const adj_off = unadjusted_off + abi_size;
36393640
3640 switch (abi_size) {3641 const tag: Mir.Inst.Tag = switch (abi_size) {
3641 1, 4 => {3642 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb else .ldrb,
3642 const offset = if (adj_off <= math.maxInt(u12)) blk: {3643 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh else .ldrh,
3643 break :blk Instruction.Offset.imm(@intCast(u12, adj_off));3644 3, 4 => .ldr,
3644 } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), .none);3645 else => unreachable,
3646 };
36453647
3646 const tag: Mir.Inst.Tag = switch (abi_size) {3648 const extra_offset = switch (abi_size) {
3647 1 => .ldrb,3649 1 => ty.isSignedInt(),
3648 4 => .ldr,3650 2 => true,
3649 else => unreachable,3651 3, 4 => false,
3650 };3652 else => unreachable,
3653 };
36513654
3652 _ = try self.addInst(.{3655 if (extra_offset) {
3653 .tag = tag,3656 const offset = if (adj_off <= math.maxInt(u8)) blk: {
3654 .data = .{ .rr_offset = .{3657 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
3655 .rt = reg,3658 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }));
3656 .rn = .fp,
3657 .offset = .{
3658 .offset = offset,
3659 .positive = false,
3660 },
3661 } },
3662 });
3663 },
3664 2 => {
3665 const offset = if (adj_off <= math.maxInt(u8)) blk: {
3666 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
3667 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }));
36683659
3669 _ = try self.addInst(.{3660 _ = try self.addInst(.{
3670 .tag = .ldrh,3661 .tag = tag,
3671 .data = .{ .rr_extra_offset = .{3662 .data = .{ .rr_extra_offset = .{
3672 .rt = reg,3663 .rt = reg,
3673 .rn = .fp,3664 .rn = .fp,
3674 .offset = .{3665 .offset = .{
3675 .offset = offset,3666 .offset = offset,
3676 .positive = false,3667 .positive = false,
3677 },3668 },
3678 } },3669 } },
3679 });3670 });
3680 },3671 } else {
3681 else => return self.fail("TODO a type of size {} is not allowed in a register", .{abi_size}),3672 const offset = if (adj_off <= math.maxInt(u12)) blk: {
3673 break :blk Instruction.Offset.imm(@intCast(u12, adj_off));
3674 } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), .none);
3675
3676 _ = try self.addInst(.{
3677 .tag = tag,
3678 .data = .{ .rr_offset = .{
3679 .rt = reg,
3680 .rn = .fp,
3681 .offset = .{
3682 .offset = offset,
3683 .positive = false,
3684 },
3685 } },
3686 });
3682 }3687 }
3683 },3688 },
3684 .stack_argument_offset => |unadjusted_off| {3689 .stack_argument_offset => |unadjusted_off| {
...@@ -3686,9 +3691,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -3686,9 +3691,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
3686 const adj_off = unadjusted_off + abi_size;3691 const adj_off = unadjusted_off + abi_size;
36873692
3688 const tag: Mir.Inst.Tag = switch (abi_size) {3693 const tag: Mir.Inst.Tag = switch (abi_size) {
3689 1 => .ldrb_stack_argument,3694 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_stack_argument else .ldrb_stack_argument,
3690 2 => .ldrh_stack_argument,3695 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_stack_argument else .ldrh_stack_argument,
3691 4 => .ldr_stack_argument,3696 3, 4 => .ldr_stack_argument,
3692 else => unreachable,3697 else => unreachable,
3693 };3698 };
36943699
src/arch/arm/Emit.zig+27-15
...@@ -115,8 +115,12 @@ pub fn emitMir(...@@ -115,8 +115,12 @@ pub fn emitMir(
115 .ldr_stack_argument => try emit.mirLoadStackArgument(inst),115 .ldr_stack_argument => try emit.mirLoadStackArgument(inst),
116 .ldrb_stack_argument => try emit.mirLoadStackArgument(inst),116 .ldrb_stack_argument => try emit.mirLoadStackArgument(inst),
117 .ldrh_stack_argument => try emit.mirLoadStackArgument(inst),117 .ldrh_stack_argument => try emit.mirLoadStackArgument(inst),
118 .ldrsb_stack_argument => try emit.mirLoadStackArgument(inst),
119 .ldrsh_stack_argument => try emit.mirLoadStackArgument(inst),
118120
119 .ldrh => try emit.mirLoadStoreExtra(inst),121 .ldrh => try emit.mirLoadStoreExtra(inst),
122 .ldrsb => try emit.mirLoadStore(inst),
123 .ldrsh => try emit.mirLoadStoreExtra(inst),
120 .strh => try emit.mirLoadStoreExtra(inst),124 .strh => try emit.mirLoadStoreExtra(inst),
121125
122 .movw => try emit.mirSpecialMove(inst),126 .movw => try emit.mirSpecialMove(inst),
...@@ -593,36 +597,42 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -593,36 +597,42 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
593597
594 const raw_offset = emit.prologue_stack_space - r_stack_offset.stack_offset;598 const raw_offset = emit.prologue_stack_space - r_stack_offset.stack_offset;
595 switch (tag) {599 switch (tag) {
596 .ldr_stack_argument => {600 .ldr_stack_argument,
601 .ldrb_stack_argument,
602 => {
597 const offset = if (raw_offset <= math.maxInt(u12)) blk: {603 const offset = if (raw_offset <= math.maxInt(u12)) blk: {
598 break :blk Instruction.Offset.imm(@intCast(u12, raw_offset));604 break :blk Instruction.Offset.imm(@intCast(u12, raw_offset));
599 } else return emit.fail("TODO mirLoadStack larger offsets", .{});605 } else return emit.fail("TODO mirLoadStack larger offsets", .{});
600606
601 try emit.writeInstruction(Instruction.ldr(607 const ldr = switch (tag) {
602 cond,608 .ldr_stack_argument => Instruction.ldr,
603 r_stack_offset.rt,609 .ldrb_stack_argument => Instruction.ldrb,
604 .fp,610 else => unreachable,
605 .{ .offset = offset },611 };
606 ));
607 },
608 .ldrb_stack_argument => {
609 const offset = if (raw_offset <= math.maxInt(u12)) blk: {
610 break :blk Instruction.Offset.imm(@intCast(u12, raw_offset));
611 } else return emit.fail("TODO mirLoadStack larger offsets", .{});
612612
613 try emit.writeInstruction(Instruction.ldrb(613 try emit.writeInstruction(ldr(
614 cond,614 cond,
615 r_stack_offset.rt,615 r_stack_offset.rt,
616 .fp,616 .fp,
617 .{ .offset = offset },617 .{ .offset = offset },
618 ));618 ));
619 },619 },
620 .ldrh_stack_argument => {620 .ldrh_stack_argument,
621 .ldrsb_stack_argument,
622 .ldrsh_stack_argument,
623 => {
621 const offset = if (raw_offset <= math.maxInt(u8)) blk: {624 const offset = if (raw_offset <= math.maxInt(u8)) blk: {
622 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, raw_offset));625 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, raw_offset));
623 } else return emit.fail("TODO mirLoadStack larger offsets", .{});626 } else return emit.fail("TODO mirLoadStack larger offsets", .{});
624627
625 try emit.writeInstruction(Instruction.ldrh(628 const ldr = switch (tag) {
629 .ldrh_stack_argument => Instruction.ldrh,
630 .ldrsb_stack_argument => Instruction.ldrsb,
631 .ldrsh_stack_argument => Instruction.ldrsh,
632 else => unreachable,
633 };
634
635 try emit.writeInstruction(ldr(
626 cond,636 cond,
627 r_stack_offset.rt,637 r_stack_offset.rt,
628 .fp,638 .fp,
...@@ -640,6 +650,8 @@ fn mirLoadStoreExtra(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -640,6 +650,8 @@ fn mirLoadStoreExtra(emit: *Emit, inst: Mir.Inst.Index) !void {
640650
641 switch (tag) {651 switch (tag) {
642 .ldrh => try emit.writeInstruction(Instruction.ldrh(cond, rr_extra_offset.rt, rr_extra_offset.rn, rr_extra_offset.offset)),652 .ldrh => try emit.writeInstruction(Instruction.ldrh(cond, rr_extra_offset.rt, rr_extra_offset.rn, rr_extra_offset.offset)),
653 .ldrsb => try emit.writeInstruction(Instruction.ldrsb(cond, rr_extra_offset.rt, rr_extra_offset.rn, rr_extra_offset.offset)),
654 .ldrsh => try emit.writeInstruction(Instruction.ldrsh(cond, rr_extra_offset.rt, rr_extra_offset.rn, rr_extra_offset.offset)),
643 .strh => try emit.writeInstruction(Instruction.strh(cond, rr_extra_offset.rt, rr_extra_offset.rn, rr_extra_offset.offset)),655 .strh => try emit.writeInstruction(Instruction.strh(cond, rr_extra_offset.rt, rr_extra_offset.rn, rr_extra_offset.offset)),
644 else => unreachable,656 else => unreachable,
645 }657 }
src/arch/arm/Mir.zig+8
...@@ -64,6 +64,14 @@ pub const Inst = struct {...@@ -64,6 +64,14 @@ pub const Inst = struct {
64 ldrh,64 ldrh,
65 /// Load Register Halfword65 /// Load Register Halfword
66 ldrh_stack_argument,66 ldrh_stack_argument,
67 /// Load Register Signed Byte
68 ldrsb,
69 /// Load Register Signed Byte
70 ldrsb_stack_argument,
71 /// Load Register Signed Halfword
72 ldrsh,
73 /// Load Register Signed Halfword
74 ldrsh_stack_argument,
67 /// Logical Shift Left75 /// Logical Shift Left
68 lsl,76 lsl,
69 /// Logical Shift Right77 /// Logical Shift Right
src/arch/arm/bits.zig+10-2
...@@ -1123,11 +1123,19 @@ pub const Instruction = union(enum) {...@@ -1123,11 +1123,19 @@ pub const Instruction = union(enum) {
1123 };1123 };
11241124
1125 pub fn strh(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction {1125 pub fn strh(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction {
1126 return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 0, 0b01, rn, rt, args.offset);1126 return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 0b0, 0b01, rn, rt, args.offset);
1127 }1127 }
11281128
1129 pub fn ldrh(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction {1129 pub fn ldrh(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction {
1130 return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 1, 0b01, rn, rt, args.offset);1130 return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 0b1, 0b01, rn, rt, args.offset);
1131 }
1132
1133 pub fn ldrsh(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction {
1134 return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 0b1, 0b11, rn, rt, args.offset);
1135 }
1136
1137 pub fn ldrsb(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction {
1138 return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 0b1, 0b10, rn, rt, args.offset);
1131 }1139 }
11321140
1133 // Block data transfer1141 // Block data transfer
test/behavior/basic.zig-1
...@@ -26,7 +26,6 @@ fn testTruncate(x: u32) u8 {...@@ -26,7 +26,6 @@ fn testTruncate(x: u32) u8 {
2626
27test "truncate to non-power-of-two integers" {27test "truncate to non-power-of-two integers" {
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
29 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3029
31 try testTrunc(u32, u1, 0b10101, 0b1);30 try testTrunc(u32, u1, 0b10101, 0b1);
32 try testTrunc(u32, u1, 0b10110, 0b0);31 try testTrunc(u32, u1, 0b10110, 0b0);
test/behavior/truncate.zig-1
...@@ -66,7 +66,6 @@ test "truncate.i0.var" {...@@ -66,7 +66,6 @@ test "truncate.i0.var" {
6666
67test "truncate on comptime integer" {67test "truncate on comptime integer" {
68 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;68 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
69 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7069
71 var x = @truncate(u16, 9999);70 var x = @truncate(u16, 9999);
72 try expect(x == 9999);71 try expect(x == 9999);