authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-30 16:23:31-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-30 16:23:31-07:00
logfb7060d3c2e8ce4d7de5560adf8ec4a26fc5f6e8
tree3710af0870e1e1d43f44830d6ff3e662761e93ce
parent0c30799d4039c30f95eee29e2c2f8f604e8b9880

stage2: implement shl_exact and shr_exact

These produce an undefined value when one bits are shifted out. New AIR instruction: shr_exact.

13 files changed, 97 insertions(+), 62 deletions(-)

src/Air.zig+4
...@@ -179,6 +179,9 @@ pub const Inst = struct {...@@ -179,6 +179,9 @@ pub const Inst = struct {
179 /// Shift right. `>>`179 /// Shift right. `>>`
180 /// Uses the `bin_op` field.180 /// Uses the `bin_op` field.
181 shr,181 shr,
182 /// Shift right. The shift produces a poison value if it shifts out any non-zero bits.
183 /// Uses the `bin_op` field.
184 shr_exact,
182 /// Shift left. `<<`185 /// Shift left. `<<`
183 /// Uses the `bin_op` field.186 /// Uses the `bin_op` field.
184 shl,187 shl,
...@@ -738,6 +741,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -738,6 +741,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
738 .ptr_add,741 .ptr_add,
739 .ptr_sub,742 .ptr_sub,
740 .shr,743 .shr,
744 .shr_exact,
741 .shl,745 .shl,
742 .shl_exact,746 .shl_exact,
743 .shl_sat,747 .shl_sat,
src/Liveness.zig+1
...@@ -261,6 +261,7 @@ fn analyzeInst(...@@ -261,6 +261,7 @@ fn analyzeInst(
261 .shl_exact,261 .shl_exact,
262 .shl_sat,262 .shl_sat,
263 .shr,263 .shr,
264 .shr_exact,
264 .atomic_store_unordered,265 .atomic_store_unordered,
265 .atomic_store_monotonic,266 .atomic_store_monotonic,
266 .atomic_store_release,267 .atomic_store_release,
src/Sema.zig+43-23
...@@ -666,7 +666,8 @@ fn analyzeBodyInner(...@@ -666,7 +666,8 @@ fn analyzeBodyInner(
666 .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst),666 .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst),
667 .ref => try sema.zirRef(block, inst),667 .ref => try sema.zirRef(block, inst),
668 .ret_err_value_code => try sema.zirRetErrValueCode(block, inst),668 .ret_err_value_code => try sema.zirRetErrValueCode(block, inst),
669 .shr => try sema.zirShr(block, inst),669 .shr => try sema.zirShr(block, inst, .shr),
670 .shr_exact => try sema.zirShr(block, inst, .shr_exact),
670 .slice_end => try sema.zirSliceEnd(block, inst),671 .slice_end => try sema.zirSliceEnd(block, inst),
671 .slice_sentinel => try sema.zirSliceSentinel(block, inst),672 .slice_sentinel => try sema.zirSliceSentinel(block, inst),
672 .slice_start => try sema.zirSliceStart(block, inst),673 .slice_start => try sema.zirSliceStart(block, inst),
...@@ -721,7 +722,6 @@ fn analyzeBodyInner(...@@ -721,7 +722,6 @@ fn analyzeBodyInner(
721 .pop_count => try sema.zirPopCount(block, inst),722 .pop_count => try sema.zirPopCount(block, inst),
722 .byte_swap => try sema.zirByteSwap(block, inst),723 .byte_swap => try sema.zirByteSwap(block, inst),
723 .bit_reverse => try sema.zirBitReverse(block, inst),724 .bit_reverse => try sema.zirBitReverse(block, inst),
724 .shr_exact => try sema.zirShrExact(block, inst),
725 .bit_offset_of => try sema.zirBitOffsetOf(block, inst),725 .bit_offset_of => try sema.zirBitOffsetOf(block, inst),
726 .offset_of => try sema.zirOffsetOf(block, inst),726 .offset_of => try sema.zirOffsetOf(block, inst),
727 .cmpxchg_strong => try sema.zirCmpxchg(block, inst, .cmpxchg_strong),727 .cmpxchg_strong => try sema.zirCmpxchg(block, inst, .cmpxchg_strong),
...@@ -7472,18 +7472,30 @@ fn zirShl(...@@ -7472,18 +7472,30 @@ fn zirShl(
7472 if (rhs_val.compareWithZero(.eq)) {7472 if (rhs_val.compareWithZero(.eq)) {
7473 return sema.addConstant(lhs_ty, lhs_val);7473 return sema.addConstant(lhs_ty, lhs_val);
7474 }7474 }
7475 const target = sema.mod.getTarget();
7475 const val = switch (air_tag) {7476 const val = switch (air_tag) {
7476 .shl_exact => return sema.fail(block, lhs_src, "TODO implement Sema for comptime shl_exact", .{}),7477 .shl_exact => val: {
7478 const shifted = try lhs_val.shl(rhs_val, sema.arena);
7479 if (lhs_ty.zigTypeTag() == .ComptimeInt) {
7480 break :val shifted;
7481 }
7482 const int_info = lhs_ty.intInfo(target);
7483 const truncated = try shifted.intTrunc(sema.arena, int_info.signedness, int_info.bits);
7484 if (truncated.compareHetero(.eq, shifted)) {
7485 break :val shifted;
7486 }
7487 return sema.addConstUndef(lhs_ty);
7488 },
74777489
7478 .shl_sat => if (lhs_ty.zigTypeTag() == .ComptimeInt)7490 .shl_sat => if (lhs_ty.zigTypeTag() == .ComptimeInt)
7479 try lhs_val.shl(rhs_val, sema.arena)7491 try lhs_val.shl(rhs_val, sema.arena)
7480 else7492 else
7481 try lhs_val.shlSat(rhs_val, lhs_ty, sema.arena, sema.mod.getTarget()),7493 try lhs_val.shlSat(rhs_val, lhs_ty, sema.arena, target),
74827494
7483 .shl => if (lhs_ty.zigTypeTag() == .ComptimeInt)7495 .shl => if (lhs_ty.zigTypeTag() == .ComptimeInt)
7484 try lhs_val.shl(rhs_val, sema.arena)7496 try lhs_val.shl(rhs_val, sema.arena)
7485 else7497 else
7486 try lhs_val.shlTrunc(rhs_val, lhs_ty, sema.arena, sema.mod.getTarget()),7498 try lhs_val.shlTrunc(rhs_val, lhs_ty, sema.arena, target),
74877499
7488 else => unreachable,7500 else => unreachable,
7489 };7501 };
...@@ -7502,19 +7514,23 @@ fn zirShl(...@@ -7502,19 +7514,23 @@ fn zirShl(
7502 return block.addBinOp(air_tag, lhs, rhs);7514 return block.addBinOp(air_tag, lhs, rhs);
7503}7515}
75047516
7505fn zirShr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {7517fn zirShr(
7518 sema: *Sema,
7519 block: *Block,
7520 inst: Zir.Inst.Index,
7521 air_tag: Air.Inst.Tag,
7522) CompileError!Air.Inst.Ref {
7506 const tracy = trace(@src());7523 const tracy = trace(@src());
7507 defer tracy.end();7524 defer tracy.end();
75087525
7509 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;7526 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
7510 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
7511 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };7527 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
7512 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };7528 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
7513 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;7529 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
7514 const lhs = sema.resolveInst(extra.lhs);7530 const lhs = sema.resolveInst(extra.lhs);
7515 const rhs = sema.resolveInst(extra.rhs);7531 const rhs = sema.resolveInst(extra.rhs);
75167532
7517 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {7533 const runtime_src = if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| rs: {
7518 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {7534 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
7519 const lhs_ty = sema.typeOf(lhs);7535 const lhs_ty = sema.typeOf(lhs);
7520 if (lhs_val.isUndef() or rhs_val.isUndef()) {7536 if (lhs_val.isUndef() or rhs_val.isUndef()) {
...@@ -7524,19 +7540,29 @@ fn zirShr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins...@@ -7524,19 +7540,29 @@ fn zirShr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
7524 if (rhs_val.compareWithZero(.eq)) {7540 if (rhs_val.compareWithZero(.eq)) {
7525 return sema.addConstant(lhs_ty, lhs_val);7541 return sema.addConstant(lhs_ty, lhs_val);
7526 }7542 }
7543 if (air_tag == .shr_exact) {
7544 // Detect if any ones would be shifted out.
7545 const bits = @intCast(u16, rhs_val.toUnsignedInt());
7546 const truncated = try lhs_val.intTrunc(sema.arena, .unsigned, bits);
7547 if (!truncated.compareWithZero(.eq)) {
7548 return sema.addConstUndef(lhs_ty);
7549 }
7550 }
7527 const val = try lhs_val.shr(rhs_val, sema.arena);7551 const val = try lhs_val.shr(rhs_val, sema.arena);
7528 return sema.addConstant(lhs_ty, val);7552 return sema.addConstant(lhs_ty, val);
7553 } else {
7554 // Even if lhs is not comptime known, we can still deduce certain things based
7555 // on rhs.
7556 // If rhs is 0, return lhs without doing any calculations.
7557 if (rhs_val.compareWithZero(.eq)) {
7558 return lhs;
7559 }
7560 break :rs lhs_src;
7529 }7561 }
7530 // Even if lhs is not comptime known, we can still deduce certain things based7562 } else rhs_src;
7531 // on rhs.
7532 // If rhs is 0, return lhs without doing any calculations.
7533 else if (rhs_val.compareWithZero(.eq)) {
7534 return lhs;
7535 }
7536 }
75377563
7538 try sema.requireRuntimeBlock(block, src);7564 try sema.requireRuntimeBlock(block, runtime_src);
7539 return block.addBinOp(.shr, lhs, rhs);7565 return block.addBinOp(air_tag, lhs, rhs);
7540}7566}
75417567
7542fn zirBitwise(7568fn zirBitwise(
...@@ -11448,12 +11474,6 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -11448,12 +11474,6 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
11448 return sema.fail(block, src, "TODO: Sema.zirBitReverse", .{});11474 return sema.fail(block, src, "TODO: Sema.zirBitReverse", .{});
11449}11475}
1145011476
11451fn zirShrExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
11452 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
11453 const src = inst_data.src();
11454 return sema.fail(block, src, "TODO: Sema.zirShrExact", .{});
11455}
11456
11457fn zirBitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {11477fn zirBitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
11458 const offset = try bitOffsetOf(sema, block, inst);11478 const offset = try bitOffsetOf(sema, block, inst);
11459 return sema.addIntUnsigned(Type.comptime_int, offset);11479 return sema.addIntUnsigned(Type.comptime_int, offset);
src/arch/aarch64/CodeGen.zig+6-6
...@@ -535,12 +535,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -535,12 +535,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
535 .cmp_gt => try self.airCmp(inst, .gt),535 .cmp_gt => try self.airCmp(inst, .gt),
536 .cmp_neq => try self.airCmp(inst, .neq),536 .cmp_neq => try self.airCmp(inst, .neq),
537537
538 .bool_and => try self.airBoolOp(inst),538 .bool_and => try self.airBoolOp(inst),
539 .bool_or => try self.airBoolOp(inst),539 .bool_or => try self.airBoolOp(inst),
540 .bit_and => try self.airBitAnd(inst),540 .bit_and => try self.airBitAnd(inst),
541 .bit_or => try self.airBitOr(inst),541 .bit_or => try self.airBitOr(inst),
542 .xor => try self.airXor(inst),542 .xor => try self.airXor(inst),
543 .shr => try self.airShr(inst),543 .shr, .shr_exact => try self.airShr(inst),
544544
545 .alloc => try self.airAlloc(inst),545 .alloc => try self.airAlloc(inst),
546 .ret_ptr => try self.airRetPtr(inst),546 .ret_ptr => try self.airRetPtr(inst),
src/arch/arm/CodeGen.zig+6-6
...@@ -527,12 +527,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -527,12 +527,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
527 .cmp_gt => try self.airCmp(inst, .gt),527 .cmp_gt => try self.airCmp(inst, .gt),
528 .cmp_neq => try self.airCmp(inst, .neq),528 .cmp_neq => try self.airCmp(inst, .neq),
529529
530 .bool_and => try self.airBoolOp(inst),530 .bool_and => try self.airBoolOp(inst),
531 .bool_or => try self.airBoolOp(inst),531 .bool_or => try self.airBoolOp(inst),
532 .bit_and => try self.airBitAnd(inst),532 .bit_and => try self.airBitAnd(inst),
533 .bit_or => try self.airBitOr(inst),533 .bit_or => try self.airBitOr(inst),
534 .xor => try self.airXor(inst),534 .xor => try self.airXor(inst),
535 .shr => try self.airShr(inst),535 .shr, .shr_exact => try self.airShr(inst),
536536
537 .alloc => try self.airAlloc(inst),537 .alloc => try self.airAlloc(inst),
538 .ret_ptr => try self.airRetPtr(inst),538 .ret_ptr => try self.airRetPtr(inst),
src/arch/riscv64/CodeGen.zig+6-6
...@@ -514,12 +514,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -514,12 +514,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
514 .cmp_gt => try self.airCmp(inst, .gt),514 .cmp_gt => try self.airCmp(inst, .gt),
515 .cmp_neq => try self.airCmp(inst, .neq),515 .cmp_neq => try self.airCmp(inst, .neq),
516516
517 .bool_and => try self.airBoolOp(inst),517 .bool_and => try self.airBoolOp(inst),
518 .bool_or => try self.airBoolOp(inst),518 .bool_or => try self.airBoolOp(inst),
519 .bit_and => try self.airBitAnd(inst),519 .bit_and => try self.airBitAnd(inst),
520 .bit_or => try self.airBitOr(inst),520 .bit_or => try self.airBitOr(inst),
521 .xor => try self.airXor(inst),521 .xor => try self.airXor(inst),
522 .shr => try self.airShr(inst),522 .shr, .shr_exact => try self.airShr(inst),
523523
524 .alloc => try self.airAlloc(inst),524 .alloc => try self.airAlloc(inst),
525 .ret_ptr => try self.airRetPtr(inst),525 .ret_ptr => try self.airRetPtr(inst),
src/arch/wasm/CodeGen.zig+2-3
...@@ -1442,8 +1442,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1442,8 +1442,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1442 .bool_and => self.airBinOp(inst, .@"and"),1442 .bool_and => self.airBinOp(inst, .@"and"),
1443 .bool_or => self.airBinOp(inst, .@"or"),1443 .bool_or => self.airBinOp(inst, .@"or"),
1444 .rem => self.airBinOp(inst, .rem),1444 .rem => self.airBinOp(inst, .rem),
1445 .shl => self.airBinOp(inst, .shl),1445 .shl, .shl_exact => self.airBinOp(inst, .shl),
1446 .shr => self.airBinOp(inst, .shr),1446 .shr, .shr_exact => self.airBinOp(inst, .shr),
1447 .xor => self.airBinOp(inst, .xor),1447 .xor => self.airBinOp(inst, .xor),
14481448
1449 .cmp_eq => self.airCmp(inst, .eq),1449 .cmp_eq => self.airCmp(inst, .eq),
...@@ -1531,7 +1531,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1531,7 +1531,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1531 .max,1531 .max,
1532 .min,1532 .min,
1533 .assembly,1533 .assembly,
1534 .shl_exact,
1535 .shl_sat,1534 .shl_sat,
1536 .ret_addr,1535 .ret_addr,
1537 .clz,1536 .clz,
src/arch/x86_64/CodeGen.zig+6-6
...@@ -578,12 +578,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -578,12 +578,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
578 .cmp_gt => try self.airCmp(inst, .gt),578 .cmp_gt => try self.airCmp(inst, .gt),
579 .cmp_neq => try self.airCmp(inst, .neq),579 .cmp_neq => try self.airCmp(inst, .neq),
580580
581 .bool_and => try self.airBoolOp(inst),581 .bool_and => try self.airBoolOp(inst),
582 .bool_or => try self.airBoolOp(inst),582 .bool_or => try self.airBoolOp(inst),
583 .bit_and => try self.airBitAnd(inst),583 .bit_and => try self.airBitAnd(inst),
584 .bit_or => try self.airBitOr(inst),584 .bit_or => try self.airBitOr(inst),
585 .xor => try self.airXor(inst),585 .xor => try self.airXor(inst),
586 .shr => try self.airShr(inst),586 .shr, .shr_exact => try self.airShr(inst),
587587
588 .alloc => try self.airAlloc(inst),588 .alloc => try self.airAlloc(inst),
589 .ret_ptr => try self.airRetPtr(inst),589 .ret_ptr => try self.airRetPtr(inst),
src/codegen/c.zig+1-1
...@@ -1470,7 +1470,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1470,7 +1470,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1470 .bit_and => try airBinOp(f, inst, " & "),1470 .bit_and => try airBinOp(f, inst, " & "),
1471 .bit_or => try airBinOp(f, inst, " | "),1471 .bit_or => try airBinOp(f, inst, " | "),
1472 .xor => try airBinOp(f, inst, " ^ "),1472 .xor => try airBinOp(f, inst, " ^ "),
1473 .shr => try airBinOp(f, inst, " >> "),1473 .shr, .shr_exact => try airBinOp(f, inst, " >> "),
1474 .shl, .shl_exact => try airBinOp(f, inst, " << "),1474 .shl, .shl_exact => try airBinOp(f, inst, " << "),
1475 .not => try airNot (f, inst),1475 .not => try airNot (f, inst),
14761476
src/codegen/llvm.zig+15-5
...@@ -2047,7 +2047,8 @@ pub const FuncGen = struct {...@@ -2047,7 +2047,8 @@ pub const FuncGen = struct {
2047 .bit_and, .bool_and => try self.airAnd(inst),2047 .bit_and, .bool_and => try self.airAnd(inst),
2048 .bit_or, .bool_or => try self.airOr(inst),2048 .bit_or, .bool_or => try self.airOr(inst),
2049 .xor => try self.airXor(inst),2049 .xor => try self.airXor(inst),
2050 .shr => try self.airShr(inst),2050 .shr => try self.airShr(inst, false),
2051 .shr_exact => try self.airShr(inst, true),
20512052
2052 .cmp_eq => try self.airCmp(inst, .eq),2053 .cmp_eq => try self.airCmp(inst, .eq),
2053 .cmp_gt => try self.airCmp(inst, .gt),2054 .cmp_gt => try self.airCmp(inst, .gt),
...@@ -3633,7 +3634,7 @@ pub const FuncGen = struct {...@@ -3633,7 +3634,7 @@ pub const FuncGen = struct {
3633 return self.builder.buildUShlSat(lhs, casted_rhs, "");3634 return self.builder.buildUShlSat(lhs, casted_rhs, "");
3634 }3635 }
36353636
3636 fn airShr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {3637 fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) !?*const llvm.Value {
3637 if (self.liveness.isUnused(inst))3638 if (self.liveness.isUnused(inst))
3638 return null;3639 return null;
3639 const bin_op = self.air.instructions.items(.data)[inst].bin_op;3640 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -3645,11 +3646,20 @@ pub const FuncGen = struct {...@@ -3645,11 +3646,20 @@ pub const FuncGen = struct {
3645 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")3646 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")
3646 else3647 else
3647 rhs;3648 rhs;
3649 const is_signed_int = self.air.typeOfIndex(inst).isSignedInt();
36483650
3649 if (self.air.typeOfIndex(inst).isSignedInt()) {3651 if (is_exact) {
3650 return self.builder.buildAShr(lhs, casted_rhs, "");3652 if (is_signed_int) {
3653 return self.builder.buildAShrExact(lhs, casted_rhs, "");
3654 } else {
3655 return self.builder.buildLShrExact(lhs, casted_rhs, "");
3656 }
3651 } else {3657 } else {
3652 return self.builder.buildLShr(lhs, casted_rhs, "");3658 if (is_signed_int) {
3659 return self.builder.buildAShr(lhs, casted_rhs, "");
3660 } else {
3661 return self.builder.buildLShr(lhs, casted_rhs, "");
3662 }
3653 }3663 }
3654 }3664 }
36553665
src/codegen/llvm/bindings.zig+6
...@@ -548,6 +548,12 @@ pub const Builder = opaque {...@@ -548,6 +548,12 @@ pub const Builder = opaque {
548 pub const buildAShr = LLVMBuildAShr;548 pub const buildAShr = LLVMBuildAShr;
549 extern fn LLVMBuildAShr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;549 extern fn LLVMBuildAShr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
550550
551 pub const buildLShrExact = ZigLLVMBuildLShrExact;
552 extern fn ZigLLVMBuildLShrExact(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
553
554 pub const buildAShrExact = ZigLLVMBuildAShrExact;
555 extern fn ZigLLVMBuildAShrExact(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
556
551 pub const buildShl = LLVMBuildShl;557 pub const buildShl = LLVMBuildShl;
552 extern fn LLVMBuildShl(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;558 extern fn LLVMBuildShl(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
553559
src/print_air.zig+1
...@@ -138,6 +138,7 @@ const Writer = struct {...@@ -138,6 +138,7 @@ const Writer = struct {
138 .shl_exact,138 .shl_exact,
139 .shl_sat,139 .shl_sat,
140 .shr,140 .shr,
141 .shr_exact,
141 .set_union_tag,142 .set_union_tag,
142 .min,143 .min,
143 .max,144 .max,
test/behavior/math.zig-6
...@@ -736,8 +736,6 @@ fn testShlTrunc(x: u16) !void {...@@ -736,8 +736,6 @@ fn testShlTrunc(x: u16) !void {
736}736}
737737
738test "exact shift left" {738test "exact shift left" {
739 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
740
741 try testShlExact(0b00110101);739 try testShlExact(0b00110101);
742 comptime try testShlExact(0b00110101);740 comptime try testShlExact(0b00110101);
743}741}
...@@ -747,8 +745,6 @@ fn testShlExact(x: u8) !void {...@@ -747,8 +745,6 @@ fn testShlExact(x: u8) !void {
747}745}
748746
749test "exact shift right" {747test "exact shift right" {
750 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
751
752 try testShrExact(0b10110100);748 try testShrExact(0b10110100);
753 comptime try testShrExact(0b10110100);749 comptime try testShrExact(0b10110100);
754}750}
...@@ -758,8 +754,6 @@ fn testShrExact(x: u8) !void {...@@ -758,8 +754,6 @@ fn testShrExact(x: u8) !void {
758}754}
759755
760test "shift left/right on u0 operand" {756test "shift left/right on u0 operand" {
761 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
762
763 const S = struct {757 const S = struct {
764 fn doTheTest() !void {758 fn doTheTest() !void {
765 var x: u0 = 0;759 var x: u0 = 0;