Commit 3f3630d7e3

Andrew Kelley <superjoe30@gmail.com>
2016-12-13 10:30:41
IR: implement the rest of the builtin functions
* returnAddress * frameAddress * addWithOverflow * subWithOverflow * mulWithOverflow * shlWithOverflow * alignOf
1 parent 8bb5f54
src/all_types.hpp
@@ -1187,6 +1187,8 @@ struct CodeGen {
     LLVMValueRef memcpy_fn_val;
     LLVMValueRef memset_fn_val;
     LLVMValueRef trap_fn_val;
+    LLVMValueRef return_address_fn_val;
+    LLVMValueRef frame_address_fn_val;
     bool error_during_imports;
     uint32_t next_node_index;
     TypeTableEntry *err_tag_type;
@@ -1420,6 +1422,10 @@ enum IrInstructionId {
     IrInstructionIdSlice,
     IrInstructionIdMemberCount,
     IrInstructionIdBreakpoint,
+    IrInstructionIdReturnAddress,
+    IrInstructionIdFrameAddress,
+    IrInstructionIdAlignOf,
+    IrInstructionIdOverflowOp,
 };
 
 struct IrInstruction {
@@ -1965,6 +1971,39 @@ struct IrInstructionBreakpoint {
     IrInstruction base;
 };
 
+struct IrInstructionReturnAddress {
+    IrInstruction base;
+};
+
+struct IrInstructionFrameAddress {
+    IrInstruction base;
+};
+
+enum IrOverflowOp {
+    IrOverflowOpAdd,
+    IrOverflowOpSub,
+    IrOverflowOpMul,
+    IrOverflowOpShl,
+};
+
+struct IrInstructionOverflowOp {
+    IrInstruction base;
+
+    IrOverflowOp op;
+    IrInstruction *type_value;
+    IrInstruction *op1;
+    IrInstruction *op2;
+    IrInstruction *result_ptr;
+
+    TypeTableEntry *result_ptr_type;
+};
+
+struct IrInstructionAlignOf {
+    IrInstruction base;
+
+    IrInstruction *type_value;
+};
+
 enum LValPurpose {
     LValPurposeNone,
     LValPurposeAssign,
src/analyze.cpp
@@ -876,7 +876,7 @@ static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *nod
     size_t backward_branch_count = 0;
     return ir_eval_const_value(g, scope, node, type_entry,
             &backward_branch_count, default_backward_branch_quota,
-            nullptr, nullptr);
+            nullptr, nullptr, node);
 }
 
 TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
src/codegen.cpp
@@ -2058,6 +2058,80 @@ static LLVMValueRef ir_render_breakpoint(CodeGen *g, IrExecutable *executable, I
     return nullptr;
 }
 
+static LLVMValueRef ir_render_return_address(CodeGen *g, IrExecutable *executable,
+        IrInstructionReturnAddress *instruction)
+{
+    LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
+    return LLVMBuildCall(g->builder, g->return_address_fn_val, &zero, 1, "");
+}
+
+static LLVMValueRef ir_render_frame_address(CodeGen *g, IrExecutable *executable,
+        IrInstructionFrameAddress *instruction)
+{
+    LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
+    return LLVMBuildCall(g->builder, g->frame_address_fn_val, &zero, 1, "");
+}
+
+static LLVMValueRef render_shl_with_overflow(CodeGen *g, IrInstructionOverflowOp *instruction) {
+    TypeTableEntry *int_type = get_underlying_type(instruction->result_ptr_type);
+    assert(int_type->id == TypeTableEntryIdInt);
+
+    LLVMValueRef op1 = ir_llvm_value(g, instruction->op1);
+    LLVMValueRef op2 = ir_llvm_value(g, instruction->op2);
+    LLVMValueRef ptr_result = ir_llvm_value(g, instruction->result_ptr);
+
+    LLVMValueRef result = LLVMBuildShl(g->builder, op1, op2, "");
+    LLVMValueRef orig_val;
+    if (int_type->data.integral.is_signed) {
+        orig_val = LLVMBuildAShr(g->builder, result, op2, "");
+    } else {
+        orig_val = LLVMBuildLShr(g->builder, result, op2, "");
+    }
+    LLVMValueRef overflow_bit = LLVMBuildICmp(g->builder, LLVMIntNE, op1, orig_val, "");
+
+    LLVMBuildStore(g->builder, result, ptr_result);
+
+    return overflow_bit;
+}
+
+static LLVMValueRef ir_render_overflow_op(CodeGen *g, IrExecutable *executable, IrInstructionOverflowOp *instruction) {
+    AddSubMul add_sub_mul;
+    switch (instruction->op) {
+        case IrOverflowOpAdd:
+            add_sub_mul = AddSubMulAdd;
+            break;
+        case IrOverflowOpSub:
+            add_sub_mul = AddSubMulAdd;
+            break;
+        case IrOverflowOpMul:
+            add_sub_mul = AddSubMulAdd;
+            break;
+        case IrOverflowOpShl:
+            return render_shl_with_overflow(g, instruction);
+    }
+
+    TypeTableEntry *int_type = get_underlying_type(instruction->result_ptr_type);
+    assert(int_type->id == TypeTableEntryIdInt);
+
+    LLVMValueRef fn_val = get_int_overflow_fn(g, int_type, add_sub_mul);
+
+    LLVMValueRef op1 = ir_llvm_value(g, instruction->op1);
+    LLVMValueRef op2 = ir_llvm_value(g, instruction->op2);
+    LLVMValueRef ptr_result = ir_llvm_value(g, instruction->result_ptr);
+
+    LLVMValueRef params[] = {
+        op1,
+        op2,
+    };
+
+    LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, "");
+    LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, "");
+    LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, "");
+    LLVMBuildStore(g->builder, result, ptr_result);
+
+    return overflow_bit;
+}
+
 static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
     AstNode *source_node = instruction->source_node;
     Scope *scope = instruction->scope;
