Commit 9b17c0ff7f

Andrew Kelley <superjoe30@gmail.com>
2016-12-11 22:30:01
IR: implement intType builtin
and int type field access and fix compile time bool not
1 parent 3429639
src/all_types.hpp
@@ -1411,6 +1411,8 @@ enum IrInstructionId {
     IrInstructionIdFence,
     IrInstructionIdDivExact,
     IrInstructionIdTruncate,
+    IrInstructionIdIntType,
+    IrInstructionIdBoolNot,
 };
 
 struct IrInstruction {
@@ -1481,7 +1483,6 @@ struct IrInstructionPhi {
 
 enum IrUnOp {
     IrUnOpInvalid,
-    IrUnOpBoolNot,
     IrUnOpBinNot,
     IrUnOpNegation,
     IrUnOpNegationWrap,
@@ -1900,6 +1901,19 @@ struct IrInstructionTruncate {
     IrInstruction *target;
 };
 
+struct IrInstructionIntType {
+    IrInstruction base;
+
+    IrInstruction *is_signed;
+    IrInstruction *bit_count;
+};
+
+struct IrInstructionBoolNot {
+    IrInstruction base;
+
+    IrInstruction *value;
+};
+
 enum LValPurpose {
     LValPurposeNone,
     LValPurposeAssign,
src/analyze.cpp
@@ -2809,3 +2809,14 @@ ConstExprValue *create_const_enum_tag(uint64_t tag) {
     init_const_enum_tag(const_val, tag);
     return const_val;
 }
+
+void init_const_bool(ConstExprValue *const_val, bool value) {
+    const_val->special = ConstValSpecialStatic;
+    const_val->data.x_bool = value;
+}
+
+ConstExprValue *create_const_bool(bool value) {
+    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    init_const_bool(const_val, value);
+    return const_val;
+}
src/analyze.hpp
@@ -98,4 +98,7 @@ ConstExprValue *create_const_float(double value);
 void init_const_enum_tag(ConstExprValue *const_val, uint64_t tag);
 ConstExprValue *create_const_enum_tag(uint64_t tag);
 
+void init_const_bool(ConstExprValue *const_val, bool value);
+ConstExprValue *create_const_bool(bool value);
+
 #endif
src/codegen.cpp
@@ -1230,11 +1230,6 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
                     zig_unreachable();
                 }
             }
-        case IrUnOpBoolNot:
-            {
-                LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(expr));
-                return LLVMBuildICmp(g->builder, LLVMIntEQ, expr, zero, "");
-            }
         case IrUnOpBinNot:
             return LLVMBuildNot(g->builder, expr, "");
         case IrUnOpAddressOf:
@@ -1339,6 +1334,12 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
     zig_unreachable();
 }
 
+static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrInstructionBoolNot *instruction) {
+    LLVMValueRef value = ir_llvm_value(g, instruction->value);
+    LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(value));
+    return LLVMBuildICmp(g->builder, LLVMIntEQ, value, zero, "");
+}
+
 static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
         IrInstructionDeclVar *decl_var_instruction)
 {
@@ -1927,6 +1928,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
         case IrInstructionIdCDefine:
         case IrInstructionIdCUndef:
         case IrInstructionIdEmbedFile:
+        case IrInstructionIdIntType:
             zig_unreachable();
         case IrInstructionIdReturn:
             return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@@ -1984,6 +1986,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
             return ir_render_div_exact(g, executable, (IrInstructionDivExact *)instruction);
         case IrInstructionIdTruncate:
             return ir_render_truncate(g, executable, (IrInstructionTruncate *)instruction);
+        case IrInstructionIdBoolNot:
+            return ir_render_bool_not(g, executable, (IrInstructionBoolNot *)instruction);
         case IrInstructionIdSwitchVar:
         case IrInstructionIdContainerInitList:
         case IrInstructionIdStructInit:
src/ir.cpp
@@ -363,6 +363,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTruncate *) {
     return IrInstructionIdTruncate;
 }
 
+static constexpr IrInstructionId ir_instruction_id(IrInstructionIntType *) {
+    return IrInstructionIdIntType;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) {
+    return IrInstructionIdBoolNot;
+}
+
 template<typename T>
 static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
     T *special_instruction = allocate<T>(1);
@@ -1455,6 +1463,32 @@ static IrInstruction *ir_build_truncate_from(IrBuilder *irb, IrInstruction *old_
     return new_instruction;
 }
 
