IR: fix codegen for arrays

master
Andrew Kelley 2016-11-21 15:01:21 -05:00
parent e80e8a8099
commit 052cd44588
4 changed files with 252 additions and 228 deletions

View File

@ -1626,6 +1626,7 @@ struct IrInstructionElemPtr {
IrInstruction *array_ptr;
IrInstruction *elem_index;
bool is_const;
bool safety_check_on;
};
struct IrInstructionVarPtr {

View File

@ -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, "");
}

View File

@ -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, "");
// }
// }
//}

View File

@ -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) {