@@ -2100,6 +2174,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
         case IrInstructionIdEmbedFile:
         case IrInstructionIdIntType:
         case IrInstructionIdMemberCount:
+        case IrInstructionIdAlignOf:
             zig_unreachable();
         case IrInstructionIdReturn:
             return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@@ -2169,6 +2244,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
             return ir_render_slice(g, executable, (IrInstructionSlice *)instruction);
         case IrInstructionIdBreakpoint:
             return ir_render_breakpoint(g, executable, (IrInstructionBreakpoint *)instruction);
+        case IrInstructionIdReturnAddress:
+            return ir_render_return_address(g, executable, (IrInstructionReturnAddress *)instruction);
+        case IrInstructionIdFrameAddress:
+            return ir_render_frame_address(g, executable, (IrInstructionFrameAddress *)instruction);
+        case IrInstructionIdOverflowOp:
+            return ir_render_overflow_op(g, executable, (IrInstructionOverflowOp *)instruction);
         case IrInstructionIdSwitchVar:
         case IrInstructionIdContainerInitList:
         case IrInstructionIdStructInit:
@@ -3300,6 +3381,8 @@ static void define_builtin_fns(CodeGen *g) {
                 &g->builtin_types.entry_i32->type_ref, 1, false);
         builtin_fn->fn_val = LLVMAddFunction(g->module, "llvm.returnaddress", fn_type);
         assert(LLVMGetIntrinsicID(builtin_fn->fn_val));
+
+        g->return_address_fn_val = builtin_fn->fn_val;
     }
     {
         BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdFrameAddress,
@@ -3310,6 +3393,8 @@ static void define_builtin_fns(CodeGen *g) {
                 &g->builtin_types.entry_i32->type_ref, 1, false);
         builtin_fn->fn_val = LLVMAddFunction(g->module, "llvm.frameaddress", fn_type);
         assert(LLVMGetIntrinsicID(builtin_fn->fn_val));
+
+        g->frame_address_fn_val = builtin_fn->fn_val;
     }
     {
         BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy", 3);
src/ir.cpp
@@ -395,6 +395,22 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBreakpoint *) {
     return IrInstructionIdBreakpoint;
 }
 
+static constexpr IrInstructionId ir_instruction_id(IrInstructionReturnAddress *) {
+    return IrInstructionIdReturnAddress;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameAddress *) {
+    return IrInstructionIdFrameAddress;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionAlignOf *) {
+    return IrInstructionIdAlignOf;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionOverflowOp *) {
+    return IrInstructionIdOverflowOp;
+}
+
 template<typename T>
 static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
     T *special_instruction = allocate<T>(1);
@@ -1632,6 +1648,67 @@ static IrInstruction *ir_build_breakpoint_from(IrBuilder *irb, IrInstruction *ol
     return new_instruction;
 }
 
+static IrInstruction *ir_build_return_address(IrBuilder *irb, Scope *scope, AstNode *source_node) {
+    IrInstructionReturnAddress *instruction = ir_build_instruction<IrInstructionReturnAddress>(irb, scope, source_node);
+    return &instruction->base;
+}
+
+static IrInstruction *ir_build_return_address_from(IrBuilder *irb, IrInstruction *old_instruction) {
+    IrInstruction *new_instruction = ir_build_return_address(irb, old_instruction->scope, old_instruction->source_node);
+    ir_link_new_instruction(new_instruction, old_instruction);
+    return new_instruction;
+}
+
+static IrInstruction *ir_build_frame_address(IrBuilder *irb, Scope *scope, AstNode *source_node) {
+    IrInstructionFrameAddress *instruction = ir_build_instruction<IrInstructionFrameAddress>(irb, scope, source_node);
+    return &instruction->base;
+}
+
+static IrInstruction *ir_build_frame_address_from(IrBuilder *irb, IrInstruction *old_instruction) {
+    IrInstruction *new_instruction = ir_build_frame_address(irb, old_instruction->scope, old_instruction->source_node);
+    ir_link_new_instruction(new_instruction, old_instruction);
+    return new_instruction;
+}
+
+static IrInstruction *ir_build_overflow_op(IrBuilder *irb, Scope *scope, AstNode *source_node,
+        IrOverflowOp op, IrInstruction *type_value, IrInstruction *op1, IrInstruction *op2,
+        IrInstruction *result_ptr, TypeTableEntry *result_ptr_type)
+{
+    IrInstructionOverflowOp *instruction = ir_build_instruction<IrInstructionOverflowOp>(irb, scope, source_node);
+    instruction->op = op;
+    instruction->type_value = type_value;
+    instruction->op1 = op1;
+    instruction->op2 = op2;
+    instruction->result_ptr = result_ptr;
+    instruction->result_ptr_type = result_ptr_type;
+
+    ir_ref_instruction(type_value);
+    ir_ref_instruction(op1);
+    ir_ref_instruction(op2);
+    ir_ref_instruction(result_ptr);
+
+    return &instruction->base;
+}
+
+static IrInstruction *ir_build_overflow_op_from(IrBuilder *irb, IrInstruction *old_instruction,
+        IrOverflowOp op, IrInstruction *type_value, IrInstruction *op1, IrInstruction *op2,
+        IrInstruction *result_ptr, TypeTableEntry *result_ptr_type)
+{
+    IrInstruction *new_instruction = ir_build_overflow_op(irb, old_instruction->scope, old_instruction->source_node,
+            op, type_value, op1, op2, result_ptr, result_ptr_type);
+    ir_link_new_instruction(new_instruction, old_instruction);
+    return new_instruction;
+}
+
+static IrInstruction *ir_build_alignof(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value) {
+    IrInstructionAlignOf *instruction = ir_build_instruction<IrInstructionAlignOf>(irb, scope, source_node);
+    instruction->type_value = type_value;
+
+    ir_ref_instruction(type_value);
+
+    return &instruction->base;
+}
+
 static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,
         bool gen_error_defers, bool gen_maybe_defers)
 {
@@ -2142,6 +2219,34 @@ static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode
     return ir_build_load_ptr(irb, scope, node, ptr_instruction);
 }
 