+static IrInstruction *ir_build_int_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *is_signed, IrInstruction *bit_count) {
+    IrInstructionIntType *instruction = ir_build_instruction<IrInstructionIntType>(irb, scope, source_node);
+    instruction->is_signed = is_signed;
+    instruction->bit_count = bit_count;
+
+    ir_ref_instruction(is_signed);
+    ir_ref_instruction(bit_count);
+
+    return &instruction->base;
+}
+
+static IrInstruction *ir_build_bool_not(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
+    IrInstructionBoolNot *instruction = ir_build_instruction<IrInstructionBoolNot>(irb, scope, source_node);
+    instruction->value = value;
+
+    ir_ref_instruction(value);
+
+    return &instruction->base;
+}
+
+static IrInstruction *ir_build_bool_not_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *value) {
+    IrInstruction *new_instruction = ir_build_bool_not(irb, old_instruction->scope, old_instruction->source_node, value);
+    ir_link_new_instruction(new_instruction, old_instruction);
+    return new_instruction;
+}
+
 static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,
         bool gen_error_defers, bool gen_maybe_defers)
 {
@@ -2262,6 +2296,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
 
                 return ir_build_truncate(irb, scope, node, arg0_value, arg1_value);
             }
+        case BuiltinFnIdIntType:
+            {
+                AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
+                IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+                if (arg0_value == irb->codegen->invalid_instruction)
+                    return arg0_value;
+
+                AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
+                IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+                if (arg1_value == irb->codegen->invalid_instruction)
+                    return arg1_value;
+
+                return ir_build_int_type(irb, scope, node, arg0_value, arg1_value);
+            }
         case BuiltinFnIdMemcpy:
         case BuiltinFnIdMemset:
         case BuiltinFnIdAlignof:
@@ -2273,7 +2321,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
         case BuiltinFnIdBreakpoint:
         case BuiltinFnIdReturnAddress:
         case BuiltinFnIdFrameAddress:
-        case BuiltinFnIdIntType:
             zig_panic("TODO IR gen more builtin functions");
     }
     zig_unreachable();
@@ -2379,6 +2426,28 @@ static IrInstruction *ir_gen_prefix_op_unwrap_maybe(IrBuilder *irb, Scope *scope
         return unwrapped_ptr;
 }
 
+static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *node) {
+    assert(node->type == NodeTypePrefixOpExpr);
+    AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
+
+    IrInstruction *value = ir_gen_node(irb, expr_node, scope);
+    if (value == irb->codegen->invalid_instruction)
+        return irb->codegen->invalid_instruction;
+
+    return ir_build_bool_not(irb, scope, node, value);
+}
+
+static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LValPurpose lval) {
+    if (lval == LValPurposeNone)
+        return value;
+    if (value == irb->codegen->invalid_instruction)
+        return value;
+
+    // We needed a pointer to a value, but we got a value. So we create
+    // an instruction which just makes a const pointer of it.
+    return ir_build_ref(irb, scope, value->source_node, value);
+}
+
 static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) {
     assert(node->type == NodeTypePrefixOpExpr);
 
@@ -2388,7 +2457,7 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
         case PrefixOpInvalid:
             zig_unreachable();
         case PrefixOpBoolNot:
-            return ir_gen_prefix_op_id(irb, scope, node, IrUnOpBoolNot);
+            return ir_lval_wrap(irb, scope, ir_gen_bool_not(irb, scope, node), lval);
         case PrefixOpBinNot:
             return ir_gen_prefix_op_id(irb, scope, node, IrUnOpBinNot);
         case PrefixOpNegation:
@@ -3124,17 +3193,6 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *scope, AstNode *nod
     return ir_build_br(irb, scope, node, dest_block, is_inline);
 }
 
-static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LValPurpose lval) {
-    if (lval == LValPurposeNone)
-        return value;
-    if (value == irb->codegen->invalid_instruction)
-        return value;
-
-    // We needed a pointer to a value, but we got a value. So we create
-    // an instruction which just makes a const pointer of it.
-    return ir_build_ref(irb, scope, value->source_node, value);
-}
-
 static IrInstruction *ir_gen_type_literal(IrBuilder *irb, Scope *scope, AstNode *node) {
     assert(node->type == NodeTypeTypeLiteral);
     return ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_type);
@@ -5136,31 +5194,6 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
     }
 }
 
