authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-10-16 14:47:55+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-10-17 20:33:04+02:00
log9336a87452eda87c19cb707484d0b6dfb4140b57
tree72d50163e2ad1389d5752de0e841b8f68755f3d5
parent6a3659c4e005d9730fb824b77b416ef33200dbfe

stage2: bitNot


4 files changed, 76 insertions(+), 16 deletions(-)

src/Sema.zig+36-2
...@@ -6627,8 +6627,42 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -6627,8 +6627,42 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
6627 const tracy = trace(@src());6627 const tracy = trace(@src());
6628 defer tracy.end();6628 defer tracy.end();
66296629
6630 _ = inst;6630 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
6631 return sema.fail(block, sema.src, "TODO implement zirBitNot", .{});6631 const src = inst_data.src();
6632 const operand_src = src; // TODO put this on the operand, not the '~'
6633
6634 const operand = sema.resolveInst(inst_data.operand);
6635 const operand_type = sema.typeOf(operand);
6636 const scalar_type = operand_type.scalarType();
6637
6638 if (scalar_type.zigTypeTag() != .Int) {
6639 return sema.fail(block, src, "unable to perform binary not operation on type '{}'", .{operand_type});
6640 }
6641
6642 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
6643 const target = sema.mod.getTarget();
6644 if (val.isUndef()) {
6645 return sema.addConstUndef(scalar_type);
6646 } else if (operand_type.zigTypeTag() == .Vector) {
6647 const vec_len = operand_type.arrayLen();
6648 var elem_val_buf: Value.ElemValueBuffer = undefined;
6649 const elems = try sema.arena.alloc(Value, vec_len);
6650 for (elems) |*elem, i| {
6651 const elem_val = val.elemValueBuffer(i, &elem_val_buf);
6652 elem.* = try elem_val.bitwiseNot(scalar_type, sema.arena, target);
6653 }
6654 return sema.addConstant(
6655 operand_type,
6656 try Value.Tag.array.create(sema.arena, elems),
6657 );
6658 } else {
6659 const result_val = try val.bitwiseNot(scalar_type, sema.arena, target);
6660 return sema.addConstant(scalar_type, result_val);
6661 }
6662 }
6663
6664 try sema.requireRuntimeBlock(block, src);
6665 return block.addTyOp(.not, operand_type, operand);
6632}6666}
66336667
6634fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {6668fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
src/value.zig+26
...@@ -2081,6 +2081,32 @@ pub const Value = extern union {...@@ -2081,6 +2081,32 @@ pub const Value = extern union {
2081 };2081 };
2082 }2082 }
20832083
2084 /// operands must be integers; handles undefined.
2085 pub fn bitwiseNot(val: Value, ty: Type, arena: *Allocator, target: Target) !Value {
2086 if (val.isUndef()) return Value.initTag(.undef);
2087
2088 const info = ty.intInfo(target);
2089
2090 // TODO is this a performance issue? maybe we should try the operation without
2091 // resorting to BigInt first.
2092 var val_space: Value.BigIntSpace = undefined;
2093 const val_bigint = val.toBigInt(&val_space);
2094 const limbs = try arena.alloc(
2095 std.math.big.Limb,
2096 std.math.big.int.calcTwosCompLimbCount(info.bits),
2097 );
2098
2099 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
2100 result_bigint.bitNotWrap(val_bigint, info.signedness, info.bits);
2101 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2102
2103 if (result_bigint.positive) {
2104 return Value.Tag.int_big_positive.create(arena, result_limbs);
2105 } else {
2106 return Value.Tag.int_big_negative.create(arena, result_limbs);
2107 }
2108 }
2109
2084 /// operands must be integers; handles undefined. 2110 /// operands must be integers; handles undefined.
2085 pub fn bitwiseAnd(lhs: Value, rhs: Value, arena: *Allocator) !Value {2111 pub fn bitwiseAnd(lhs: Value, rhs: Value, arena: *Allocator) !Value {
2086 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);2112 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
test/behavior/math.zig+14
...@@ -235,3 +235,17 @@ test "comptime_int param and return" {...@@ -235,3 +235,17 @@ test "comptime_int param and return" {
235fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int {235fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int {
236 return a + b;236 return a + b;
237}237}
238
239test "binary not" {
240 try expect(comptime x: {
241 break :x ~@as(u16, 0b1010101010101010) == 0b0101010101010101;
242 });
243 try expect(comptime x: {
244 break :x ~@as(u64, 2147483647) == 18446744071562067968;
245 });
246 try testBinaryNot(0b1010101010101010);
247}
248
249fn testBinaryNot(x: u16) !void {
250 try expect(~x == 0b0101010101010101);
251}
test/behavior/math_stage1.zig-14
...@@ -219,20 +219,6 @@ const DivResult = struct {...@@ -219,20 +219,6 @@ const DivResult = struct {
219 remainder: u64,219 remainder: u64,
220};220};
221221
222test "binary not" {
223 try expect(comptime x: {
224 break :x ~@as(u16, 0b1010101010101010) == 0b0101010101010101;
225 });
226 try expect(comptime x: {
227 break :x ~@as(u64, 2147483647) == 18446744071562067968;
228 });
229 try testBinaryNot(0b1010101010101010);
230}
231
232fn testBinaryNot(x: u16) !void {
233 try expect(~x == 0b0101010101010101);
234}
235
236test "small int addition" {222test "small int addition" {
237 var x: u2 = 0;223 var x: u2 = 0;
238 try expect(x == 0);224 try expect(x == 0);