+static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *node, IrOverflowOp op) {
+    assert(node->type == NodeTypeFnCallExpr);
+
+    AstNode *type_node = node->data.fn_call_expr.params.at(0);
+    AstNode *op1_node = node->data.fn_call_expr.params.at(1);
+    AstNode *op2_node = node->data.fn_call_expr.params.at(2);
+    AstNode *result_ptr_node = node->data.fn_call_expr.params.at(3);
+
+
+    IrInstruction *type_value = ir_gen_node(irb, type_node, scope);
+    if (type_value == irb->codegen->invalid_instruction)
+        return irb->codegen->invalid_instruction;
+
+    IrInstruction *op1 = ir_gen_node(irb, op1_node, scope);
+    if (op1 == irb->codegen->invalid_instruction)
+        return irb->codegen->invalid_instruction;
+
+    IrInstruction *op2 = ir_gen_node(irb, op2_node, scope);
+    if (op2 == irb->codegen->invalid_instruction)
+        return irb->codegen->invalid_instruction;
+
+    IrInstruction *result_ptr = ir_gen_node(irb, result_ptr_node, scope);
+    if (result_ptr == irb->codegen->invalid_instruction)
+        return irb->codegen->invalid_instruction;
+
+    return ir_build_overflow_op(irb, scope, node, op, type_value, op1, op2, result_ptr, nullptr);
+}
+
 static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node) {
     assert(node->type == NodeTypeFnCallExpr);
 
@@ -2522,14 +2627,27 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
             }
         case BuiltinFnIdBreakpoint:
             return ir_build_breakpoint(irb, scope, node);
+        case BuiltinFnIdReturnAddress:
+            return ir_build_return_address(irb, scope, node);
+        case BuiltinFnIdFrameAddress:
+            return ir_build_frame_address(irb, scope, node);
         case BuiltinFnIdAlignof:
+            {
+                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;
+
+                return ir_build_alignof(irb, scope, node, arg0_value);
+            }
         case BuiltinFnIdAddWithOverflow:
+            return ir_gen_overflow_op(irb, scope, node, IrOverflowOpAdd);
         case BuiltinFnIdSubWithOverflow:
+            return ir_gen_overflow_op(irb, scope, node, IrOverflowOpSub);
         case BuiltinFnIdMulWithOverflow:
+            return ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul);
         case BuiltinFnIdShlWithOverflow:
-        case BuiltinFnIdReturnAddress:
-        case BuiltinFnIdFrameAddress:
-            zig_panic("TODO IR gen more builtin functions");
+            return ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl);
     }
     zig_unreachable();
 }
@@ -2749,10 +2867,6 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
         type_instruction = nullptr;
     }
 
-    IrInstruction *init_value = ir_gen_node(irb, variable_declaration->expr, scope);
-    if (init_value == irb->codegen->invalid_instruction)
-        return init_value;
-
     bool is_shadowable = false;
     bool is_const = variable_declaration->is_const;
     bool is_extern = variable_declaration->is_extern;
@@ -2768,6 +2882,10 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
         return irb->codegen->invalid_instruction;
     }
 
+    IrInstruction *init_value = ir_gen_node(irb, variable_declaration->expr, scope);
+    if (init_value == irb->codegen->invalid_instruction)
+        return init_value;
+
     return ir_build_var_decl(irb, scope, node, var, type_instruction, init_value);
 }
 
@@ -4057,9 +4175,9 @@ static TypeTableEntry *ir_analyze_void(IrAnalyze *ira, IrInstruction *instructio
 
 static TypeTableEntry *ir_analyze_const_ptr(IrAnalyze *ira, IrInstruction *instruction,
         ConstExprValue *pointee, TypeTableEntry *pointee_type, bool depends_on_compile_var,
-        ConstPtrSpecial special)
+        ConstPtrSpecial special, bool ptr_is_const)
 {
-    TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, pointee_type, true);
+    TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, pointee_type, ptr_is_const);
     ConstExprValue *const_val = ir_build_const_from(ira, instruction,
             depends_on_compile_var || pointee->depends_on_compile_var);
     const_val->data.x_ptr.base_ptr = pointee;