-static TypeTableEntry *ir_analyze_unary_bool_not(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
-    IrInstruction *value = un_op_instruction->value->other;
-    if (value->type_entry->id == TypeTableEntryIdInvalid)
-        return ira->codegen->builtin_types.entry_invalid;
-
-    TypeTableEntry *bool_type = ira->codegen->builtin_types.entry_bool;
-
-    IrInstruction *casted_value = ir_get_casted_value(ira, value, bool_type);
-    if (casted_value->type_entry->id == TypeTableEntryIdInvalid)
-        return ira->codegen->builtin_types.entry_invalid;
-
-    ConstExprValue *operand_val = &casted_value->static_value;
-    if (operand_val->special != ConstValSpecialRuntime) {
-        ConstExprValue *result_val = &un_op_instruction->base.static_value;
-        result_val->special = ConstValSpecialStatic;
-        result_val->depends_on_compile_var = operand_val->depends_on_compile_var;
-        result_val->data.x_bool = !operand_val->data.x_bool;
-        return bool_type;
-    }
-
-    ir_build_un_op_from(&ira->new_irb, &un_op_instruction->base, IrUnOpBoolNot, casted_value);
-
-    return bool_type;
-}
-
 static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
     assert(un_op_instruction->op_id == IrUnOpError);
     IrInstruction *value = un_op_instruction->value->other;
@@ -5425,8 +5458,6 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio
     switch (op_id) {
         case IrUnOpInvalid:
             zig_unreachable();
-        case IrUnOpBoolNot:
-            return ir_analyze_unary_bool_not(ira, un_op_instruction);
         case IrUnOpBinNot:
             zig_panic("TODO analyze PrefixOpBinNot");
             //{
@@ -5961,9 +5992,22 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
                 buf_sprintf("use of undeclared error value '%s'", buf_ptr(field_name)));
             return ira->codegen->builtin_types.entry_invalid;
         } else if (child_type->id == TypeTableEntryIdInt) {
-            zig_panic("TODO integer type field");
+            if (buf_eql_str(field_name, "bit_count")) {
+                return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+                    create_const_unsigned_negative(child_type->data.integral.bit_count, false),
+                    ira->codegen->builtin_types.entry_num_lit_int, depends_on_compile_var, ConstPtrSpecialNone);
+            } else if (buf_eql_str(field_name, "is_signed")) {
+                return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+                    create_const_bool(child_type->data.integral.is_signed),
+                    ira->codegen->builtin_types.entry_bool, depends_on_compile_var, ConstPtrSpecialNone);
+            } else {
+                ir_add_error(ira, &field_ptr_instruction->base,
+                    buf_sprintf("type '%s' has no member called '%s'",
+                        buf_ptr(&child_type->name), buf_ptr(field_name)));
+                return ira->codegen->builtin_types.entry_invalid;
+            }
         } else {
-            add_node_error(ira->codegen, source_node,
+            ir_add_error(ira, &field_ptr_instruction->base,
                 buf_sprintf("type '%s' does not support field access", buf_ptr(&container_type->name)));
             return ira->codegen->builtin_types.entry_invalid;
         }
@@ -7620,6 +7664,47 @@ static TypeTableEntry *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruc
     return dest_type;
 }
 
+static TypeTableEntry *ir_analyze_instruction_int_type(IrAnalyze *ira, IrInstructionIntType *instruction) {
+    IrInstruction *is_signed_value = instruction->is_signed->other;
+    bool is_signed;
+    if (!ir_resolve_bool(ira, is_signed_value, &is_signed))
+        return ira->codegen->builtin_types.entry_invalid;
+
+    IrInstruction *bit_count_value = instruction->bit_count->other;
+    uint64_t bit_count;
+    if (!ir_resolve_usize(ira, bit_count_value, &bit_count))
+        return ira->codegen->builtin_types.entry_invalid;
+
+    bool depends_on_compile_var = is_signed_value->static_value.depends_on_compile_var ||
+        bit_count_value->static_value.depends_on_compile_var;
+
+    ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
+    out_val->data.x_type = get_int_type(ira->codegen, is_signed, bit_count);
+    return ira->codegen->builtin_types.entry_type;
+}
+
+static TypeTableEntry *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) {
+    IrInstruction *value = instruction->value->other;
+    if (value->type_entry->id == TypeTableEntryIdInvalid)
+        return ira->codegen->builtin_types.entry_invalid;
+
+    TypeTableEntry *bool_type = ira->codegen->builtin_types.entry_bool;
+
+    IrInstruction *casted_value = ir_get_casted_value(ira, value, bool_type);
+    if (casted_value->type_entry->id == TypeTableEntryIdInvalid)
+        return ira->codegen->builtin_types.entry_invalid;
+
+    if (casted_value->static_value.special != ConstValSpecialRuntime) {
+        bool depends_on_compile_var = casted_value->static_value.depends_on_compile_var;
+        ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
+        out_val->data.x_bool = !casted_value->static_value.data.x_bool;
+        return bool_type;
+    }
+
+    ir_build_bool_not_from(&ira->new_irb, &instruction->base, casted_value);
+    return bool_type;
+}
+
 static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
     switch (instruction->id) {
         case IrInstructionIdInvalid:
@@ -7730,6 +7815,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
             return ir_analyze_instruction_div_exact(ira, (IrInstructionDivExact *)instruction);
         case IrInstructionIdTruncate:
             return ir_analyze_instruction_truncate(ira, (IrInstructionTruncate *)instruction);
+        case IrInstructionIdIntType:
+            return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction);
+        case IrInstructionIdBoolNot:
+            return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction);
         case IrInstructionIdCast:
         case IrInstructionIdStructFieldPtr:
         case IrInstructionIdEnumFieldPtr:
