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
15751575 .compare_flags_signed, .compare_flags_unsigned => unreachable,
15761576 .embedded_in_code => unreachable,
15771577 .register => |dst_reg| {
1578 try self.genLdrRegister(dst_reg, reg, elem_size);
1578 try self.genLdrRegister(dst_reg, reg, elem_ty);
15791579 },
15801580 .stack_offset => |off| {
15811581 if (elem_size <= 4) {
......@@ -1676,7 +1676,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
16761676
16771677 switch (value) {
16781678 .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);
16801680 },
16811681 else => {
16821682 if (value_ty.abiSize(self.target.*) <= 4) {
......@@ -2241,68 +2241,71 @@ fn binOp(
22412241 }
22422242}
22432243
2244fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, abi_size: u32) !void {
2245 switch (abi_size) {
2246 1, 3, 4 => {
2247 const tag: Mir.Inst.Tag = switch (abi_size) {
2248 1 => .ldrb,
2249 3, 4 => .ldr,
2250 else => unreachable,
2251 };
2244fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) !void {
2245 const abi_size = ty.abiSize(self.target.*);
22522246
2253 _ = try self.addInst(.{
2254 .tag = tag,
2255 .data = .{ .rr_offset = .{
2256 .rt = dest_reg,
2257 .rn = addr_reg,
2258 .offset = .{ .offset = Instruction.Offset.none },
2259 } },
2260 });
2261 },
2262 2 => {
2263 _ = try self.addInst(.{
2264 .tag = .ldrh,
2265 .data = .{ .rr_extra_offset = .{
2266 .rt = dest_reg,
2267 .rn = addr_reg,
2268 .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },
2269 } },
2270 });
2271 },
2272 else => unreachable, // invalid abi_size for a register
2273 }
2247 const tag: Mir.Inst.Tag = switch (abi_size) {
2248 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb else .ldrb,
2249 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh else .ldrh,
2250 3, 4 => .ldr,
2251 else => unreachable,
2252 };
2253
2254 const rr_offset: Mir.Inst.Data = .{ .rr_offset = .{
2255 .rt = dest_reg,
2256 .rn = addr_reg,
2257 .offset = .{ .offset = Instruction.Offset.none },
2258 } };
2259 const rr_extra_offset: Mir.Inst.Data = .{ .rr_extra_offset = .{
2260 .rt = dest_reg,
2261 .rn = addr_reg,
2262 .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },
2263 } };
2264
2265 const data: Mir.Inst.Data = switch (abi_size) {
2266 1 => if (ty.isSignedInt()) rr_extra_offset else rr_offset,
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 });
22742276}
22752277
2276fn genStrRegister(self: *Self, source_reg: Register, addr_reg: Register, abi_size: u32) !void {
2277 switch (abi_size) {
2278 1, 3, 4 => {
2279 const tag: Mir.Inst.Tag = switch (abi_size) {
2280 1 => .strb,
2281 3, 4 => .str,
2282 else => unreachable,
2283 };
2278fn genStrRegister(self: *Self, source_reg: Register, addr_reg: Register, ty: Type) !void {
2279 const abi_size = ty.abiSize(self.target.*);
22842280
2285 _ = try self.addInst(.{
2286 .tag = tag,
2287 .data = .{ .rr_offset = .{
2288 .rt = source_reg,
2289 .rn = addr_reg,
2290 .offset = .{ .offset = Instruction.Offset.none },
2291 } },
2292 });
2293 },
2294 2 => {
2295 _ = try self.addInst(.{
2296 .tag = .strh,
2297 .data = .{ .rr_extra_offset = .{
2298 .rt = source_reg,
2299 .rn = addr_reg,
2300 .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },
2301 } },
2302 });
2303 },
2304 else => unreachable, // invalid abi_size for a register
2305 }
2281 const tag: Mir.Inst.Tag = switch (abi_size) {
2282 1 => .strb,
2283 2 => .strh,
2284 3, 4 => .str,
2285 else => unreachable,
2286 };
2287
2288 const rr_offset: Mir.Inst.Data = .{ .rr_offset = .{
2289 .rt = source_reg,
2290 .rn = addr_reg,
2291 .offset = .{ .offset = Instruction.Offset.none },
2292 } };
2293 const rr_extra_offset: Mir.Inst.Data = .{ .rr_extra_offset = .{
2294 .rt = source_reg,
2295 .rn = addr_reg,
2296 .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },
2297 } };
2298
2299 const data: Mir.Inst.Data = switch (abi_size) {
2300 1, 3, 4 => rr_offset,
2301 2 => rr_extra_offset,
2302 else => unreachable,
2303 };
2304
2305 _ = try self.addInst(.{
2306 .tag = tag,
2307 .data = data,
2308 });
23062309}
23072310
23082311fn genInlineMemcpy(
......@@ -2895,8 +2898,6 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
28952898}
28962899
28972900fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
2898 _ = operand;
2899
29002901 const error_type = ty.errorUnionSet();
29012902 const payload_type = ty.errorUnionPayload();
29022903
......@@ -3630,55 +3631,59 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
36303631 // The value is in memory at a hard-coded address.
36313632 // If the type is a pointer, it means the pointer address is at this memory location.
36323633 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);
36343635 },
36353636 .stack_offset => |unadjusted_off| {
36363637 // TODO: maybe addressing from sp instead of fp
36373638 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
36383639 const adj_off = unadjusted_off + abi_size;
36393640
3640 switch (abi_size) {
3641 1, 4 => {
3642 const offset = if (adj_off <= math.maxInt(u12)) blk: {
3643 break :blk Instruction.Offset.imm(@intCast(u12, adj_off));
3644 } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), .none);
3641 const tag: Mir.Inst.Tag = switch (abi_size) {
3642 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb else .ldrb,
3643 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh else .ldrh,
3644 3, 4 => .ldr,
3645 else => unreachable,
3646 };
36453647
3646 const tag: Mir.Inst.Tag = switch (abi_size) {
3647 1 => .ldrb,
3648 4 => .ldr,
3649 else => unreachable,
3650 };
3648 const extra_offset = switch (abi_size) {
3649 1 => ty.isSignedInt(),
3650 2 => true,
3651 3, 4 => false,
3652 else => unreachable,
3653 };
36513654
3652 _ = try self.addInst(.{
3653 .tag = tag,
3654 .data = .{ .rr_offset = .{
3655 .rt = reg,
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 }));
3655 if (extra_offset) {
3656 const offset = if (adj_off <= math.maxInt(u8)) blk: {
3657 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
3658 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }));
36683659
3669 _ = try self.addInst(.{
3670 .tag = .ldrh,
3671 .data = .{ .rr_extra_offset = .{
3672 .rt = reg,
3673 .rn = .fp,
3674 .offset = .{
3675 .offset = offset,
3676 .positive = false,
3677 },
3678 } },
3679 });
3680 },
3681 else => return self.fail("TODO a type of size {} is not allowed in a register", .{abi_size}),
3660 _ = try self.addInst(.{
3661 .tag = tag,
3662 .data = .{ .rr_extra_offset = .{
3663 .rt = reg,
3664 .rn = .fp,
3665 .offset = .{
3666 .offset = offset,
3667 .positive = false,
3668 },
3669 } },
3670 });
3671 } else {
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 });
36823687 }
36833688 },
36843689 .stack_argument_offset => |unadjusted_off| {
......@@ -3686,9 +3691,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
36863691 const adj_off = unadjusted_off + abi_size;
36873692
36883693 const tag: Mir.Inst.Tag = switch (abi_size) {
3689 1 => .ldrb_stack_argument,
3690 2 => .ldrh_stack_argument,
3691 4 => .ldr_stack_argument,
3694 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_stack_argument else .ldrb_stack_argument,
3695 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_stack_argument else .ldrh_stack_argument,
3696 3, 4 => .ldr_stack_argument,
36923697 else => unreachable,
36933698 };
36943699
src/arch/arm/Emit.zig+27-15
......@@ -115,8 +115,12 @@ pub fn emitMir(
115115 .ldr_stack_argument => try emit.mirLoadStackArgument(inst),
116116 .ldrb_stack_argument => try emit.mirLoadStackArgument(inst),
117117 .ldrh_stack_argument => try emit.mirLoadStackArgument(inst),
118 .ldrsb_stack_argument => try emit.mirLoadStackArgument(inst),
119 .ldrsh_stack_argument => try emit.mirLoadStackArgument(inst),
118120
119121 .ldrh => try emit.mirLoadStoreExtra(inst),
122 .ldrsb => try emit.mirLoadStore(inst),
123 .ldrsh => try emit.mirLoadStoreExtra(inst),
120124 .strh => try emit.mirLoadStoreExtra(inst),
121125
122126 .movw => try emit.mirSpecialMove(inst),
......@@ -593,36 +597,42 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
593597
594598 const raw_offset = emit.prologue_stack_space - r_stack_offset.stack_offset;
595599 switch (tag) {
596 .ldr_stack_argument => {
600 .ldr_stack_argument,
601 .ldrb_stack_argument,
602 => {
597603 const offset = if (raw_offset <= math.maxInt(u12)) blk: {
598604 break :blk Instruction.Offset.imm(@intCast(u12, raw_offset));
599605 } else return emit.fail("TODO mirLoadStack larger offsets", .{});
600606
601 try emit.writeInstruction(Instruction.ldr(
602 cond,
603 r_stack_offset.rt,
604 .fp,
605 .{ .offset = offset },
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", .{});
607 const ldr = switch (tag) {
608 .ldr_stack_argument => Instruction.ldr,
609 .ldrb_stack_argument => Instruction.ldrb,
610 else => unreachable,
611 };
612612
613 try emit.writeInstruction(Instruction.ldrb(
613 try emit.writeInstruction(ldr(
614614 cond,
615615 r_stack_offset.rt,
616616 .fp,
617617 .{ .offset = offset },
618618 ));
619619 },
620 .ldrh_stack_argument => {
620 .ldrh_stack_argument,
621 .ldrsb_stack_argument,
622 .ldrsh_stack_argument,
623 => {
621624 const offset = if (raw_offset <= math.maxInt(u8)) blk: {
622625 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, raw_offset));
623626 } 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(
626636 cond,
627637 r_stack_offset.rt,
628638 .fp,
......@@ -640,6 +650,8 @@ fn mirLoadStoreExtra(emit: *Emit, inst: Mir.Inst.Index) !void {
640650
641651 switch (tag) {
642652 .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)),
643655 .strh => try emit.writeInstruction(Instruction.strh(cond, rr_extra_offset.rt, rr_extra_offset.rn, rr_extra_offset.offset)),
644656 else => unreachable,
645657 }
src/arch/arm/Mir.zig+8
......@@ -64,6 +64,14 @@ pub const Inst = struct {
6464 ldrh,
6565 /// Load Register Halfword
6666 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,
6775 /// Logical Shift Left
6876 lsl,
6977 /// Logical Shift Right
src/arch/arm/bits.zig+10-2
......@@ -1123,11 +1123,19 @@ pub const Instruction = union(enum) {
11231123 };
11241124
11251125 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);
11271127 }
11281128
11291129 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);
11311139 }
11321140
11331141 // Block data transfer
test/behavior/basic.zig-1
......@@ -26,7 +26,6 @@ fn testTruncate(x: u32) u8 {
2626
2727test "truncate to non-power-of-two integers" {
2828 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
29 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3029
3130 try testTrunc(u32, u1, 0b10101, 0b1);
3231 try testTrunc(u32, u1, 0b10110, 0b0);
test/behavior/truncate.zig-1
......@@ -66,7 +66,6 @@ test "truncate.i0.var" {
6666
6767test "truncate on comptime integer" {
6868 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
69 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7069
7170 var x = @truncate(u16, 9999);
7271 try expect(x == 9999);