diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2016-12-12 00:31:35 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2016-12-12 00:31:35 -0500 |
| commit | ef63bc9cca6370f03d76a2a19dd7cdd7e23270d4 (patch) | |
| tree | fca2d675e920c9809d7a7b3d9ed858e44589d286 /src | |
| parent | fb2157063060682a314cb8f2e34efc7989646455 (diff) | |
| download | zig-ef63bc9cca6370f03d76a2a19dd7cdd7e23270d4.tar.gz zig-ef63bc9cca6370f03d76a2a19dd7cdd7e23270d4.zip | |
IR: implement memcpy, memset, and slice expression
Diffstat (limited to 'src')
| -rw-r--r-- | src/all_types.hpp | 29 | ||||
| -rw-r--r-- | src/ast_render.cpp | 14 | ||||
| -rw-r--r-- | src/codegen.cpp | 156 | ||||
| -rw-r--r-- | src/ir.cpp | 757 | ||||
| -rw-r--r-- | src/ir_print.cpp | 41 |
5 files changed, 695 insertions, 302 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp index b6bb24fdb2..cecb6d4f5c 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1415,6 +1415,9 @@ enum IrInstructionId { IrInstructionIdIntType, IrInstructionIdBoolNot, IrInstructionIdAlloca, + IrInstructionIdMemset, + IrInstructionIdMemcpy, + IrInstructionIdSlice, }; struct IrInstruction { @@ -1924,6 +1927,32 @@ struct IrInstructionAlloca { LLVMValueRef tmp_ptr; }; +struct IrInstructionMemset { + IrInstruction base; + + IrInstruction *dest_ptr; + IrInstruction *byte; + IrInstruction *count; +}; + +struct IrInstructionMemcpy { + IrInstruction base; + + IrInstruction *dest_ptr; + IrInstruction *src_ptr; + IrInstruction *count; +}; + +struct IrInstructionSlice { + IrInstruction base; + + IrInstruction *ptr; + IrInstruction *start; + IrInstruction *end; + bool is_const; + LLVMValueRef tmp_ptr; +}; + enum LValPurpose { LValPurposeNone, LValPurposeAssign, diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 929aa17c6f..013408b4b7 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -849,11 +849,23 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { fprintf(ar->f, "%scontinue", inline_str); break; } + case NodeTypeSliceExpr: + { + render_node_ungrouped(ar, node->data.slice_expr.array_ref_expr); + fprintf(ar->f, "["); + render_node_grouped(ar, node->data.slice_expr.start); + fprintf(ar->f, "..."); + if (node->data.slice_expr.end) + render_node_grouped(ar, node->data.slice_expr.end); + fprintf(ar->f, "]"); + if (node->data.slice_expr.is_const) + fprintf(ar->f, "const"); + break; + } case NodeTypeFnDecl: case NodeTypeParamDecl: case NodeTypeErrorValueDecl: case NodeTypeUnwrapErrorExpr: - case NodeTypeSliceExpr: case NodeTypeStructField: case NodeTypeUse: case NodeTypeZeroesLiteral: diff --git a/src/codegen.cpp b/src/codegen.cpp index ae259f0573..37d83c3dfc 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1906,6 +1906,153 @@ static LLVMValueRef ir_render_alloca(CodeGen *g, IrExecutable *executable, IrIns return instruction->tmp_ptr; } +static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutable *executable, IrInstructionMemset *instruction) { + LLVMValueRef dest_ptr = ir_llvm_value(g, instruction->dest_ptr); + LLVMValueRef char_val = ir_llvm_value(g, instruction->byte); + LLVMValueRef len_val = ir_llvm_value(g, instruction->count); + + LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); + + LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, ""); + + LLVMValueRef params[] = { + dest_ptr_casted, // dest pointer + char_val, // source pointer + len_val, // byte count + LLVMConstInt(LLVMInt32Type(), 1, false), // align in bytes + LLVMConstNull(LLVMInt1Type()), // is volatile + }; + + LLVMBuildCall(g->builder, g->memset_fn_val, params, 5, ""); + return nullptr; +} + +static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutable *executable, IrInstructionMemcpy *instruction) { + LLVMValueRef dest_ptr = ir_llvm_value(g, instruction->dest_ptr); + LLVMValueRef src_ptr = ir_llvm_value(g, instruction->src_ptr); + LLVMValueRef len_val = ir_llvm_value(g, instruction->count); + + LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); + + LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, ""); + LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr, ptr_u8, ""); + + LLVMValueRef params[] = { + dest_ptr_casted, // dest pointer + src_ptr_casted, // source pointer + len_val, // byte count + LLVMConstInt(LLVMInt32Type(), 1, false), // align in bytes + LLVMConstNull(LLVMInt1Type()), // is volatile + }; + + LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, ""); + return nullptr; +} + +static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInstructionSlice *instruction) { + TypeTableEntry *array_type = get_underlying_type(instruction->ptr->type_entry); + + LLVMValueRef tmp_struct_ptr = instruction->tmp_ptr; + LLVMValueRef array_ptr = ir_llvm_value(g, instruction->ptr); + + bool want_debug_safety = ir_want_debug_safety(g, &instruction->base); + + if (array_type->id == TypeTableEntryIdArray) { + LLVMValueRef start_val = ir_llvm_value(g, instruction->start); + LLVMValueRef end_val; + if (instruction->end) { + end_val = ir_llvm_value(g, instruction->end); + } else { + end_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, array_type->data.array.len, false); + } + + if (want_debug_safety) { + add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); + if (instruction->end) { + LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->type_ref, + array_type->data.array.len, false); + add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end); + } + } + + LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, ""); + LLVMValueRef indices[] = { + LLVMConstNull(g->builtin_types.entry_usize->type_ref), + start_val, + }; + LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); + LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr); + + LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); + LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); + LLVMBuildStore(g->builder, len_value, len_field_ptr); + + return tmp_struct_ptr; + } else if (array_type->id == TypeTableEntryIdPointer) { + LLVMValueRef start_val = ir_llvm_value(g, instruction->start); + LLVMValueRef end_val = ir_llvm_value(g, instruction->end); + + if (want_debug_safety) { + add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); + } + + LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, ""); + LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, ""); + LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr); + + LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); + LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); + LLVMBuildStore(g->builder, len_value, len_field_ptr); + + return tmp_struct_ptr; + } 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); + + size_t ptr_index = array_type->data.structure.fields[0].gen_index; + assert(ptr_index != SIZE_MAX); + size_t len_index = array_type->data.structure.fields[1].gen_index; + assert(len_index != SIZE_MAX); + + LLVMValueRef prev_end = nullptr; + if (!instruction->end || want_debug_safety) { + LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, len_index, ""); + prev_end = LLVMBuildLoad(g->builder, src_len_ptr, ""); + } + + LLVMValueRef start_val = ir_llvm_value(g, instruction->start); + LLVMValueRef end_val; + if (instruction->end) { + end_val = ir_llvm_value(g, instruction->end); + } else { + end_val = prev_end; + } + + if (want_debug_safety) { + assert(prev_end); + add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); + if (instruction->end) { + add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, prev_end); + } + } + + LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, ptr_index, ""); + LLVMValueRef src_ptr = LLVMBuildLoad(g->builder, src_ptr_ptr, ""); + LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, ptr_index, ""); + LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, len_index, ""); + LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr); + + LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, len_index, ""); + LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); + LLVMBuildStore(g->builder, len_value, len_field_ptr); + + return tmp_struct_ptr; + } else { + zig_unreachable(); + } +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -2008,6 +2155,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_bool_not(g, executable, (IrInstructionBoolNot *)instruction); case IrInstructionIdAlloca: return ir_render_alloca(g, executable, (IrInstructionAlloca *)instruction); + case IrInstructionIdMemset: + return ir_render_memset(g, executable, (IrInstructionMemset *)instruction); + case IrInstructionIdMemcpy: + return ir_render_memcpy(g, executable, (IrInstructionMemcpy *)instruction); + case IrInstructionIdSlice: + return ir_render_slice(g, executable, (IrInstructionSlice *)instruction); case IrInstructionIdSwitchVar: case IrInstructionIdContainerInitList: case IrInstructionIdStructInit: @@ -2590,6 +2743,9 @@ static void do_code_gen(CodeGen *g) { } else if (instruction->id == IrInstructionIdAlloca) { IrInstructionAlloca *alloca_instruction = (IrInstructionAlloca *)instruction; slot = &alloca_instruction->tmp_ptr; + } else if (instruction->id == IrInstructionIdSlice) { + IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction; + slot = &slice_instruction->tmp_ptr; } else { zig_unreachable(); } diff --git a/src/ir.cpp b/src/ir.cpp index 6c1712d704..c74ba0ce47 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -375,6 +375,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAlloca *) { return IrInstructionIdAlloca; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionMemset *) { + return IrInstructionIdMemset; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionMemcpy *) { + return IrInstructionIdMemcpy; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionSlice *) { + return IrInstructionIdSlice; +} + template<typename T> static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { T *special_instruction = allocate<T>(1); @@ -1514,6 +1526,76 @@ static IrInstruction *ir_build_alloca_from(IrBuilder *irb, IrInstruction *old_in return new_instruction; } +static IrInstruction *ir_build_memset(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *dest_ptr, IrInstruction *byte, IrInstruction *count) +{ + IrInstructionMemset *instruction = ir_build_instruction<IrInstructionMemset>(irb, scope, source_node); + instruction->dest_ptr = dest_ptr; + instruction->byte = byte; + instruction->count = count; + + ir_ref_instruction(dest_ptr); + ir_ref_instruction(byte); + ir_ref_instruction(count); + + return &instruction->base; +} + +static IrInstruction *ir_build_memset_from(IrBuilder *irb, IrInstruction *old_instruction, + IrInstruction *dest_ptr, IrInstruction *byte, IrInstruction *count) +{ + IrInstruction *new_instruction = ir_build_memset(irb, old_instruction->scope, old_instruction->source_node, dest_ptr, byte, count); + ir_link_new_instruction(new_instruction, old_instruction); + return new_instruction; +} + +static IrInstruction *ir_build_memcpy(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *dest_ptr, IrInstruction *src_ptr, IrInstruction *count) +{ + IrInstructionMemcpy *instruction = ir_build_instruction<IrInstructionMemcpy>(irb, scope, source_node); + instruction->dest_ptr = dest_ptr; + instruction->src_ptr = src_ptr; + instruction->count = count; + + ir_ref_instruction(dest_ptr); + ir_ref_instruction(src_ptr); + ir_ref_instruction(count); + + return &instruction->base; +} + +static IrInstruction *ir_build_memcpy_from(IrBuilder *irb, IrInstruction *old_instruction, + IrInstruction *dest_ptr, IrInstruction *src_ptr, IrInstruction *count) +{ + IrInstruction *new_instruction = ir_build_memcpy(irb, old_instruction->scope, old_instruction->source_node, dest_ptr, src_ptr, count); + ir_link_new_instruction(new_instruction, old_instruction); + return new_instruction; +} + +static IrInstruction *ir_build_slice(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool is_const) +{ + IrInstructionSlice *instruction = ir_build_instruction<IrInstructionSlice>(irb, scope, source_node); + instruction->ptr = ptr; + instruction->start = start; + instruction->end = end; + instruction->is_const = is_const; + + ir_ref_instruction(ptr); + ir_ref_instruction(start); + if (end) ir_ref_instruction(end); + + return &instruction->base; +} + +static IrInstruction *ir_build_slice_from(IrBuilder *irb, IrInstruction *old_instruction, + IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool is_const) +{ + IrInstruction *new_instruction = ir_build_slice(irb, old_instruction->scope, old_instruction->source_node, ptr, start, end, is_const); + ir_link_new_instruction(new_instruction, old_instruction); + return new_instruction; +} + static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, bool gen_error_defers, bool gen_maybe_defers) { @@ -2350,7 +2432,43 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return ir_build_alloca(irb, scope, node, arg0_value, arg1_value); } case BuiltinFnIdMemcpy: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_instruction) + return arg1_value; + + AstNode *arg2_node = node->data.fn_call_expr.params.at(2); + IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope); + if (arg2_value == irb->codegen->invalid_instruction) + return arg2_value; + + return ir_build_memcpy(irb, scope, node, arg0_value, arg1_value, arg2_value); + } case BuiltinFnIdMemset: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_instruction) + return arg1_value; + + AstNode *arg2_node = node->data.fn_call_expr.params.at(2); + IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope); + if (arg2_value == irb->codegen->invalid_instruction) + return arg2_value; + + return ir_build_memset(irb, scope, node, arg0_value, arg1_value, arg2_value); + } case BuiltinFnIdAlignof: case BuiltinFnIdMemberCount: case BuiltinFnIdAddWithOverflow: @@ -3252,12 +3370,45 @@ static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode return ir_build_const_void(irb, parent_scope, node); } +static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeSliceExpr); + + AstNodeSliceExpr *slice_expr = &node->data.slice_expr; + AstNode *array_node = slice_expr->array_ref_expr; + AstNode *start_node = slice_expr->start; + AstNode *end_node = slice_expr->end; + + IrInstruction *ptr_value = ir_gen_node(irb, array_node, scope); + if (ptr_value == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; + + IrInstruction *start_value = ir_gen_node(irb, start_node, scope); + if (ptr_value == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; + + IrInstruction *end_value; + if (end_node) { + end_value = ir_gen_node(irb, end_node, scope); + if (end_value == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; + } else { + end_value = nullptr; + } + + return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, slice_expr->is_const); +} + static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, LValPurpose lval) { assert(scope); switch (node->type) { case NodeTypeStructValueField: + case NodeTypeRoot: + case NodeTypeParamDecl: + case NodeTypeUse: + case NodeTypeSwitchProng: + case NodeTypeSwitchRange: zig_unreachable(); case NodeTypeBlock: return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node), lval); @@ -3319,21 +3470,17 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_lval_wrap(irb, scope, ir_gen_continue(irb, scope, node), lval); case NodeTypeDefer: return ir_lval_wrap(irb, scope, ir_gen_defer(irb, scope, node), lval); - case NodeTypeUnwrapErrorExpr: case NodeTypeSliceExpr: + return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval); + case NodeTypeUnwrapErrorExpr: case NodeTypeCharLiteral: case NodeTypeZeroesLiteral: case NodeTypeVarLiteral: - case NodeTypeRoot: case NodeTypeFnProto: case NodeTypeFnDef: case NodeTypeFnDecl: - case NodeTypeParamDecl: - case NodeTypeUse: case NodeTypeContainerDecl: case NodeTypeStructField: - case NodeTypeSwitchProng: - case NodeTypeSwitchRange: case NodeTypeErrorValueDecl: case NodeTypeTypeDecl: zig_panic("TODO more IR gen for node types"); @@ -4304,17 +4451,11 @@ static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_inst } TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, value->type_entry, true); - if (handle_is_ptr(value->type_entry)) { - // this instruction is a noop - codegen can pass the pointer we already have as the result - ir_link_new_instruction(value, source_instruction); - return ptr_type; - } else { - FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); - assert(fn_entry); - IrInstruction *new_instruction = ir_build_ref_from(&ira->new_irb, source_instruction, value); - fn_entry->alloca_list.append(new_instruction); - return ptr_type; - } + FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); + assert(fn_entry); + IrInstruction *new_instruction = ir_build_ref_from(&ira->new_irb, source_instruction, value); + fn_entry->alloca_list.append(new_instruction); + return ptr_type; } @@ -7978,6 +8119,295 @@ static TypeTableEntry *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructi zig_unreachable(); } +static TypeTableEntry *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructionMemset *instruction) { + IrInstruction *dest_ptr = instruction->dest_ptr->other; + if (dest_ptr->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *byte_value = instruction->byte->other; + if (byte_value->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *count_value = instruction->count->other; + if (count_value->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize; + TypeTableEntry *u8 = ira->codegen->builtin_types.entry_u8; + TypeTableEntry *u8_ptr = get_pointer_to_type(ira->codegen, u8, false); + + IrInstruction *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr); + if (casted_dest_ptr->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *casted_byte = ir_implicit_cast(ira, byte_value, u8); + if (casted_byte->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *casted_count = ir_implicit_cast(ira, count_value, usize); + if (casted_count->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + if (casted_dest_ptr->static_value.special == ConstValSpecialStatic && + casted_byte->static_value.special == ConstValSpecialStatic && + casted_count->static_value.special == ConstValSpecialStatic) + { + ConstExprValue *dest_ptr_val = &casted_dest_ptr->static_value; + + ConstExprValue *dest_elements; + size_t start; + size_t bound_end; + if (dest_ptr_val->data.x_ptr.index == SIZE_MAX) { + dest_elements = dest_ptr_val->data.x_ptr.base_ptr; + start = 0; + bound_end = 1; + } else { + ConstExprValue *array_val = dest_ptr_val->data.x_ptr.base_ptr; + dest_elements = array_val->data.x_array.elements; + start = dest_ptr_val->data.x_ptr.index; + bound_end = array_val->data.x_array.size; + } + + size_t count = casted_count->static_value.data.x_bignum.data.x_uint; + size_t end = start + count; + if (end > bound_end) { + ir_add_error(ira, count_value, buf_sprintf("out of bounds pointer access")); + return ira->codegen->builtin_types.entry_invalid; + } + + ConstExprValue *byte_val = &casted_byte->static_value; + for (size_t i = start; i < end; i += 1) { + dest_elements[i] = *byte_val; + } + + ir_build_const_from(ira, &instruction->base, false); + return ira->codegen->builtin_types.entry_void; + } + + ir_build_memset_from(&ira->new_irb, &instruction->base, casted_dest_ptr, casted_byte, casted_count); + return ira->codegen->builtin_types.entry_void; +} + +static TypeTableEntry *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructionMemcpy *instruction) { + IrInstruction *dest_ptr = instruction->dest_ptr->other; + if (dest_ptr->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *src_ptr = instruction->src_ptr->other; + if (src_ptr->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *count_value = instruction->count->other; + if (count_value->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize; + TypeTableEntry *u8 = ira->codegen->builtin_types.entry_u8; + TypeTableEntry *u8_ptr_mut = get_pointer_to_type(ira->codegen, u8, false); + TypeTableEntry *u8_ptr_const = get_pointer_to_type(ira->codegen, u8, true); + + IrInstruction *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr_mut); + if (casted_dest_ptr->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *casted_src_ptr = ir_implicit_cast(ira, src_ptr, u8_ptr_const); + if (casted_src_ptr->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *casted_count = ir_implicit_cast(ira, count_value, usize); + if (casted_count->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + if (casted_dest_ptr->static_value.special == ConstValSpecialStatic && + casted_src_ptr->static_value.special == ConstValSpecialStatic && + casted_count->static_value.special == ConstValSpecialStatic) + { + size_t count = casted_count->static_value.data.x_bignum.data.x_uint; + + ConstExprValue *dest_ptr_val = &casted_dest_ptr->static_value; + ConstExprValue *dest_elements; + size_t dest_start; + size_t dest_end; + if (dest_ptr_val->data.x_ptr.index == SIZE_MAX) { + dest_elements = dest_ptr_val->data.x_ptr.base_ptr; + dest_start = 0; + dest_end = 1; + } else { + ConstExprValue *array_val = dest_ptr_val->data.x_ptr.base_ptr; + dest_elements = array_val->data.x_array.elements; + dest_start = dest_ptr_val->data.x_ptr.index; + dest_end = array_val->data.x_array.size; + } + + if (dest_start + count > dest_end) { + ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access")); + return ira->codegen->builtin_types.entry_invalid; + } + + ConstExprValue *src_ptr_val = &casted_src_ptr->static_value; + ConstExprValue *src_elements; + size_t src_start; + size_t src_end; + if (src_ptr_val->data.x_ptr.index == SIZE_MAX) { + src_elements = src_ptr_val->data.x_ptr.base_ptr; + src_start = 0; + src_end = 1; + } else { + ConstExprValue *array_val = src_ptr_val->data.x_ptr.base_ptr; + src_elements = array_val->data.x_array.elements; + src_start = src_ptr_val->data.x_ptr.index; + src_end = array_val->data.x_array.size; + } + + if (src_start + count > src_end) { + ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access")); + return ira->codegen->builtin_types.entry_invalid; + } + + // TODO check for noalias violations - this should be generalized to work for any function + + for (size_t i = 0; i < count; i += 1) { + dest_elements[dest_start + i] = src_elements[src_start + i]; + } + + ir_build_const_from(ira, &instruction->base, false); + return ira->codegen->builtin_types.entry_void; + } + + ir_build_memcpy_from(&ira->new_irb, &instruction->base, casted_dest_ptr, casted_src_ptr, casted_count); + return ira->codegen->builtin_types.entry_void; +} + +static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructionSlice *instruction) { + IrInstruction *ptr = instruction->ptr->other; + if (ptr->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *start = instruction->start->other; + if (start->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize; + IrInstruction *casted_start = ir_implicit_cast(ira, start, usize); + if (casted_start->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *end; + if (instruction->end) { + end = instruction->end->other; + if (end->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + end = ir_implicit_cast(ira, end, usize); + if (end->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + } else { + end = nullptr; + } + + TypeTableEntry *array_type = get_underlying_type(ptr->type_entry); + + TypeTableEntry *return_type; + + if (array_type->id == TypeTableEntryIdArray) { + return_type = get_slice_type(ira->codegen, array_type->data.array.child_type, instruction->is_const); + } else if (array_type->id == TypeTableEntryIdPointer) { + return_type = get_slice_type(ira->codegen, array_type->data.pointer.child_type, instruction->is_const); + if (!end) { + ir_add_error(ira, &instruction->base, buf_sprintf("slice of pointer must include end value")); + return ira->codegen->builtin_types.entry_invalid; + } + } else if (is_slice(array_type)) { + return_type = get_slice_type(ira->codegen, + array_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type, + instruction->is_const); + } else { + ir_add_error(ira, &instruction->base, + buf_sprintf("slice of non-array type '%s'", buf_ptr(&ptr->type_entry->name))); + // TODO if this is a typedecl, add error note showing the declaration of the type decl + return ira->codegen->builtin_types.entry_invalid; + } + + if (ptr->static_value.special == ConstValSpecialStatic && + casted_start->static_value.special == ConstValSpecialStatic && + (!end || end->static_value.special == ConstValSpecialStatic)) + { + bool depends_on_compile_var = + ptr->static_value.depends_on_compile_var || + casted_start->static_value.depends_on_compile_var || + (end ? end->static_value.depends_on_compile_var : false); + + ConstExprValue *base_ptr; + size_t abs_offset; + size_t rel_end; + if (array_type->id == TypeTableEntryIdArray) { + base_ptr = &ptr->static_value; + abs_offset = 0; + rel_end = array_type->data.array.len; + } else if (array_type->id == TypeTableEntryIdPointer) { + base_ptr = ptr->static_value.data.x_ptr.base_ptr; + abs_offset = ptr->static_value.data.x_ptr.index; + if (abs_offset == SIZE_MAX) { + rel_end = 1; + } else { + rel_end = base_ptr->data.x_array.size - abs_offset; + } + } else if (is_slice(array_type)) { + ConstExprValue *ptr_val = &ptr->static_value.data.x_struct.fields[slice_ptr_index]; + ConstExprValue *len_val = &ptr->static_value.data.x_struct.fields[slice_len_index]; + base_ptr = ptr_val->data.x_ptr.base_ptr; + abs_offset = ptr_val->data.x_ptr.index; + + if (ptr_val->data.x_ptr.index == SIZE_MAX) { + rel_end = 1; + } else { + rel_end = len_val->data.x_bignum.data.x_uint; + } + } else { + zig_unreachable(); + } + + uint64_t start_scalar = casted_start->static_value.data.x_bignum.data.x_uint; + if (start_scalar > rel_end) { + ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice")); + return ira->codegen->builtin_types.entry_invalid; + } + + uint64_t end_scalar; + if (end) { + end_scalar = end->static_value.data.x_bignum.data.x_uint; + } else { + end_scalar = rel_end; + } + if (end_scalar > rel_end) { + ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice")); + return ira->codegen->builtin_types.entry_invalid; + } + if (start_scalar > end_scalar) { + ir_add_error(ira, &instruction->base, buf_sprintf("slice start is greater than end")); + return ira->codegen->builtin_types.entry_invalid; + } + + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var); + out_val->data.x_struct.fields = allocate<ConstExprValue>(2); + + ConstExprValue *ptr_val = &out_val->data.x_struct.fields[slice_ptr_index]; + ptr_val->special = ConstValSpecialStatic; + ptr_val->data.x_ptr.base_ptr = base_ptr; + ptr_val->data.x_ptr.index = (abs_offset != SIZE_MAX) ? (abs_offset + start_scalar) : SIZE_MAX; + + ConstExprValue *len_val = &out_val->data.x_struct.fields[slice_len_index]; + len_val->special = ConstValSpecialStatic; + bignum_init_unsigned(&len_val->data.x_bignum, rel_end); + + return return_type; + } + + IrInstruction *new_instruction = ir_build_slice_from(&ira->new_irb, &instruction->base, ptr, casted_start, end, instruction->is_const); + ir_add_alloca(ira, new_instruction, return_type); + + return return_type; +} + static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -8094,6 +8524,12 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction); case IrInstructionIdAlloca: return ir_analyze_instruction_alloca(ira, (IrInstructionAlloca *)instruction); + case IrInstructionIdMemset: + return ir_analyze_instruction_memset(ira, (IrInstructionMemset *)instruction); + case IrInstructionIdMemcpy: + return ir_analyze_instruction_memcpy(ira, (IrInstructionMemcpy *)instruction); + case IrInstructionIdSlice: + return ir_analyze_instruction_slice(ira, (IrInstructionSlice *)instruction); case IrInstructionIdCast: case IrInstructionIdStructFieldPtr: case IrInstructionIdEnumFieldPtr: @@ -8195,6 +8631,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCUndef: case IrInstructionIdCmpxchg: case IrInstructionIdFence: + case IrInstructionIdMemset: + case IrInstructionIdMemcpy: return true; case IrInstructionIdPhi: case IrInstructionIdUnOp: @@ -8236,6 +8674,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdIntType: case IrInstructionIdBoolNot: case IrInstructionIdAlloca: + case IrInstructionIdSlice: return false; case IrInstructionIdAsm: { @@ -8281,62 +8720,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { // // return g->builtin_types.entry_bool; // } -// case BuiltinFnIdMemcpy: -// { -// AstNode *dest_node = node->data.fn_call_expr.params.at(0); -// AstNode *src_node = node->data.fn_call_expr.params.at(1); -// AstNode *len_node = node->data.fn_call_expr.params.at(2); -// TypeTableEntry *dest_type = analyze_expression(g, import, context, nullptr, dest_node); -// TypeTableEntry *src_type = analyze_expression(g, import, context, nullptr, src_node); -// analyze_expression(g, import, context, builtin_fn->param_types[2], len_node); -// -// if (dest_type->id != TypeTableEntryIdInvalid && -// dest_type->id != TypeTableEntryIdPointer) -// { -// add_node_error(g, dest_node, -// buf_sprintf("expected pointer argument, found '%s'", buf_ptr(&dest_type->name))); -// } -// -// if (src_type->id != TypeTableEntryIdInvalid && -// src_type->id != TypeTableEntryIdPointer) -// { -// add_node_error(g, src_node, -// buf_sprintf("expected pointer argument, found '%s'", buf_ptr(&src_type->name))); -// } -// -// if (dest_type->id == TypeTableEntryIdPointer && -// src_type->id == TypeTableEntryIdPointer) -// { -// uint64_t dest_align = get_memcpy_align(g, dest_type->data.pointer.child_type); -// uint64_t src_align = get_memcpy_align(g, src_type->data.pointer.child_type); -// if (dest_align != src_align) { -// add_node_error(g, dest_node, buf_sprintf( -// "misaligned memcpy, '%s' has alignment '%" PRIu64 ", '%s' has alignment %" PRIu64, -// buf_ptr(&dest_type->name), dest_align, -// buf_ptr(&src_type->name), src_align)); -// } -// } -// -// return builtin_fn->return_type; -// } -// case BuiltinFnIdMemset: -// { -// AstNode *dest_node = node->data.fn_call_expr.params.at(0); -// AstNode *char_node = node->data.fn_call_expr.params.at(1); -// AstNode *len_node = node->data.fn_call_expr.params.at(2); -// TypeTableEntry *dest_type = analyze_expression(g, import, context, nullptr, dest_node); -// analyze_expression(g, import, context, builtin_fn->param_types[1], char_node); -// analyze_expression(g, import, context, builtin_fn->param_types[2], len_node); -// -// if (dest_type->id != TypeTableEntryIdInvalid && -// dest_type->id != TypeTableEntryIdPointer) -// { -// add_node_error(g, dest_node, -// buf_sprintf("expected pointer argument, found '%s'", buf_ptr(&dest_type->name))); -// } -// -// return builtin_fn->return_type; -// } // case BuiltinFnIdAlignof: // { // AstNode *type_node = node->data.fn_call_expr.params.at(0); @@ -8455,51 +8838,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { // } // zig_unreachable(); //} -//static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, -// AstNode *node) -//{ -// assert(node->type == NodeTypeSliceExpr); -// -// TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr, -// node->data.slice_expr.array_ref_expr); -// -// TypeTableEntry *return_type; -// -// if (array_type->id == TypeTableEntryIdInvalid) { -// return_type = g->builtin_types.entry_invalid; -// } else if (array_type->id == TypeTableEntryIdArray) { -// return_type = get_slice_type(g, array_type->data.array.child_type, -// node->data.slice_expr.is_const); -// } else if (array_type->id == TypeTableEntryIdPointer) { -// return_type = get_slice_type(g, array_type->data.pointer.child_type, -// node->data.slice_expr.is_const); -// } else if (array_type->id == TypeTableEntryIdStruct && -// array_type->data.structure.is_slice) -// { -// return_type = get_slice_type(g, -// array_type->data.structure.fields[0].type_entry->data.pointer.child_type, -// node->data.slice_expr.is_const); -// } else { -// add_node_error(g, node, -// buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name))); -// return_type = g->builtin_types.entry_invalid; -// } -// -// if (return_type->id != TypeTableEntryIdInvalid) { -// node->data.slice_expr.resolved_struct_val_expr.type_entry = return_type; -// node->data.slice_expr.resolved_struct_val_expr.source_node = node; -// context->fn_entry->struct_val_expr_alloca_list.append(&node->data.slice_expr.resolved_struct_val_expr); -// } -// -// analyze_expression(g, import, context, g->builtin_types.entry_usize, node->data.slice_expr.start); -// -// if (node->data.slice_expr.end) { -// analyze_expression(g, import, context, g->builtin_types.entry_usize, node->data.slice_expr.end); -// } -// -// return return_type; -//} -// //static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, // AstNode *node, LValPurpose purpose) //{ @@ -8656,65 +8994,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { // } // case BuiltinFnIdShlWithOverflow: // return gen_shl_with_overflow(g, node); -// case BuiltinFnIdMemcpy: -// { -// size_t fn_call_param_count = node->data.fn_call_expr.params.length; -// assert(fn_call_param_count == 3); -// -// AstNode *dest_node = node->data.fn_call_expr.params.at(0); -// TypeTableEntry *dest_type = get_expr_type(dest_node); -// -// LLVMValueRef dest_ptr = gen_expr(g, dest_node); -// LLVMValueRef src_ptr = gen_expr(g, node->data.fn_call_expr.params.at(1)); -// LLVMValueRef len_val = gen_expr(g, node->data.fn_call_expr.params.at(2)); -// -// LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); -// -// LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, ""); -// LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr, ptr_u8, ""); -// -// uint64_t align_in_bytes = get_memcpy_align(g, dest_type->data.pointer.child_type); -// -// LLVMValueRef params[] = { -// dest_ptr_casted, // dest pointer -// src_ptr_casted, // source pointer -// len_val, // byte count -// LLVMConstInt(LLVMInt32Type(), align_in_bytes, false), // align in bytes -// LLVMConstNull(LLVMInt1Type()), // is volatile -// }; -// -// LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, ""); -// return nullptr; -// } -// case BuiltinFnIdMemset: -// { -// size_t fn_call_param_count = node->data.fn_call_expr.params.length; -// assert(fn_call_param_count == 3); -// -// AstNode *dest_node = node->data.fn_call_expr.params.at(0); -// TypeTableEntry *dest_type = get_expr_type(dest_node); -// -// LLVMValueRef dest_ptr = gen_expr(g, dest_node); -// LLVMValueRef char_val = gen_expr(g, node->data.fn_call_expr.params.at(1)); -// LLVMValueRef len_val = gen_expr(g, node->data.fn_call_expr.params.at(2)); -// -// LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); -// -// LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, ""); -// -// uint64_t align_in_bytes = get_memcpy_align(g, dest_type->data.pointer.child_type); -// -// LLVMValueRef params[] = { -// dest_ptr_casted, // dest pointer -// char_val, // source pointer -// len_val, // byte count -// LLVMConstInt(LLVMInt32Type(), align_in_bytes, false), // align in bytes -// LLVMConstNull(LLVMInt1Type()), // is volatile -// }; -// -// LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, ""); -// return nullptr; -// } // case BuiltinFnIdAlignof: // case BuiltinFnIdMinValue: // case BuiltinFnIdMaxValue: @@ -8789,25 +9068,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { // } //} // -//static LLVMValueRef gen_array_base_ptr(CodeGen *g, AstNode *node) { -// TypeTableEntry *type_entry = get_expr_type(node); -// -// LLVMValueRef array_ptr; -// if (node->type == NodeTypeFieldAccessExpr) { -// array_ptr = gen_field_access_expr(g, node, true); -// if (type_entry->id == TypeTableEntryIdPointer) { -// // we have a double pointer so we must dereference it once -// array_ptr = LLVMBuildLoad(g->builder, array_ptr, ""); -// } -// } else { -// array_ptr = gen_expr(g, node); -// } -// -// assert(!array_ptr || LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); -// -// return array_ptr; -//} -// //static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) { // assert(node->type == NodeTypeArrayAccessExpr); // @@ -8820,111 +9080,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { // return gen_array_elem_ptr(g, node, array_ptr, array_type, subscript_value); //} // -//static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) { -// assert(node->type == NodeTypeSliceExpr); -// -// AstNode *array_ref_node = node->data.slice_expr.array_ref_expr; -// TypeTableEntry *array_type = get_expr_type(array_ref_node); -// -// LLVMValueRef tmp_struct_ptr = node->data.slice_expr.resolved_struct_val_expr.ptr; -// LLVMValueRef array_ptr = gen_array_base_ptr(g, array_ref_node); -// -// if (array_type->id == TypeTableEntryIdArray) { -// LLVMValueRef start_val = gen_expr(g, node->data.slice_expr.start); -// LLVMValueRef end_val; -// if (node->data.slice_expr.end) { -// end_val = gen_expr(g, node->data.slice_expr.end); -// } else { -// end_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, array_type->data.array.len, false); -// } -// -// if (want_debug_safety(g, node)) { -// add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); -// if (node->data.slice_expr.end) { -// LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->type_ref, -// array_type->data.array.len, false); -// add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end); -// } -// } -// -// LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, ""); -// LLVMValueRef indices[] = { -// LLVMConstNull(g->builtin_types.entry_usize->type_ref), -// start_val, -// }; -// LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); -// LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr); -// -// LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, ""); -// LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); -// LLVMBuildStore(g->builder, len_value, len_field_ptr); -// -// return tmp_struct_ptr; -// } else if (array_type->id == TypeTableEntryIdPointer) { -// LLVMValueRef start_val = gen_expr(g, node->data.slice_expr.start); -// LLVMValueRef end_val = gen_expr(g, node->data.slice_expr.end); -// -// if (want_debug_safety(g, node)) { -// add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); -// } -// -// LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, ""); -// LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, ""); -// LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr); -// -// LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, ""); -// LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); -// LLVMBuildStore(g->builder, len_value, len_field_ptr); -// -// return tmp_struct_ptr; -// } 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); -// -// size_t ptr_index = array_type->data.structure.fields[0].gen_index; -// assert(ptr_index != SIZE_MAX); -// size_t len_index = array_type->data.structure.fields[1].gen_index; -// assert(len_index != SIZE_MAX); -// -// LLVMValueRef prev_end = nullptr; -// if (!node->data.slice_expr.end || want_debug_safety(g, node)) { -// LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, len_index, ""); -// prev_end = LLVMBuildLoad(g->builder, src_len_ptr, ""); -// } -// -// LLVMValueRef start_val = gen_expr(g, node->data.slice_expr.start); -// LLVMValueRef end_val; -// if (node->data.slice_expr.end) { -// end_val = gen_expr(g, node->data.slice_expr.end); -// } else { -// end_val = prev_end; -// } -// -// if (want_debug_safety(g, node)) { -// assert(prev_end); -// add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); -// if (node->data.slice_expr.end) { -// add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, prev_end); -// } -// } -// -// LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, ptr_index, ""); -// LLVMValueRef src_ptr = LLVMBuildLoad(g->builder, src_ptr_ptr, ""); -// LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, ptr_index, ""); -// LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, len_index, ""); -// LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr); -// -// LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, len_index, ""); -// LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); -// LLVMBuildStore(g->builder, len_value, len_field_ptr); -// -// return tmp_struct_ptr; -// } else { -// zig_unreachable(); -// } -//} -// //static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) { // assert(node->type == NodeTypeUnwrapErrorExpr); // diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 1adebca1fa..1c62dc13fd 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -774,6 +774,38 @@ static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) { ir_print_other_instruction(irp, instruction->value); } +static void ir_print_memset(IrPrint *irp, IrInstructionMemset *instruction) { + fprintf(irp->f, "@memset("); + ir_print_other_instruction(irp, instruction->dest_ptr); + fprintf(irp->f, ", "); + ir_print_other_instruction(irp, instruction->byte); + fprintf(irp->f, ", "); + ir_print_other_instruction(irp, instruction->count); + fprintf(irp->f, ")"); +} + +static void ir_print_memcpy(IrPrint *irp, IrInstructionMemcpy *instruction) { + fprintf(irp->f, "@memcpy("); + ir_print_other_instruction(irp, instruction->dest_ptr); + fprintf(irp->f, ", "); + ir_print_other_instruction(irp, instruction->src_ptr); + fprintf(irp->f, ", "); + ir_print_other_instruction(irp, instruction->count); + fprintf(irp->f, ")"); +} + +static void ir_print_slice(IrPrint *irp, IrInstructionSlice *instruction) { + ir_print_other_instruction(irp, instruction->ptr); + fprintf(irp->f, "["); + ir_print_other_instruction(irp, instruction->start); + fprintf(irp->f, "..."); + if (instruction->end) + ir_print_other_instruction(irp, instruction->end); + fprintf(irp->f, "]"); + if (instruction->is_const) + fprintf(irp->f, "const"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -959,6 +991,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdBoolNot: ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction); break; + case IrInstructionIdMemset: + ir_print_memset(irp, (IrInstructionMemset *)instruction); + break; + case IrInstructionIdMemcpy: + ir_print_memcpy(irp, (IrInstructionMemcpy *)instruction); + break; + case IrInstructionIdSlice: + ir_print_slice(irp, (IrInstructionSlice *)instruction); + break; } fprintf(irp->f, "\n"); } |