@@ -7869,6 +7958,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
         case IrInstructionIdEmbedFile:
         case IrInstructionIdDivExact:
         case IrInstructionIdTruncate:
+        case IrInstructionIdIntType:
+        case IrInstructionIdBoolNot:
             return false;
         case IrInstructionIdAsm:
             {
@@ -7880,45 +7971,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
 }
 
 // TODO port over all this commented out code into new IR way of doing things
-//static TypeTableEntry *analyze_int_type(CodeGen *g, ImportTableEntry *import,
-//        BlockContext *context, AstNode *node)
-//{
-//    AstNode **is_signed_node = &node->data.fn_call_expr.params.at(0);
-//    AstNode **bit_count_node = &node->data.fn_call_expr.params.at(1);
-//
-//    TypeTableEntry *bool_type = g->builtin_types.entry_bool;
-//    TypeTableEntry *usize_type = g->builtin_types.entry_usize;
-//    TypeTableEntry *is_signed_type = analyze_expression(g, import, context, bool_type, *is_signed_node);
-//    TypeTableEntry *bit_count_type = analyze_expression(g, import, context, usize_type, *bit_count_node);
-//
-//    if (is_signed_type->id == TypeTableEntryIdInvalid ||
-//        bit_count_type->id == TypeTableEntryIdInvalid)
-//    {
-//        return g->builtin_types.entry_invalid;
-//    }
-//
-//    ConstExprValue *is_signed_val = &get_resolved_expr(*is_signed_node)->const_val;
-//    ConstExprValue *bit_count_val = &get_resolved_expr(*bit_count_node)->const_val;
-//
-//    AstNode *bad_node = nullptr;
-//    if (!is_signed_val->ok) {
-//        bad_node = *is_signed_node;
-//    } else if (!bit_count_val->ok) {
-//        bad_node = *bit_count_node;
-//    }
-//    if (bad_node) {
-//        add_node_error(g, bad_node, buf_sprintf("unable to evaluate constant expression"));
-//        return g->builtin_types.entry_invalid;
-//    }
-//
-//    bool depends_on_compile_var = is_signed_val->depends_on_compile_var || bit_count_val->depends_on_compile_var;
-//
-//    TypeTableEntry *int_type = get_int_type(g, is_signed_val->data.x_bool,
-//            bit_count_val->data.x_bignum.data.x_uint);
-//    return resolve_expr_const_val_as_type(g, node, int_type, depends_on_compile_var);
-//
-//}
-//
 //static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
 //        TypeTableEntry *expected_type, AstNode *node)
 //{
@@ -8049,8 +8101,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
 //        case BuiltinFnIdFrameAddress:
 //            mark_impure_fn(g, context, node);
 //            return builtin_fn->return_type;
-//        case BuiltinFnIdIntType:
-//            return analyze_int_type(g, import, context, node);
 //    }
 //    zig_unreachable();
 //}
@@ -8215,34 +8265,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
 //    return return_type;
 //}
 //
