authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-18 22:24:41-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-18 22:24:41-05:00
logd94cb0566be6463594f0904aa759de9e52585842
tree470044a3b58fbeee7e270617da76fca54b3a6f0f
parentbf7cde62c52b370f953db2cd6167a156771d8343

IR: correctly codegening memset and memcpy


7 files changed, 33 insertions(+), 56 deletions(-)

doc/langref.md+4-6
...@@ -404,7 +404,7 @@ Function Operation...@@ -404,7 +404,7 @@ Function Operation
404@shlWithOverflow(inline T: type, a: T, b: T, result: &T) -> bool *x = a << b404@shlWithOverflow(inline T: type, a: T, b: T, result: &T) -> bool *x = a << b
405```405```
406406
407### @memset(dest, c: u8, byte_count: usize)407### @memset(dest: &T, c: u8, byte_count: usize)
408408
409This function sets a region of memory to `c`. `dest` is a pointer.409This function sets a region of memory to `c`. `dest` is a pointer.
410410
...@@ -412,11 +412,10 @@ This function is a low level intrinsic with no safety mechanisms. Most higher...@@ -412,11 +412,10 @@ This function is a low level intrinsic with no safety mechanisms. Most higher
412level code will not use this function, instead using something like this:412level code will not use this function, instead using something like this:
413413
414```zig414```zig
415// assume dest is a slice415for (destSlice) |*b| *b = c;
416for (dest) |*b| *b = c;
417```416```
418417
419### @memcpy(dest, source, byte_count: usize)418### @memcpy(noalias dest: &T, noalias source: &const T, byte_count: usize)
420419
421This function copies bytes from one region of memory to another. `dest` and420This function copies bytes from one region of memory to another. `dest` and
422`source` are both pointers and must not overlap.421`source` are both pointers and must not overlap.
...@@ -426,8 +425,7 @@ level code will not use this function, instead using something like this:...@@ -426,8 +425,7 @@ level code will not use this function, instead using something like this:
426425
427```zig426```zig
428const mem = @import("std").mem;427const mem = @import("std").mem;
429// assume dest and source are slices428mem.copy(destSlice, sourceSlice);
430mem.copy(dest, source);
431```429```
432430
433### @breakpoint()431### @breakpoint()
src/all_types.hpp-2
...@@ -870,7 +870,6 @@ uint32_t generic_fn_type_id_hash(GenericFnTypeId *id);...@@ -870,7 +870,6 @@ uint32_t generic_fn_type_id_hash(GenericFnTypeId *id);
870bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b);870bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b);
871871
872872
873static const size_t fn_type_id_prealloc_param_info_count = 4;
874struct FnTypeId {873struct FnTypeId {
875 TypeTableEntry *return_type;874 TypeTableEntry *return_type;
876 FnTypeParamInfo *param_info;875 FnTypeParamInfo *param_info;
...@@ -879,7 +878,6 @@ struct FnTypeId {...@@ -879,7 +878,6 @@ struct FnTypeId {
879 bool is_naked;878 bool is_naked;
880 bool is_cold;879 bool is_cold;
881 bool is_extern;880 bool is_extern;
882 FnTypeParamInfo prealloc_param_info[fn_type_id_prealloc_param_info_count];
883};881};
884882
885uint32_t fn_type_id_hash(FnTypeId*);883uint32_t fn_type_id_hash(FnTypeId*);
src/analyze.cpp+1-9
...@@ -682,9 +682,6 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id, bool gen_debug_inf...@@ -682,9 +682,6 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id, bool gen_debug_inf
682 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);682 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
683 fn_type->deep_const = true;683 fn_type->deep_const = true;
684 fn_type->data.fn.fn_type_id = *fn_type_id;684 fn_type->data.fn.fn_type_id = *fn_type_id;
685 if (fn_type_id->param_info == &fn_type_id->prealloc_param_info[0]) {
686 fn_type->data.fn.fn_type_id.param_info = &fn_type->data.fn.fn_type_id.prealloc_param_info[0];
687 }
688685
689 if (fn_type_id->is_cold) {686 if (fn_type_id->is_cold) {
690 fn_type->data.fn.calling_convention = LLVMColdCallConv;687 fn_type->data.fn.calling_convention = LLVMColdCallConv;
...@@ -915,12 +912,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor...@@ -915,12 +912,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
915 fn_type_id.is_naked = is_naked;912 fn_type_id.is_naked = is_naked;
916 fn_type_id.is_cold = is_cold;913 fn_type_id.is_cold = is_cold;
917 fn_type_id.param_count = fn_proto->params.length;914 fn_type_id.param_count = fn_proto->params.length;
918915 fn_type_id.param_info = allocate_nonzero<FnTypeParamInfo>(fn_type_id.param_count);
919 if (fn_type_id.param_count > fn_type_id_prealloc_param_info_count) {
920 fn_type_id.param_info = allocate_nonzero<FnTypeParamInfo>(fn_type_id.param_count);
921 } else {
922 fn_type_id.param_info = &fn_type_id.prealloc_param_info[0];
923 }
924916
925 fn_type_id.is_var_args = fn_proto->is_var_args;917 fn_type_id.is_var_args = fn_proto->is_var_args;
926 fn_type_id.return_type = analyze_type_expr(g, import, context, fn_proto->return_type);918 fn_type_id.return_type = analyze_type_expr(g, import, context, fn_proto->return_type);
src/codegen.cpp+15-25
...@@ -1483,7 +1483,8 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn...@@ -1483,7 +1483,8 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn
1483}1483}
14841484
1485static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrInstructionElemPtr *instruction) {1485static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrInstructionElemPtr *instruction) {
1486 LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array_ptr);1486 LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->array_ptr);
1487 LLVMValueRef array_ptr = LLVMBuildLoad(g->builder, array_ptr_ptr, "");
1487 LLVMValueRef subscript_value = ir_llvm_value(g, instruction->elem_index);1488 LLVMValueRef subscript_value = ir_llvm_value(g, instruction->elem_index);
1488 TypeTableEntry *array_type = instruction->array_ptr->type_entry;1489 TypeTableEntry *array_type = instruction->array_ptr->type_entry;
1489 return gen_array_elem_ptr(g, instruction->base.source_node, array_ptr, array_type, subscript_value);1490 return gen_array_elem_ptr(g, instruction->base.source_node, array_ptr, array_type, subscript_value);
...@@ -3265,19 +3266,6 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {...@@ -3265,19 +3266,6 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {
3265 }3266 }
3266}3267}
32673268
3268static void get_c_type_node(CodeGen *g, AstNode *type_node, Buf *out_buf) {
3269 Expr *expr = get_resolved_expr(type_node);
3270 assert(expr->instruction->type_entry);
3271 assert(expr->instruction->type_entry->id == TypeTableEntryIdMetaType);
3272
3273 ConstExprValue *const_val = &expr->instruction->static_value;
3274 assert(const_val->special != ConstValSpecialRuntime);
3275
3276 TypeTableEntry *type_entry = const_val->data.x_type;
3277
3278 return get_c_type(g, type_entry, out_buf);
3279}
3280
3281void codegen_generate_h_file(CodeGen *g) {3269void codegen_generate_h_file(CodeGen *g) {
3282 assert(!g->is_test_build);3270 assert(!g->is_test_build);
32833271
...@@ -3303,25 +3291,27 @@ void codegen_generate_h_file(CodeGen *g) {...@@ -3303,25 +3291,27 @@ void codegen_generate_h_file(CodeGen *g) {
3303 if (fn_proto->top_level_decl.visib_mod != VisibModExport)3291 if (fn_proto->top_level_decl.visib_mod != VisibModExport)
3304 continue;3292 continue;
33053293
3294 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;
3306 Buf return_type_c = BUF_INIT;3295 Buf return_type_c = BUF_INIT;
3307 get_c_type(g, fn_table_entry->type_entry->data.fn.fn_type_id.return_type, &return_type_c);3296 get_c_type(g, fn_type_id->return_type, &return_type_c);
33083297
3309 buf_appendf(&h_buf, "%s %s %s(",3298 buf_appendf(&h_buf, "%s %s %s(",
3310 buf_ptr(export_macro),3299 buf_ptr(export_macro),
3311 buf_ptr(&return_type_c),3300 buf_ptr(&return_type_c),
3312 buf_ptr(fn_proto->name));3301 buf_ptr(&fn_table_entry->symbol_name));
33133302
3314 Buf param_type_c = BUF_INIT;3303 Buf param_type_c = BUF_INIT;
3315 if (fn_proto->params.length) {3304 if (fn_type_id->param_count > 0) {
3316 for (size_t param_i = 0; param_i < fn_proto->params.length; param_i += 1) {3305 for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
3306 FnTypeParamInfo *param_info = &fn_type_id->param_info[param_i];
3317 AstNode *param_decl_node = fn_proto->params.at(param_i);3307 AstNode *param_decl_node = fn_proto->params.at(param_i);
3318 AstNode *param_type = param_decl_node->data.param_decl.type;3308 Buf *param_name = param_decl_node->data.param_decl.name;
3319 get_c_type_node(g, param_type, &param_type_c);3309
3320 buf_appendf(&h_buf, "%s %s",3310 const char *comma_str = (param_i == 0) ? "" : ", ";
3321 buf_ptr(&param_type_c),3311 const char *restrict_str = param_info->is_noalias ? "restrict" : "";
3322 buf_ptr(param_decl_node->data.param_decl.name));3312 get_c_type(g, param_info->type, &param_type_c);
3323 if (param_i < fn_proto->params.length - 1)3313 buf_appendf(&h_buf, "%s%s%s %s", comma_str, buf_ptr(&param_type_c),
3324 buf_appendf(&h_buf, ", ");3314 restrict_str, buf_ptr(param_name));
3325 }3315 }
3326 buf_appendf(&h_buf, ")");3316 buf_appendf(&h_buf, ")");
3327 } else {3317 } else {
src/ir.cpp+6-2
...@@ -36,6 +36,7 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont...@@ -36,6 +36,7 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont
36static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction);36static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction);
3737
38ConstExprValue *const_ptr_pointee(ConstExprValue *const_val) {38ConstExprValue *const_ptr_pointee(ConstExprValue *const_val) {
39 assert(const_val->special == ConstValSpecialStatic);
39 ConstExprValue *base_ptr = const_val->data.x_ptr.base_ptr;40 ConstExprValue *base_ptr = const_val->data.x_ptr.base_ptr;
40 size_t index = const_val->data.x_ptr.index;41 size_t index = const_val->data.x_ptr.index;
4142
...@@ -3620,7 +3621,6 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc...@@ -3620,7 +3621,6 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
3620 assert(ptr_type->id == TypeTableEntryIdPointer);3621 assert(ptr_type->id == TypeTableEntryIdPointer);
36213622
3622 TypeTableEntry *array_type = ptr_type->data.pointer.child_type;3623 TypeTableEntry *array_type = ptr_type->data.pointer.child_type;
3623 ConstExprValue *array_ptr_val = const_ptr_pointee(&array_ptr->static_value);
3624 TypeTableEntry *return_type;3624 TypeTableEntry *return_type;
36253625
3626 if (array_type->id == TypeTableEntryIdInvalid) {3626 if (array_type->id == TypeTableEntryIdInvalid) {
...@@ -3659,7 +3659,11 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc...@@ -3659,7 +3659,11 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
3659 }3659 }
3660 }3660 }
36613661
3662 if (array_ptr_val->special != ConstValSpecialRuntime) {3662 ConstExprValue *array_ptr_val;
3663 if (array_ptr->static_value.special != ConstValSpecialRuntime &&
3664 (array_ptr_val = const_ptr_pointee(&array_ptr->static_value)) &&
3665 array_ptr_val->special != ConstValSpecialRuntime)
3666 {
3663 bool depends_on_compile_var = array_ptr_val->depends_on_compile_var ||3667 bool depends_on_compile_var = array_ptr_val->depends_on_compile_var ||
3664 casted_elem_index->static_value.depends_on_compile_var;3668 casted_elem_index->static_value.depends_on_compile_var;
3665 ConstExprValue *out_val = ir_build_const_from(ira, &elem_ptr_instruction->base, depends_on_compile_var);3669 ConstExprValue *out_val = ir_build_const_from(ira, &elem_ptr_instruction->base, depends_on_compile_var);
src/parseh.cpp+1-6
...@@ -602,12 +602,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const...@@ -602,12 +602,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const
602 }602 }
603 }603 }
604604
605 if (fn_type_id.param_count > fn_type_id_prealloc_param_info_count) {605 fn_type_id.param_info = allocate_nonzero<FnTypeParamInfo>(fn_type_id.param_count);
606 fn_type_id.param_info = allocate_nonzero<FnTypeParamInfo>(fn_type_id.param_count);
607 } else {
608 fn_type_id.param_info = &fn_type_id.prealloc_param_info[0];
609 }
610
611 for (size_t i = 0; i < fn_type_id.param_count; i += 1) {606 for (size_t i = 0; i < fn_type_id.param_count; i += 1) {
612 QualType qt = fn_proto_ty->getParamType(i);607 QualType qt = fn_proto_ty->getParamType(i);
613 TypeTableEntry *param_type = resolve_qual_type(c, qt, decl);608 TypeTableEntry *param_type = resolve_qual_type(c, qt, decl);
std/builtin.zig+6-6
...@@ -1,24 +1,24 @@...@@ -1,24 +1,24 @@
1// These functions are provided when not linking against libc because LLVM1// These functions are provided when not linking against libc because LLVM
2// sometimes generates code that calls them.2// sometimes generates code that calls them.
33
4// TODO dest should be nullable and return value should be nullable
4export fn memset(dest: &u8, c: u8, n: usize) -> &u8 {5export fn memset(dest: &u8, c: u8, n: usize) -> &u8 {
5 @setDebugSafety(this, false);6 @setDebugSafety(this, false);
67
7 var index: usize = 0;8 var index: usize = 0;
8 while (index != n) {9 while (index != n; index += 1)
9 dest[index] = c;10 dest[index] = c;
10 index += 1;11
11 }
12 return dest;12 return dest;
13}13}
1414
15// TODO dest, source, and return value should be nullable
15export fn memcpy(noalias dest: &u8, noalias src: &const u8, n: usize) -> &u8 {16export fn memcpy(noalias dest: &u8, noalias src: &const u8, n: usize) -> &u8 {
16 @setDebugSafety(this, false);17 @setDebugSafety(this, false);
1718
18 var index: usize = 0;19 var index: usize = 0;
19 while (index != n) {20 while (index != n; index += 1)
20 dest[index] = src[index];21 dest[index] = src[index];
21 index += 1;22
22 }
23 return dest;23 return dest;
24}24}