| author | |
| committer | |
| log | 6a5094872f10acc629543cc7f10533b438d0283a |
| tree | 05ed7336e741900b904fca61c7f63012648a6aea |
| parent | df10e998ee4a935f49943fb5c0ef134f336c6ee3 |
| parent | 2e22f7e5a5ff51aa4a1672e011cdc07b08a9a661 |
| signature |
stage2: implement shr and shl10 files changed, 198 insertions(+), 7 deletions(-)
src/Air.zig+8| ... | ... | @@ -94,6 +94,12 @@ pub const Inst = struct { |
| 94 | 94 | /// Result type is the same as both operands. |
| 95 | 95 | /// Uses the `bin_op` field. |
| 96 | 96 | bit_or, |
| 97 | /// Shift right. `>>` | |
| 98 | /// Uses the `bin_op` field. | |
| 99 | shr, | |
| 100 | /// Shift left. `<<` | |
| 101 | /// Uses the `bin_op` field. | |
| 102 | shl, | |
| 97 | 103 | /// Bitwise XOR. `^` |
| 98 | 104 | /// Uses the `bin_op` field. |
| 99 | 105 | xor, |
| ... | ... | @@ -445,6 +451,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 445 | 451 | .xor, |
| 446 | 452 | .ptr_add, |
| 447 | 453 | .ptr_sub, |
| 454 | .shr, | |
| 455 | .shl, | |
| 448 | 456 | => return air.typeOf(datas[inst].bin_op.lhs), |
| 449 | 457 | |
| 450 | 458 | .cmp_lt, |
src/Liveness.zig+2| ... | ... | @@ -249,6 +249,8 @@ fn analyzeInst( |
| 249 | 249 | .ptr_slice_elem_val, |
| 250 | 250 | .ptr_elem_val, |
| 251 | 251 | .ptr_ptr_elem_val, |
| 252 | .shl, | |
| 253 | .shr, | |
| 252 | 254 | => { |
| 253 | 255 | const o = inst_datas[inst].bin_op; |
| 254 | 256 | return trackOperands(a, new_set, inst, main_tomb, .{ o.lhs, o.rhs, .none }); |
src/Sema.zig+60-7| ... | ... | @@ -5294,17 +5294,50 @@ fn zirShl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!A |
| 5294 | 5294 | const tracy = trace(@src()); |
| 5295 | 5295 | defer tracy.end(); |
| 5296 | 5296 | |
| 5297 | _ = block; | |
| 5298 | _ = inst; | |
| 5299 | return sema.mod.fail(&block.base, sema.src, "TODO implement zirShl", .{}); | |
| 5297 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | |
| 5298 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | |
| 5299 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; | |
| 5300 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; | |
| 5301 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | |
| 5302 | const lhs = sema.resolveInst(extra.lhs); | |
| 5303 | const rhs = sema.resolveInst(extra.rhs); | |
| 5304 | ||
| 5305 | if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| { | |
| 5306 | if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| { | |
| 5307 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | |
| 5308 | return sema.addConstUndef(sema.typeOf(lhs)); | |
| 5309 | } | |
| 5310 | return sema.mod.fail(&block.base, src, "TODO implement comptime shl", .{}); | |
| 5311 | } | |
| 5312 | } | |
| 5313 | ||
| 5314 | try sema.requireRuntimeBlock(block, src); | |
| 5315 | return block.addBinOp(.shl, lhs, rhs); | |
| 5300 | 5316 | } |
| 5301 | 5317 | |
| 5302 | 5318 | fn zirShr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 5303 | 5319 | const tracy = trace(@src()); |
| 5304 | 5320 | defer tracy.end(); |
| 5305 | 5321 | |
| 5306 | _ = inst; | |
| 5307 | return sema.mod.fail(&block.base, sema.src, "TODO implement zirShr", .{}); | |
| 5322 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | |
| 5323 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | |
| 5324 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; | |
| 5325 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; | |
| 5326 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | |
| 5327 | const lhs = sema.resolveInst(extra.lhs); | |
| 5328 | const rhs = sema.resolveInst(extra.rhs); | |
| 5329 | ||
| 5330 | if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| { | |
| 5331 | if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| { | |
| 5332 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | |
| 5333 | return sema.addConstUndef(sema.typeOf(lhs)); | |
| 5334 | } | |
| 5335 | return sema.mod.fail(&block.base, src, "TODO implement comptime shr", .{}); | |
| 5336 | } | |
| 5337 | } | |
| 5338 | ||
| 5339 | try sema.requireRuntimeBlock(block, src); | |
| 5340 | return block.addBinOp(.shr, lhs, rhs); | |
| 5308 | 5341 | } |
| 5309 | 5342 | |
| 5310 | 5343 | fn zirBitwise( |
| ... | ... | @@ -6001,13 +6034,33 @@ fn zirTypeofElem(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Compile |
| 6001 | 6034 | fn zirTypeofLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 6002 | 6035 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 6003 | 6036 | const src = inst_data.src(); |
| 6004 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirTypeofLog2IntType", .{}); | |
| 6037 | const operand = sema.resolveInst(inst_data.operand); | |
| 6038 | const operand_ty = sema.typeOf(operand); | |
| 6039 | return sema.log2IntType(block, operand_ty, src); | |
| 6005 | 6040 | } |
| 6006 | 6041 | |
| 6007 | 6042 | fn zirLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 6008 | 6043 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 6009 | 6044 | const src = inst_data.src(); |
| 6010 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirLog2IntType", .{}); | |
| 6045 | const operand = try sema.resolveType(block, src, inst_data.operand); | |
| 6046 | return sema.log2IntType(block, operand, src); | |
| 6047 | } | |
| 6048 | ||
| 6049 | fn log2IntType(sema: *Sema, block: *Scope.Block, operand: Type, src: LazySrcLoc) CompileError!Air.Inst.Ref { | |
| 6050 | if (operand.zigTypeTag() != .Int) return sema.mod.fail( | |
| 6051 | &block.base, | |
| 6052 | src, | |
| 6053 | "bit shifting operation expected integer type, found '{}'", | |
| 6054 | .{operand}, | |
| 6055 | ); | |
| 6056 | ||
| 6057 | var count: u16 = 0; | |
| 6058 | var s = operand.bitSize(sema.mod.getTarget()) - 1; | |
| 6059 | while (s != 0) : (s >>= 1) { | |
| 6060 | count += 1; | |
| 6061 | } | |
| 6062 | const res = try Module.makeIntType(sema.arena, .unsigned, count); | |
| 6063 | return sema.addType(res); | |
| 6011 | 6064 | } |
| 6012 | 6065 | |
| 6013 | 6066 | fn zirTypeofPeer( |
src/codegen.zig+20| ... | ... | @@ -822,6 +822,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 822 | 822 | .bit_and => try self.airBitAnd(inst), |
| 823 | 823 | .bit_or => try self.airBitOr(inst), |
| 824 | 824 | .xor => try self.airXor(inst), |
| 825 | .shr => try self.airShr(inst), | |
| 826 | .shl => try self.airShl(inst), | |
| 825 | 827 | |
| 826 | 828 | .alloc => try self.airAlloc(inst), |
| 827 | 829 | .arg => try self.airArg(inst), |
| ... | ... | @@ -1272,6 +1274,24 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1272 | 1274 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1273 | 1275 | } |
| 1274 | 1276 | |
| 1277 | fn airShl(self: *Self, inst: Air.Inst.Index) !void { | |
| 1278 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 1279 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) { | |
| 1280 | .arm, .armeb => try self.genArmBinOp(inst, bin_op.lhs, bin_op.rhs, .shl), | |
| 1281 | else => return self.fail("TODO implement shl for {}", .{self.target.cpu.arch}), | |
| 1282 | }; | |
| 1283 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | |
| 1284 | } | |
| 1285 | ||
| 1286 | fn airShr(self: *Self, inst: Air.Inst.Index) !void { | |
| 1287 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 1288 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) { | |
| 1289 | .arm, .armeb => try self.genArmBinOp(inst, bin_op.lhs, bin_op.rhs, .shr), | |
| 1290 | else => return self.fail("TODO implement shr for {}", .{self.target.cpu.arch}), | |
| 1291 | }; | |
| 1292 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | |
| 1293 | } | |
| 1294 | ||
| 1275 | 1295 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 1276 | 1296 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1277 | 1297 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) { |
src/codegen/c.zig+3| ... | ... | @@ -871,6 +871,9 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM |
| 871 | 871 | .bit_or => try airBinOp(o, inst, " | "), |
| 872 | 872 | .xor => try airBinOp(o, inst, " ^ "), |
| 873 | 873 | |
| 874 | .shr => try airBinOp(o, inst, " >> "), | |
| 875 | .shl => try airBinOp(o, inst, " << "), | |
| 876 | ||
| 874 | 877 | .not => try airNot( o, inst), |
| 875 | 878 | |
| 876 | 879 | .optional_payload => try airOptionalPayload(o, inst), |
src/codegen/llvm.zig+38| ... | ... | @@ -993,6 +993,9 @@ pub const FuncGen = struct { |
| 993 | 993 | .bit_or, .bool_or => try self.airOr(inst), |
| 994 | 994 | .xor => try self.airXor(inst), |
| 995 | 995 | |
| 996 | .shl => try self.airShl(inst), | |
| 997 | .shr => try self.airShr(inst), | |
| 998 | ||
| 996 | 999 | .cmp_eq => try self.airCmp(inst, .eq), |
| 997 | 1000 | .cmp_gt => try self.airCmp(inst, .gt), |
| 998 | 1001 | .cmp_gte => try self.airCmp(inst, .gte), |
| ... | ... | @@ -1736,6 +1739,41 @@ pub const FuncGen = struct { |
| 1736 | 1739 | return self.builder.buildXor(lhs, rhs, ""); |
| 1737 | 1740 | } |
| 1738 | 1741 | |
| 1742 | fn airShl(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | |
| 1743 | if (self.liveness.isUnused(inst)) | |
| 1744 | return null; | |
| 1745 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 1746 | const lhs = try self.resolveInst(bin_op.lhs); | |
| 1747 | const rhs = try self.resolveInst(bin_op.rhs); | |
| 1748 | const lhs_type = self.air.typeOf(bin_op.lhs); | |
| 1749 | const tg = self.dg.module.getTarget(); | |
| 1750 | const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg)) | |
| 1751 | self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "") | |
| 1752 | else | |
| 1753 | rhs; | |
| 1754 | return self.builder.buildShl(lhs, casted_rhs, ""); | |
| 1755 | } | |
| 1756 | ||
| 1757 | fn airShr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | |
| 1758 | if (self.liveness.isUnused(inst)) | |
| 1759 | return null; | |
| 1760 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 1761 | const lhs = try self.resolveInst(bin_op.lhs); | |
| 1762 | const rhs = try self.resolveInst(bin_op.rhs); | |
| 1763 | const lhs_type = self.air.typeOf(bin_op.lhs); | |
| 1764 | const tg = self.dg.module.getTarget(); | |
| 1765 | const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg)) | |
| 1766 | self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "") | |
| 1767 | else | |
| 1768 | rhs; | |
| 1769 | ||
| 1770 | if (self.air.typeOfIndex(inst).isSignedInt()) { | |
| 1771 | return self.builder.buildAShr(lhs, casted_rhs, ""); | |
| 1772 | } else { | |
| 1773 | return self.builder.buildLShr(lhs, casted_rhs, ""); | |
| 1774 | } | |
| 1775 | } | |
| 1776 | ||
| 1739 | 1777 | fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 1740 | 1778 | if (self.liveness.isUnused(inst)) |
| 1741 | 1779 | return null; |
src/codegen/llvm/bindings.zig+17| ... | ... | @@ -290,6 +290,14 @@ pub const Builder = opaque { |
| 290 | 290 | pub const getInsertBlock = LLVMGetInsertBlock; |
| 291 | 291 | extern fn LLVMGetInsertBlock(Builder: *const Builder) *const BasicBlock; |
| 292 | 292 | |
| 293 | pub const buildZExt = LLVMBuildZExt; | |
| 294 | extern fn LLVMBuildZExt( | |
| 295 | *const Builder, | |
| 296 | Value: *const Value, | |
| 297 | DestTy: *const Type, | |
| 298 | Name: [*:0]const u8, | |
| 299 | ) *const Value; | |
| 300 | ||
| 293 | 301 | pub const buildCall = LLVMBuildCall; |
| 294 | 302 | extern fn LLVMBuildCall( |
| 295 | 303 | *const Builder, |
| ... | ... | @@ -381,6 +389,15 @@ pub const Builder = opaque { |
| 381 | 389 | pub const buildAnd = LLVMBuildAnd; |
| 382 | 390 | extern fn LLVMBuildAnd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; |
| 383 | 391 | |
| 392 | pub const buildLShr = LLVMBuildLShr; | |
| 393 | extern fn LLVMBuildLShr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; | |
| 394 | ||
| 395 | pub const buildAShr = LLVMBuildAShr; | |
| 396 | extern fn LLVMBuildAShr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; | |
| 397 | ||
| 398 | pub const buildShl = LLVMBuildShl; | |
| 399 | extern fn LLVMBuildShl(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; | |
| 400 | ||
| 384 | 401 | pub const buildOr = LLVMBuildOr; |
| 385 | 402 | extern fn LLVMBuildOr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; |
| 386 | 403 |
src/print_air.zig+2| ... | ... | @@ -127,6 +127,8 @@ const Writer = struct { |
| 127 | 127 | .ptr_slice_elem_val, |
| 128 | 128 | .ptr_elem_val, |
| 129 | 129 | .ptr_ptr_elem_val, |
| 130 | .shl, | |
| 131 | .shr, | |
| 130 | 132 | => try w.writeBinOp(s, inst), |
| 131 | 133 | |
| 132 | 134 | .is_null, |
test/stage2/cbe.zig+25| ... | ... | @@ -808,6 +808,31 @@ pub fn addCases(ctx: *TestContext) !void { |
| 808 | 808 | }); |
| 809 | 809 | } |
| 810 | 810 | |
| 811 | { | |
| 812 | var case = ctx.exeFromCompiledC("shift right + left", .{}); | |
| 813 | case.addCompareOutput( | |
| 814 | \\pub export fn main() c_int { | |
| 815 | \\ var i: u32 = 16; | |
| 816 | \\ assert(i >> 1, 8); | |
| 817 | \\ return 0; | |
| 818 | \\} | |
| 819 | \\fn assert(a: u32, b: u32) void { | |
| 820 | \\ if (a != b) unreachable; | |
| 821 | \\} | |
| 822 | , ""); | |
| 823 | ||
| 824 | case.addCompareOutput( | |
| 825 | \\pub export fn main() c_int { | |
| 826 | \\ var i: u32 = 16; | |
| 827 | \\ assert(i << 1, 32); | |
| 828 | \\ return 0; | |
| 829 | \\} | |
| 830 | \\fn assert(a: u32, b: u32) void { | |
| 831 | \\ if (a != b) unreachable; | |
| 832 | \\} | |
| 833 | , ""); | |
| 834 | } | |
| 835 | ||
| 811 | 836 | { |
| 812 | 837 | var case = ctx.exeFromCompiledC("inferred error sets", .{}); |
| 813 | 838 |
test/stage2/llvm.zig+23| ... | ... | @@ -28,6 +28,29 @@ pub fn addCases(ctx: *TestContext) !void { |
| 28 | 28 | , ""); |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | { | |
| 32 | var case = ctx.exeUsingLlvmBackend("shift right + left", linux_x64); | |
| 33 | ||
| 34 | case.addCompareOutput( | |
| 35 | \\pub export fn main() void { | |
| 36 | \\ var i: u32 = 16; | |
| 37 | \\ assert(i >> 1, 8); | |
| 38 | \\} | |
| 39 | \\fn assert(a: u32, b: u32) void { | |
| 40 | \\ if (a != b) unreachable; | |
| 41 | \\} | |
| 42 | , ""); | |
| 43 | case.addCompareOutput( | |
| 44 | \\pub export fn main() void { | |
| 45 | \\ var i: u32 = 16; | |
| 46 | \\ assert(i << 1, 32); | |
| 47 | \\} | |
| 48 | \\fn assert(a: u32, b: u32) void { | |
| 49 | \\ if (a != b) unreachable; | |
| 50 | \\} | |
| 51 | , ""); | |
| 52 | } | |
| 53 | ||
| 31 | 54 | { |
| 32 | 55 | var case = ctx.exeUsingLlvmBackend("llvm hello world", linux_x64); |
| 33 | 56 |