authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-02-26 22:50:31+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-02-26 22:50:31+01:00
log058e482247c73ecb6404c7c1e3d2194f4aa9e059
tree3477f4e9793eda2c0e7c0be6cb431db445c473e6
parent8349a644d0b9d4b2d58d736a14cdcc567a9e9b89
parentf48f4baf676061742adb9674bc5e43e82c63f96a
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10996 from joachimschmidt557/stage2-arm

stage2 ARM: implement truncate to integers with <= 32 bits

6 files changed, 297 insertions(+), 137 deletions(-)

src/arch/arm/CodeGen.zig+175-109
...@@ -439,7 +439,7 @@ fn gen(self: *Self) !void {...@@ -439,7 +439,7 @@ fn gen(self: *Self) !void {
439 // the code. Therefore, we can just delete439 // the code. Therefore, we can just delete
440 // the space initially reserved for the440 // the space initially reserved for the
441 // jump441 // jump
442 self.mir_instructions.len -= 1;442 self.mir_instructions.orderedRemove(self.exitlude_jump_relocs.items[0]);
443 } else for (self.exitlude_jump_relocs.items) |jmp_reloc| {443 } else for (self.exitlude_jump_relocs.items) |jmp_reloc| {
444 self.mir_instructions.set(jmp_reloc, .{444 self.mir_instructions.set(jmp_reloc, .{
445 .tag = .b,445 .tag = .b,
...@@ -749,6 +749,17 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u...@@ -749,6 +749,17 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u
749/// Use a pointer instruction as the basis for allocating stack memory.749/// Use a pointer instruction as the basis for allocating stack memory.
750fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {750fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
751 const elem_ty = self.air.typeOfIndex(inst).elemType();751 const elem_ty = self.air.typeOfIndex(inst).elemType();
752
753 if (!elem_ty.hasRuntimeBits()) {
754 // As this stack item will never be dereferenced at runtime,
755 // return the current stack offset
756 try self.stack.putNoClobber(self.gpa, self.next_stack_offset, .{
757 .inst = inst,
758 .size = 0,
759 });
760 return self.next_stack_offset;
761 }
762
752 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch {763 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch {
753 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty});764 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty});
754 };765 };
...@@ -872,11 +883,61 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {...@@ -872,11 +883,61 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
872 if (self.liveness.isUnused(inst))883 if (self.liveness.isUnused(inst))
873 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });884 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
874885
886 const operand_ty = self.air.typeOf(ty_op.operand);
875 const operand = try self.resolveInst(ty_op.operand);887 const operand = try self.resolveInst(ty_op.operand);
876 _ = operand;888 const info_a = operand_ty.intInfo(self.target.*);
889 const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*);
877890
878 return self.fail("TODO implement trunc for {}", .{self.target.cpu.arch});891 const result: MCValue = blk: {
879 // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });892 if (info_b.bits <= 32) {
893 const operand_reg = switch (operand) {
894 .register => |r| r,
895 else => operand_reg: {
896 if (info_a.bits <= 32) {
897 break :operand_reg try self.copyToTmpRegister(operand_ty, operand);
898 } else {
899 return self.fail("TODO load least significant word into register", .{});
900 }
901 },
902 };
903 self.register_manager.freezeRegs(&.{operand_reg});
904 defer self.register_manager.unfreezeRegs(&.{operand_reg});
905
906 const dest_reg = dest_reg: {
907 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
908 break :dest_reg operand_reg;
909 }
910
911 break :dest_reg try self.register_manager.allocReg(null);
912 };
913
914 switch (info_b.bits) {
915 32 => {
916 try self.genSetReg(operand_ty, dest_reg, .{ .register = operand_reg });
917 break :blk MCValue{ .register = dest_reg };
918 },
919 else => {
920 _ = try self.addInst(.{
921 .tag = switch (info_b.signedness) {
922 .signed => .sbfx,
923 .unsigned => .ubfx,
924 },
925 .data = .{ .rr_lsb_width = .{
926 .rd = dest_reg,
927 .rn = operand_reg,
928 .lsb = 0,
929 .width = @intCast(u6, info_b.bits),
930 } },
931 });
932 break :blk MCValue{ .register = dest_reg };
933 },
934 }
935 } else {
936 return self.fail("TODO: truncate to ints > 32 bits", .{});
937 }
938 };
939
940 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
880}941}
881942
882fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {943fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {
...@@ -1514,7 +1575,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -1514,7 +1575,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
1514 .compare_flags_signed, .compare_flags_unsigned => unreachable,1575 .compare_flags_signed, .compare_flags_unsigned => unreachable,
1515 .embedded_in_code => unreachable,1576 .embedded_in_code => unreachable,
1516 .register => |dst_reg| {1577 .register => |dst_reg| {
1517 try self.genLdrRegister(dst_reg, reg, elem_size);1578 try self.genLdrRegister(dst_reg, reg, elem_ty);
1518 },1579 },
1519 .stack_offset => |off| {1580 .stack_offset => |off| {
1520 if (elem_size <= 4) {1581 if (elem_size <= 4) {
...@@ -1615,7 +1676,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -1615,7 +1676,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
16151676
1616 switch (value) {1677 switch (value) {
1617 .register => |value_reg| {1678 .register => |value_reg| {
1618 try self.genStrRegister(value_reg, addr_reg, @intCast(u32, value_ty.abiSize(self.target.*)));1679 try self.genStrRegister(value_reg, addr_reg, value_ty);
1619 },1680 },
1620 else => {1681 else => {
1621 if (value_ty.abiSize(self.target.*) <= 4) {1682 if (value_ty.abiSize(self.target.*) <= 4) {
...@@ -2180,68 +2241,71 @@ fn binOp(...@@ -2180,68 +2241,71 @@ fn binOp(
2180 }2241 }
2181}2242}
21822243
2183fn 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 {
2184 switch (abi_size) {2245 const abi_size = ty.abiSize(self.target.*);
2185 1, 3, 4 => {
2186 const tag: Mir.Inst.Tag = switch (abi_size) {
2187 1 => .ldrb,
2188 3, 4 => .ldr,
2189 else => unreachable,
2190 };
21912246
2192 _ = try self.addInst(.{2247 const tag: Mir.Inst.Tag = switch (abi_size) {
2193 .tag = tag,2248 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb else .ldrb,
2194 .data = .{ .rr_offset = .{2249 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh else .ldrh,
2195 .rt = dest_reg,2250 3, 4 => .ldr,
2196 .rn = addr_reg,2251 else => unreachable,
2197 .offset = .{ .offset = Instruction.Offset.none },2252 };
2198 } },2253
2199 });2254 const rr_offset: Mir.Inst.Data = .{ .rr_offset = .{
2200 },2255 .rt = dest_reg,
2201 2 => {2256 .rn = addr_reg,
2202 _ = try self.addInst(.{2257 .offset = .{ .offset = Instruction.Offset.none },
2203 .tag = .ldrh,2258 } };
2204 .data = .{ .rr_extra_offset = .{2259 const rr_extra_offset: Mir.Inst.Data = .{ .rr_extra_offset = .{
2205 .rt = dest_reg,2260 .rt = dest_reg,
2206 .rn = addr_reg,2261 .rn = addr_reg,
2207 .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },2262 .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },
2208 } },2263 } };
2209 });2264
2210 },2265 const data: Mir.Inst.Data = switch (abi_size) {
2211 else => unreachable, // invalid abi_size for a register2266 1 => if (ty.isSignedInt()) rr_extra_offset else rr_offset,
2212 }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 });
2213}2276}
22142277
2215fn 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 {
2216 switch (abi_size) {2279 const abi_size = ty.abiSize(self.target.*);
2217 1, 3, 4 => {
2218 const tag: Mir.Inst.Tag = switch (abi_size) {
2219 1 => .strb,
2220 3, 4 => .str,
2221 else => unreachable,
2222 };
22232280
2224 _ = try self.addInst(.{2281 const tag: Mir.Inst.Tag = switch (abi_size) {
2225 .tag = tag,2282 1 => .strb,
2226 .data = .{ .rr_offset = .{2283 2 => .strh,
2227 .rt = source_reg,2284 3, 4 => .str,
2228 .rn = addr_reg,2285 else => unreachable,
2229 .offset = .{ .offset = Instruction.Offset.none },2286 };
2230 } },2287
2231 });2288 const rr_offset: Mir.Inst.Data = .{ .rr_offset = .{
2232 },2289 .rt = source_reg,
2233 2 => {2290 .rn = addr_reg,
2234 _ = try self.addInst(.{2291 .offset = .{ .offset = Instruction.Offset.none },
2235 .tag = .strh,2292 } };
2236 .data = .{ .rr_extra_offset = .{2293 const rr_extra_offset: Mir.Inst.Data = .{ .rr_extra_offset = .{
2237 .rt = source_reg,2294 .rt = source_reg,
2238 .rn = addr_reg,2295 .rn = addr_reg,
2239 .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },2296 .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },
2240 } },2297 } };
2241 });2298
2242 },2299 const data: Mir.Inst.Data = switch (abi_size) {
2243 else => unreachable, // invalid abi_size for a register2300 1, 3, 4 => rr_offset,
2244 }2301 2 => rr_extra_offset,
2302 else => unreachable,
2303 };
2304
2305 _ = try self.addInst(.{
2306 .tag = tag,
2307 .data = data,
2308 });
2245}2309}
22462310
2247fn genInlineMemcpy(2311fn genInlineMemcpy(
...@@ -2834,8 +2898,6 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {...@@ -2834,8 +2898,6 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
2834}2898}
28352899
2836fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {2900fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
2837 _ = operand;
2838
2839 const error_type = ty.errorUnionSet();2901 const error_type = ty.errorUnionSet();
2840 const payload_type = ty.errorUnionPayload();2902 const payload_type = ty.errorUnionPayload();
28412903
...@@ -3569,55 +3631,59 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -3569,55 +3631,59 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
3569 // The value is in memory at a hard-coded address.3631 // The value is in memory at a hard-coded address.
3570 // 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.
3571 try self.genSetReg(ty, reg, .{ .immediate = @intCast(u32, addr) });3633 try self.genSetReg(ty, reg, .{ .immediate = @intCast(u32, addr) });
3572 try self.genLdrRegister(reg, reg, @intCast(u32, ty.abiSize(self.target.*)));3634 try self.genLdrRegister(reg, reg, ty);
3573 },3635 },
3574 .stack_offset => |unadjusted_off| {3636 .stack_offset => |unadjusted_off| {
3575 // TODO: maybe addressing from sp instead of fp3637 // TODO: maybe addressing from sp instead of fp
3576 const abi_size = @intCast(u32, ty.abiSize(self.target.*));3638 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
3577 const adj_off = unadjusted_off + abi_size;3639 const adj_off = unadjusted_off + abi_size;
35783640
3579 switch (abi_size) {3641 const tag: Mir.Inst.Tag = switch (abi_size) {
3580 1, 4 => {3642 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb else .ldrb,
3581 const offset = if (adj_off <= math.maxInt(u12)) blk: {3643 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh else .ldrh,
3582 break :blk Instruction.Offset.imm(@intCast(u12, adj_off));3644 3, 4 => .ldr,
3583 } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), .none);3645 else => unreachable,
3646 };
35843647
3585 const tag: Mir.Inst.Tag = switch (abi_size) {3648 const extra_offset = switch (abi_size) {
3586 1 => .ldrb,3649 1 => ty.isSignedInt(),
3587 4 => .ldr,3650 2 => true,
3588 else => unreachable,3651 3, 4 => false,
3589 };3652 else => unreachable,
3653 };
35903654
3591 _ = try self.addInst(.{3655 if (extra_offset) {
3592 .tag = tag,3656 const offset = if (adj_off <= math.maxInt(u8)) blk: {
3593 .data = .{ .rr_offset = .{3657 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
3594 .rt = reg,3658 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }));
3595 .rn = .fp,
3596 .offset = .{
3597 .offset = offset,
3598 .positive = false,
3599 },
3600 } },
3601 });
3602 },
3603 2 => {
3604 const offset = if (adj_off <= math.maxInt(u8)) blk: {
3605 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
3606 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }));
36073659
3608 _ = try self.addInst(.{3660 _ = try self.addInst(.{
3609 .tag = .ldrh,3661 .tag = tag,
3610 .data = .{ .rr_extra_offset = .{3662 .data = .{ .rr_extra_offset = .{
3611 .rt = reg,3663 .rt = reg,
3612 .rn = .fp,3664 .rn = .fp,
3613 .offset = .{3665 .offset = .{
3614 .offset = offset,3666 .offset = offset,
3615 .positive = false,3667 .positive = false,
3616 },3668 },
3617 } },3669 } },
3618 });3670 });
3619 },3671 } else {
3620 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 });
3621 }3687 }
3622 },3688 },
3623 .stack_argument_offset => |unadjusted_off| {3689 .stack_argument_offset => |unadjusted_off| {
...@@ -3625,9 +3691,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -3625,9 +3691,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
3625 const adj_off = unadjusted_off + abi_size;3691 const adj_off = unadjusted_off + abi_size;
36263692
3627 const tag: Mir.Inst.Tag = switch (abi_size) {3693 const tag: Mir.Inst.Tag = switch (abi_size) {
3628 1 => .ldrb_stack_argument,3694 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_stack_argument else .ldrb_stack_argument,
3629 2 => .ldrh_stack_argument,3695 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_stack_argument else .ldrh_stack_argument,
3630 4 => .ldr_stack_argument,3696 3, 4 => .ldr_stack_argument,
3631 else => unreachable,3697 else => unreachable,
3632 };3698 };
36333699
src/arch/arm/Emit.zig+46-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),
...@@ -130,6 +134,9 @@ pub fn emitMir(...@@ -130,6 +134,9 @@ pub fn emitMir(
130 .push => try emit.mirBlockDataTransfer(inst),134 .push => try emit.mirBlockDataTransfer(inst),
131135
132 .svc => try emit.mirSupervisorCall(inst),136 .svc => try emit.mirSupervisorCall(inst),
137
138 .sbfx => try emit.mirBitFieldExtract(inst),
139 .ubfx => try emit.mirBitFieldExtract(inst),
133 }140 }
134 }141 }
135}142}
...@@ -590,36 +597,42 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -590,36 +597,42 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
590597
591 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;
592 switch (tag) {599 switch (tag) {
593 .ldr_stack_argument => {600 .ldr_stack_argument,
601 .ldrb_stack_argument,
602 => {
594 const offset = if (raw_offset <= math.maxInt(u12)) blk: {603 const offset = if (raw_offset <= math.maxInt(u12)) blk: {
595 break :blk Instruction.Offset.imm(@intCast(u12, raw_offset));604 break :blk Instruction.Offset.imm(@intCast(u12, raw_offset));
596 } else return emit.fail("TODO mirLoadStack larger offsets", .{});605 } else return emit.fail("TODO mirLoadStack larger offsets", .{});
597606
598 try emit.writeInstruction(Instruction.ldr(607 const ldr = switch (tag) {
599 cond,608 .ldr_stack_argument => Instruction.ldr,
600 r_stack_offset.rt,609 .ldrb_stack_argument => Instruction.ldrb,
601 .fp,610 else => unreachable,
602 .{ .offset = offset },611 };
603 ));
604 },
605 .ldrb_stack_argument => {
606 const offset = if (raw_offset <= math.maxInt(u12)) blk: {
607 break :blk Instruction.Offset.imm(@intCast(u12, raw_offset));
608 } else return emit.fail("TODO mirLoadStack larger offsets", .{});
609612
610 try emit.writeInstruction(Instruction.ldrb(613 try emit.writeInstruction(ldr(
611 cond,614 cond,
612 r_stack_offset.rt,615 r_stack_offset.rt,
613 .fp,616 .fp,
614 .{ .offset = offset },617 .{ .offset = offset },
615 ));618 ));
616 },619 },
617 .ldrh_stack_argument => {620 .ldrh_stack_argument,
621 .ldrsb_stack_argument,
622 .ldrsh_stack_argument,
623 => {
618 const offset = if (raw_offset <= math.maxInt(u8)) blk: {624 const offset = if (raw_offset <= math.maxInt(u8)) blk: {
619 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, raw_offset));625 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, raw_offset));
620 } else return emit.fail("TODO mirLoadStack larger offsets", .{});626 } else return emit.fail("TODO mirLoadStack larger offsets", .{});
621627
622 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(
623 cond,636 cond,
624 r_stack_offset.rt,637 r_stack_offset.rt,
625 .fp,638 .fp,
...@@ -637,6 +650,8 @@ fn mirLoadStoreExtra(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -637,6 +650,8 @@ fn mirLoadStoreExtra(emit: *Emit, inst: Mir.Inst.Index) !void {
637650
638 switch (tag) {651 switch (tag) {
639 .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)),
640 .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)),
641 else => unreachable,656 else => unreachable,
642 }657 }
...@@ -691,3 +706,19 @@ fn mirSupervisorCall(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -691,3 +706,19 @@ fn mirSupervisorCall(emit: *Emit, inst: Mir.Inst.Index) !void {
691 else => unreachable,706 else => unreachable,
692 }707 }
693}708}
709
710fn mirBitFieldExtract(emit: *Emit, inst: Mir.Inst.Index) !void {
711 const tag = emit.mir.instructions.items(.tag)[inst];
712 const cond = emit.mir.instructions.items(.cond)[inst];
713 const rr_lsb_width = emit.mir.instructions.items(.data)[inst].rr_lsb_width;
714 const rd = rr_lsb_width.rd;
715 const rn = rr_lsb_width.rn;
716 const lsb = rr_lsb_width.lsb;
717 const width = rr_lsb_width.width;
718
719 switch (tag) {
720 .sbfx => try emit.writeInstruction(Instruction.sbfx(cond, rd, rn, lsb, width)),
721 .ubfx => try emit.writeInstruction(Instruction.ubfx(cond, rd, rn, lsb, width)),
722 else => unreachable,
723 }
724}
src/arch/arm/Mir.zig+22
...@@ -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
...@@ -88,6 +96,8 @@ pub const Inst = struct {...@@ -88,6 +96,8 @@ pub const Inst = struct {
88 push,96 push,
89 /// Reverse Subtract97 /// Reverse Subtract
90 rsb,98 rsb,
99 /// Signed Bit Field Extract
100 sbfx,
91 /// Store Register101 /// Store Register
92 str,102 str,
93 /// Store Register Byte103 /// Store Register Byte
...@@ -98,6 +108,8 @@ pub const Inst = struct {...@@ -98,6 +108,8 @@ pub const Inst = struct {
98 sub,108 sub,
99 /// Supervisor Call109 /// Supervisor Call
100 svc,110 svc,
111 /// Unsigned Bit Field Extract
112 ubfx,
101 };113 };
102114
103 /// The position of an MIR instruction within the `Mir` instructions array.115 /// The position of an MIR instruction within the `Mir` instructions array.
...@@ -179,6 +191,16 @@ pub const Inst = struct {...@@ -179,6 +191,16 @@ pub const Inst = struct {
179 rn: Register,191 rn: Register,
180 offset: bits.Instruction.ExtraLoadStoreOffsetArgs,192 offset: bits.Instruction.ExtraLoadStoreOffsetArgs,
181 },193 },
194 /// Two registers and a lsb (range 0-31) and a width (range
195 /// 1-32)
196 ///
197 /// Used by e.g. sbfx
198 rr_lsb_width: struct {
199 rd: Register,
200 rn: Register,
201 lsb: u5,
202 width: u6,
203 },
182 /// Three registers204 /// Three registers
183 ///205 ///
184 /// Used by e.g. mul206 /// Used by e.g. mul
src/arch/arm/bits.zig+54-2
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const DW = std.dwarf;2const DW = std.dwarf;
3const assert = std.debug.assert;
3const testing = std.testing;4const testing = std.testing;
45
5/// The condition field specifies the flags necessary for an6/// The condition field specifies the flags necessary for an
...@@ -237,6 +238,17 @@ pub const Instruction = union(enum) {...@@ -237,6 +238,17 @@ pub const Instruction = union(enum) {
237 fixed_3: u5 = 0b00010,238 fixed_3: u5 = 0b00010,
238 cond: u4,239 cond: u4,
239 },240 },
241 bit_field_extract: packed struct {
242 rn: u4,
243 fixed_1: u3 = 0b101,
244 lsb: u5,
245 rd: u4,
246 widthm1: u5,
247 fixed_2: u1 = 0b1,
248 unsigned: u1,
249 fixed_3: u5 = 0b01111,
250 cond: u4,
251 },
240 single_data_transfer: packed struct {252 single_data_transfer: packed struct {
241 offset: u12,253 offset: u12,
242 rd: u4,254 rd: u4,
...@@ -576,6 +588,7 @@ pub const Instruction = union(enum) {...@@ -576,6 +588,7 @@ pub const Instruction = union(enum) {
576 .multiply => |v| @bitCast(u32, v),588 .multiply => |v| @bitCast(u32, v),
577 .multiply_long => |v| @bitCast(u32, v),589 .multiply_long => |v| @bitCast(u32, v),
578 .integer_saturating_arithmetic => |v| @bitCast(u32, v),590 .integer_saturating_arithmetic => |v| @bitCast(u32, v),
591 .bit_field_extract => |v| @bitCast(u32, v),
579 .single_data_transfer => |v| @bitCast(u32, v),592 .single_data_transfer => |v| @bitCast(u32, v),
580 .extra_load_store => |v| @bitCast(u32, v),593 .extra_load_store => |v| @bitCast(u32, v),
581 .block_data_transfer => |v| @bitCast(u32, v),594 .block_data_transfer => |v| @bitCast(u32, v),
...@@ -691,6 +704,27 @@ pub const Instruction = union(enum) {...@@ -691,6 +704,27 @@ pub const Instruction = union(enum) {
691 };704 };
692 }705 }
693706
707 fn bitFieldExtract(
708 unsigned: u1,
709 cond: Condition,
710 rd: Register,
711 rn: Register,
712 lsb: u5,
713 width: u6,
714 ) Instruction {
715 assert(width > 0 and width <= 32);
716 return Instruction{
717 .bit_field_extract = .{
718 .rn = rn.id(),
719 .lsb = lsb,
720 .rd = rd.id(),
721 .widthm1 = @intCast(u5, width - 1),
722 .unsigned = unsigned,
723 .cond = @enumToInt(cond),
724 },
725 };
726 }
727
694 fn singleDataTransfer(728 fn singleDataTransfer(
695 cond: Condition,729 cond: Condition,
696 rd: Register,730 rd: Register,
...@@ -1044,6 +1078,16 @@ pub const Instruction = union(enum) {...@@ -1044,6 +1078,16 @@ pub const Instruction = union(enum) {
1044 return multiplyLong(cond, 1, 1, 1, rdhi, rdlo, rm, rn);1078 return multiplyLong(cond, 1, 1, 1, rdhi, rdlo, rm, rn);
1045 }1079 }
10461080
1081 // Bit field extract
1082
1083 pub fn ubfx(cond: Condition, rd: Register, rn: Register, lsb: u5, width: u6) Instruction {
1084 return bitFieldExtract(0b1, cond, rd, rn, lsb, width);
1085 }
1086
1087 pub fn sbfx(cond: Condition, rd: Register, rn: Register, lsb: u5, width: u6) Instruction {
1088 return bitFieldExtract(0b0, cond, rd, rn, lsb, width);
1089 }
1090
1047 // Single data transfer1091 // Single data transfer
10481092
1049 pub const OffsetArgs = struct {1093 pub const OffsetArgs = struct {
...@@ -1079,11 +1123,19 @@ pub const Instruction = union(enum) {...@@ -1079,11 +1123,19 @@ pub const Instruction = union(enum) {
1079 };1123 };
10801124
1081 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 {
1082 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);
1083 }1127 }
10841128
1085 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 {
1086 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);
1087 }1139 }
10881140
1089 // Block data transfer1141 // Block data transfer
test/behavior/basic.zig-2
...@@ -16,7 +16,6 @@ test "empty function with comments" {...@@ -16,7 +16,6 @@ test "empty function with comments" {
1616
17test "truncate" {17test "truncate" {
18 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;18 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2019
21 try expect(testTruncate(0x10fd) == 0xfd);20 try expect(testTruncate(0x10fd) == 0xfd);
22 comptime try expect(testTruncate(0x10fd) == 0xfd);21 comptime try expect(testTruncate(0x10fd) == 0xfd);
...@@ -27,7 +26,6 @@ fn testTruncate(x: u32) u8 {...@@ -27,7 +26,6 @@ fn testTruncate(x: u32) u8 {
2726
28test "truncate to non-power-of-two integers" {27test "truncate to non-power-of-two integers" {
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
30 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3129
32 try testTrunc(u32, u1, 0b10101, 0b1);30 try testTrunc(u32, u1, 0b10101, 0b1);
33 try testTrunc(u32, u1, 0b10110, 0b0);31 try testTrunc(u32, u1, 0b10110, 0b0);
test/behavior/truncate.zig-9
...@@ -4,7 +4,6 @@ const expect = std.testing.expect;...@@ -4,7 +4,6 @@ const expect = std.testing.expect;
44
5test "truncate u0 to larger integer allowed and has comptime known result" {5test "truncate u0 to larger integer allowed and has comptime known result" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
87
9 var x: u0 = 0;8 var x: u0 = 0;
10 const y = @truncate(u8, x);9 const y = @truncate(u8, x);
...@@ -13,7 +12,6 @@ test "truncate u0 to larger integer allowed and has comptime known result" {...@@ -13,7 +12,6 @@ test "truncate u0 to larger integer allowed and has comptime known result" {
1312
14test "truncate.u0.literal" {13test "truncate.u0.literal" {
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;14 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1715
18 var z = @truncate(u0, 0);16 var z = @truncate(u0, 0);
19 try expect(z == 0);17 try expect(z == 0);
...@@ -21,7 +19,6 @@ test "truncate.u0.literal" {...@@ -21,7 +19,6 @@ test "truncate.u0.literal" {
2119
22test "truncate.u0.const" {20test "truncate.u0.const" {
23 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2522
26 const c0: usize = 0;23 const c0: usize = 0;
27 var z = @truncate(u0, c0);24 var z = @truncate(u0, c0);
...@@ -30,7 +27,6 @@ test "truncate.u0.const" {...@@ -30,7 +27,6 @@ test "truncate.u0.const" {
3027
31test "truncate.u0.var" {28test "truncate.u0.var" {
32 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3430
35 var d: u8 = 2;31 var d: u8 = 2;
36 var z = @truncate(u0, d);32 var z = @truncate(u0, d);
...@@ -39,7 +35,6 @@ test "truncate.u0.var" {...@@ -39,7 +35,6 @@ test "truncate.u0.var" {
3935
40test "truncate i0 to larger integer allowed and has comptime known result" {36test "truncate i0 to larger integer allowed and has comptime known result" {
41 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;37 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
42 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
4338
44 var x: i0 = 0;39 var x: i0 = 0;
45 const y = @truncate(i8, x);40 const y = @truncate(i8, x);
...@@ -48,7 +43,6 @@ test "truncate i0 to larger integer allowed and has comptime known result" {...@@ -48,7 +43,6 @@ test "truncate i0 to larger integer allowed and has comptime known result" {
4843
49test "truncate.i0.literal" {44test "truncate.i0.literal" {
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;45 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
51 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
5246
53 var z = @truncate(i0, 0);47 var z = @truncate(i0, 0);
54 try expect(z == 0);48 try expect(z == 0);
...@@ -56,7 +50,6 @@ test "truncate.i0.literal" {...@@ -56,7 +50,6 @@ test "truncate.i0.literal" {
5650
57test "truncate.i0.const" {51test "truncate.i0.const" {
58 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;52 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
59 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6053
61 const c0: isize = 0;54 const c0: isize = 0;
62 var z = @truncate(i0, c0);55 var z = @truncate(i0, c0);
...@@ -65,7 +58,6 @@ test "truncate.i0.const" {...@@ -65,7 +58,6 @@ test "truncate.i0.const" {
6558
66test "truncate.i0.var" {59test "truncate.i0.var" {
67 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;60 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
68 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6961
70 var d: i8 = 2;62 var d: i8 = 2;
71 var z = @truncate(i0, d);63 var z = @truncate(i0, d);
...@@ -74,7 +66,6 @@ test "truncate.i0.var" {...@@ -74,7 +66,6 @@ test "truncate.i0.var" {
7466
75test "truncate on comptime integer" {67test "truncate on comptime integer" {
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;68 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
77 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7869
79 var x = @truncate(u16, 9999);70 var x = @truncate(u16, 9999);
80 try expect(x == 9999);71 try expect(x == 9999);