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
404404@shlWithOverflow(inline T: type, a: T, b: T, result: &T) -> bool *x = a << b
405405```
406406
407### @memset(dest, c: u8, byte_count: usize)
407### @memset(dest: &T, c: u8, byte_count: usize)
408408
409409This 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
412412level code will not use this function, instead using something like this:
413413
414414```zig
415// assume dest is a slice
416for (dest) |*b| *b = c;
415for (destSlice) |*b| *b = c;
417416```
418417
419### @memcpy(dest, source, byte_count: usize)
418### @memcpy(noalias dest: &T, noalias source: &const T, byte_count: usize)
420419
421420This function copies bytes from one region of memory to another. `dest` and
422421`source` are both pointers and must not overlap.
......@@ -426,8 +425,7 @@ level code will not use this function, instead using something like this:
426425
427426```zig
428427const mem = @import("std").mem;
429// assume dest and source are slices
430mem.copy(dest, source);
428mem.copy(destSlice, sourceSlice);
431429```
432430
433431### @breakpoint()
src/all_types.hpp-2
......@@ -870,7 +870,6 @@ uint32_t generic_fn_type_id_hash(GenericFnTypeId *id);
870870bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b);
871871
872872
873static const size_t fn_type_id_prealloc_param_info_count = 4;
874873struct FnTypeId {
875874 TypeTableEntry *return_type;
876875 FnTypeParamInfo *param_info;
......@@ -879,7 +878,6 @@ struct FnTypeId {
879878 bool is_naked;
880879 bool is_cold;
881880 bool is_extern;
882 FnTypeParamInfo prealloc_param_info[fn_type_id_prealloc_param_info_count];
883881};
884882
885883uint32_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
682682 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
683683 fn_type->deep_const = true;
684684 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
689686 if (fn_type_id->is_cold) {
690687 fn_type->data.fn.calling_convention = LLVMColdCallConv;
......@@ -915,12 +912,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
915912 fn_type_id.is_naked = is_naked;
916913 fn_type_id.is_cold = is_cold;
917914 fn_type_id.param_count = fn_proto->params.length;
918
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 }
915 fn_type_id.param_info = allocate_nonzero<FnTypeParamInfo>(fn_type_id.param_count);
924916
925917 fn_type_id.is_var_args = fn_proto->is_var_args;
926918 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
14831483}
14841484
14851485static 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, "");
14871488 LLVMValueRef subscript_value = ir_llvm_value(g, instruction->elem_index);
14881489 TypeTableEntry *array_type = instruction->array_ptr->type_entry;
14891490 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) {
32653266 }
32663267}
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
32813269void codegen_generate_h_file(CodeGen *g) {
32823270 assert(!g->is_test_build);
32833271
......@@ -3303,25 +3291,27 @@ void codegen_generate_h_file(CodeGen *g) {
33033291 if (fn_proto->top_level_decl.visib_mod != VisibModExport)
33043292 continue;
33053293
3294 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;
33063295 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
33093298 buf_appendf(&h_buf, "%s %s %s(",
33103299 buf_ptr(export_macro),
33113300 buf_ptr(&return_type_c),
3312 buf_ptr(fn_proto->name));
3301 buf_ptr(&fn_table_entry->symbol_name));
33133302
33143303 Buf param_type_c = BUF_INIT;
3315 if (fn_proto->params.length) {
3316 for (size_t param_i = 0; param_i < fn_proto->params.length; param_i += 1) {
3304 if (fn_type_id->param_count > 0) {
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];
33173307 AstNode *param_decl_node = fn_proto->params.at(param_i);
3318 AstNode *param_type = param_decl_node->data.param_decl.type;
3319 get_c_type_node(g, param_type, &param_type_c);
3320 buf_appendf(&h_buf, "%s %s",
3321 buf_ptr(&param_type_c),
3322 buf_ptr(param_decl_node->data.param_decl.name));
3323 if (param_i < fn_proto->params.length - 1)
3324 buf_appendf(&h_buf, ", ");
3308 Buf *param_name = param_decl_node->data.param_decl.name;
3309
3310 const char *comma_str = (param_i == 0) ? "" : ", ";
3311 const char *restrict_str = param_info->is_noalias ? "restrict" : "";
3312 get_c_type(g, param_info->type, &param_type_c);
3313 buf_appendf(&h_buf, "%s%s%s %s", comma_str, buf_ptr(&param_type_c),
3314 restrict_str, buf_ptr(param_name));
33253315 }
33263316 buf_appendf(&h_buf, ")");
33273317 } else {
src/ir.cpp+6-2
......@@ -36,6 +36,7 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont
3636static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction);
3737
3838ConstExprValue *const_ptr_pointee(ConstExprValue *const_val) {
39 assert(const_val->special == ConstValSpecialStatic);
3940 ConstExprValue *base_ptr = const_val->data.x_ptr.base_ptr;
4041 size_t index = const_val->data.x_ptr.index;
4142
......@@ -3620,7 +3621,6 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
36203621 assert(ptr_type->id == TypeTableEntryIdPointer);
36213622
36223623 TypeTableEntry *array_type = ptr_type->data.pointer.child_type;
3623 ConstExprValue *array_ptr_val = const_ptr_pointee(&array_ptr->static_value);
36243624 TypeTableEntry *return_type;
36253625
36263626 if (array_type->id == TypeTableEntryIdInvalid) {
......@@ -3659,7 +3659,11 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
36593659 }
36603660 }
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 {
36633667 bool depends_on_compile_var = array_ptr_val->depends_on_compile_var ||
36643668 casted_elem_index->static_value.depends_on_compile_var;
36653669 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
602602 }
603603 }
604604
605 if (fn_type_id.param_count > fn_type_id_prealloc_param_info_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
605 fn_type_id.param_info = allocate_nonzero<FnTypeParamInfo>(fn_type_id.param_count);
611606 for (size_t i = 0; i < fn_type_id.param_count; i += 1) {
612607 QualType qt = fn_proto_ty->getParamType(i);
613608 TypeTableEntry *param_type = resolve_qual_type(c, qt, decl);
std/builtin.zig+6-6
......@@ -1,24 +1,24 @@
11// These functions are provided when not linking against libc because LLVM
22// sometimes generates code that calls them.
33
4// TODO dest should be nullable and return value should be nullable
45export fn memset(dest: &u8, c: u8, n: usize) -> &u8 {
56 @setDebugSafety(this, false);
67
78 var index: usize = 0;
8 while (index != n) {
9 while (index != n; index += 1)
910 dest[index] = c;
10 index += 1;
11 }
11
1212 return dest;
1313}
1414
15// TODO dest, source, and return value should be nullable
1516export fn memcpy(noalias dest: &u8, noalias src: &const u8, n: usize) -> &u8 {
1617 @setDebugSafety(this, false);
1718
1819 var index: usize = 0;
19 while (index != n) {
20 while (index != n; index += 1)
2021 dest[index] = src[index];
21 index += 1;
22 }
22
2323 return dest;
2424}