authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-19 23:47:44-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-08-19 23:47:44-04:00
log6a5094872f10acc629543cc7f10533b438d0283a
tree05ed7336e741900b904fca61c7f63012648a6aea
parentdf10e998ee4a935f49943fb5c0ef134f336c6ee3
parent2e22f7e5a5ff51aa4a1672e011cdc07b08a9a661
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #9587 from g-w1/sh

stage2: implement shr and shl

10 files changed, 198 insertions(+), 7 deletions(-)

src/Air.zig+8
......@@ -94,6 +94,12 @@ pub const Inst = struct {
9494 /// Result type is the same as both operands.
9595 /// Uses the `bin_op` field.
9696 bit_or,
97 /// Shift right. `>>`
98 /// Uses the `bin_op` field.
99 shr,
100 /// Shift left. `<<`
101 /// Uses the `bin_op` field.
102 shl,
97103 /// Bitwise XOR. `^`
98104 /// Uses the `bin_op` field.
99105 xor,
......@@ -445,6 +451,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
445451 .xor,
446452 .ptr_add,
447453 .ptr_sub,
454 .shr,
455 .shl,
448456 => return air.typeOf(datas[inst].bin_op.lhs),
449457
450458 .cmp_lt,
src/Liveness.zig+2
......@@ -249,6 +249,8 @@ fn analyzeInst(
249249 .ptr_slice_elem_val,
250250 .ptr_elem_val,
251251 .ptr_ptr_elem_val,
252 .shl,
253 .shr,
252254 => {
253255 const o = inst_datas[inst].bin_op;
254256 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
52945294 const tracy = trace(@src());
52955295 defer tracy.end();
52965296
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);
53005316}
53015317
53025318fn zirShr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
53035319 const tracy = trace(@src());
53045320 defer tracy.end();
53055321
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);
53085341}
53095342
53105343fn zirBitwise(
......@@ -6001,13 +6034,33 @@ fn zirTypeofElem(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Compile
60016034fn zirTypeofLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
60026035 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
60036036 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);
60056040}
60066041
60076042fn zirLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
60086043 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
60096044 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
6049fn 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);
60116064}
60126065
60136066fn zirTypeofPeer(
src/codegen.zig+20
......@@ -822,6 +822,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
822822 .bit_and => try self.airBitAnd(inst),
823823 .bit_or => try self.airBitOr(inst),
824824 .xor => try self.airXor(inst),
825 .shr => try self.airShr(inst),
826 .shl => try self.airShl(inst),
825827
826828 .alloc => try self.airAlloc(inst),
827829 .arg => try self.airArg(inst),
......@@ -1272,6 +1274,24 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
12721274 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
12731275 }
12741276
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
12751295 fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
12761296 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
12771297 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
871871 .bit_or => try airBinOp(o, inst, " | "),
872872 .xor => try airBinOp(o, inst, " ^ "),
873873
874 .shr => try airBinOp(o, inst, " >> "),
875 .shl => try airBinOp(o, inst, " << "),
876
874877 .not => try airNot( o, inst),
875878
876879 .optional_payload => try airOptionalPayload(o, inst),
src/codegen/llvm.zig+38
......@@ -993,6 +993,9 @@ pub const FuncGen = struct {
993993 .bit_or, .bool_or => try self.airOr(inst),
994994 .xor => try self.airXor(inst),
995995
996 .shl => try self.airShl(inst),
997 .shr => try self.airShr(inst),
998
996999 .cmp_eq => try self.airCmp(inst, .eq),
9971000 .cmp_gt => try self.airCmp(inst, .gt),
9981001 .cmp_gte => try self.airCmp(inst, .gte),
......@@ -1736,6 +1739,41 @@ pub const FuncGen = struct {
17361739 return self.builder.buildXor(lhs, rhs, "");
17371740 }
17381741
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
17391777 fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
17401778 if (self.liveness.isUnused(inst))
17411779 return null;
src/codegen/llvm/bindings.zig+17
......@@ -290,6 +290,14 @@ pub const Builder = opaque {
290290 pub const getInsertBlock = LLVMGetInsertBlock;
291291 extern fn LLVMGetInsertBlock(Builder: *const Builder) *const BasicBlock;
292292
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
293301 pub const buildCall = LLVMBuildCall;
294302 extern fn LLVMBuildCall(
295303 *const Builder,
......@@ -381,6 +389,15 @@ pub const Builder = opaque {
381389 pub const buildAnd = LLVMBuildAnd;
382390 extern fn LLVMBuildAnd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
383391
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
384401 pub const buildOr = LLVMBuildOr;
385402 extern fn LLVMBuildOr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
386403
src/print_air.zig+2
......@@ -127,6 +127,8 @@ const Writer = struct {
127127 .ptr_slice_elem_val,
128128 .ptr_elem_val,
129129 .ptr_ptr_elem_val,
130 .shl,
131 .shr,
130132 => try w.writeBinOp(s, inst),
131133
132134 .is_null,
test/stage2/cbe.zig+25
......@@ -808,6 +808,31 @@ pub fn addCases(ctx: *TestContext) !void {
808808 });
809809 }
810810
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
811836 {
812837 var case = ctx.exeFromCompiledC("inferred error sets", .{});
813838
test/stage2/llvm.zig+23
......@@ -28,6 +28,29 @@ pub fn addCases(ctx: *TestContext) !void {
2828 , "");
2929 }
3030
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
3154 {
3255 var case = ctx.exeUsingLlvmBackend("llvm hello world", linux_x64);
3356