| author | |
| committer | |
| log | 058e482247c73ecb6404c7c1e3d2194f4aa9e059 |
| tree | 3477f4e9793eda2c0e7c0be6cb431db445c473e6 |
| parent | 8349a644d0b9d4b2d58d736a14cdcc567a9e9b89 |
| parent | f48f4baf676061742adb9674bc5e43e82c63f96a |
| signature |
stage2 ARM: implement truncate to integers with <= 32 bits6 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 delete | 439 | // the code. Therefore, we can just delete |
| 440 | // the space initially reserved for the | 440 | // the space initially reserved for the |
| 441 | // jump | 441 | // 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. |
| 750 | fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { | 750 | fn 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 }); |
| 874 | 885 | ||
| 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.*); | ||
| 877 | 890 | ||
| 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 | } |
| 881 | 942 | ||
| 882 | fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { | 943 | fn 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 |
| 1615 | 1676 | ||
| 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 | } |
| 2182 | 2243 | ||
| 2183 | fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, abi_size: u32) !void { | 2244 | fn 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 | }; | ||
| 2191 | 2246 | ||
| 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 register | 2266 | 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 | } |
| 2214 | 2277 | ||
| 2215 | fn genStrRegister(self: *Self, source_reg: Register, addr_reg: Register, abi_size: u32) !void { | 2278 | fn 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 | }; | ||
| 2223 | 2280 | ||
| 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 register | 2300 | 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 | } |
| 2246 | 2310 | ||
| 2247 | fn genInlineMemcpy( | 2311 | fn 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 | } |
| 2835 | 2899 | ||
| 2836 | fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { | 2900 | fn 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(); |
| 2841 | 2903 | ||
| ... | @@ -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 fp | 3637 | // 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; |
| 3578 | 3640 | ||
| 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 | }; | ||
| 3584 | 3647 | ||
| 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 | }; | ||
| 3590 | 3654 | ||
| 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 })); | ||
| 3607 | 3659 | ||
| 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; |
| 3626 | 3692 | ||
| 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 | }; |
| 3633 | 3699 |
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), | ||
| 118 | 120 | ||
| 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), |
| 121 | 125 | ||
| 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), |
| 131 | 135 | ||
| 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 { |
| 590 | 597 | ||
| 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", .{}); |
| 597 | 606 | ||
| 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", .{}); | ||
| 609 | 612 | ||
| 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", .{}); |
| 621 | 627 | ||
| 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 { |
| 637 | 650 | ||
| 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 | |||
| 710 | fn 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 Halfword | 65 | /// 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 Left | 75 | /// Logical Shift Left |
| 68 | lsl, | 76 | lsl, |
| 69 | /// Logical Shift Right | 77 | /// 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 Subtract | 97 | /// Reverse Subtract |
| 90 | rsb, | 98 | rsb, |
| 99 | /// Signed Bit Field Extract | ||
| 100 | sbfx, | ||
| 91 | /// Store Register | 101 | /// Store Register |
| 92 | str, | 102 | str, |
| 93 | /// Store Register Byte | 103 | /// 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 Call | 109 | /// Supervisor Call |
| 100 | svc, | 110 | svc, |
| 111 | /// Unsigned Bit Field Extract | ||
| 112 | ubfx, | ||
| 101 | }; | 113 | }; |
| 102 | 114 | ||
| 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 registers | 204 | /// Three registers |
| 183 | /// | 205 | /// |
| 184 | /// Used by e.g. mul | 206 | /// Used by e.g. mul |
src/arch/arm/bits.zig+54-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const DW = std.dwarf; | 2 | const DW = std.dwarf; |
| 3 | const assert = std.debug.assert; | ||
| 3 | const testing = std.testing; | 4 | const testing = std.testing; |
| 4 | 5 | ||
| 5 | /// The condition field specifies the flags necessary for an | 6 | /// 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 | } |
| 693 | 706 | ||
| 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 | } |
| 1046 | 1080 | ||
| 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 transfer | 1091 | // Single data transfer |
| 1048 | 1092 | ||
| 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 | }; |
| 1080 | 1124 | ||
| 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 | } |
| 1084 | 1128 | ||
| 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 | } |
| 1088 | 1140 | ||
| 1089 | // Block data transfer | 1141 | // 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" { |
| 16 | 16 | ||
| 17 | test "truncate" { | 17 | test "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; | ||
| 20 | 19 | ||
| 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 { |
| 27 | 26 | ||
| 28 | test "truncate to non-power-of-two integers" { | 27 | test "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; | ||
| 31 | 29 | ||
| 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; |
| 4 | 4 | ||
| 5 | test "truncate u0 to larger integer allowed and has comptime known result" { | 5 | test "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; | ||
| 8 | 7 | ||
| 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" { |
| 13 | 12 | ||
| 14 | test "truncate.u0.literal" { | 13 | test "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; | ||
| 17 | 15 | ||
| 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" { |
| 21 | 19 | ||
| 22 | test "truncate.u0.const" { | 20 | test "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; | ||
| 25 | 22 | ||
| 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" { |
| 30 | 27 | ||
| 31 | test "truncate.u0.var" { | 28 | test "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; | ||
| 34 | 30 | ||
| 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" { |
| 39 | 35 | ||
| 40 | test "truncate i0 to larger integer allowed and has comptime known result" { | 36 | test "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; | ||
| 43 | 38 | ||
| 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" { |
| 48 | 43 | ||
| 49 | test "truncate.i0.literal" { | 44 | test "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; | ||
| 52 | 46 | ||
| 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" { |
| 56 | 50 | ||
| 57 | test "truncate.i0.const" { | 51 | test "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; | ||
| 60 | 53 | ||
| 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" { |
| 65 | 58 | ||
| 66 | test "truncate.i0.var" { | 59 | test "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; | ||
| 69 | 61 | ||
| 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" { |
| 74 | 66 | ||
| 75 | test "truncate on comptime integer" { | 67 | test "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; | ||
| 78 | 69 | ||
| 79 | var x = @truncate(u16, 9999); | 70 | var x = @truncate(u16, 9999); |
| 80 | try expect(x == 9999); | 71 | try expect(x == 9999); |