| author | |
| committer | |
| log | d9d9fea6aee7fd0f4dadb53e41f9884330229051 |
| tree | eb8197c3f6551a0dec931bcffb7fa3dad4a52aef |
| parent | f95a8ddafa53d4cee591c82bd5ed3eb0eac4a51b |
| signature |
6 files changed, 119 insertions(+), 125 deletions(-)
src/arch/aarch64/CodeGen.zig+41-97| ... | ... | @@ -2056,7 +2056,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2056 | 2056 | .undef => unreachable, |
| 2057 | 2057 | .compare_flags_signed, .compare_flags_unsigned => unreachable, |
| 2058 | 2058 | .register => |dst_reg| { |
| 2059 | try self.genLdrRegister(dst_reg, addr_reg, elem_size); | |
| 2059 | try self.genLdrRegister(dst_reg, addr_reg, elem_ty); | |
| 2060 | 2060 | }, |
| 2061 | 2061 | .stack_offset => |off| { |
| 2062 | 2062 | if (elem_size <= 8) { |
| ... | ... | @@ -2210,98 +2210,47 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2210 | 2210 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2211 | 2211 | } |
| 2212 | 2212 | |
| 2213 | fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, abi_size: u64) !void { | |
| 2214 | switch (abi_size) { | |
| 2215 | 1 => { | |
| 2216 | _ = try self.addInst(.{ | |
| 2217 | .tag = .ldrb_immediate, | |
| 2218 | .data = .{ .load_store_register_immediate = .{ | |
| 2219 | .rt = value_reg.to32(), | |
| 2220 | .rn = addr_reg, | |
| 2221 | .offset = Instruction.LoadStoreOffset.none.immediate, | |
| 2222 | } }, | |
| 2223 | }); | |
| 2224 | }, | |
| 2225 | 2 => { | |
| 2226 | _ = try self.addInst(.{ | |
| 2227 | .tag = .ldrh_immediate, | |
| 2228 | .data = .{ .load_store_register_immediate = .{ | |
| 2229 | .rt = value_reg.to32(), | |
| 2230 | .rn = addr_reg, | |
| 2231 | .offset = Instruction.LoadStoreOffset.none.immediate, | |
| 2232 | } }, | |
| 2233 | }); | |
| 2234 | }, | |
| 2235 | 4 => { | |
| 2236 | _ = try self.addInst(.{ | |
| 2237 | .tag = .ldr_immediate, | |
| 2238 | .data = .{ .load_store_register_immediate = .{ | |
| 2239 | .rt = value_reg.to32(), | |
| 2240 | .rn = addr_reg, | |
| 2241 | .offset = Instruction.LoadStoreOffset.none.immediate, | |
| 2242 | } }, | |
| 2243 | }); | |
| 2244 | }, | |
| 2245 | 8 => { | |
| 2246 | _ = try self.addInst(.{ | |
| 2247 | .tag = .ldr_immediate, | |
| 2248 | .data = .{ .load_store_register_immediate = .{ | |
| 2249 | .rt = value_reg.to64(), | |
| 2250 | .rn = addr_reg, | |
| 2251 | .offset = Instruction.LoadStoreOffset.none.immediate, | |
| 2252 | } }, | |
| 2253 | }); | |
| 2254 | }, | |
| 2213 | fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type) !void { | |
| 2214 | const abi_size = ty.abiSize(self.target.*); | |
| 2215 | ||
| 2216 | const tag: Mir.Inst.Tag = switch (abi_size) { | |
| 2217 | 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_immediate else .ldrb_immediate, | |
| 2218 | 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_immediate else .ldrh_immediate, | |
| 2219 | 4 => .ldr_immediate, | |
| 2220 | 8 => .ldr_immediate, | |
| 2255 | 2221 | 3, 5, 6, 7 => return self.fail("TODO: genLdrRegister for more abi_sizes", .{}), |
| 2256 | 2222 | else => unreachable, |
| 2257 | } | |
| 2223 | }; | |
| 2224 | ||
| 2225 | _ = try self.addInst(.{ | |
| 2226 | .tag = tag, | |
| 2227 | .data = .{ .load_store_register_immediate = .{ | |
| 2228 | .rt = value_reg, | |
| 2229 | .rn = addr_reg, | |
| 2230 | .offset = Instruction.LoadStoreOffset.none.immediate, | |
| 2231 | } }, | |
| 2232 | }); | |
| 2258 | 2233 | } |
| 2259 | 2234 | |
| 2260 | fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, abi_size: u64) !void { | |
| 2261 | switch (abi_size) { | |
| 2262 | 1 => { | |
| 2263 | _ = try self.addInst(.{ | |
| 2264 | .tag = .strb_immediate, | |
| 2265 | .data = .{ .load_store_register_immediate = .{ | |
| 2266 | .rt = value_reg.to32(), | |
| 2267 | .rn = addr_reg, | |
| 2268 | .offset = Instruction.LoadStoreOffset.none.immediate, | |
| 2269 | } }, | |
| 2270 | }); | |
| 2271 | }, | |
| 2272 | 2 => { | |
| 2273 | _ = try self.addInst(.{ | |
| 2274 | .tag = .strh_immediate, | |
| 2275 | .data = .{ .load_store_register_immediate = .{ | |
| 2276 | .rt = value_reg.to32(), | |
| 2277 | .rn = addr_reg, | |
| 2278 | .offset = Instruction.LoadStoreOffset.none.immediate, | |
| 2279 | } }, | |
| 2280 | }); | |
| 2281 | }, | |
| 2282 | 4 => { | |
| 2283 | _ = try self.addInst(.{ | |
| 2284 | .tag = .str_immediate, | |
| 2285 | .data = .{ .load_store_register_immediate = .{ | |
| 2286 | .rt = value_reg.to32(), | |
| 2287 | .rn = addr_reg, | |
| 2288 | .offset = Instruction.LoadStoreOffset.none.immediate, | |
| 2289 | } }, | |
| 2290 | }); | |
| 2291 | }, | |
| 2292 | 8 => { | |
| 2293 | _ = try self.addInst(.{ | |
| 2294 | .tag = .str_immediate, | |
| 2295 | .data = .{ .load_store_register_immediate = .{ | |
| 2296 | .rt = value_reg.to64(), | |
| 2297 | .rn = addr_reg, | |
| 2298 | .offset = Instruction.LoadStoreOffset.none.immediate, | |
| 2299 | } }, | |
| 2300 | }); | |
| 2301 | }, | |
| 2235 | fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type) !void { | |
| 2236 | const abi_size = ty.abiSize(self.target.*); | |
| 2237 | ||
| 2238 | const tag: Mir.Inst.Tag = switch (abi_size) { | |
| 2239 | 1 => .strb_immediate, | |
| 2240 | 2 => .strh_immediate, | |
| 2241 | 4, 8 => .str_immediate, | |
| 2302 | 2242 | 3, 5, 6, 7 => return self.fail("TODO: genStrRegister for more abi_sizes", .{}), |
| 2303 | 2243 | else => unreachable, |
| 2304 | } | |
| 2244 | }; | |
| 2245 | ||
| 2246 | _ = try self.addInst(.{ | |
| 2247 | .tag = tag, | |
| 2248 | .data = .{ .load_store_register_immediate = .{ | |
| 2249 | .rt = value_reg, | |
| 2250 | .rn = addr_reg, | |
| 2251 | .offset = Instruction.LoadStoreOffset.none.immediate, | |
| 2252 | } }, | |
| 2253 | }); | |
| 2305 | 2254 | } |
| 2306 | 2255 | |
| 2307 | 2256 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { |
| ... | ... | @@ -2326,7 +2275,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2326 | 2275 | |
| 2327 | 2276 | switch (value) { |
| 2328 | 2277 | .register => |value_reg| { |
| 2329 | try self.genStrRegister(value_reg, addr_reg, abi_size); | |
| 2278 | try self.genStrRegister(value_reg, addr_reg, value_ty); | |
| 2330 | 2279 | }, |
| 2331 | 2280 | else => { |
| 2332 | 2281 | if (abi_size <= 8) { |
| ... | ... | @@ -3624,7 +3573,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3624 | 3573 | // The value is in memory at a hard-coded address. |
| 3625 | 3574 | // If the type is a pointer, it means the pointer address is at this memory location. |
| 3626 | 3575 | try self.genSetReg(ty, reg.to64(), .{ .immediate = addr }); |
| 3627 | try self.genLdrRegister(reg, reg.to64(), ty.abiSize(self.target.*)); | |
| 3576 | try self.genLdrRegister(reg, reg.to64(), ty); | |
| 3628 | 3577 | }, |
| 3629 | 3578 | .stack_offset => |off| { |
| 3630 | 3579 | const abi_size = ty.abiSize(self.target.*); |
| ... | ... | @@ -3632,21 +3581,16 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3632 | 3581 | switch (abi_size) { |
| 3633 | 3582 | 1, 2, 4, 8 => { |
| 3634 | 3583 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 3635 | 1 => .ldrb_stack, | |
| 3636 | 2 => .ldrh_stack, | |
| 3584 | 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_stack else .ldrb_stack, | |
| 3585 | 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_stack else .ldrh_stack, | |
| 3637 | 3586 | 4, 8 => .ldr_stack, |
| 3638 | 3587 | else => unreachable, // unexpected abi size |
| 3639 | 3588 | }; |
| 3640 | const rt: Register = switch (abi_size) { | |
| 3641 | 1, 2, 4 => reg.to32(), | |
| 3642 | 8 => reg.to64(), | |
| 3643 | else => unreachable, // unexpected abi size | |
| 3644 | }; | |
| 3645 | 3589 | |
| 3646 | 3590 | _ = try self.addInst(.{ |
| 3647 | 3591 | .tag = tag, |
| 3648 | 3592 | .data = .{ .load_store_stack = .{ |
| 3649 | .rt = rt, | |
| 3593 | .rt = reg, | |
| 3650 | 3594 | .offset = @intCast(u32, off), |
| 3651 | 3595 | } }, |
| 3652 | 3596 | }); |
src/arch/aarch64/Emit.zig+12-2| ... | ... | @@ -131,6 +131,8 @@ pub fn emitMir( |
| 131 | 131 | .ldr_stack => try emit.mirLoadStoreStack(inst), |
| 132 | 132 | .ldrb_stack => try emit.mirLoadStoreStack(inst), |
| 133 | 133 | .ldrh_stack => try emit.mirLoadStoreStack(inst), |
| 134 | .ldrsb_stack => try emit.mirLoadStoreStack(inst), | |
| 135 | .ldrsh_stack => try emit.mirLoadStoreStack(inst), | |
| 134 | 136 | .str_stack => try emit.mirLoadStoreStack(inst), |
| 135 | 137 | .strb_stack => try emit.mirLoadStoreStack(inst), |
| 136 | 138 | .strh_stack => try emit.mirLoadStoreStack(inst), |
| ... | ... | @@ -145,6 +147,9 @@ pub fn emitMir( |
| 145 | 147 | .ldr_immediate => try emit.mirLoadStoreRegisterImmediate(inst), |
| 146 | 148 | .ldrb_immediate => try emit.mirLoadStoreRegisterImmediate(inst), |
| 147 | 149 | .ldrh_immediate => try emit.mirLoadStoreRegisterImmediate(inst), |
| 150 | .ldrsb_immediate => try emit.mirLoadStoreRegisterImmediate(inst), | |
| 151 | .ldrsh_immediate => try emit.mirLoadStoreRegisterImmediate(inst), | |
| 152 | .ldrsw_immediate => try emit.mirLoadStoreRegisterImmediate(inst), | |
| 148 | 153 | .str_immediate => try emit.mirLoadStoreRegisterImmediate(inst), |
| 149 | 154 | .strb_immediate => try emit.mirLoadStoreRegisterImmediate(inst), |
| 150 | 155 | .strh_immediate => try emit.mirLoadStoreRegisterImmediate(inst), |
| ... | ... | @@ -847,14 +852,14 @@ fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 847 | 852 | |
| 848 | 853 | const raw_offset = emit.stack_size - load_store_stack.offset; |
| 849 | 854 | const offset = switch (tag) { |
| 850 | .ldrb_stack, .strb_stack => blk: { | |
| 855 | .ldrb_stack, .ldrsb_stack, .strb_stack => blk: { | |
| 851 | 856 | if (math.cast(u12, raw_offset)) |imm| { |
| 852 | 857 | break :blk Instruction.LoadStoreOffset.imm(imm); |
| 853 | 858 | } else |_| { |
| 854 | 859 | return emit.fail("TODO load/store stack byte with larger offset", .{}); |
| 855 | 860 | } |
| 856 | 861 | }, |
| 857 | .ldrh_stack, .strh_stack => blk: { | |
| 862 | .ldrh_stack, .ldrsh_stack, .strh_stack => blk: { | |
| 858 | 863 | assert(std.mem.isAlignedGeneric(u32, raw_offset, 2)); // misaligned stack entry |
| 859 | 864 | if (math.cast(u12, @divExact(raw_offset, 2))) |imm| { |
| 860 | 865 | break :blk Instruction.LoadStoreOffset.imm(imm); |
| ... | ... | @@ -883,6 +888,8 @@ fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 883 | 888 | .ldr_stack => try emit.writeInstruction(Instruction.ldr(rt, .sp, offset)), |
| 884 | 889 | .ldrb_stack => try emit.writeInstruction(Instruction.ldrb(rt, .sp, offset)), |
| 885 | 890 | .ldrh_stack => try emit.writeInstruction(Instruction.ldrh(rt, .sp, offset)), |
| 891 | .ldrsb_stack => try emit.writeInstruction(Instruction.ldrsb(rt, .sp, offset)), | |
| 892 | .ldrsh_stack => try emit.writeInstruction(Instruction.ldrsh(rt, .sp, offset)), | |
| 886 | 893 | .str_stack => try emit.writeInstruction(Instruction.str(rt, .sp, offset)), |
| 887 | 894 | .strb_stack => try emit.writeInstruction(Instruction.strb(rt, .sp, offset)), |
| 888 | 895 | .strh_stack => try emit.writeInstruction(Instruction.strh(rt, .sp, offset)), |
| ... | ... | @@ -901,6 +908,9 @@ fn mirLoadStoreRegisterImmediate(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 901 | 908 | .ldr_immediate => try emit.writeInstruction(Instruction.ldr(rt, rn, offset)), |
| 902 | 909 | .ldrb_immediate => try emit.writeInstruction(Instruction.ldrb(rt, rn, offset)), |
| 903 | 910 | .ldrh_immediate => try emit.writeInstruction(Instruction.ldrh(rt, rn, offset)), |
| 911 | .ldrsb_immediate => try emit.writeInstruction(Instruction.ldrsb(rt, rn, offset)), | |
| 912 | .ldrsh_immediate => try emit.writeInstruction(Instruction.ldrsh(rt, rn, offset)), | |
| 913 | .ldrsw_immediate => try emit.writeInstruction(Instruction.ldrsw(rt, rn, offset)), | |
| 904 | 914 | .str_immediate => try emit.writeInstruction(Instruction.str(rt, rn, offset)), |
| 905 | 915 | .strb_immediate => try emit.writeInstruction(Instruction.strb(rt, rn, offset)), |
| 906 | 916 | .strh_immediate => try emit.writeInstruction(Instruction.strh(rt, rn, offset)), |
src/arch/aarch64/Mir.zig+10| ... | ... | @@ -100,6 +100,16 @@ pub const Inst = struct { |
| 100 | 100 | ldrh_immediate, |
| 101 | 101 | /// Load Register Halfword (register) |
| 102 | 102 | ldrh_register, |
| 103 | /// Load Register Signed Byte (immediate) | |
| 104 | ldrsb_immediate, | |
| 105 | /// Pseudo-instruction: Load signed byte from stack | |
| 106 | ldrsb_stack, | |
| 107 | /// Load Register Signed Halfword (immediate) | |
| 108 | ldrsh_immediate, | |
| 109 | /// Pseudo-instruction: Load signed halfword from stack | |
| 110 | ldrsh_stack, | |
| 111 | /// Load Register Signed Word (immediate) | |
| 112 | ldrsw_immediate, | |
| 103 | 113 | /// Logical Shift Left (immediate) |
| 104 | 114 | lsl_immediate, |
| 105 | 115 | /// Logical Shift Left (register) |
src/arch/aarch64/bits.zig+56-22| ... | ... | @@ -665,18 +665,24 @@ pub const Instruction = union(enum) { |
| 665 | 665 | |
| 666 | 666 | /// Which kind of load/store to perform |
| 667 | 667 | const LoadStoreVariant = enum { |
| 668 | /// 32-bit or 64-bit | |
| 668 | /// 32 bits or 64 bits | |
| 669 | 669 | str, |
| 670 | /// 16-bit, zero-extended | |
| 671 | strh, | |
| 672 | /// 8-bit, zero-extended | |
| 670 | /// 8 bits, zero-extended | |
| 673 | 671 | strb, |
| 674 | /// 32-bit or 64-bit | |
| 672 | /// 16 bits, zero-extended | |
| 673 | strh, | |
| 674 | /// 32 bits or 64 bits | |
| 675 | 675 | ldr, |
| 676 | /// 16-bit, zero-extended | |
| 677 | ldrh, | |
| 678 | /// 8-bit, zero-extended | |
| 676 | /// 8 bits, zero-extended | |
| 679 | 677 | ldrb, |
| 678 | /// 16 bits, zero-extended | |
| 679 | ldrh, | |
| 680 | /// 8 bits, sign extended | |
| 681 | ldrsb, | |
| 682 | /// 16 bits, sign extended | |
| 683 | ldrsh, | |
| 684 | /// 32 bits, sign extended | |
| 685 | ldrsw, | |
| 680 | 686 | }; |
| 681 | 687 | |
| 682 | 688 | fn loadStoreRegister( |
| ... | ... | @@ -689,6 +695,7 @@ pub const Instruction = union(enum) { |
| 689 | 695 | assert(rn.id() != Register.xzr.id()); |
| 690 | 696 | |
| 691 | 697 | const off = offset.toU12(); |
| 698 | ||
| 692 | 699 | const op1: u2 = blk: { |
| 693 | 700 | switch (offset) { |
| 694 | 701 | .immediate => |imm| switch (imm) { |
| ... | ... | @@ -699,10 +706,35 @@ pub const Instruction = union(enum) { |
| 699 | 706 | } |
| 700 | 707 | break :blk 0b00; |
| 701 | 708 | }; |
| 702 | const opc: u2 = switch (variant) { | |
| 703 | .ldr, .ldrh, .ldrb => 0b01, | |
| 704 | .str, .strh, .strb => 0b00, | |
| 709 | ||
| 710 | const opc: u2 = blk: { | |
| 711 | switch (variant) { | |
| 712 | .ldr, .ldrh, .ldrb => break :blk 0b01, | |
| 713 | .str, .strh, .strb => break :blk 0b00, | |
| 714 | .ldrsb, | |
| 715 | .ldrsh, | |
| 716 | => switch (rt.size()) { | |
| 717 | 32 => break :blk 0b11, | |
| 718 | 64 => break :blk 0b10, | |
| 719 | else => unreachable, // unexpected register size | |
| 720 | }, | |
| 721 | .ldrsw => break :blk 0b10, | |
| 722 | } | |
| 723 | }; | |
| 724 | ||
| 725 | const size: u2 = blk: { | |
| 726 | switch (variant) { | |
| 727 | .ldr, .str => switch (rt.size()) { | |
| 728 | 32 => break :blk 0b10, | |
| 729 | 64 => break :blk 0b11, | |
| 730 | else => unreachable, // unexpected register size | |
| 731 | }, | |
| 732 | .ldrsw => break :blk 0b10, | |
| 733 | .ldrh, .ldrsh, .strh => break :blk 0b01, | |
| 734 | .ldrb, .ldrsb, .strb => break :blk 0b00, | |
| 735 | } | |
| 705 | 736 | }; |
| 737 | ||
| 706 | 738 | return Instruction{ |
| 707 | 739 | .load_store_register = .{ |
| 708 | 740 | .rt = rt.enc(), |
| ... | ... | @@ -711,17 +743,7 @@ pub const Instruction = union(enum) { |
| 711 | 743 | .opc = opc, |
| 712 | 744 | .op1 = op1, |
| 713 | 745 | .v = 0, |
| 714 | .size = blk: { | |
| 715 | switch (variant) { | |
| 716 | .ldr, .str => switch (rt.size()) { | |
| 717 | 32 => break :blk 0b10, | |
| 718 | 64 => break :blk 0b11, | |
| 719 | else => unreachable, // unexpected register size | |
| 720 | }, | |
| 721 | .ldrh, .strh => break :blk 0b01, | |
| 722 | .ldrb, .strb => break :blk 0b00, | |
| 723 | } | |
| 724 | }, | |
| 746 | .size = size, | |
| 725 | 747 | }, |
| 726 | 748 | }; |
| 727 | 749 | } |
| ... | ... | @@ -1150,6 +1172,18 @@ pub const Instruction = union(enum) { |
| 1150 | 1172 | return loadStoreRegister(rt, rn, offset, .ldrb); |
| 1151 | 1173 | } |
| 1152 | 1174 | |
| 1175 | pub fn ldrsb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { | |
| 1176 | return loadStoreRegister(rt, rn, offset, .ldrsb); | |
| 1177 | } | |
| 1178 | ||
| 1179 | pub fn ldrsh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { | |
| 1180 | return loadStoreRegister(rt, rn, offset, .ldrsh); | |
| 1181 | } | |
| 1182 | ||
| 1183 | pub fn ldrsw(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { | |
| 1184 | return loadStoreRegister(rt, rn, offset, .ldrsw); | |
| 1185 | } | |
| 1186 | ||
| 1153 | 1187 | pub fn str(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { |
| 1154 | 1188 | return loadStoreRegister(rt, rn, offset, .str); |
| 1155 | 1189 | } |
test/behavior/basic.zig-2| ... | ... | @@ -23,8 +23,6 @@ fn testTruncate(x: u32) u8 { |
| 23 | 23 | } |
| 24 | 24 | |
| 25 | 25 | test "truncate to non-power-of-two integers" { |
| 26 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 27 | ||
| 28 | 26 | try testTrunc(u32, u1, 0b10101, 0b1); |
| 29 | 27 | try testTrunc(u32, u1, 0b10110, 0b0); |
| 30 | 28 | try testTrunc(u32, u2, 0b10101, 0b01); |
test/behavior/truncate.zig-2| ... | ... | @@ -49,8 +49,6 @@ test "truncate.i0.var" { |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | 51 | test "truncate on comptime integer" { |
| 52 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 53 | ||
| 54 | 52 | var x = @truncate(u16, 9999); |
| 55 | 53 | try expect(x == 9999); |
| 56 | 54 | var y = @truncate(u16, -21555); |