@@ -4086,7 +4204,7 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value) {
 
 IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
         TypeTableEntry *expected_type, size_t *backward_branch_count, size_t backward_branch_quota,
-        FnTableEntry *fn_entry, Buf *c_import_buf)
+        FnTableEntry *fn_entry, Buf *c_import_buf, AstNode *source_node)
 {
     IrExecutable ir_executable = {0};
     ir_executable.is_inline = true;
@@ -4122,7 +4240,7 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node
 
     IrInstruction *result = ir_exec_const_result(&analyzed_executable);
     if (!result) {
-        add_node_error(codegen, node, buf_sprintf("unable to evaluate constant expression"));
+        add_node_error(codegen, source_node, buf_sprintf("unable to evaluate constant expression"));
         return codegen->invalid_instruction;
     }
 
@@ -4499,7 +4617,9 @@ static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_inst
         ConstExprValue *val = ir_resolve_const(ira, value);
         if (!val)
             return ira->codegen->builtin_types.entry_invalid;
-        return ir_analyze_const_ptr(ira, source_instruction, val, value->type_entry, false, ConstPtrSpecialNone);
+        bool ptr_is_const = true;
+        return ir_analyze_const_ptr(ira, source_instruction, val, value->type_entry,
+                false, ConstPtrSpecialNone, ptr_is_const);
     }
 
     TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, value->type_entry, true);
@@ -5230,11 +5350,16 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
     var->type = result_type;
     assert(var->type);
 
-    if (casted_init_value->static_value.special == ConstValSpecialStatic) {
+    if (casted_init_value->static_value.special != ConstValSpecialRuntime) {
         if (var->mem_slot_index != SIZE_MAX) {
             assert(var->mem_slot_index < ira->exec_context.mem_slot_count);
             ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
             *mem_slot = casted_init_value->static_value;
+
+            if (var->is_inline) {
+                ir_build_const_from(ira, &decl_var_instruction->base, false);
+                return ira->codegen->builtin_types.entry_void;
+            }
         }
     } else if (var->is_inline) {
         ir_add_error(ira, &decl_var_instruction->base,
@@ -5403,7 +5528,8 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
         // Analyze the fn body block like any other constant expression.
         AstNode *body_node = fn_entry->fn_def_node->data.fn_def.body;
         IrInstruction *result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type,
-            ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry, nullptr);
+            ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry,
+            nullptr, call_instruction->base.source_node);
         if (result->type_entry->id == TypeTableEntryIdInvalid)
             return ira->codegen->builtin_types.entry_invalid;
 
@@ -6055,7 +6181,7 @@ static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruc
 
     if (mem_slot && mem_slot->special != ConstValSpecialRuntime) {
         ConstPtrSpecial ptr_special = var->is_inline ? ConstPtrSpecialInline : ConstPtrSpecialNone;
-        return ir_analyze_const_ptr(ira, instruction, mem_slot, var->type, false, ptr_special);
+        return ir_analyze_const_ptr(ira, instruction, mem_slot, var->type, false, ptr_special, var->src_is_const);
     } else {
         ir_build_var_ptr_from(&ira->new_irb, instruction, var);
         return get_pointer_to_type(ira->codegen, var->type, false);
@@ -6270,7 +6396,9 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
             const_val->special = ConstValSpecialStatic;
             const_val->data.x_fn = fn_entry;
 
-            return ir_analyze_const_ptr(ira, source_instruction, const_val, fn_entry->type_entry, depends_on_compile_var, ConstPtrSpecialNone);
+            bool ptr_is_const = true;
+            return ir_analyze_const_ptr(ira, source_instruction, const_val, fn_entry->type_entry,
+                    depends_on_compile_var, ConstPtrSpecialNone, ptr_is_const);
         }
         case TldIdContainer:
         {
@@ -6283,7 +6411,9 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
             const_val->special = ConstValSpecialStatic;
             const_val->data.x_type = tld_container->type_entry;
 
-            return ir_analyze_const_ptr(ira, source_instruction, const_val, tld_container->type_entry, depends_on_compile_var, ConstPtrSpecialNone);
+            bool ptr_is_const = true;
+            return ir_analyze_const_ptr(ira, source_instruction, const_val, tld_container->type_entry,
+                    depends_on_compile_var, ConstPtrSpecialNone, ptr_is_const);
         }
         case TldIdTypeDef:
         {
@@ -6296,7 +6426,9 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
             const_val->special = ConstValSpecialStatic;
             const_val->data.x_type = tld_typedef->type_entry;
 
-            return ir_analyze_const_ptr(ira, source_instruction, const_val, tld_typedef->type_entry, depends_on_compile_var, ConstPtrSpecialNone);
+            bool ptr_is_const = true;
+            return ir_analyze_const_ptr(ira, source_instruction, const_val, tld_typedef->type_entry,
+                    depends_on_compile_var, ConstPtrSpecialNone, ptr_is_const);
         }
     }
     zig_unreachable();
@@ -6332,7 +6464,9 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
             bignum_init_unsigned(&len_val->data.x_bignum, container_type->data.array.len);
 
             TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
