authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-02-24 22:18:21+01:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-02-26 12:59:57+01:00
log8ef80cfaab2a74506d7b3a866dc066d9cd281f55
tree5f96c3e02d299e29a9738c74ae429b9f967aac9d
parentdb82c1b9820449f2d1e6ef54dd32ec3ffd3c583f
signaturelock-open Commit is signed but in an unrecognized format.

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


6 files changed, 142 insertions(+), 13 deletions(-)

src/arch/arm/CodeGen.zig+65-4
......@@ -439,7 +439,7 @@ fn gen(self: *Self) !void {
439439 // the code. Therefore, we can just delete
440440 // the space initially reserved for the
441441 // jump
442 self.mir_instructions.len -= 1;
442 self.mir_instructions.orderedRemove(self.exitlude_jump_relocs.items[0]);
443443 } else for (self.exitlude_jump_relocs.items) |jmp_reloc| {
444444 self.mir_instructions.set(jmp_reloc, .{
445445 .tag = .b,
......@@ -749,6 +749,17 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u
749749/// Use a pointer instruction as the basis for allocating stack memory.
750750fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
751751 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
752763 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch {
753764 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty});
754765 };
......@@ -872,11 +883,61 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
872883 if (self.liveness.isUnused(inst))
873884 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
874885
886 const operand_ty = self.air.typeOf(ty_op.operand);
875887 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});
879 // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
891 const result: MCValue = blk: {
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 });
880941}
881942
882943fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {
src/arch/arm/Emit.zig+19
......@@ -130,6 +130,9 @@ pub fn emitMir(
130130 .push => try emit.mirBlockDataTransfer(inst),
131131
132132 .svc => try emit.mirSupervisorCall(inst),
133
134 .sbfx => try emit.mirBitFieldExtract(inst),
135 .ubfx => try emit.mirBitFieldExtract(inst),
133136 }
134137 }
135138}
......@@ -691,3 +694,19 @@ fn mirSupervisorCall(emit: *Emit, inst: Mir.Inst.Index) !void {
691694 else => unreachable,
692695 }
693696}
697
698fn mirBitFieldExtract(emit: *Emit, inst: Mir.Inst.Index) !void {
699 const tag = emit.mir.instructions.items(.tag)[inst];
700 const cond = emit.mir.instructions.items(.cond)[inst];
701 const rr_lsb_width = emit.mir.instructions.items(.data)[inst].rr_lsb_width;
702 const rd = rr_lsb_width.rd;
703 const rn = rr_lsb_width.rn;
704 const lsb = rr_lsb_width.lsb;
705 const width = rr_lsb_width.width;
706
707 switch (tag) {
708 .sbfx => try emit.writeInstruction(Instruction.sbfx(cond, rd, rn, lsb, width)),
709 .ubfx => try emit.writeInstruction(Instruction.ubfx(cond, rd, rn, lsb, width)),
710 else => unreachable,
711 }
712}
src/arch/arm/Mir.zig+14
......@@ -88,6 +88,8 @@ pub const Inst = struct {
8888 push,
8989 /// Reverse Subtract
9090 rsb,
91 /// Signed Bit Field Extract
92 sbfx,
9193 /// Store Register
9294 str,
9395 /// Store Register Byte
......@@ -98,6 +100,8 @@ pub const Inst = struct {
98100 sub,
99101 /// Supervisor Call
100102 svc,
103 /// Unsigned Bit Field Extract
104 ubfx,
101105 };
102106
103107 /// The position of an MIR instruction within the `Mir` instructions array.
......@@ -179,6 +183,16 @@ pub const Inst = struct {
179183 rn: Register,
180184 offset: bits.Instruction.ExtraLoadStoreOffsetArgs,
181185 },
186 /// Two registers and a lsb (range 0-31) and a width (range
187 /// 1-32)
188 ///
189 /// Used by e.g. sbfx
190 rr_lsb_width: struct {
191 rd: Register,
192 rn: Register,
193 lsb: u5,
194 width: u6,
195 },
182196 /// Three registers
183197 ///
184198 /// Used by e.g. mul
src/arch/arm/bits.zig+44
......@@ -1,5 +1,6 @@
11const std = @import("std");
22const DW = std.dwarf;
3const assert = std.debug.assert;
34const testing = std.testing;
45
56/// The condition field specifies the flags necessary for an
......@@ -237,6 +238,17 @@ pub const Instruction = union(enum) {
237238 fixed_3: u5 = 0b00010,
238239 cond: u4,
239240 },
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 },
240252 single_data_transfer: packed struct {
241253 offset: u12,
242254 rd: u4,
......@@ -576,6 +588,7 @@ pub const Instruction = union(enum) {
576588 .multiply => |v| @bitCast(u32, v),
577589 .multiply_long => |v| @bitCast(u32, v),
578590 .integer_saturating_arithmetic => |v| @bitCast(u32, v),
591 .bit_field_extract => |v| @bitCast(u32, v),
579592 .single_data_transfer => |v| @bitCast(u32, v),
580593 .extra_load_store => |v| @bitCast(u32, v),
581594 .block_data_transfer => |v| @bitCast(u32, v),
......@@ -691,6 +704,27 @@ pub const Instruction = union(enum) {
691704 };
692705 }
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
694728 fn singleDataTransfer(
695729 cond: Condition,
696730 rd: Register,
......@@ -1044,6 +1078,16 @@ pub const Instruction = union(enum) {
10441078 return multiplyLong(cond, 1, 1, 1, rdhi, rdlo, rm, rn);
10451079 }
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
10471091 // Single data transfer
10481092
10491093 pub const OffsetArgs = struct {
test/behavior/basic.zig-1
......@@ -16,7 +16,6 @@ test "empty function with comments" {
1616
1717test "truncate" {
1818 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2019
2120 try expect(testTruncate(0x10fd) == 0xfd);
2221 comptime try expect(testTruncate(0x10fd) == 0xfd);
test/behavior/truncate.zig-8
......@@ -4,7 +4,6 @@ const expect = std.testing.expect;
44
55test "truncate u0 to larger integer allowed and has comptime known result" {
66 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
87
98 var x: u0 = 0;
109 const y = @truncate(u8, x);
......@@ -13,7 +12,6 @@ test "truncate u0 to larger integer allowed and has comptime known result" {
1312
1413test "truncate.u0.literal" {
1514 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1715
1816 var z = @truncate(u0, 0);
1917 try expect(z == 0);
......@@ -21,7 +19,6 @@ test "truncate.u0.literal" {
2119
2220test "truncate.u0.const" {
2321 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2522
2623 const c0: usize = 0;
2724 var z = @truncate(u0, c0);
......@@ -30,7 +27,6 @@ test "truncate.u0.const" {
3027
3128test "truncate.u0.var" {
3229 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3430
3531 var d: u8 = 2;
3632 var z = @truncate(u0, d);
......@@ -39,7 +35,6 @@ test "truncate.u0.var" {
3935
4036test "truncate i0 to larger integer allowed and has comptime known result" {
4137 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
42 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
4338
4439 var x: i0 = 0;
4540 const y = @truncate(i8, x);
......@@ -48,7 +43,6 @@ test "truncate i0 to larger integer allowed and has comptime known result" {
4843
4944test "truncate.i0.literal" {
5045 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
51 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
5246
5347 var z = @truncate(i0, 0);
5448 try expect(z == 0);
......@@ -56,7 +50,6 @@ test "truncate.i0.literal" {
5650
5751test "truncate.i0.const" {
5852 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
59 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6053
6154 const c0: isize = 0;
6255 var z = @truncate(i0, c0);
......@@ -65,7 +58,6 @@ test "truncate.i0.const" {
6558
6659test "truncate.i0.var" {
6760 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
68 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6961
7062 var d: i8 = 2;
7163 var z = @truncate(i0, d);