Commit 5f89393acb

Andrew Kelley <superjoe30@gmail.com>
2016-12-31 08:23:39
IR: implement binary not instruction
1 parent 2ccdaee
Changed files (4)
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;
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);
 
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);
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) {