-            return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val, usize, false, ConstPtrSpecialNone);
+            bool ptr_is_const = true;
+            return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val,
+                    usize, false, ConstPtrSpecialNone, ptr_is_const);
         } else {
             add_node_error(ira->codegen, source_node,
                 buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
@@ -6363,8 +6497,10 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
                 TypeEnumField *field = find_enum_type_field(child_type, field_name);
                 if (field) {
                     if (field->type_entry->id == TypeTableEntryIdVoid) {
-                        return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, create_const_enum_tag(field->value),
-                                child_type, depends_on_compile_var, ConstPtrSpecialNone);
+                        bool ptr_is_const = true;
+                        return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+                                create_const_enum_tag(field->value), child_type, depends_on_compile_var,
+                                ConstPtrSpecialNone, ptr_is_const);
                     } else {
                         zig_panic("TODO enum tag type");
                     }
@@ -6387,8 +6523,9 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
                 const_val->special = ConstValSpecialStatic;
                 const_val->data.x_pure_err = err_table_entry->value;
 
+                bool ptr_is_const = true;
                 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, const_val,
-                        child_type, depends_on_compile_var, ConstPtrSpecialNone);
+                        child_type, depends_on_compile_var, ConstPtrSpecialNone, ptr_is_const);
             }
 
             ir_add_error(ira, &field_ptr_instruction->base,
@@ -6396,13 +6533,17 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
             return ira->codegen->builtin_types.entry_invalid;
         } else if (child_type->id == TypeTableEntryIdInt) {
             if (buf_eql_str(field_name, "bit_count")) {
+                bool ptr_is_const = true;
                 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);
+                    ira->codegen->builtin_types.entry_num_lit_int, depends_on_compile_var,
+                    ConstPtrSpecialNone, ptr_is_const);
             } else if (buf_eql_str(field_name, "is_signed")) {
+                bool ptr_is_const = true;
                 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);
