diff --git a/src/all_types.hpp b/src/all_types.hpp index efc67a1a3..a1325a5fd 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1626,6 +1626,7 @@ struct IrInstructionElemPtr { IrInstruction *array_ptr; IrInstruction *elem_index; bool is_const; + bool safety_check_on; }; struct IrInstructionVarPtr { diff --git a/src/codegen.cpp b/src/codegen.cpp index aa4588dd4..45cdd400c 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -455,55 +455,6 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT } } -static LLVMValueRef gen_array_elem_ptr(CodeGen *g, AstNode *source_node, LLVMValueRef array_ptr, - TypeTableEntry *array_type, LLVMValueRef subscript_value) -{ - assert(subscript_value); - - if (!type_has_bits(array_type)) { - return nullptr; - } - - if (array_type->id == TypeTableEntryIdArray) { - if (want_debug_safety(g, source_node)) { - LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->type_ref, - array_type->data.array.len, false); - add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, end); - } - LLVMValueRef indices[] = { - LLVMConstNull(g->builtin_types.entry_usize->type_ref), - subscript_value - }; - return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); - } else if (array_type->id == TypeTableEntryIdPointer) { - assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); - LLVMValueRef indices[] = { - subscript_value - }; - return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 1, ""); - } else if (array_type->id == TypeTableEntryIdStruct) { - assert(array_type->data.structure.is_slice); - assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); - assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); - - if (want_debug_safety(g, source_node)) { - size_t len_index = array_type->data.structure.fields[1].gen_index; - assert(len_index != SIZE_MAX); - LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, len_index, ""); - LLVMValueRef len = LLVMBuildLoad(g->builder, len_ptr, ""); - add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, len); - } - - size_t ptr_index = array_type->data.structure.fields[0].gen_index; - assert(ptr_index != SIZE_MAX); - LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, ptr_index, ""); - LLVMValueRef ptr = LLVMBuildLoad(g->builder, ptr_ptr, ""); - return LLVMBuildInBoundsGEP(g->builder, ptr, &subscript_value, 1, ""); - } else { - zig_unreachable(); - } -} - static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddSubMul op, LLVMValueRef val1, LLVMValueRef val2) { @@ -640,83 +591,98 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns return nullptr; } -static LLVMValueRef ir_render_bin_op_bool(CodeGen *g, IrExecutable *executable, - IrInstructionBinOp *bin_op_instruction) +static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry, + LLVMValueRef val1, LLVMValueRef val2) { - IrBinOp op_id = bin_op_instruction->op_id; - LLVMValueRef op1 = ir_llvm_value(g, bin_op_instruction->op1); - LLVMValueRef op2 = ir_llvm_value(g, bin_op_instruction->op2); - if (op_id == IrBinOpBoolOr) { - return LLVMBuildOr(g->builder, op1, op2, ""); - } else if (op_id == IrBinOpBoolAnd) { - return LLVMBuildAnd(g->builder, op1, op2, ""); + // for unsigned left shifting, we do the wrapping shift, then logically shift + // right the same number of bits + // if the values don't match, we have an overflow + // for signed left shifting we do the same except arithmetic shift right + + assert(type_entry->id == TypeTableEntryIdInt); + + LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, ""); + LLVMValueRef orig_val; + if (type_entry->data.integral.is_signed) { + orig_val = LLVMBuildAShr(g->builder, result, val2, ""); } else { - zig_unreachable(); + orig_val = LLVMBuildLShr(g->builder, result, val2, ""); } + LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, ""); + + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk"); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail"); + LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); + + LLVMPositionBuilderAtEnd(g->builder, fail_block); + gen_debug_safety_crash(g); + + LLVMPositionBuilderAtEnd(g->builder, ok_block); + return result; } -static LLVMValueRef ir_render_bin_op_cmp(CodeGen *g, IrExecutable *executable, - IrInstructionBinOp *bin_op_instruction) +static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, LLVMValueRef val2, + TypeTableEntry *type_entry, bool exact) { - IrBinOp op_id = bin_op_instruction->op_id; - LLVMValueRef val1 = ir_llvm_value(g, bin_op_instruction->op1); - LLVMValueRef val2 = ir_llvm_value(g, bin_op_instruction->op2); - TypeTableEntry *op1_type = bin_op_instruction->op1->type_entry; - TypeTableEntry *op2_type = bin_op_instruction->op2->type_entry; - assert(op1_type == op2_type); - - if (op1_type->id == TypeTableEntryIdFloat) { - LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id); - return LLVMBuildFCmp(g->builder, pred, val1, val2, ""); - } else if (op1_type->id == TypeTableEntryIdInt) { - LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, op1_type->data.integral.is_signed); - return LLVMBuildICmp(g->builder, pred, val1, val2, ""); - } else if (op1_type->id == TypeTableEntryIdEnum) { - if (op1_type->data.enumeration.gen_field_count == 0) { - LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); - return LLVMBuildICmp(g->builder, pred, val1, val2, ""); + if (want_debug_safety(g, source_node)) { + LLVMValueRef zero = LLVMConstNull(type_entry->type_ref); + LLVMValueRef is_zero_bit; + if (type_entry->id == TypeTableEntryIdInt) { + is_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, zero, ""); + } else if (type_entry->id == TypeTableEntryIdFloat) { + is_zero_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, val2, zero, ""); } else { zig_unreachable(); } - } else if (op1_type->id == TypeTableEntryIdPureError || - op1_type->id == TypeTableEntryIdPointer || - op1_type->id == TypeTableEntryIdBool) - { - LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); - return LLVMBuildICmp(g->builder, pred, val1, val2, ""); - } else { - zig_unreachable(); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroOk"); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroFail"); + LLVMBuildCondBr(g->builder, is_zero_bit, fail_block, ok_block); + + LLVMPositionBuilderAtEnd(g->builder, fail_block); + gen_debug_safety_crash(g); + + LLVMPositionBuilderAtEnd(g->builder, ok_block); } -} -static LLVMValueRef ir_render_bin_op_add(CodeGen *g, IrExecutable *executable, - IrInstructionBinOp *bin_op_instruction) -{ - IrBinOp op_id = bin_op_instruction->op_id; - IrInstruction *op1 = bin_op_instruction->op1; - IrInstruction *op2 = bin_op_instruction->op2; + if (type_entry->id == TypeTableEntryIdFloat) { + assert(!exact); + return LLVMBuildFDiv(g->builder, val1, val2, ""); + } - assert(op1->type_entry == op2->type_entry); + assert(type_entry->id == TypeTableEntryIdInt); - LLVMValueRef op1_value = ir_llvm_value(g, op1); - LLVMValueRef op2_value = ir_llvm_value(g, op2); + if (exact) { + if (want_debug_safety(g, source_node)) { + LLVMValueRef remainder_val; + if (type_entry->data.integral.is_signed) { + remainder_val = LLVMBuildSRem(g->builder, val1, val2, ""); + } else { + remainder_val = LLVMBuildURem(g->builder, val1, val2, ""); + } + LLVMValueRef zero = LLVMConstNull(type_entry->type_ref); + LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, ""); - if (op1->type_entry->id == TypeTableEntryIdFloat) { - return LLVMBuildFAdd(g->builder, op1_value, op2_value, ""); - } else if (op1->type_entry->id == TypeTableEntryIdInt) { - bool is_wrapping = (op_id == IrBinOpAddWrap); - if (is_wrapping) { - return LLVMBuildAdd(g->builder, op1_value, op2_value, ""); - } else if (ir_want_debug_safety(g, &bin_op_instruction->base)) { - return gen_overflow_op(g, op1->type_entry, AddSubMulAdd, op1_value, op2_value); - } else if (op1->type_entry->data.integral.is_signed) { - return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, ""); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactOk"); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactFail"); + LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); + + LLVMPositionBuilderAtEnd(g->builder, fail_block); + gen_debug_safety_crash(g); + + LLVMPositionBuilderAtEnd(g->builder, ok_block); + } + if (type_entry->data.integral.is_signed) { + return LLVMBuildExactSDiv(g->builder, val1, val2, ""); } else { - return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, ""); + return ZigLLVMBuildExactUDiv(g->builder, val1, val2, ""); } } else { - zig_unreachable(); + if (type_entry->data.integral.is_signed) { + return LLVMBuildSDiv(g->builder, val1, val2, ""); + } else { + return LLVMBuildUDiv(g->builder, val1, val2, ""); + } } } @@ -724,37 +690,146 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, IrInstructionBinOp *bin_op_instruction) { IrBinOp op_id = bin_op_instruction->op_id; + IrInstruction *op1 = bin_op_instruction->op1; + IrInstruction *op2 = bin_op_instruction->op2; + AstNode *source_node = bin_op_instruction->base.source_node; + + assert(op1->type_entry == op2->type_entry); + + LLVMValueRef op1_value = ir_llvm_value(g, op1); + LLVMValueRef op2_value = ir_llvm_value(g, op2); switch (op_id) { case IrBinOpInvalid: case IrBinOpArrayCat: case IrBinOpArrayMult: zig_unreachable(); case IrBinOpBoolOr: + return LLVMBuildOr(g->builder, op1_value, op2_value, ""); case IrBinOpBoolAnd: - return ir_render_bin_op_bool(g, executable, bin_op_instruction); + return LLVMBuildAnd(g->builder, op1_value, op2_value, ""); case IrBinOpCmpEq: case IrBinOpCmpNotEq: case IrBinOpCmpLessThan: case IrBinOpCmpGreaterThan: case IrBinOpCmpLessOrEq: case IrBinOpCmpGreaterOrEq: - return ir_render_bin_op_cmp(g, executable, bin_op_instruction); + if (op1->type_entry->id == TypeTableEntryIdFloat) { + LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id); + return LLVMBuildFCmp(g->builder, pred, op1_value, op2_value, ""); + } else if (op1->type_entry->id == TypeTableEntryIdInt) { + LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, op1->type_entry->data.integral.is_signed); + return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); + } else if (op1->type_entry->id == TypeTableEntryIdEnum) { + if (op1->type_entry->data.enumeration.gen_field_count == 0) { + LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); + return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); + } else { + zig_unreachable(); + } + } else if (op1->type_entry->id == TypeTableEntryIdPureError || + op1->type_entry->id == TypeTableEntryIdPointer || + op1->type_entry->id == TypeTableEntryIdBool) + { + LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); + return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); + } else { + zig_unreachable(); + } case IrBinOpAdd: case IrBinOpAddWrap: - return ir_render_bin_op_add(g, executable, bin_op_instruction); + if (op1->type_entry->id == TypeTableEntryIdFloat) { + return LLVMBuildFAdd(g->builder, op1_value, op2_value, ""); + } else if (op1->type_entry->id == TypeTableEntryIdInt) { + bool is_wrapping = (op_id == IrBinOpAddWrap); + if (is_wrapping) { + return LLVMBuildAdd(g->builder, op1_value, op2_value, ""); + } else if (ir_want_debug_safety(g, &bin_op_instruction->base)) { + return gen_overflow_op(g, op1->type_entry, AddSubMulAdd, op1_value, op2_value); + } else if (op1->type_entry->data.integral.is_signed) { + return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, ""); + } else { + return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, ""); + } + } else { + zig_unreachable(); + } case IrBinOpBinOr: + return LLVMBuildOr(g->builder, op1_value, op2_value, ""); case IrBinOpBinXor: + return LLVMBuildXor(g->builder, op1_value, op2_value, ""); case IrBinOpBinAnd: + return LLVMBuildAnd(g->builder, op1_value, op2_value, ""); case IrBinOpBitShiftLeft: case IrBinOpBitShiftLeftWrap: + { + assert(op1->type_entry->id == TypeTableEntryIdInt); + bool is_wrapping = (op_id == IrBinOpBitShiftLeftWrap); + if (is_wrapping) { + return LLVMBuildShl(g->builder, op1_value, op2_value, ""); + } else if (want_debug_safety(g, source_node)) { + return gen_overflow_shl_op(g, op1->type_entry, op1_value, op2_value); + } else if (op1->type_entry->data.integral.is_signed) { + return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_value, ""); + } else { + return ZigLLVMBuildNUWShl(g->builder, op1_value, op2_value, ""); + } + } case IrBinOpBitShiftRight: + assert(op1->type_entry->id == TypeTableEntryIdInt); + if (op1->type_entry->data.integral.is_signed) { + return LLVMBuildAShr(g->builder, op1_value, op2_value, ""); + } else { + return LLVMBuildLShr(g->builder, op1_value, op2_value, ""); + } case IrBinOpSub: case IrBinOpSubWrap: + if (op1->type_entry->id == TypeTableEntryIdFloat) { + return LLVMBuildFSub(g->builder, op1_value, op2_value, ""); + } else if (op1->type_entry->id == TypeTableEntryIdInt) { + bool is_wrapping = (op_id == IrBinOpSubWrap); + if (is_wrapping) { + return LLVMBuildSub(g->builder, op1_value, op2_value, ""); + } else if (want_debug_safety(g, source_node)) { + return gen_overflow_op(g, op1->type_entry, AddSubMulSub, op1_value, op2_value); + } else if (op1->type_entry->data.integral.is_signed) { + return LLVMBuildNSWSub(g->builder, op1_value, op2_value, ""); + } else { + return LLVMBuildNUWSub(g->builder, op1_value, op2_value, ""); + } + } else { + zig_unreachable(); + } case IrBinOpMult: case IrBinOpMultWrap: + if (op1->type_entry->id == TypeTableEntryIdFloat) { + return LLVMBuildFMul(g->builder, op1_value, op2_value, ""); + } else if (op1->type_entry->id == TypeTableEntryIdInt) { + bool is_wrapping = (op_id == IrBinOpMultWrap); + if (is_wrapping) { + return LLVMBuildMul(g->builder, op1_value, op2_value, ""); + } else if (want_debug_safety(g, source_node)) { + return gen_overflow_op(g, op1->type_entry, AddSubMulMul, op1_value, op2_value); + } else if (op1->type_entry->data.integral.is_signed) { + return LLVMBuildNSWMul(g->builder, op1_value, op2_value, ""); + } else { + return LLVMBuildNUWMul(g->builder, op1_value, op2_value, ""); + } + } else { + zig_unreachable(); + } case IrBinOpDiv: + return gen_div(g, source_node, op1_value, op2_value, op1->type_entry, false); case IrBinOpMod: - zig_panic("TODO render more bin ops to LLVM"); + if (op1->type_entry->id == TypeTableEntryIdFloat) { + return LLVMBuildFRem(g->builder, op1_value, op2_value, ""); + } else { + assert(op1->type_entry->id == TypeTableEntryIdInt); + if (op1->type_entry->data.integral.is_signed) { + return LLVMBuildSRem(g->builder, op1_value, op2_value, ""); + } else { + return LLVMBuildURem(g->builder, op1_value, op2_value, ""); + } + } } zig_unreachable(); } @@ -1242,10 +1317,56 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrInstructionElemPtr *instruction) { LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->array_ptr); - LLVMValueRef array_ptr = LLVMBuildLoad(g->builder, array_ptr_ptr, ""); + TypeTableEntry *array_ptr_type = instruction->array_ptr->type_entry; + assert(array_ptr_type->id == TypeTableEntryIdPointer); + TypeTableEntry *array_type = array_ptr_type->data.pointer.child_type; + LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type); LLVMValueRef subscript_value = ir_llvm_value(g, instruction->elem_index); - TypeTableEntry *array_type = instruction->array_ptr->type_entry; - return gen_array_elem_ptr(g, instruction->base.source_node, array_ptr, array_type, subscript_value); + assert(subscript_value); + + if (!type_has_bits(array_type)) + return nullptr; + + bool safety_check_on = ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on; + + if (array_type->id == TypeTableEntryIdArray) { + if (safety_check_on) { + LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->type_ref, + array_type->data.array.len, false); + add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, end); + } + LLVMValueRef indices[] = { + LLVMConstNull(g->builtin_types.entry_usize->type_ref), + subscript_value + }; + return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); + } else if (array_type->id == TypeTableEntryIdPointer) { + assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); + LLVMValueRef indices[] = { + subscript_value + }; + return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 1, ""); + } else if (array_type->id == TypeTableEntryIdStruct) { + assert(array_type->data.structure.is_slice); + assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); + assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); + + if (safety_check_on) { + size_t len_index = array_type->data.structure.fields[1].gen_index; + assert(len_index != SIZE_MAX); + LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, len_index, ""); + LLVMValueRef len = LLVMBuildLoad(g->builder, len_ptr, ""); + add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, len); + } + + size_t ptr_index = array_type->data.structure.fields[0].gen_index; + assert(ptr_index != SIZE_MAX); + LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, ptr_index, ""); + LLVMValueRef ptr = LLVMBuildLoad(g->builder, ptr_ptr, ""); + return LLVMBuildInBoundsGEP(g->builder, ptr, &subscript_value, 1, ""); + } else { + zig_unreachable(); + } } static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) { @@ -1423,7 +1544,6 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template), buf_ptr(&constraint_buf), is_volatile, false); - set_debug_source_node(g, asm_node); return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, ""); } diff --git a/src/ir.cpp b/src/ir.cpp index 761454413..47f0b9f23 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -506,11 +506,12 @@ static IrInstruction *ir_build_var_ptr_from(IrBuilder *irb, IrInstruction *old_i } static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, AstNode *source_node, IrInstruction *array_ptr, - IrInstruction *elem_index) + IrInstruction *elem_index, bool safety_check_on) { IrInstructionElemPtr *instruction = ir_build_instruction(irb, source_node); instruction->array_ptr = array_ptr; instruction->elem_index = elem_index; + instruction->safety_check_on = safety_check_on; ir_ref_instruction(array_ptr); ir_ref_instruction(elem_index); @@ -519,9 +520,10 @@ static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, AstNode *source_node, Ir } static IrInstruction *ir_build_elem_ptr_from(IrBuilder *irb, IrInstruction *old_instruction, - IrInstruction *array_ptr, IrInstruction *elem_index) + IrInstruction *array_ptr, IrInstruction *elem_index, bool safety_check_on) { - IrInstruction *new_instruction = ir_build_elem_ptr(irb, old_instruction->source_node, array_ptr, elem_index); + IrInstruction *new_instruction = ir_build_elem_ptr(irb, old_instruction->source_node, array_ptr, elem_index, + safety_check_on); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } @@ -1353,7 +1355,8 @@ static IrInstruction *ir_gen_array_access(IrBuilder *irb, AstNode *node, LValPur if (subscript_instruction == irb->codegen->invalid_instruction) return subscript_instruction; - IrInstruction *ptr_instruction = ir_build_elem_ptr(irb, node, array_ref_instruction, subscript_instruction); + IrInstruction *ptr_instruction = ir_build_elem_ptr(irb, node, array_ref_instruction, + subscript_instruction, true); if (lval != LValPurposeNone) return ptr_instruction; @@ -1840,7 +1843,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, AstNode *node) { ir_build_cond_br(irb, node, cond, body_block, end_block, is_inline); ir_set_cursor_at_end(irb, body_block); - IrInstruction *elem_ptr = ir_build_elem_ptr(irb, node, array_val, index_val); + IrInstruction *elem_ptr = ir_build_elem_ptr(irb, node, array_val, index_val, true); IrInstruction *elem_val; if (node->data.for_expr.elem_is_ptr) { elem_val = elem_ptr; @@ -3960,6 +3963,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc if (casted_elem_index == ira->codegen->invalid_instruction) return ira->codegen->builtin_types.entry_invalid; + bool safety_check_on = true; if (casted_elem_index->static_value.special != ConstValSpecialRuntime) { uint64_t index = casted_elem_index->static_value.data.x_bignum.data.x_uint; if (array_type->id == TypeTableEntryIdArray) { @@ -3970,6 +3974,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc index, array_len)); return ira->codegen->builtin_types.entry_invalid; } + safety_check_on = false; } ConstExprValue *array_ptr_val; @@ -4031,7 +4036,8 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc } - ir_build_elem_ptr_from(&ira->new_irb, &elem_ptr_instruction->base, array_ptr, casted_elem_index); + ir_build_elem_ptr_from(&ira->new_irb, &elem_ptr_instruction->base, array_ptr, + casted_elem_index, safety_check_on); return return_type; } @@ -8668,18 +8674,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no // return target_ref; //} // -//static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { -// assert(node->type == NodeTypeBinOpExpr); -// -// LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1); -// LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2); -// -// TypeTableEntry *op1_type = get_expr_type(node->data.bin_op_expr.op1); -// TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2); -// return gen_arithmetic_bin_op(g, node, val1, val2, op1_type, op2_type, node->data.bin_op_expr.bin_op); -// -//} -// //static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) { // assert(node->type == NodeTypeBinOpExpr); // @@ -9678,97 +9672,3 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no // LLVMPositionBuilderAtEnd(g->builder, basic_block); // return nullptr; //} -//static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry, -// LLVMValueRef val1, LLVMValueRef val2) -//{ -// // for unsigned left shifting, we do the wrapping shift, then logically shift -// // right the same number of bits -// // if the values don't match, we have an overflow -// // for signed left shifting we do the same except arithmetic shift right -// -// assert(type_entry->id == TypeTableEntryIdInt); -// -// LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, ""); -// LLVMValueRef orig_val; -// if (type_entry->data.integral.is_signed) { -// orig_val = LLVMBuildAShr(g->builder, result, val2, ""); -// } else { -// orig_val = LLVMBuildLShr(g->builder, result, val2, ""); -// } -// LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, ""); -// -// LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk"); -// LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail"); -// LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); -// -// LLVMPositionBuilderAtEnd(g->builder, fail_block); -// gen_debug_safety_crash(g); -// -// LLVMPositionBuilderAtEnd(g->builder, ok_block); -// return result; -//} -// -//static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, LLVMValueRef val2, -// TypeTableEntry *type_entry, bool exact) -//{ -// -// if (want_debug_safety(g, source_node)) { -// LLVMValueRef zero = LLVMConstNull(type_entry->type_ref); -// LLVMValueRef is_zero_bit; -// if (type_entry->id == TypeTableEntryIdInt) { -// is_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, zero, ""); -// } else if (type_entry->id == TypeTableEntryIdFloat) { -// is_zero_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, val2, zero, ""); -// } else { -// zig_unreachable(); -// } -// LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroOk"); -// LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroFail"); -// LLVMBuildCondBr(g->builder, is_zero_bit, fail_block, ok_block); -// -// LLVMPositionBuilderAtEnd(g->builder, fail_block); -// gen_debug_safety_crash(g); -// -// LLVMPositionBuilderAtEnd(g->builder, ok_block); -// } -// -// if (type_entry->id == TypeTableEntryIdFloat) { -// assert(!exact); -// return LLVMBuildFDiv(g->builder, val1, val2, ""); -// } -// -// assert(type_entry->id == TypeTableEntryIdInt); -// -// if (exact) { -// if (want_debug_safety(g, source_node)) { -// LLVMValueRef remainder_val; -// if (type_entry->data.integral.is_signed) { -// remainder_val = LLVMBuildSRem(g->builder, val1, val2, ""); -// } else { -// remainder_val = LLVMBuildURem(g->builder, val1, val2, ""); -// } -// LLVMValueRef zero = LLVMConstNull(type_entry->type_ref); -// LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, ""); -// -// LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactOk"); -// LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactFail"); -// LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); -// -// LLVMPositionBuilderAtEnd(g->builder, fail_block); -// gen_debug_safety_crash(g); -// -// LLVMPositionBuilderAtEnd(g->builder, ok_block); -// } -// if (type_entry->data.integral.is_signed) { -// return LLVMBuildExactSDiv(g->builder, val1, val2, ""); -// } else { -// return ZigLLVMBuildExactUDiv(g->builder, val1, val2, ""); -// } -// } else { -// if (type_entry->data.integral.is_signed) { -// return LLVMBuildSDiv(g->builder, val1, val2, ""); -// } else { -// return LLVMBuildUDiv(g->builder, val1, val2, ""); -// } -// } -//} diff --git a/src/ir_print.cpp b/src/ir_print.cpp index dc20ac3ed..b51adaf7d 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -359,6 +359,9 @@ static void ir_print_elem_ptr(IrPrint *irp, IrInstructionElemPtr *instruction) { fprintf(irp->f, "["); ir_print_other_instruction(irp, instruction->elem_index); fprintf(irp->f, "]"); + if (!instruction->safety_check_on) { + fprintf(irp->f, " // no safety"); + } } static void ir_print_var_ptr(IrPrint *irp, IrInstructionVarPtr *instruction) {