diff --git a/src/bignum.cpp b/src/bignum.cpp index 3830862bce..192c16e636 100644 --- a/src/bignum.cpp +++ b/src/bignum.cpp @@ -142,6 +142,13 @@ void bignum_negate(BigNum *dest, BigNum *op) { } } +void bignum_not(BigNum *dest, BigNum *op, int bit_count) { + assert(op->kind == BigNumKindInt); + uint64_t bits = ~bignum_to_twos_complement(op); + bits &= (1LL << bit_count) - 1; + bignum_init_signed(dest, bits); +} + void bignum_cast_to_float(BigNum *dest, BigNum *op) { assert(op->kind == BigNumKindInt); dest->kind = BigNumKindFloat; diff --git a/src/bignum.hpp b/src/bignum.hpp index 44087f1f5a..f028b36bef 100644 --- a/src/bignum.hpp +++ b/src/bignum.hpp @@ -48,6 +48,7 @@ bool bignum_shr(BigNum *dest, BigNum *op1, BigNum *op2); void bignum_negate(BigNum *dest, BigNum *op); void bignum_cast_to_float(BigNum *dest, BigNum *op); void bignum_cast_to_int(BigNum *dest, BigNum *op); +void bignum_not(BigNum *dest, BigNum *op, int bit_count); void bignum_truncate(BigNum *dest, int bit_count); diff --git a/src/ir.cpp b/src/ir.cpp index aba7aff3bd..cc386d80e1 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -7811,27 +7811,40 @@ static TypeTableEntry *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *un return ira->codegen->builtin_types.entry_invalid; } +static TypeTableEntry *ir_analyze_bin_not(IrAnalyze *ira, IrInstructionUnOp *instruction) { + IrInstruction *value = instruction->value->other; + TypeTableEntry *expr_type = value->value.type; + if (expr_type->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + if (expr_type->id == TypeTableEntryIdInt) { + if (instr_is_comptime(value)) { + ConstExprValue *target_const_val = ir_resolve_const(ira, value, UndefBad); + if (!target_const_val) + return ira->codegen->builtin_types.entry_invalid; + + bool depends_on_compile_var = value->value.depends_on_compile_var; + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var); + bignum_not(&out_val->data.x_bignum, &target_const_val->data.x_bignum, expr_type->data.integral.bit_count); + return expr_type; + } + + ir_build_un_op_from(&ira->new_irb, &instruction->base, IrUnOpBinNot, value); + return expr_type; + } + + ir_add_error(ira, &instruction->base, + buf_sprintf("unable to perform binary not operation on type '%s'", buf_ptr(&expr_type->name))); + return ira->codegen->builtin_types.entry_invalid; +} + static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { IrUnOp op_id = un_op_instruction->op_id; switch (op_id) { case IrUnOpInvalid: zig_unreachable(); case IrUnOpBinNot: - zig_panic("TODO analyze PrefixOpBinNot"); - //{ - // TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type, - // *expr_node); - // if (expr_type->id == TypeTableEntryIdInvalid) { - // return expr_type; - // } else if (expr_type->id == TypeTableEntryIdInt) { - // return expr_type; - // } else { - // add_node_error(g, node, buf_sprintf("unable to perform binary not operation on type '%s'", - // buf_ptr(&expr_type->name))); - // return g->builtin_types.entry_invalid; - // } - // // TODO const expr eval - //} + return ir_analyze_bin_not(ira, un_op_instruction); case IrUnOpNegation: case IrUnOpNegationWrap: return ir_analyze_negation(ira, un_op_instruction); diff --git a/test/cases/math.zig b/test/cases/math.zig index 259285e83a..dff38643cf 100644 --- a/test/cases/math.zig +++ b/test/cases/math.zig @@ -164,6 +164,16 @@ const DivResult = struct { remainder: u64, }; +fn binaryNot() { + @setFnTest(this); + + assert(~u16(0b1010101010101010) == 0b0101010101010101); + testBinaryNot(0b1010101010101010); +} + +fn testBinaryNot(x: u16) { + assert(~x == 0b0101010101010101); +} // TODO const assert = @import("std").debug.assert; fn assert(ok: bool) {