+                    ira->codegen->builtin_types.entry_bool, depends_on_compile_var,
+                    ConstPtrSpecialNone, ptr_is_const);
             } else {
                 ir_add_error(ira, &field_ptr_instruction->base,
                     buf_sprintf("type '%s' has no member called '%s'",
@@ -7713,7 +7854,8 @@ static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruc
     // Execute the C import block like an inline function
     TypeTableEntry *void_type = ira->codegen->builtin_types.entry_void;
     IrInstruction *result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type,
-        ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, &cimport_scope->buf);
+        ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr,
+        &cimport_scope->buf, block_node);
     if (result->type_entry->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
@@ -8492,6 +8634,125 @@ static TypeTableEntry *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstr
     return ira->codegen->builtin_types.entry_void;
 }
 
+static TypeTableEntry *ir_analyze_instruction_return_address(IrAnalyze *ira, IrInstructionReturnAddress *instruction) {
+    ir_build_return_address_from(&ira->new_irb, &instruction->base);
+
+    TypeTableEntry *u8 = ira->codegen->builtin_types.entry_u8;
+    TypeTableEntry *u8_ptr_const = get_pointer_to_type(ira->codegen, u8, true);
+    return u8_ptr_const;
+}
+
+static TypeTableEntry *ir_analyze_instruction_frame_address(IrAnalyze *ira, IrInstructionFrameAddress *instruction) {
+    ir_build_frame_address_from(&ira->new_irb, &instruction->base);
+
+    TypeTableEntry *u8 = ira->codegen->builtin_types.entry_u8;
+    TypeTableEntry *u8_ptr_const = get_pointer_to_type(ira->codegen, u8, true);
+    return u8_ptr_const;
+}
+
+static TypeTableEntry *ir_analyze_instruction_alignof(IrAnalyze *ira, IrInstructionAlignOf *instruction) {
+    IrInstruction *type_value = instruction->type_value->other;
+    if (type_value->type_entry->id == TypeTableEntryIdInvalid)
+        return ira->codegen->builtin_types.entry_invalid;
+    TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
+
+    if (type_entry->id == TypeTableEntryIdInvalid) {
+        return ira->codegen->builtin_types.entry_invalid;
+    } else if (type_entry->id == TypeTableEntryIdUnreachable) {
+        add_node_error(ira->codegen, first_executing_node(instruction->type_value->source_node),
+                buf_sprintf("no align available for type '%s'", buf_ptr(&type_entry->name)));
+        return ira->codegen->builtin_types.entry_invalid;
+    } else {
+        uint64_t align_in_bytes = LLVMABISizeOfType(ira->codegen->target_data_ref, type_entry->type_ref);
+        bool depends_on_compile_var = type_value->static_value.depends_on_compile_var;
+        ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
+        bignum_init_unsigned(&out_val->data.x_bignum, align_in_bytes);
+        return ira->codegen->builtin_types.entry_num_lit_int;
+    }
+}
+
+static TypeTableEntry *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstructionOverflowOp *instruction) {
+    IrInstruction *type_value = instruction->type_value->other;
+    if (type_value->type_entry->id == TypeTableEntryIdInvalid)
+        return ira->codegen->builtin_types.entry_invalid;
+    TypeTableEntry *dest_type = ir_resolve_type(ira, type_value);
+    TypeTableEntry *canon_type = get_underlying_type(dest_type);
+    if (canon_type->id == TypeTableEntryIdInvalid)
+        return ira->codegen->builtin_types.entry_invalid;
+
+    if (canon_type->id != TypeTableEntryIdInt) {
+        ir_add_error(ira, type_value,
+            buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name)));
+        // TODO if this is a typedecl, add error note showing the declaration of the type decl
+        return ira->codegen->builtin_types.entry_invalid;
+    }
+
+    IrInstruction *op1 = instruction->op1->other;
+    if (op1->type_entry->id == TypeTableEntryIdInvalid)
+        return ira->codegen->builtin_types.entry_invalid;
+
+    IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, dest_type);
+    if (casted_op1->type_entry->id == TypeTableEntryIdInvalid)
+        return ira->codegen->builtin_types.entry_invalid;
+
+    IrInstruction *op2 = instruction->op2->other;
+    if (op2->type_entry->id == TypeTableEntryIdInvalid)
+        return ira->codegen->builtin_types.entry_invalid;
+
+    IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, dest_type);
+    if (casted_op2->type_entry->id == TypeTableEntryIdInvalid)
+        return ira->codegen->builtin_types.entry_invalid;
+
+    IrInstruction *result_ptr = instruction->result_ptr->other;
+    if (result_ptr->type_entry->id == TypeTableEntryIdInvalid)
+        return ira->codegen->builtin_types.entry_invalid;
+
+    TypeTableEntry *expected_ptr_type = get_pointer_to_type(ira->codegen, dest_type, false);
+    IrInstruction *casted_result_ptr = ir_implicit_cast(ira, result_ptr, expected_ptr_type);
+    if (casted_result_ptr->type_entry->id == TypeTableEntryIdInvalid)
+        return ira->codegen->builtin_types.entry_invalid;
+
+    if (casted_op1->static_value.special == ConstValSpecialStatic &&
+        casted_op2->static_value.special == ConstValSpecialStatic &&
+        casted_result_ptr->static_value.special == ConstValSpecialStatic)
+    {
+        bool depends_on_compile_var = type_value->static_value.depends_on_compile_var ||
+            casted_op1->static_value.depends_on_compile_var || casted_op2->static_value.depends_on_compile_var ||
+            casted_result_ptr->static_value.depends_on_compile_var;
+        ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
+        BigNum *op1_bignum = &casted_op1->static_value.data.x_bignum;
+        BigNum *op2_bignum = &casted_op2->static_value.data.x_bignum;
+        ConstExprValue *pointee_val = const_ptr_pointee(&casted_result_ptr->static_value);
+        BigNum *dest_bignum = &pointee_val->data.x_bignum;
+        switch (instruction->op) {
+            case IrOverflowOpAdd:
+                out_val->data.x_bool = bignum_add(dest_bignum, op1_bignum, op2_bignum);
+                break;
+            case IrOverflowOpSub:
+                out_val->data.x_bool = bignum_add(dest_bignum, op1_bignum, op2_bignum);
+                break;
+            case IrOverflowOpMul:
+                out_val->data.x_bool = bignum_add(dest_bignum, op1_bignum, op2_bignum);
+                break;
+            case IrOverflowOpShl:
+                out_val->data.x_bool = bignum_add(dest_bignum, op1_bignum, op2_bignum);
+                break;
+        }
+        if (!bignum_fits_in_bits(dest_bignum, canon_type->data.integral.bit_count,
+            canon_type->data.integral.is_signed))
+        {
+            out_val->data.x_bool = true;
+            bignum_truncate(dest_bignum, canon_type->data.integral.bit_count);
+        }
+        pointee_val->special = ConstValSpecialStatic;
+        return ira->codegen->builtin_types.entry_bool;
+    }
+
+    ir_build_overflow_op_from(&ira->new_irb, &instruction->base, instruction->op, type_value,
+        casted_op1, casted_op2, casted_result_ptr, dest_type);
+    return ira->codegen->builtin_types.entry_bool;
+}
+
 static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
     switch (instruction->id) {
         case IrInstructionIdInvalid:
@@ -8618,6 +8879,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
             return ir_analyze_instruction_member_count(ira, (IrInstructionMemberCount *)instruction);
         case IrInstructionIdBreakpoint:
             return ir_analyze_instruction_breakpoint(ira, (IrInstructionBreakpoint *)instruction);
+        case IrInstructionIdReturnAddress:
+            return ir_analyze_instruction_return_address(ira, (IrInstructionReturnAddress *)instruction);
+        case IrInstructionIdFrameAddress:
+            return ir_analyze_instruction_frame_address(ira, (IrInstructionFrameAddress *)instruction);
+        case IrInstructionIdAlignOf:
+            return ir_analyze_instruction_alignof(ira, (IrInstructionAlignOf *)instruction);
+        case IrInstructionIdOverflowOp:
+            return ir_analyze_instruction_overflow_op(ira, (IrInstructionOverflowOp *)instruction);
         case IrInstructionIdCast:
         case IrInstructionIdStructFieldPtr:
         case IrInstructionIdEnumFieldPtr:
@@ -8722,6 +8991,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
         case IrInstructionIdMemset:
         case IrInstructionIdMemcpy:
         case IrInstructionIdBreakpoint:
+        case IrInstructionIdOverflowOp: // TODO when we support multiple returns this can be side effect free
             return true;
         case IrInstructionIdPhi:
         case IrInstructionIdUnOp:
@@ -8765,6 +9035,9 @@ bool ir_has_side_effects(IrInstruction *instruction) {
         case IrInstructionIdAlloca:
         case IrInstructionIdSlice:
         case IrInstructionIdMemberCount:
+        case IrInstructionIdAlignOf:
+        case IrInstructionIdReturnAddress:
+        case IrInstructionIdFrameAddress:
             return false;
         case IrInstructionIdAsm:
             {
@@ -8776,63 +9049,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_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
-//        TypeTableEntry *expected_type, AstNode *node)
-//{
-//
-//    switch (builtin_fn->id) {
-//        case BuiltinFnIdInvalid:
-//            zig_unreachable();
-//        case BuiltinFnIdAddWithOverflow:
-//        case BuiltinFnIdSubWithOverflow:
-//        case BuiltinFnIdMulWithOverflow:
-//        case BuiltinFnIdShlWithOverflow:
-//            {
-//                AstNode *type_node = node->data.fn_call_expr.params.at(0);
-//                TypeTableEntry *int_type = analyze_type_expr(g, import, context, type_node);
-//                if (int_type->id == TypeTableEntryIdInvalid) {
-//                    return g->builtin_types.entry_bool;
-//                } else if (int_type->id == TypeTableEntryIdInt) {
-//                    AstNode *op1_node = node->data.fn_call_expr.params.at(1);
-//                    AstNode *op2_node = node->data.fn_call_expr.params.at(2);
-//                    AstNode *result_node = node->data.fn_call_expr.params.at(3);
-//
-//                    analyze_expression(g, import, context, int_type, op1_node);
-//                    analyze_expression(g, import, context, int_type, op2_node);
-//                    analyze_expression(g, import, context, get_pointer_to_type(g, int_type, false),
-//                            result_node);
-//                } else {
-//                    add_node_error(g, type_node,
-//                        buf_sprintf("expected integer type, found '%s'", buf_ptr(&int_type->name)));
-//                }
-//
-//                // TODO constant expression evaluation
-//
-//                return g->builtin_types.entry_bool;
-//            }
-//        case BuiltinFnIdAlignof:
-//            {
-//                AstNode *type_node = node->data.fn_call_expr.params.at(0);
-//                TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node);
-//                if (type_entry->id == TypeTableEntryIdInvalid) {
-//                    return g->builtin_types.entry_invalid;
-//                } else if (type_entry->id == TypeTableEntryIdUnreachable) {
-//                    add_node_error(g, first_executing_node(type_node),
-//                            buf_sprintf("no align available for type '%s'", buf_ptr(&type_entry->name)));
-//                    return g->builtin_types.entry_invalid;
-//                } else {
-//                    uint64_t align_in_bytes = LLVMABISizeOfType(g->target_data_ref, type_entry->type_ref);
-//                    return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,
-//                            align_in_bytes, false);
-//                }
-//            }
-//        case BuiltinFnIdReturnAddress:
-//        case BuiltinFnIdFrameAddress:
-//            mark_impure_fn(g, context, node);
-//            return builtin_fn->return_type;
-//    }
-//    zig_unreachable();
-//}
 
 //static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
 //        TypeTableEntry *expected_type, AstNode *node)
@@ -8948,110 +9164,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
 //    }
 //}
 //
-//static LLVMValueRef gen_shl_with_overflow(CodeGen *g, AstNode *node) {
-//    assert(node->type == NodeTypeFnCallExpr);
-//
-//    size_t fn_call_param_count = node->data.fn_call_expr.params.length;
-//    assert(fn_call_param_count == 4);
-//
-//    TypeTableEntry *int_type = get_type_for_type_node(node->data.fn_call_expr.params.at(0));
-//    assert(int_type->id == TypeTableEntryIdInt);
-//
-//    LLVMValueRef val1 = gen_expr(g, node->data.fn_call_expr.params.at(1));
-//    LLVMValueRef val2 = gen_expr(g, node->data.fn_call_expr.params.at(2));
-//    LLVMValueRef ptr_result = gen_expr(g, node->data.fn_call_expr.params.at(3));
-//
-//    LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, "");
-//    LLVMValueRef orig_val;
-//    if (int_type->data.integral.is_signed) {
-//        orig_val = LLVMBuildAShr(g->builder, result, val2, "");
-//    } else {
-//        orig_val = LLVMBuildLShr(g->builder, result, val2, "");
-//    }
-//    LLVMValueRef overflow_bit = LLVMBuildICmp(g->builder, LLVMIntNE, val1, orig_val, "");
-//
-//    LLVMBuildStore(g->builder, result, ptr_result);
-//
-//    return overflow_bit;
-//}
-//
-//static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
-//    assert(node->type == NodeTypeFnCallExpr);
-//    AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
-//    assert(fn_ref_expr->type == NodeTypeSymbol);
-//    BuiltinFnEntry *builtin_fn = node->data.fn_call_expr.builtin_fn;
-//
-//    switch (builtin_fn->id) {
-//        case BuiltinFnIdInvalid:
-//        case BuiltinFnIdTypeof:
-//            zig_unreachable();
-//        case BuiltinFnIdAddWithOverflow:
-//        case BuiltinFnIdSubWithOverflow:
-//        case BuiltinFnIdMulWithOverflow:
-//            {
-//                size_t fn_call_param_count = node->data.fn_call_expr.params.length;
-//                assert(fn_call_param_count == 4);
-//
-//                TypeTableEntry *int_type = get_type_for_type_node(node->data.fn_call_expr.params.at(0));
-//                AddSubMul add_sub_mul;
-//                if (builtin_fn->id == BuiltinFnIdAddWithOverflow) {
-//                    add_sub_mul = AddSubMulAdd;
-//                } else if (builtin_fn->id == BuiltinFnIdSubWithOverflow) {
-//                    add_sub_mul = AddSubMulSub;
-//                } else if (builtin_fn->id == BuiltinFnIdMulWithOverflow) {
-//                    add_sub_mul = AddSubMulMul;
-//                } else {
-//                    zig_unreachable();
-//                }
-//                LLVMValueRef fn_val = get_int_overflow_fn(g, int_type, add_sub_mul);
-//
-//                LLVMValueRef op1 = gen_expr(g, node->data.fn_call_expr.params.at(1));
-//                LLVMValueRef op2 = gen_expr(g, node->data.fn_call_expr.params.at(2));
-//                LLVMValueRef ptr_result = gen_expr(g, node->data.fn_call_expr.params.at(3));
-//
-//                LLVMValueRef params[] = {
-//                    op1,
-//                    op2,
-//                };
-//
-//                LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, "");
-//                LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, "");
-//                LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, "");
-//                LLVMBuildStore(g->builder, result, ptr_result);
-//
-//                return overflow_bit;
-//            }
-//        case BuiltinFnIdShlWithOverflow:
-//            return gen_shl_with_overflow(g, node);
-//        case BuiltinFnIdAlignof:
-//        case BuiltinFnIdMinValue:
-//        case BuiltinFnIdMaxValue:
-//            // caught by constant expression eval codegen
-//            zig_unreachable();
-//        case BuiltinFnIdCompileVar:
-//            return nullptr;
-//        case BuiltinFnIdFrameAddress:
-//        case BuiltinFnIdReturnAddress:
-//            {
-//                LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
-//                return LLVMBuildCall(g->builder, builtin_fn->fn_val, &zero, 1, "");
-//            }
-//        case BuiltinFnIdCmpExchange:
-//            return gen_cmp_exchange(g, node);
-//        case BuiltinFnIdFence:
-//            return gen_fence(g, node);
-//        case BuiltinFnIdUnreachable:
-//            zig_panic("moved to ir render");
-//        case BuiltinFnIdSetFnTest:
-//        case BuiltinFnIdSetFnStaticEval:
-//        case BuiltinFnIdSetFnNoInline:
-//        case BuiltinFnIdSetDebugSafety:
-//            // do nothing
-//            return nullptr;
-//    }
-//    zig_unreachable();
-//}
-//
 //static LLVMValueRef gen_enum_value_expr(CodeGen *g, AstNode *node, TypeTableEntry *enum_type,
 //        AstNode *arg_node)
 //{
src/ir.hpp
@@ -15,7 +15,7 @@ IrInstruction *ir_gen_fn(CodeGen *g, FnTableEntry *fn_entry);
 
 IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
         TypeTableEntry *expected_type, size_t *backward_branch_count, size_t backward_branch_quota,
-        FnTableEntry *fn_entry, Buf *c_import_buf);
+        FnTableEntry *fn_entry, Buf *c_import_buf, AstNode *source_node);
 
 TypeTableEntry *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable,
         TypeTableEntry *expected_type, AstNode *expected_type_source_node);