-//static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
-//        AstNode *node)
-//{
-//    assert(node->type == NodeTypeBinOpExpr);
-//    BinOpType bin_op_type = node->data.bin_op_expr.bin_op;
-//
-//    AstNode *op1 = node->data.bin_op_expr.op1;
-//    AstNode *op2 = node->data.bin_op_expr.op2;
-//    TypeTableEntry *op1_type = analyze_expression(g, import, context, g->builtin_types.entry_bool, op1);
-//    TypeTableEntry *op2_type = analyze_expression(g, import, context, g->builtin_types.entry_bool, op2);
-//
-//    if (op1_type->id == TypeTableEntryIdInvalid ||
-//        op2_type->id == TypeTableEntryIdInvalid)
-//    {
-//        return g->builtin_types.entry_invalid;
-//    }
-//
-//    ConstExprValue *op1_val = &get_resolved_expr(op1)->const_val;
-//    ConstExprValue *op2_val = &get_resolved_expr(op2)->const_val;
-//    if (!op1_val->ok || !op2_val->ok) {
-//        return g->builtin_types.entry_bool;
-//    }
-//
-//    ConstExprValue *out_val = &get_resolved_expr(node)->const_val;
-//    eval_const_expr_bin_op(op1_val, op1_type, bin_op_type, op2_val, op2_type, out_val);
-//    return g->builtin_types.entry_bool;
-//}
-//
 //static TypeTableEntry *analyze_array_mult(CodeGen *g, ImportTableEntry *import, BlockContext *context,
 //        TypeTableEntry *expected_type, AstNode *node)
 //{
@@ -8402,7 +8424,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
 //    switch (builtin_fn->id) {
 //        case BuiltinFnIdInvalid:
 //        case BuiltinFnIdTypeof:
-//        case BuiltinFnIdIntType:
 //            zig_unreachable();
 //        case BuiltinFnIdAddWithOverflow:
 //        case BuiltinFnIdSubWithOverflow:
src/ir_print.cpp
@@ -279,8 +279,6 @@ static const char *ir_un_op_id_str(IrUnOp op_id) {
     switch (op_id) {
         case IrUnOpInvalid:
             zig_unreachable();
-        case IrUnOpBoolNot:
-            return "!";
         case IrUnOpBinNot:
             return "~";
         case IrUnOpNegation:
@@ -755,6 +753,19 @@ static void ir_print_truncate(IrPrint *irp, IrInstructionTruncate *instruction)
     fprintf(irp->f, ")");
 }
 
+static void ir_print_int_type(IrPrint *irp, IrInstructionIntType *instruction) {
+    fprintf(irp->f, "@intType(");
+    ir_print_other_instruction(irp, instruction->is_signed);
+    fprintf(irp->f, ", ");
+    ir_print_other_instruction(irp, instruction->bit_count);
+    fprintf(irp->f, ")");
+}
+
+static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) {
+    fprintf(irp->f, "! ");
+    ir_print_other_instruction(irp, instruction->value);
+}
+
 static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
     ir_print_prefix(irp, instruction);
     switch (instruction->id) {
@@ -931,6 +942,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
         case IrInstructionIdTruncate:
             ir_print_truncate(irp, (IrInstructionTruncate *)instruction);
             break;
+        case IrInstructionIdIntType:
+            ir_print_int_type(irp, (IrInstructionIntType *)instruction);
+            break;
+        case IrInstructionIdBoolNot:
+            ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction);
+            break;
     }
     fprintf(irp->f, "\n");
 }
test/self_hosted2.zig
@@ -299,6 +299,35 @@ fn testTruncate(x: u32) -> u8 {
     @truncate(u8, x)
 }
 
+fn intTypeBuiltin() {
+    assert(@intType(true, 8) == i8);
+    assert(@intType(true, 16) == i16);
+    assert(@intType(true, 32) == i32);
+    assert(@intType(true, 64) == i64);
+
+    assert(@intType(false, 8) == u8);
+    assert(@intType(false, 16) == u16);
+    assert(@intType(false, 32) == u32);
+    assert(@intType(false, 64) == u64);
+
+    assert(i8.bit_count == 8);
+    assert(i16.bit_count == 16);
+    assert(i32.bit_count == 32);
+    assert(i64.bit_count == 64);
+
+    assert(i8.is_signed);
+    assert(i16.is_signed);
+    assert(i32.is_signed);
+    assert(i64.is_signed);
+    assert(isize.is_signed);
+
+    assert(!u8.is_signed);
+    assert(!u16.is_signed);
+    assert(!u32.is_signed);
+    assert(!u64.is_signed);
+    assert(!usize.is_signed);
+
+}
 
 fn assert(ok: bool) {
     if (!ok)
@@ -331,6 +360,7 @@ fn runAllTests() {
     fence();
     exactDivision();
     truncate();
+    intTypeBuiltin();
 }
 
 export nakedcc fn _start() -> unreachable {