| author | |
| committer | |
| log | fb7060d3c2e8ce4d7de5560adf8ec4a26fc5f6e8 |
| tree | 3710af0870e1e1d43f44830d6ff3e662761e93ce |
| parent | 0c30799d4039c30f95eee29e2c2f8f604e8b9880 |
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 | }, | ||
| 7477 | 7489 | ||
| 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 | else | 7492 | 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), |
| 7482 | 7494 | ||
| 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 | else | 7497 | 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), |
| 7487 | 7499 | ||
| 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 | } |
| 7504 | 7516 | ||
| 7505 | fn zirShr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 7517 | fn 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(); |
| 7508 | 7525 | ||
| 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); |
| 7516 | 7532 | ||
| 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 based | 7562 | } 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 | } | ||
| 7537 | 7563 | ||
| 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 | } |
| 7541 | 7567 | ||
| 7542 | fn zirBitwise( | 7568 | fn 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 | } |
| 11450 | 11476 | ||
| 11451 | fn 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 | |||
| 11457 | fn zirBitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 11477 | fn 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), |
| 537 | 537 | ||
| 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), |
| 544 | 544 | ||
| 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), |
| 529 | 529 | ||
| 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), |
| 536 | 536 | ||
| 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), |
| 516 | 516 | ||
| 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), |
| 523 | 523 | ||
| 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), |
| 1448 | 1448 | ||
| 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), |
| 580 | 580 | ||
| 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), |
| 587 | 587 | ||
| 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), |
| 1476 | 1476 |
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), | ||
| 2051 | 2052 | ||
| 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 | } |
| 3635 | 3636 | ||
| 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 | else | 3647 | else |
| 3647 | rhs; | 3648 | rhs; |
| 3649 | const is_signed_int = self.air.typeOfIndex(inst).isSignedInt(); | ||
| 3648 | 3650 | ||
| 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 | } |
| 3655 | 3665 |
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; |
| 550 | 550 | ||
| 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; |
| 553 | 559 |
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 | } |
| 737 | 737 | ||
| 738 | test "exact shift left" { | 738 | test "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 | } |
| 748 | 746 | ||
| 749 | test "exact shift right" { | 747 | test "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 | } |
| 759 | 755 | ||
| 760 | test "shift left/right on u0 operand" { | 756 | test "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; |