authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-12 00:31:35-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-12 00:31:35-05:00
logef63bc9cca6370f03d76a2a19dd7cdd7e23270d4
treefca2d675e920c9809d7a7b3d9ed858e44589d286
parentfb2157063060682a314cb8f2e34efc7989646455

IR: implement memcpy, memset, and slice expression


7 files changed, 707 insertions(+), 305 deletions(-)

doc/langref.md+6-2
...@@ -417,7 +417,7 @@ Function Operation...@@ -417,7 +417,7 @@ Function Operation
417@shlWithOverflow(inline T: type, a: T, b: T, result: &T) -> bool *x = a << b417@shlWithOverflow(inline T: type, a: T, b: T, result: &T) -> bool *x = a << b
418```418```
419419
420### @memset(dest: &T, c: u8, byte_count: usize)420### @memset(dest: &u8, c: u8, byte_count: usize)
421421
422This function sets a region of memory to `c`. `dest` is a pointer.422This function sets a region of memory to `c`. `dest` is a pointer.
423423
...@@ -428,7 +428,9 @@ level code will not use this function, instead using something like this:...@@ -428,7 +428,9 @@ level code will not use this function, instead using something like this:
428for (destSlice) |*b| *b = c;428for (destSlice) |*b| *b = c;
429```429```
430430
431### @memcpy(noalias dest: &T, noalias source: &const T, byte_count: usize)431The optimizer is intelligent enough to turn the above snippet into a memset.
432
433### @memcpy(noalias dest: &u8, noalias source: &const u8, byte_count: usize)
432434
433This function copies bytes from one region of memory to another. `dest` and435This function copies bytes from one region of memory to another. `dest` and
434`source` are both pointers and must not overlap.436`source` are both pointers and must not overlap.
...@@ -441,6 +443,8 @@ const mem = @import("std").mem;...@@ -441,6 +443,8 @@ const mem = @import("std").mem;
441mem.copy(destSlice, sourceSlice);443mem.copy(destSlice, sourceSlice);
442```444```
443445
446The optimizer is intelligent enough to turn the above snippet into a memcpy.
447
444### @breakpoint()448### @breakpoint()
445449
446This function inserts a platform-specific debug trap instruction which causes450This function inserts a platform-specific debug trap instruction which causes
src/all_types.hpp+29
...@@ -1415,6 +1415,9 @@ enum IrInstructionId {...@@ -1415,6 +1415,9 @@ enum IrInstructionId {
1415 IrInstructionIdIntType,1415 IrInstructionIdIntType,
1416 IrInstructionIdBoolNot,1416 IrInstructionIdBoolNot,
1417 IrInstructionIdAlloca,1417 IrInstructionIdAlloca,
1418 IrInstructionIdMemset,
1419 IrInstructionIdMemcpy,
1420 IrInstructionIdSlice,
1418};1421};
14191422
1420struct IrInstruction {1423struct IrInstruction {
...@@ -1924,6 +1927,32 @@ struct IrInstructionAlloca {...@@ -1924,6 +1927,32 @@ struct IrInstructionAlloca {
1924 LLVMValueRef tmp_ptr;1927 LLVMValueRef tmp_ptr;
1925};1928};
19261929
1930struct IrInstructionMemset {
1931 IrInstruction base;
1932
1933 IrInstruction *dest_ptr;
1934 IrInstruction *byte;
1935 IrInstruction *count;
1936};
1937
1938struct IrInstructionMemcpy {
1939 IrInstruction base;
1940
1941 IrInstruction *dest_ptr;
1942 IrInstruction *src_ptr;
1943 IrInstruction *count;
1944};
1945
1946struct IrInstructionSlice {
1947 IrInstruction base;
1948
1949 IrInstruction *ptr;
1950 IrInstruction *start;
1951 IrInstruction *end;
1952 bool is_const;
1953 LLVMValueRef tmp_ptr;
1954};
1955
1927enum LValPurpose {1956enum LValPurpose {
1928 LValPurposeNone,1957 LValPurposeNone,
1929 LValPurposeAssign,1958 LValPurposeAssign,
src/ast_render.cpp+13-1
...@@ -849,11 +849,23 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -849,11 +849,23 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
849 fprintf(ar->f, "%scontinue", inline_str);849 fprintf(ar->f, "%scontinue", inline_str);
850 break;850 break;
851 }851 }
852 case NodeTypeSliceExpr:
853 {
854 render_node_ungrouped(ar, node->data.slice_expr.array_ref_expr);
855 fprintf(ar->f, "[");
856 render_node_grouped(ar, node->data.slice_expr.start);
857 fprintf(ar->f, "...");
858 if (node->data.slice_expr.end)
859 render_node_grouped(ar, node->data.slice_expr.end);
860 fprintf(ar->f, "]");
861 if (node->data.slice_expr.is_const)
862 fprintf(ar->f, "const");
863 break;
864 }
852 case NodeTypeFnDecl:865 case NodeTypeFnDecl:
853 case NodeTypeParamDecl:866 case NodeTypeParamDecl:
854 case NodeTypeErrorValueDecl:867 case NodeTypeErrorValueDecl:
855 case NodeTypeUnwrapErrorExpr:868 case NodeTypeUnwrapErrorExpr:
856 case NodeTypeSliceExpr:
857 case NodeTypeStructField:869 case NodeTypeStructField:
858 case NodeTypeUse:870 case NodeTypeUse:
859 case NodeTypeZeroesLiteral:871 case NodeTypeZeroesLiteral:
src/codegen.cpp+156
...@@ -1906,6 +1906,153 @@ static LLVMValueRef ir_render_alloca(CodeGen *g, IrExecutable *executable, IrIns...@@ -1906,6 +1906,153 @@ static LLVMValueRef ir_render_alloca(CodeGen *g, IrExecutable *executable, IrIns
1906 return instruction->tmp_ptr;1906 return instruction->tmp_ptr;
1907}1907}
19081908
1909static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutable *executable, IrInstructionMemset *instruction) {
1910 LLVMValueRef dest_ptr = ir_llvm_value(g, instruction->dest_ptr);
1911 LLVMValueRef char_val = ir_llvm_value(g, instruction->byte);
1912 LLVMValueRef len_val = ir_llvm_value(g, instruction->count);
1913
1914 LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
1915
1916 LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, "");
1917
1918 LLVMValueRef params[] = {
1919 dest_ptr_casted, // dest pointer
1920 char_val, // source pointer
1921 len_val, // byte count
1922 LLVMConstInt(LLVMInt32Type(), 1, false), // align in bytes
1923 LLVMConstNull(LLVMInt1Type()), // is volatile
1924 };
1925
1926 LLVMBuildCall(g->builder, g->memset_fn_val, params, 5, "");
1927 return nullptr;
1928}
1929
1930static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutable *executable, IrInstructionMemcpy *instruction) {
1931 LLVMValueRef dest_ptr = ir_llvm_value(g, instruction->dest_ptr);
1932 LLVMValueRef src_ptr = ir_llvm_value(g, instruction->src_ptr);
1933 LLVMValueRef len_val = ir_llvm_value(g, instruction->count);
1934
1935 LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
1936
1937 LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, "");
1938 LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr, ptr_u8, "");
1939
1940 LLVMValueRef params[] = {
1941 dest_ptr_casted, // dest pointer
1942 src_ptr_casted, // source pointer
1943 len_val, // byte count
1944 LLVMConstInt(LLVMInt32Type(), 1, false), // align in bytes
1945 LLVMConstNull(LLVMInt1Type()), // is volatile
1946 };
1947
1948 LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");
1949 return nullptr;
1950}
1951
1952static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInstructionSlice *instruction) {
1953 TypeTableEntry *array_type = get_underlying_type(instruction->ptr->type_entry);
1954
1955 LLVMValueRef tmp_struct_ptr = instruction->tmp_ptr;
1956 LLVMValueRef array_ptr = ir_llvm_value(g, instruction->ptr);
1957
1958 bool want_debug_safety = ir_want_debug_safety(g, &instruction->base);
1959
1960 if (array_type->id == TypeTableEntryIdArray) {
1961 LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
1962 LLVMValueRef end_val;
1963 if (instruction->end) {
1964 end_val = ir_llvm_value(g, instruction->end);
1965 } else {
1966 end_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, array_type->data.array.len, false);
1967 }
1968
1969 if (want_debug_safety) {
1970 add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
1971 if (instruction->end) {
1972 LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
1973 array_type->data.array.len, false);
1974 add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end);
1975 }
1976 }
1977
1978 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, "");
1979 LLVMValueRef indices[] = {
1980 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
1981 start_val,
1982 };
1983 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");
1984 LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr);
1985
1986 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, "");
1987 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
1988 LLVMBuildStore(g->builder, len_value, len_field_ptr);
1989
1990 return tmp_struct_ptr;
1991 } else if (array_type->id == TypeTableEntryIdPointer) {
1992 LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
1993 LLVMValueRef end_val = ir_llvm_value(g, instruction->end);
1994
1995 if (want_debug_safety) {
1996 add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
1997 }
1998
1999 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, "");
2000 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, "");
2001 LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr);
2002
2003 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, "");
2004 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
2005 LLVMBuildStore(g->builder, len_value, len_field_ptr);
2006
2007 return tmp_struct_ptr;
2008 } else if (array_type->id == TypeTableEntryIdStruct) {
2009 assert(array_type->data.structure.is_slice);
2010 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
2011 assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);
2012
2013 size_t ptr_index = array_type->data.structure.fields[0].gen_index;
2014 assert(ptr_index != SIZE_MAX);
2015 size_t len_index = array_type->data.structure.fields[1].gen_index;
2016 assert(len_index != SIZE_MAX);
2017
2018 LLVMValueRef prev_end = nullptr;
2019 if (!instruction->end || want_debug_safety) {
2020 LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, len_index, "");
2021 prev_end = LLVMBuildLoad(g->builder, src_len_ptr, "");
2022 }
2023
2024 LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
2025 LLVMValueRef end_val;
2026 if (instruction->end) {
2027 end_val = ir_llvm_value(g, instruction->end);
2028 } else {
2029 end_val = prev_end;
2030 }
2031
2032 if (want_debug_safety) {
2033 assert(prev_end);
2034 add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
2035 if (instruction->end) {
2036 add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, prev_end);
2037 }
2038 }
2039
2040 LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, ptr_index, "");
2041 LLVMValueRef src_ptr = LLVMBuildLoad(g->builder, src_ptr_ptr, "");
2042 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, ptr_index, "");
2043 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, len_index, "");
2044 LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr);
2045
2046 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, len_index, "");
2047 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
2048 LLVMBuildStore(g->builder, len_value, len_field_ptr);
2049
2050 return tmp_struct_ptr;
2051 } else {
2052 zig_unreachable();
2053 }
2054}
2055
1909static void set_debug_location(CodeGen *g, IrInstruction *instruction) {2056static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
1910 AstNode *source_node = instruction->source_node;2057 AstNode *source_node = instruction->source_node;
1911 Scope *scope = instruction->scope;2058 Scope *scope = instruction->scope;
...@@ -2008,6 +2155,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -2008,6 +2155,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
2008 return ir_render_bool_not(g, executable, (IrInstructionBoolNot *)instruction);2155 return ir_render_bool_not(g, executable, (IrInstructionBoolNot *)instruction);
2009 case IrInstructionIdAlloca:2156 case IrInstructionIdAlloca:
2010 return ir_render_alloca(g, executable, (IrInstructionAlloca *)instruction);2157 return ir_render_alloca(g, executable, (IrInstructionAlloca *)instruction);
2158 case IrInstructionIdMemset:
2159 return ir_render_memset(g, executable, (IrInstructionMemset *)instruction);
2160 case IrInstructionIdMemcpy:
2161 return ir_render_memcpy(g, executable, (IrInstructionMemcpy *)instruction);
2162 case IrInstructionIdSlice:
2163 return ir_render_slice(g, executable, (IrInstructionSlice *)instruction);
2011 case IrInstructionIdSwitchVar:2164 case IrInstructionIdSwitchVar:
2012 case IrInstructionIdContainerInitList:2165 case IrInstructionIdContainerInitList:
2013 case IrInstructionIdStructInit:2166 case IrInstructionIdStructInit:
...@@ -2590,6 +2743,9 @@ static void do_code_gen(CodeGen *g) {...@@ -2590,6 +2743,9 @@ static void do_code_gen(CodeGen *g) {
2590 } else if (instruction->id == IrInstructionIdAlloca) {2743 } else if (instruction->id == IrInstructionIdAlloca) {
2591 IrInstructionAlloca *alloca_instruction = (IrInstructionAlloca *)instruction;2744 IrInstructionAlloca *alloca_instruction = (IrInstructionAlloca *)instruction;
2592 slot = &alloca_instruction->tmp_ptr;2745 slot = &alloca_instruction->tmp_ptr;
2746 } else if (instruction->id == IrInstructionIdSlice) {
2747 IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction;
2748 slot = &slice_instruction->tmp_ptr;
2593 } else {2749 } else {
2594 zig_unreachable();2750 zig_unreachable();
2595 }2751 }
src/ir.cpp+456-301
...@@ -375,6 +375,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAlloca *) {...@@ -375,6 +375,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAlloca *) {
375 return IrInstructionIdAlloca;375 return IrInstructionIdAlloca;
376}376}
377377
378static constexpr IrInstructionId ir_instruction_id(IrInstructionMemset *) {
379 return IrInstructionIdMemset;
380}
381
382static constexpr IrInstructionId ir_instruction_id(IrInstructionMemcpy *) {
383 return IrInstructionIdMemcpy;
384}
385
386static constexpr IrInstructionId ir_instruction_id(IrInstructionSlice *) {
387 return IrInstructionIdSlice;
388}
389
378template<typename T>390template<typename T>
379static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {391static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
380 T *special_instruction = allocate<T>(1);392 T *special_instruction = allocate<T>(1);
...@@ -1514,6 +1526,76 @@ static IrInstruction *ir_build_alloca_from(IrBuilder *irb, IrInstruction *old_in...@@ -1514,6 +1526,76 @@ static IrInstruction *ir_build_alloca_from(IrBuilder *irb, IrInstruction *old_in
1514 return new_instruction;1526 return new_instruction;
1515}1527}
15161528
1529static IrInstruction *ir_build_memset(IrBuilder *irb, Scope *scope, AstNode *source_node,
1530 IrInstruction *dest_ptr, IrInstruction *byte, IrInstruction *count)
1531{
1532 IrInstructionMemset *instruction = ir_build_instruction<IrInstructionMemset>(irb, scope, source_node);
1533 instruction->dest_ptr = dest_ptr;
1534 instruction->byte = byte;
1535 instruction->count = count;
1536
1537 ir_ref_instruction(dest_ptr);
1538 ir_ref_instruction(byte);
1539 ir_ref_instruction(count);
1540
1541 return &instruction->base;
1542}
1543
1544static IrInstruction *ir_build_memset_from(IrBuilder *irb, IrInstruction *old_instruction,
1545 IrInstruction *dest_ptr, IrInstruction *byte, IrInstruction *count)
1546{
1547 IrInstruction *new_instruction = ir_build_memset(irb, old_instruction->scope, old_instruction->source_node, dest_ptr, byte, count);
1548 ir_link_new_instruction(new_instruction, old_instruction);
1549 return new_instruction;
1550}
1551
1552static IrInstruction *ir_build_memcpy(IrBuilder *irb, Scope *scope, AstNode *source_node,
1553 IrInstruction *dest_ptr, IrInstruction *src_ptr, IrInstruction *count)
1554{
1555 IrInstructionMemcpy *instruction = ir_build_instruction<IrInstructionMemcpy>(irb, scope, source_node);
1556 instruction->dest_ptr = dest_ptr;
1557 instruction->src_ptr = src_ptr;
1558 instruction->count = count;
1559
1560 ir_ref_instruction(dest_ptr);
1561 ir_ref_instruction(src_ptr);
1562 ir_ref_instruction(count);
1563
1564 return &instruction->base;
1565}
1566
1567static IrInstruction *ir_build_memcpy_from(IrBuilder *irb, IrInstruction *old_instruction,
1568 IrInstruction *dest_ptr, IrInstruction *src_ptr, IrInstruction *count)
1569{
1570 IrInstruction *new_instruction = ir_build_memcpy(irb, old_instruction->scope, old_instruction->source_node, dest_ptr, src_ptr, count);
1571 ir_link_new_instruction(new_instruction, old_instruction);
1572 return new_instruction;
1573}
1574
1575static IrInstruction *ir_build_slice(IrBuilder *irb, Scope *scope, AstNode *source_node,
1576 IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool is_const)
1577{
1578 IrInstructionSlice *instruction = ir_build_instruction<IrInstructionSlice>(irb, scope, source_node);
1579 instruction->ptr = ptr;
1580 instruction->start = start;
1581 instruction->end = end;
1582 instruction->is_const = is_const;
1583
1584 ir_ref_instruction(ptr);
1585 ir_ref_instruction(start);
1586 if (end) ir_ref_instruction(end);
1587
1588 return &instruction->base;
1589}
1590
1591static IrInstruction *ir_build_slice_from(IrBuilder *irb, IrInstruction *old_instruction,
1592 IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool is_const)
1593{
1594 IrInstruction *new_instruction = ir_build_slice(irb, old_instruction->scope, old_instruction->source_node, ptr, start, end, is_const);
1595 ir_link_new_instruction(new_instruction, old_instruction);
1596 return new_instruction;
1597}
1598
1517static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,1599static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,
1518 bool gen_error_defers, bool gen_maybe_defers)1600 bool gen_error_defers, bool gen_maybe_defers)
1519{1601{
...@@ -2350,7 +2432,43 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -2350,7 +2432,43 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
2350 return ir_build_alloca(irb, scope, node, arg0_value, arg1_value);2432 return ir_build_alloca(irb, scope, node, arg0_value, arg1_value);
2351 }2433 }
2352 case BuiltinFnIdMemcpy:2434 case BuiltinFnIdMemcpy:
2435 {
2436 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
2437 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
2438 if (arg0_value == irb->codegen->invalid_instruction)
2439 return arg0_value;
2440
2441 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
2442 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
2443 if (arg1_value == irb->codegen->invalid_instruction)
2444 return arg1_value;
2445
2446 AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
2447 IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
2448 if (arg2_value == irb->codegen->invalid_instruction)
2449 return arg2_value;
2450
2451 return ir_build_memcpy(irb, scope, node, arg0_value, arg1_value, arg2_value);
2452 }
2353 case BuiltinFnIdMemset:2453 case BuiltinFnIdMemset:
2454 {
2455 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
2456 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
2457 if (arg0_value == irb->codegen->invalid_instruction)
2458 return arg0_value;
2459
2460 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
2461 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
2462 if (arg1_value == irb->codegen->invalid_instruction)
2463 return arg1_value;
2464
2465 AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
2466 IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
2467 if (arg2_value == irb->codegen->invalid_instruction)
2468 return arg2_value;
2469
2470 return ir_build_memset(irb, scope, node, arg0_value, arg1_value, arg2_value);
2471 }
2354 case BuiltinFnIdAlignof:2472 case BuiltinFnIdAlignof:
2355 case BuiltinFnIdMemberCount:2473 case BuiltinFnIdMemberCount:
2356 case BuiltinFnIdAddWithOverflow:2474 case BuiltinFnIdAddWithOverflow:
...@@ -3252,12 +3370,45 @@ static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode...@@ -3252,12 +3370,45 @@ static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode
3252 return ir_build_const_void(irb, parent_scope, node);3370 return ir_build_const_void(irb, parent_scope, node);
3253}3371}
32543372
3373static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node) {
3374 assert(node->type == NodeTypeSliceExpr);
3375
3376 AstNodeSliceExpr *slice_expr = &node->data.slice_expr;
3377 AstNode *array_node = slice_expr->array_ref_expr;
3378 AstNode *start_node = slice_expr->start;
3379 AstNode *end_node = slice_expr->end;
3380
3381 IrInstruction *ptr_value = ir_gen_node(irb, array_node, scope);
3382 if (ptr_value == irb->codegen->invalid_instruction)
3383 return irb->codegen->invalid_instruction;
3384
3385 IrInstruction *start_value = ir_gen_node(irb, start_node, scope);
3386 if (ptr_value == irb->codegen->invalid_instruction)
3387 return irb->codegen->invalid_instruction;
3388
3389 IrInstruction *end_value;
3390 if (end_node) {
3391 end_value = ir_gen_node(irb, end_node, scope);
3392 if (end_value == irb->codegen->invalid_instruction)
3393 return irb->codegen->invalid_instruction;
3394 } else {
3395 end_value = nullptr;
3396 }
3397
3398 return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, slice_expr->is_const);
3399}
3400
3255static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,3401static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,
3256 LValPurpose lval)3402 LValPurpose lval)
3257{3403{
3258 assert(scope);3404 assert(scope);
3259 switch (node->type) {3405 switch (node->type) {
3260 case NodeTypeStructValueField:3406 case NodeTypeStructValueField:
3407 case NodeTypeRoot:
3408 case NodeTypeParamDecl:
3409 case NodeTypeUse:
3410 case NodeTypeSwitchProng:
3411 case NodeTypeSwitchRange:
3261 zig_unreachable();3412 zig_unreachable();
3262 case NodeTypeBlock:3413 case NodeTypeBlock:
3263 return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node), lval);3414 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...@@ -3319,21 +3470,17 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
3319 return ir_lval_wrap(irb, scope, ir_gen_continue(irb, scope, node), lval);3470 return ir_lval_wrap(irb, scope, ir_gen_continue(irb, scope, node), lval);
3320 case NodeTypeDefer:3471 case NodeTypeDefer:
3321 return ir_lval_wrap(irb, scope, ir_gen_defer(irb, scope, node), lval);3472 return ir_lval_wrap(irb, scope, ir_gen_defer(irb, scope, node), lval);
3322 case NodeTypeUnwrapErrorExpr:
3323 case NodeTypeSliceExpr:3473 case NodeTypeSliceExpr:
3474 return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval);
3475 case NodeTypeUnwrapErrorExpr:
3324 case NodeTypeCharLiteral:3476 case NodeTypeCharLiteral:
3325 case NodeTypeZeroesLiteral:3477 case NodeTypeZeroesLiteral:
3326 case NodeTypeVarLiteral:3478 case NodeTypeVarLiteral:
3327 case NodeTypeRoot:
3328 case NodeTypeFnProto:3479 case NodeTypeFnProto:
3329 case NodeTypeFnDef:3480 case NodeTypeFnDef:
3330 case NodeTypeFnDecl:3481 case NodeTypeFnDecl:
3331 case NodeTypeParamDecl:
3332 case NodeTypeUse:
3333 case NodeTypeContainerDecl:3482 case NodeTypeContainerDecl:
3334 case NodeTypeStructField:3483 case NodeTypeStructField:
3335 case NodeTypeSwitchProng:
3336 case NodeTypeSwitchRange:
3337 case NodeTypeErrorValueDecl:3484 case NodeTypeErrorValueDecl:
3338 case NodeTypeTypeDecl:3485 case NodeTypeTypeDecl:
3339 zig_panic("TODO more IR gen for node types");3486 zig_panic("TODO more IR gen for node types");
...@@ -4304,17 +4451,11 @@ static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_inst...@@ -4304,17 +4451,11 @@ static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_inst
4304 }4451 }
43054452
4306 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, value->type_entry, true);4453 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, value->type_entry, true);
4307 if (handle_is_ptr(value->type_entry)) {4454 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
4308 // this instruction is a noop - codegen can pass the pointer we already have as the result4455 assert(fn_entry);
4309 ir_link_new_instruction(value, source_instruction);4456 IrInstruction *new_instruction = ir_build_ref_from(&ira->new_irb, source_instruction, value);
4310 return ptr_type;4457 fn_entry->alloca_list.append(new_instruction);
4311 } else {4458 return ptr_type;
4312 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
4313 assert(fn_entry);
4314 IrInstruction *new_instruction = ir_build_ref_from(&ira->new_irb, source_instruction, value);
4315 fn_entry->alloca_list.append(new_instruction);
4316 return ptr_type;
4317 }
4318}4459}
43194460
43204461
...@@ -7978,6 +8119,295 @@ static TypeTableEntry *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructi...@@ -7978,6 +8119,295 @@ static TypeTableEntry *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructi
7978 zig_unreachable();8119 zig_unreachable();
7979}8120}
79808121
8122static TypeTableEntry *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructionMemset *instruction) {
8123 IrInstruction *dest_ptr = instruction->dest_ptr->other;
8124 if (dest_ptr->type_entry->id == TypeTableEntryIdInvalid)
8125 return ira->codegen->builtin_types.entry_invalid;
8126
8127 IrInstruction *byte_value = instruction->byte->other;
8128 if (byte_value->type_entry->id == TypeTableEntryIdInvalid)
8129 return ira->codegen->builtin_types.entry_invalid;
8130
8131 IrInstruction *count_value = instruction->count->other;
8132 if (count_value->type_entry->id == TypeTableEntryIdInvalid)
8133 return ira->codegen->builtin_types.entry_invalid;
8134
8135 TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
8136 TypeTableEntry *u8 = ira->codegen->builtin_types.entry_u8;
8137 TypeTableEntry *u8_ptr = get_pointer_to_type(ira->codegen, u8, false);
8138
8139 IrInstruction *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr);
8140 if (casted_dest_ptr->type_entry->id == TypeTableEntryIdInvalid)
8141 return ira->codegen->builtin_types.entry_invalid;
8142
8143 IrInstruction *casted_byte = ir_implicit_cast(ira, byte_value, u8);
8144 if (casted_byte->type_entry->id == TypeTableEntryIdInvalid)
8145 return ira->codegen->builtin_types.entry_invalid;
8146
8147 IrInstruction *casted_count = ir_implicit_cast(ira, count_value, usize);
8148 if (casted_count->type_entry->id == TypeTableEntryIdInvalid)
8149 return ira->codegen->builtin_types.entry_invalid;
8150
8151 if (casted_dest_ptr->static_value.special == ConstValSpecialStatic &&
8152 casted_byte->static_value.special == ConstValSpecialStatic &&
8153 casted_count->static_value.special == ConstValSpecialStatic)
8154 {
8155 ConstExprValue *dest_ptr_val = &casted_dest_ptr->static_value;
8156
8157 ConstExprValue *dest_elements;
8158 size_t start;
8159 size_t bound_end;
8160 if (dest_ptr_val->data.x_ptr.index == SIZE_MAX) {
8161 dest_elements = dest_ptr_val->data.x_ptr.base_ptr;
8162 start = 0;
8163 bound_end = 1;
8164 } else {
8165 ConstExprValue *array_val = dest_ptr_val->data.x_ptr.base_ptr;
8166 dest_elements = array_val->data.x_array.elements;
8167 start = dest_ptr_val->data.x_ptr.index;
8168 bound_end = array_val->data.x_array.size;
8169 }
8170
8171 size_t count = casted_count->static_value.data.x_bignum.data.x_uint;
8172 size_t end = start + count;
8173 if (end > bound_end) {
8174 ir_add_error(ira, count_value, buf_sprintf("out of bounds pointer access"));
8175 return ira->codegen->builtin_types.entry_invalid;
8176 }
8177
8178 ConstExprValue *byte_val = &casted_byte->static_value;
8179 for (size_t i = start; i < end; i += 1) {
8180 dest_elements[i] = *byte_val;
8181 }
8182
8183 ir_build_const_from(ira, &instruction->base, false);
8184 return ira->codegen->builtin_types.entry_void;
8185 }
8186
8187 ir_build_memset_from(&ira->new_irb, &instruction->base, casted_dest_ptr, casted_byte, casted_count);
8188 return ira->codegen->builtin_types.entry_void;
8189}
8190
8191static TypeTableEntry *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructionMemcpy *instruction) {
8192 IrInstruction *dest_ptr = instruction->dest_ptr->other;
8193 if (dest_ptr->type_entry->id == TypeTableEntryIdInvalid)
8194 return ira->codegen->builtin_types.entry_invalid;
8195
8196 IrInstruction *src_ptr = instruction->src_ptr->other;
8197 if (src_ptr->type_entry->id == TypeTableEntryIdInvalid)
8198 return ira->codegen->builtin_types.entry_invalid;
8199
8200 IrInstruction *count_value = instruction->count->other;
8201 if (count_value->type_entry->id == TypeTableEntryIdInvalid)
8202 return ira->codegen->builtin_types.entry_invalid;
8203
8204 TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
8205 TypeTableEntry *u8 = ira->codegen->builtin_types.entry_u8;
8206 TypeTableEntry *u8_ptr_mut = get_pointer_to_type(ira->codegen, u8, false);
8207 TypeTableEntry *u8_ptr_const = get_pointer_to_type(ira->codegen, u8, true);
8208
8209 IrInstruction *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr_mut);
8210 if (casted_dest_ptr->type_entry->id == TypeTableEntryIdInvalid)
8211 return ira->codegen->builtin_types.entry_invalid;
8212
8213 IrInstruction *casted_src_ptr = ir_implicit_cast(ira, src_ptr, u8_ptr_const);
8214 if (casted_src_ptr->type_entry->id == TypeTableEntryIdInvalid)
8215 return ira->codegen->builtin_types.entry_invalid;
8216
8217 IrInstruction *casted_count = ir_implicit_cast(ira, count_value, usize);
8218 if (casted_count->type_entry->id == TypeTableEntryIdInvalid)
8219 return ira->codegen->builtin_types.entry_invalid;
8220
8221 if (casted_dest_ptr->static_value.special == ConstValSpecialStatic &&
8222 casted_src_ptr->static_value.special == ConstValSpecialStatic &&
8223 casted_count->static_value.special == ConstValSpecialStatic)
8224 {
8225 size_t count = casted_count->static_value.data.x_bignum.data.x_uint;
8226
8227 ConstExprValue *dest_ptr_val = &casted_dest_ptr->static_value;
8228 ConstExprValue *dest_elements;
8229 size_t dest_start;
8230 size_t dest_end;
8231 if (dest_ptr_val->data.x_ptr.index == SIZE_MAX) {
8232 dest_elements = dest_ptr_val->data.x_ptr.base_ptr;
8233 dest_start = 0;
8234 dest_end = 1;
8235 } else {
8236 ConstExprValue *array_val = dest_ptr_val->data.x_ptr.base_ptr;
8237 dest_elements = array_val->data.x_array.elements;
8238 dest_start = dest_ptr_val->data.x_ptr.index;
8239 dest_end = array_val->data.x_array.size;
8240 }
8241
8242 if (dest_start + count > dest_end) {
8243 ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access"));
8244 return ira->codegen->builtin_types.entry_invalid;
8245 }
8246
8247 ConstExprValue *src_ptr_val = &casted_src_ptr->static_value;
8248 ConstExprValue *src_elements;
8249 size_t src_start;
8250 size_t src_end;
8251 if (src_ptr_val->data.x_ptr.index == SIZE_MAX) {
8252 src_elements = src_ptr_val->data.x_ptr.base_ptr;
8253 src_start = 0;
8254 src_end = 1;
8255 } else {
8256 ConstExprValue *array_val = src_ptr_val->data.x_ptr.base_ptr;
8257 src_elements = array_val->data.x_array.elements;
8258 src_start = src_ptr_val->data.x_ptr.index;
8259 src_end = array_val->data.x_array.size;
8260 }
8261
8262 if (src_start + count > src_end) {
8263 ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access"));
8264 return ira->codegen->builtin_types.entry_invalid;
8265 }
8266
8267 // TODO check for noalias violations - this should be generalized to work for any function
8268
8269 for (size_t i = 0; i < count; i += 1) {
8270 dest_elements[dest_start + i] = src_elements[src_start + i];
8271 }
8272
8273 ir_build_const_from(ira, &instruction->base, false);
8274 return ira->codegen->builtin_types.entry_void;
8275 }
8276
8277 ir_build_memcpy_from(&ira->new_irb, &instruction->base, casted_dest_ptr, casted_src_ptr, casted_count);
8278 return ira->codegen->builtin_types.entry_void;
8279}
8280
8281static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructionSlice *instruction) {
8282 IrInstruction *ptr = instruction->ptr->other;
8283 if (ptr->type_entry->id == TypeTableEntryIdInvalid)
8284 return ira->codegen->builtin_types.entry_invalid;
8285
8286 IrInstruction *start = instruction->start->other;
8287 if (start->type_entry->id == TypeTableEntryIdInvalid)
8288 return ira->codegen->builtin_types.entry_invalid;
8289
8290 TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
8291 IrInstruction *casted_start = ir_implicit_cast(ira, start, usize);
8292 if (casted_start->type_entry->id == TypeTableEntryIdInvalid)
8293 return ira->codegen->builtin_types.entry_invalid;
8294
8295 IrInstruction *end;
8296 if (instruction->end) {
8297 end = instruction->end->other;
8298 if (end->type_entry->id == TypeTableEntryIdInvalid)
8299 return ira->codegen->builtin_types.entry_invalid;
8300 end = ir_implicit_cast(ira, end, usize);
8301 if (end->type_entry->id == TypeTableEntryIdInvalid)
8302 return ira->codegen->builtin_types.entry_invalid;
8303 } else {
8304 end = nullptr;
8305 }
8306
8307 TypeTableEntry *array_type = get_underlying_type(ptr->type_entry);
8308
8309 TypeTableEntry *return_type;
8310
8311 if (array_type->id == TypeTableEntryIdArray) {
8312 return_type = get_slice_type(ira->codegen, array_type->data.array.child_type, instruction->is_const);
8313 } else if (array_type->id == TypeTableEntryIdPointer) {
8314 return_type = get_slice_type(ira->codegen, array_type->data.pointer.child_type, instruction->is_const);
8315 if (!end) {
8316 ir_add_error(ira, &instruction->base, buf_sprintf("slice of pointer must include end value"));
8317 return ira->codegen->builtin_types.entry_invalid;
8318 }
8319 } else if (is_slice(array_type)) {
8320 return_type = get_slice_type(ira->codegen,
8321 array_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
8322 instruction->is_const);
8323 } else {
8324 ir_add_error(ira, &instruction->base,
8325 buf_sprintf("slice of non-array type '%s'", buf_ptr(&ptr->type_entry->name)));
8326 // TODO if this is a typedecl, add error note showing the declaration of the type decl
8327 return ira->codegen->builtin_types.entry_invalid;
8328 }
8329
8330 if (ptr->static_value.special == ConstValSpecialStatic &&
8331 casted_start->static_value.special == ConstValSpecialStatic &&
8332 (!end || end->static_value.special == ConstValSpecialStatic))
8333 {
8334 bool depends_on_compile_var =
8335 ptr->static_value.depends_on_compile_var ||
8336 casted_start->static_value.depends_on_compile_var ||
8337 (end ? end->static_value.depends_on_compile_var : false);
8338
8339 ConstExprValue *base_ptr;
8340 size_t abs_offset;
8341 size_t rel_end;
8342 if (array_type->id == TypeTableEntryIdArray) {
8343 base_ptr = &ptr->static_value;
8344 abs_offset = 0;
8345 rel_end = array_type->data.array.len;
8346 } else if (array_type->id == TypeTableEntryIdPointer) {
8347 base_ptr = ptr->static_value.data.x_ptr.base_ptr;
8348 abs_offset = ptr->static_value.data.x_ptr.index;
8349 if (abs_offset == SIZE_MAX) {
8350 rel_end = 1;
8351 } else {
8352 rel_end = base_ptr->data.x_array.size - abs_offset;
8353 }
8354 } else if (is_slice(array_type)) {
8355 ConstExprValue *ptr_val = &ptr->static_value.data.x_struct.fields[slice_ptr_index];
8356 ConstExprValue *len_val = &ptr->static_value.data.x_struct.fields[slice_len_index];
8357 base_ptr = ptr_val->data.x_ptr.base_ptr;
8358 abs_offset = ptr_val->data.x_ptr.index;
8359
8360 if (ptr_val->data.x_ptr.index == SIZE_MAX) {
8361 rel_end = 1;
8362 } else {
8363 rel_end = len_val->data.x_bignum.data.x_uint;
8364 }
8365 } else {
8366 zig_unreachable();
8367 }
8368
8369 uint64_t start_scalar = casted_start->static_value.data.x_bignum.data.x_uint;
8370 if (start_scalar > rel_end) {
8371 ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice"));
8372 return ira->codegen->builtin_types.entry_invalid;
8373 }
8374
8375 uint64_t end_scalar;
8376 if (end) {
8377 end_scalar = end->static_value.data.x_bignum.data.x_uint;
8378 } else {
8379 end_scalar = rel_end;
8380 }
8381 if (end_scalar > rel_end) {
8382 ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice"));
8383 return ira->codegen->builtin_types.entry_invalid;
8384 }
8385 if (start_scalar > end_scalar) {
8386 ir_add_error(ira, &instruction->base, buf_sprintf("slice start is greater than end"));
8387 return ira->codegen->builtin_types.entry_invalid;
8388 }
8389
8390 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
8391 out_val->data.x_struct.fields = allocate<ConstExprValue>(2);
8392
8393 ConstExprValue *ptr_val = &out_val->data.x_struct.fields[slice_ptr_index];
8394 ptr_val->special = ConstValSpecialStatic;
8395 ptr_val->data.x_ptr.base_ptr = base_ptr;
8396 ptr_val->data.x_ptr.index = (abs_offset != SIZE_MAX) ? (abs_offset + start_scalar) : SIZE_MAX;
8397
8398 ConstExprValue *len_val = &out_val->data.x_struct.fields[slice_len_index];
8399 len_val->special = ConstValSpecialStatic;
8400 bignum_init_unsigned(&len_val->data.x_bignum, rel_end);
8401
8402 return return_type;
8403 }
8404
8405 IrInstruction *new_instruction = ir_build_slice_from(&ira->new_irb, &instruction->base, ptr, casted_start, end, instruction->is_const);
8406 ir_add_alloca(ira, new_instruction, return_type);
8407
8408 return return_type;
8409}
8410
7981static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {8411static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
7982 switch (instruction->id) {8412 switch (instruction->id) {
7983 case IrInstructionIdInvalid:8413 case IrInstructionIdInvalid:
...@@ -8094,6 +8524,12 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -8094,6 +8524,12 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
8094 return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction);8524 return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction);
8095 case IrInstructionIdAlloca:8525 case IrInstructionIdAlloca:
8096 return ir_analyze_instruction_alloca(ira, (IrInstructionAlloca *)instruction);8526 return ir_analyze_instruction_alloca(ira, (IrInstructionAlloca *)instruction);
8527 case IrInstructionIdMemset:
8528 return ir_analyze_instruction_memset(ira, (IrInstructionMemset *)instruction);
8529 case IrInstructionIdMemcpy:
8530 return ir_analyze_instruction_memcpy(ira, (IrInstructionMemcpy *)instruction);
8531 case IrInstructionIdSlice:
8532 return ir_analyze_instruction_slice(ira, (IrInstructionSlice *)instruction);
8097 case IrInstructionIdCast:8533 case IrInstructionIdCast:
8098 case IrInstructionIdStructFieldPtr:8534 case IrInstructionIdStructFieldPtr:
8099 case IrInstructionIdEnumFieldPtr:8535 case IrInstructionIdEnumFieldPtr:
...@@ -8195,6 +8631,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -8195,6 +8631,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
8195 case IrInstructionIdCUndef:8631 case IrInstructionIdCUndef:
8196 case IrInstructionIdCmpxchg:8632 case IrInstructionIdCmpxchg:
8197 case IrInstructionIdFence:8633 case IrInstructionIdFence:
8634 case IrInstructionIdMemset:
8635 case IrInstructionIdMemcpy:
8198 return true;8636 return true;
8199 case IrInstructionIdPhi:8637 case IrInstructionIdPhi:
8200 case IrInstructionIdUnOp:8638 case IrInstructionIdUnOp:
...@@ -8236,6 +8674,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -8236,6 +8674,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
8236 case IrInstructionIdIntType:8674 case IrInstructionIdIntType:
8237 case IrInstructionIdBoolNot:8675 case IrInstructionIdBoolNot:
8238 case IrInstructionIdAlloca:8676 case IrInstructionIdAlloca:
8677 case IrInstructionIdSlice:
8239 return false;8678 return false;
8240 case IrInstructionIdAsm:8679 case IrInstructionIdAsm:
8241 {8680 {
...@@ -8281,62 +8720,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -8281,62 +8720,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
8281//8720//
8282// return g->builtin_types.entry_bool;8721// return g->builtin_types.entry_bool;
8283// }8722// }
8284// case BuiltinFnIdMemcpy:
8285// {
8286// AstNode *dest_node = node->data.fn_call_expr.params.at(0);
8287// AstNode *src_node = node->data.fn_call_expr.params.at(1);
8288// AstNode *len_node = node->data.fn_call_expr.params.at(2);
8289// TypeTableEntry *dest_type = analyze_expression(g, import, context, nullptr, dest_node);
8290// TypeTableEntry *src_type = analyze_expression(g, import, context, nullptr, src_node);
8291// analyze_expression(g, import, context, builtin_fn->param_types[2], len_node);
8292//
8293// if (dest_type->id != TypeTableEntryIdInvalid &&
8294// dest_type->id != TypeTableEntryIdPointer)
8295// {
8296// add_node_error(g, dest_node,
8297// buf_sprintf("expected pointer argument, found '%s'", buf_ptr(&dest_type->name)));
8298// }
8299//
8300// if (src_type->id != TypeTableEntryIdInvalid &&
8301// src_type->id != TypeTableEntryIdPointer)
8302// {
8303// add_node_error(g, src_node,
8304// buf_sprintf("expected pointer argument, found '%s'", buf_ptr(&src_type->name)));
8305// }
8306//
8307// if (dest_type->id == TypeTableEntryIdPointer &&
8308// src_type->id == TypeTableEntryIdPointer)
8309// {
8310// uint64_t dest_align = get_memcpy_align(g, dest_type->data.pointer.child_type);
8311// uint64_t src_align = get_memcpy_align(g, src_type->data.pointer.child_type);
8312// if (dest_align != src_align) {
8313// add_node_error(g, dest_node, buf_sprintf(
8314// "misaligned memcpy, '%s' has alignment '%" PRIu64 ", '%s' has alignment %" PRIu64,
8315// buf_ptr(&dest_type->name), dest_align,
8316// buf_ptr(&src_type->name), src_align));
8317// }
8318// }
8319//
8320// return builtin_fn->return_type;
8321// }
8322// case BuiltinFnIdMemset:
8323// {
8324// AstNode *dest_node = node->data.fn_call_expr.params.at(0);
8325// AstNode *char_node = node->data.fn_call_expr.params.at(1);
8326// AstNode *len_node = node->data.fn_call_expr.params.at(2);
8327// TypeTableEntry *dest_type = analyze_expression(g, import, context, nullptr, dest_node);
8328// analyze_expression(g, import, context, builtin_fn->param_types[1], char_node);
8329// analyze_expression(g, import, context, builtin_fn->param_types[2], len_node);
8330//
8331// if (dest_type->id != TypeTableEntryIdInvalid &&
8332// dest_type->id != TypeTableEntryIdPointer)
8333// {
8334// add_node_error(g, dest_node,
8335// buf_sprintf("expected pointer argument, found '%s'", buf_ptr(&dest_type->name)));
8336// }
8337//
8338// return builtin_fn->return_type;
8339// }
8340// case BuiltinFnIdAlignof:8723// case BuiltinFnIdAlignof:
8341// {8724// {
8342// AstNode *type_node = node->data.fn_call_expr.params.at(0);8725// AstNode *type_node = node->data.fn_call_expr.params.at(0);
...@@ -8455,51 +8838,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -8455,51 +8838,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
8455// }8838// }
8456// zig_unreachable();8839// zig_unreachable();
8457//}8840//}
8458//static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
8459// AstNode *node)
8460//{
8461// assert(node->type == NodeTypeSliceExpr);
8462//
8463// TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr,
8464// node->data.slice_expr.array_ref_expr);
8465//
8466// TypeTableEntry *return_type;
8467//
8468// if (array_type->id == TypeTableEntryIdInvalid) {
8469// return_type = g->builtin_types.entry_invalid;
8470// } else if (array_type->id == TypeTableEntryIdArray) {
8471// return_type = get_slice_type(g, array_type->data.array.child_type,
8472// node->data.slice_expr.is_const);
8473// } else if (array_type->id == TypeTableEntryIdPointer) {
8474// return_type = get_slice_type(g, array_type->data.pointer.child_type,
8475// node->data.slice_expr.is_const);
8476// } else if (array_type->id == TypeTableEntryIdStruct &&
8477// array_type->data.structure.is_slice)
8478// {
8479// return_type = get_slice_type(g,
8480// array_type->data.structure.fields[0].type_entry->data.pointer.child_type,
8481// node->data.slice_expr.is_const);
8482// } else {
8483// add_node_error(g, node,
8484// buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name)));
8485// return_type = g->builtin_types.entry_invalid;
8486// }
8487//
8488// if (return_type->id != TypeTableEntryIdInvalid) {
8489// node->data.slice_expr.resolved_struct_val_expr.type_entry = return_type;
8490// node->data.slice_expr.resolved_struct_val_expr.source_node = node;
8491// context->fn_entry->struct_val_expr_alloca_list.append(&node->data.slice_expr.resolved_struct_val_expr);
8492// }
8493//
8494// analyze_expression(g, import, context, g->builtin_types.entry_usize, node->data.slice_expr.start);
8495//
8496// if (node->data.slice_expr.end) {
8497// analyze_expression(g, import, context, g->builtin_types.entry_usize, node->data.slice_expr.end);
8498// }
8499//
8500// return return_type;
8501//}
8502//
8503//static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,8841//static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
8504// AstNode *node, LValPurpose purpose)8842// AstNode *node, LValPurpose purpose)
8505//{8843//{
...@@ -8656,65 +8994,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -8656,65 +8994,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
8656// }8994// }
8657// case BuiltinFnIdShlWithOverflow:8995// case BuiltinFnIdShlWithOverflow:
8658// return gen_shl_with_overflow(g, node);8996// return gen_shl_with_overflow(g, node);
8659// case BuiltinFnIdMemcpy:
8660// {
8661// size_t fn_call_param_count = node->data.fn_call_expr.params.length;
8662// assert(fn_call_param_count == 3);
8663//
8664// AstNode *dest_node = node->data.fn_call_expr.params.at(0);
8665// TypeTableEntry *dest_type = get_expr_type(dest_node);
8666//
8667// LLVMValueRef dest_ptr = gen_expr(g, dest_node);
8668// LLVMValueRef src_ptr = gen_expr(g, node->data.fn_call_expr.params.at(1));
8669// LLVMValueRef len_val = gen_expr(g, node->data.fn_call_expr.params.at(2));
8670//
8671// LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
8672//
8673// LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, "");
8674// LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr, ptr_u8, "");
8675//
8676// uint64_t align_in_bytes = get_memcpy_align(g, dest_type->data.pointer.child_type);
8677//
8678// LLVMValueRef params[] = {
8679// dest_ptr_casted, // dest pointer
8680// src_ptr_casted, // source pointer
8681// len_val, // byte count
8682// LLVMConstInt(LLVMInt32Type(), align_in_bytes, false), // align in bytes
8683// LLVMConstNull(LLVMInt1Type()), // is volatile
8684// };
8685//
8686// LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, "");
8687// return nullptr;
8688// }
8689// case BuiltinFnIdMemset:
8690// {
8691// size_t fn_call_param_count = node->data.fn_call_expr.params.length;
8692// assert(fn_call_param_count == 3);
8693//
8694// AstNode *dest_node = node->data.fn_call_expr.params.at(0);
8695// TypeTableEntry *dest_type = get_expr_type(dest_node);
8696//
8697// LLVMValueRef dest_ptr = gen_expr(g, dest_node);
8698// LLVMValueRef char_val = gen_expr(g, node->data.fn_call_expr.params.at(1));
8699// LLVMValueRef len_val = gen_expr(g, node->data.fn_call_expr.params.at(2));
8700//
8701// LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
8702//
8703// LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, "");
8704//
8705// uint64_t align_in_bytes = get_memcpy_align(g, dest_type->data.pointer.child_type);
8706//
8707// LLVMValueRef params[] = {
8708// dest_ptr_casted, // dest pointer
8709// char_val, // source pointer
8710// len_val, // byte count
8711// LLVMConstInt(LLVMInt32Type(), align_in_bytes, false), // align in bytes
8712// LLVMConstNull(LLVMInt1Type()), // is volatile
8713// };
8714//
8715// LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, "");
8716// return nullptr;
8717// }
8718// case BuiltinFnIdAlignof:8997// case BuiltinFnIdAlignof:
8719// case BuiltinFnIdMinValue:8998// case BuiltinFnIdMinValue:
8720// case BuiltinFnIdMaxValue:8999// case BuiltinFnIdMaxValue:
...@@ -8789,25 +9068,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -8789,25 +9068,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
8789// }9068// }
8790//}9069//}
8791//9070//
8792//static LLVMValueRef gen_array_base_ptr(CodeGen *g, AstNode *node) {
8793// TypeTableEntry *type_entry = get_expr_type(node);
8794//
8795// LLVMValueRef array_ptr;
8796// if (node->type == NodeTypeFieldAccessExpr) {
8797// array_ptr = gen_field_access_expr(g, node, true);
8798// if (type_entry->id == TypeTableEntryIdPointer) {
8799// // we have a double pointer so we must dereference it once
8800// array_ptr = LLVMBuildLoad(g->builder, array_ptr, "");
8801// }
8802// } else {
8803// array_ptr = gen_expr(g, node);
8804// }
8805//
8806// assert(!array_ptr || LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
8807//
8808// return array_ptr;
8809//}
8810//
8811//static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {9071//static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
8812// assert(node->type == NodeTypeArrayAccessExpr);9072// assert(node->type == NodeTypeArrayAccessExpr);
8813//9073//
...@@ -8820,111 +9080,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -8820,111 +9080,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
8820// return gen_array_elem_ptr(g, node, array_ptr, array_type, subscript_value);9080// return gen_array_elem_ptr(g, node, array_ptr, array_type, subscript_value);
8821//}9081//}
8822//9082//
8823//static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) {
8824// assert(node->type == NodeTypeSliceExpr);
8825//
8826// AstNode *array_ref_node = node->data.slice_expr.array_ref_expr;
8827// TypeTableEntry *array_type = get_expr_type(array_ref_node);
8828//
8829// LLVMValueRef tmp_struct_ptr = node->data.slice_expr.resolved_struct_val_expr.ptr;
8830// LLVMValueRef array_ptr = gen_array_base_ptr(g, array_ref_node);
8831//
8832// if (array_type->id == TypeTableEntryIdArray) {
8833// LLVMValueRef start_val = gen_expr(g, node->data.slice_expr.start);
8834// LLVMValueRef end_val;
8835// if (node->data.slice_expr.end) {
8836// end_val = gen_expr(g, node->data.slice_expr.end);
8837// } else {
8838// end_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, array_type->data.array.len, false);
8839// }
8840//
8841// if (want_debug_safety(g, node)) {
8842// add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
8843// if (node->data.slice_expr.end) {
8844// LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
8845// array_type->data.array.len, false);
8846// add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end);
8847// }
8848// }
8849//
8850// LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, "");
8851// LLVMValueRef indices[] = {
8852// LLVMConstNull(g->builtin_types.entry_usize->type_ref),
8853// start_val,
8854// };
8855// LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");
8856// LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr);
8857//
8858// LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, "");
8859// LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
8860// LLVMBuildStore(g->builder, len_value, len_field_ptr);
8861//
8862// return tmp_struct_ptr;
8863// } else if (array_type->id == TypeTableEntryIdPointer) {
8864// LLVMValueRef start_val = gen_expr(g, node->data.slice_expr.start);
8865// LLVMValueRef end_val = gen_expr(g, node->data.slice_expr.end);
8866//
8867// if (want_debug_safety(g, node)) {
8868// add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
8869// }
8870//
8871// LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, "");
8872// LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, "");
8873// LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr);
8874//
8875// LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, "");
8876// LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
8877// LLVMBuildStore(g->builder, len_value, len_field_ptr);
8878//
8879// return tmp_struct_ptr;
8880// } else if (array_type->id == TypeTableEntryIdStruct) {
8881// assert(array_type->data.structure.is_slice);
8882// assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
8883// assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);
8884//
8885// size_t ptr_index = array_type->data.structure.fields[0].gen_index;
8886// assert(ptr_index != SIZE_MAX);
8887// size_t len_index = array_type->data.structure.fields[1].gen_index;
8888// assert(len_index != SIZE_MAX);
8889//
8890// LLVMValueRef prev_end = nullptr;
8891// if (!node->data.slice_expr.end || want_debug_safety(g, node)) {
8892// LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, len_index, "");
8893// prev_end = LLVMBuildLoad(g->builder, src_len_ptr, "");
8894// }
8895//
8896// LLVMValueRef start_val = gen_expr(g, node->data.slice_expr.start);
8897// LLVMValueRef end_val;
8898// if (node->data.slice_expr.end) {
8899// end_val = gen_expr(g, node->data.slice_expr.end);
8900// } else {
8901// end_val = prev_end;
8902// }
8903//
8904// if (want_debug_safety(g, node)) {
8905// assert(prev_end);
8906// add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
8907// if (node->data.slice_expr.end) {
8908// add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, prev_end);
8909// }
8910// }
8911//
8912// LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, ptr_index, "");
8913// LLVMValueRef src_ptr = LLVMBuildLoad(g->builder, src_ptr_ptr, "");
8914// LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, ptr_index, "");
8915// LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, len_index, "");
8916// LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr);
8917//
8918// LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, len_index, "");
8919// LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
8920// LLVMBuildStore(g->builder, len_value, len_field_ptr);
8921//
8922// return tmp_struct_ptr;
8923// } else {
8924// zig_unreachable();
8925// }
8926//}
8927//
8928//static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) {9083//static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) {
8929// assert(node->type == NodeTypeUnwrapErrorExpr);9084// assert(node->type == NodeTypeUnwrapErrorExpr);
8930//9085//
src/ir_print.cpp+41
...@@ -774,6 +774,38 @@ static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) {...@@ -774,6 +774,38 @@ static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) {
774 ir_print_other_instruction(irp, instruction->value);774 ir_print_other_instruction(irp, instruction->value);
775}775}
776776
777static void ir_print_memset(IrPrint *irp, IrInstructionMemset *instruction) {
778 fprintf(irp->f, "@memset(");
779 ir_print_other_instruction(irp, instruction->dest_ptr);
780 fprintf(irp->f, ", ");
781 ir_print_other_instruction(irp, instruction->byte);
782 fprintf(irp->f, ", ");
783 ir_print_other_instruction(irp, instruction->count);
784 fprintf(irp->f, ")");
785}
786
787static void ir_print_memcpy(IrPrint *irp, IrInstructionMemcpy *instruction) {
788 fprintf(irp->f, "@memcpy(");
789 ir_print_other_instruction(irp, instruction->dest_ptr);
790 fprintf(irp->f, ", ");
791 ir_print_other_instruction(irp, instruction->src_ptr);
792 fprintf(irp->f, ", ");
793 ir_print_other_instruction(irp, instruction->count);
794 fprintf(irp->f, ")");
795}
796
797static void ir_print_slice(IrPrint *irp, IrInstructionSlice *instruction) {
798 ir_print_other_instruction(irp, instruction->ptr);
799 fprintf(irp->f, "[");
800 ir_print_other_instruction(irp, instruction->start);
801 fprintf(irp->f, "...");
802 if (instruction->end)
803 ir_print_other_instruction(irp, instruction->end);
804 fprintf(irp->f, "]");
805 if (instruction->is_const)
806 fprintf(irp->f, "const");
807}
808
777static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {809static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
778 ir_print_prefix(irp, instruction);810 ir_print_prefix(irp, instruction);
779 switch (instruction->id) {811 switch (instruction->id) {
...@@ -959,6 +991,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -959,6 +991,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
959 case IrInstructionIdBoolNot:991 case IrInstructionIdBoolNot:
960 ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction);992 ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction);
961 break;993 break;
994 case IrInstructionIdMemset:
995 ir_print_memset(irp, (IrInstructionMemset *)instruction);
996 break;
997 case IrInstructionIdMemcpy:
998 ir_print_memcpy(irp, (IrInstructionMemcpy *)instruction);
999 break;
1000 case IrInstructionIdSlice:
1001 ir_print_slice(irp, (IrInstructionSlice *)instruction);
1002 break;
962 }1003 }
963 fprintf(irp->f, "\n");1004 fprintf(irp->f, "\n");
964}1005}
std/mem.zig+6-1
...@@ -44,8 +44,13 @@ pub struct Allocator {...@@ -44,8 +44,13 @@ pub struct Allocator {
44/// Copy all of source into dest at position 0.44/// Copy all of source into dest at position 0.
45/// dest.len must be >= source.len.45/// dest.len must be >= source.len.
46pub fn copy(inline T: type, dest: []T, source: []const T) {46pub fn copy(inline T: type, dest: []T, source: []const T) {
47 @setDebugSafety(this, false);
47 assert(dest.len >= source.len);48 assert(dest.len >= source.len);
48 @memcpy(dest.ptr, source.ptr, @sizeOf(T) * source.len);49 for (source) |s, i| dest[i] = s;
50}
51
52pub fn set(inline T: type, dest: []T, value: T) {
53 for (dest) |*d| *d = value;
49}54}
5055
51/// Return < 0, == 0, or > 0 if memory a is less than, equal to, or greater than,56/// Return < 0, == 0, or > 0 if memory a is less than, equal to, or greater than,