Commit 052cd44588
Changed files (4)
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 {
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, "");
}
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<IrInstructionElemPtr>(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, "");
-// }
-// }
-//}
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) {