src/ir_print.cpp
@@ -816,6 +816,45 @@ static void ir_print_breakpoint(IrPrint *irp, IrInstructionBreakpoint *instructi
     fprintf(irp->f, "@breakpoint()");
 }
 
+static void ir_print_frame_address(IrPrint *irp, IrInstructionFrameAddress *instruction) {
+    fprintf(irp->f, "@frameAddress()");
+}
+
+static void ir_print_return_address(IrPrint *irp, IrInstructionReturnAddress *instruction) {
+    fprintf(irp->f, "@returnAddress()");
+}
+
+static void ir_print_alignof(IrPrint *irp, IrInstructionAlignOf *instruction) {
+    fprintf(irp->f, "@alignOf(");
+    ir_print_other_instruction(irp, instruction->type_value);
+    fprintf(irp->f, ")");
+}
+
+static void ir_print_overflow_op(IrPrint *irp, IrInstructionOverflowOp *instruction) {
+    switch (instruction->op) {
+        case IrOverflowOpAdd:
+            fprintf(irp->f, "@addWithOverflow(");
+            break;
+        case IrOverflowOpSub:
+            fprintf(irp->f, "@subWithOverflow(");
+            break;
+        case IrOverflowOpMul:
+            fprintf(irp->f, "@mulWithOverflow(");
+            break;
+        case IrOverflowOpShl:
+            fprintf(irp->f, "@shlWithOverflow(");
+            break;
+    }
+    ir_print_other_instruction(irp, instruction->type_value);
+    fprintf(irp->f, ", ");
+    ir_print_other_instruction(irp, instruction->op1);
+    fprintf(irp->f, ", ");
+    ir_print_other_instruction(irp, instruction->op2);
+    fprintf(irp->f, ", ");
+    ir_print_other_instruction(irp, instruction->result_ptr);
+    fprintf(irp->f, ")");
+}
+
 static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
     ir_print_prefix(irp, instruction);
     switch (instruction->id) {
@@ -1016,6 +1055,18 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
         case IrInstructionIdBreakpoint:
             ir_print_breakpoint(irp, (IrInstructionBreakpoint *)instruction);
             break;
+        case IrInstructionIdReturnAddress:
+            ir_print_return_address(irp, (IrInstructionReturnAddress *)instruction);
+            break;
+        case IrInstructionIdFrameAddress:
+            ir_print_frame_address(irp, (IrInstructionFrameAddress *)instruction);
+            break;
+        case IrInstructionIdAlignOf:
+            ir_print_alignof(irp, (IrInstructionAlignOf *)instruction);
+            break;
+        case IrInstructionIdOverflowOp:
+            ir_print_overflow_op(irp, (IrInstructionOverflowOp *)instruction);
+            break;
     }
     fprintf(irp->f, "\n");
 }
test/self_hosted2.zig
@@ -329,6 +329,20 @@ fn intTypeBuiltin() {
 
 }
 
+fn overflowIntrinsics() {
+    var result: u8 = undefined;
+    assert(@addWithOverflow(u8, 250, 100, &result));
+    assert(!@addWithOverflow(u8, 100, 150, &result));
+    assert(result == 250);
+}
+
+fn shlWithOverflow() {
+    var result: u16 = undefined;
+    assert(@shlWithOverflow(u16, 0b0010111111111111, 3, &result));
+    assert(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result));
+    assert(result == 0b1011111111111100);
+}
+
 fn assert(ok: bool) {
     if (!ok)
         @unreachable();
@@ -361,6 +375,8 @@ fn runAllTests() {
     exactDivision();
     truncate();
     intTypeBuiltin();
+    overflowIntrinsics();
+    shlWithOverflow();
 }
 
 export nakedcc fn _start() -> unreachable {