| author | |
| committer | |
| log | 9336a87452eda87c19cb707484d0b6dfb4140b57 |
| tree | 72d50163e2ad1389d5752de0e841b8f68755f3d5 |
| parent | 6a3659c4e005d9730fb824b77b416ef33200dbfe |
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(); |
| 6629 | 6629 | ||
| 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 | } |
| 6633 | 6667 | ||
| 6634 | fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 6668 | fn 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 | } |
| 2083 | 2083 | ||
| 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" { |
| 235 | fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int { | 235 | fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int { |
| 236 | return a + b; | 236 | return a + b; |
| 237 | } | 237 | } |
| 238 | |||
| 239 | test "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 | |||
| 249 | fn 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 | }; |
| 221 | 221 | ||
| 222 | test "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 | |||
| 232 | fn testBinaryNot(x: u16) !void { | ||
| 233 | try expect(~x == 0b0101010101010101); | ||
| 234 | } | ||
| 235 | |||
| 236 | test "small int addition" { | 222 | test "small int addition" { |
| 237 | var x: u2 = 0; | 223 | var x: u2 = 0; |
| 238 | try expect(x == 0); | 224 | try expect(x == 0); |