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
417417@shlWithOverflow(inline T: type, a: T, b: T, result: &T) -> bool *x = a << b
418418```
419419
420### @memset(dest: &T, c: u8, byte_count: usize)
420### @memset(dest: &u8, c: u8, byte_count: usize)
421421
422422This 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:
428428for (destSlice) |*b| *b = c;
429429```
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
433435This function copies bytes from one region of memory to another. `dest` and
434436`source` are both pointers and must not overlap.
......@@ -441,6 +443,8 @@ const mem = @import("std").mem;
441443mem.copy(destSlice, sourceSlice);
442444```
443445
446The optimizer is intelligent enough to turn the above snippet into a memcpy.
447
444448### @breakpoint()
445449
446450This function inserts a platform-specific debug trap instruction which causes
src/all_types.hpp+29
......@@ -1415,6 +1415,9 @@ enum IrInstructionId {
14151415 IrInstructionIdIntType,
14161416 IrInstructionIdBoolNot,
14171417 IrInstructionIdAlloca,
1418 IrInstructionIdMemset,
1419 IrInstructionIdMemcpy,
1420 IrInstructionIdSlice,
14181421};
14191422
14201423struct IrInstruction {
......@@ -1924,6 +1927,32 @@ struct IrInstructionAlloca {
19241927 LLVMValueRef tmp_ptr;
19251928};
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
19271956enum LValPurpose {
19281957 LValPurposeNone,
19291958 LValPurposeAssign,
src/ast_render.cpp+13-1
......@@ -849,11 +849,23 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
849849 fprintf(ar->f, "%scontinue", inline_str);
850850 break;
851851 }
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 }
852865 case NodeTypeFnDecl:
853866 case NodeTypeParamDecl:
854867 case NodeTypeErrorValueDecl:
855868 case NodeTypeUnwrapErrorExpr:
856 case NodeTypeSliceExpr:
857869 case NodeTypeStructField:
858870 case NodeTypeUse:
859871 case NodeTypeZeroesLiteral:
src/codegen.cpp+156
......@@ -1906,6 +1906,153 @@ static LLVMValueRef ir_render_alloca(CodeGen *g, IrExecutable *executable, IrIns
19061906 return instruction->tmp_ptr;
19071907}
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
19092056static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
19102057 AstNode *source_node = instruction->source_node;
19112058 Scope *scope = instruction->scope;
......@@ -2008,6 +2155,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
20082155 return ir_render_bool_not(g, executable, (IrInstructionBoolNot *)instruction);
20092156 case IrInstructionIdAlloca:
20102157 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);
20112164 case IrInstructionIdSwitchVar:
20122165 case IrInstructionIdContainerInitList:
20132166 case IrInstructionIdStructInit:
......@@ -2590,6 +2743,9 @@ static void do_code_gen(CodeGen *g) {
25902743 } else if (instruction->id == IrInstructionIdAlloca) {
25912744 IrInstructionAlloca *alloca_instruction = (IrInstructionAlloca *)instruction;
25922745 slot = &alloca_instruction->tmp_ptr;
2746 } else if (instruction->id == IrInstructionIdSlice) {
2747 IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction;
2748 slot = &slice_instruction->tmp_ptr;
25932749 } else {
25942750 zig_unreachable();
25952751 }
src/ir.cpp+456-301
......@@ -375,6 +375,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAlloca *) {
375375 return IrInstructionIdAlloca;
376376}
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
378390template<typename T>
379391static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
380392 T *special_instruction = allocate<T>(1);
......@@ -1514,6 +1526,76 @@ static IrInstruction *ir_build_alloca_from(IrBuilder *irb, IrInstruction *old_in
15141526 return new_instruction;
15151527}
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
15171599static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,
15181600 bool gen_error_defers, bool gen_maybe_defers)
15191601{
......@@ -2350,7 +2432,43 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
23502432 return ir_build_alloca(irb, scope, node, arg0_value, arg1_value);
23512433 }
23522434 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 }
23532453 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 }
23542472 case BuiltinFnIdAlignof:
23552473 case BuiltinFnIdMemberCount:
23562474 case BuiltinFnIdAddWithOverflow:
......@@ -3252,12 +3370,45 @@ static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode
32523370 return ir_build_const_void(irb, parent_scope, node);
32533371}
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
32553401static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,
32563402 LValPurpose lval)
32573403{
32583404 assert(scope);
32593405 switch (node->type) {
32603406 case NodeTypeStructValueField:
3407 case NodeTypeRoot:
3408 case NodeTypeParamDecl:
3409 case NodeTypeUse:
3410 case NodeTypeSwitchProng:
3411 case NodeTypeSwitchRange:
32613412 zig_unreachable();
32623413 case NodeTypeBlock:
32633414 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
33193470 return ir_lval_wrap(irb, scope, ir_gen_continue(irb, scope, node), lval);
33203471 case NodeTypeDefer:
33213472 return ir_lval_wrap(irb, scope, ir_gen_defer(irb, scope, node), lval);
3322 case NodeTypeUnwrapErrorExpr:
33233473 case NodeTypeSliceExpr:
3474 return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval);
3475 case NodeTypeUnwrapErrorExpr:
33243476 case NodeTypeCharLiteral:
33253477 case NodeTypeZeroesLiteral:
33263478 case NodeTypeVarLiteral:
3327 case NodeTypeRoot:
33283479 case NodeTypeFnProto:
33293480 case NodeTypeFnDef:
33303481 case NodeTypeFnDecl:
3331 case NodeTypeParamDecl:
3332 case NodeTypeUse:
33333482 case NodeTypeContainerDecl:
33343483 case NodeTypeStructField:
3335 case NodeTypeSwitchProng:
3336 case NodeTypeSwitchRange:
33373484 case NodeTypeErrorValueDecl:
33383485 case NodeTypeTypeDecl:
33393486 zig_panic("TODO more IR gen for node types");
......@@ -4304,17 +4451,11 @@ static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_inst
43044451 }
43054452
43064453 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, value->type_entry, true);
4307 if (handle_is_ptr(value->type_entry)) {
4308 // this instruction is a noop - codegen can pass the pointer we already have as the result
4309 ir_link_new_instruction(value, source_instruction);
4310 return ptr_type;
4311 } else {
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 }
4454 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
4455 assert(fn_entry);
4456 IrInstruction *new_instruction = ir_build_ref_from(&ira->new_irb, source_instruction, value);
4457 fn_entry->alloca_list.append(new_instruction);
4458 return ptr_type;
43184459}
43194460
43204461
......@@ -7978,6 +8119,295 @@ static TypeTableEntry *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructi
79788119 zig_unreachable();
79798120}
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
79818411static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
79828412 switch (instruction->id) {
79838413 case IrInstructionIdInvalid:
......@@ -8094,6 +8524,12 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
80948524 return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction);
80958525 case IrInstructionIdAlloca:
80968526 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);
80978533 case IrInstructionIdCast:
80988534 case IrInstructionIdStructFieldPtr:
80998535 case IrInstructionIdEnumFieldPtr:
......@@ -8195,6 +8631,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
81958631 case IrInstructionIdCUndef:
81968632 case IrInstructionIdCmpxchg:
81978633 case IrInstructionIdFence:
8634 case IrInstructionIdMemset:
8635 case IrInstructionIdMemcpy:
81988636 return true;
81998637 case IrInstructionIdPhi:
82008638 case IrInstructionIdUnOp:
......@@ -8236,6 +8674,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
82368674 case IrInstructionIdIntType:
82378675 case IrInstructionIdBoolNot:
82388676 case IrInstructionIdAlloca:
8677 case IrInstructionIdSlice:
82398678 return false;
82408679 case IrInstructionIdAsm:
82418680 {
......@@ -8281,62 +8720,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
82818720//
82828721// return g->builtin_types.entry_bool;
82838722// }
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// }
83408723// case BuiltinFnIdAlignof:
83418724// {
83428725// AstNode *type_node = node->data.fn_call_expr.params.at(0);
......@@ -8455,51 +8838,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
84558838// }
84568839// zig_unreachable();
84578840//}
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//
85038841//static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
85048842// AstNode *node, LValPurpose purpose)
85058843//{
......@@ -8656,65 +8994,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
86568994// }
86578995// case BuiltinFnIdShlWithOverflow:
86588996// 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// }
87188997// case BuiltinFnIdAlignof:
87198998// case BuiltinFnIdMinValue:
87208999// case BuiltinFnIdMaxValue:
......@@ -8789,25 +9068,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
87899068// }
87909069//}
87919070//
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//
88119071//static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
88129072// assert(node->type == NodeTypeArrayAccessExpr);
88139073//
......@@ -8820,111 +9080,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
88209080// return gen_array_elem_ptr(g, node, array_ptr, array_type, subscript_value);
88219081//}
88229082//
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//
89289083//static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) {
89299084// assert(node->type == NodeTypeUnwrapErrorExpr);
89309085//
src/ir_print.cpp+41
......@@ -774,6 +774,38 @@ static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) {
774774 ir_print_other_instruction(irp, instruction->value);
775775}
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
777809static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
778810 ir_print_prefix(irp, instruction);
779811 switch (instruction->id) {
......@@ -959,6 +991,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
959991 case IrInstructionIdBoolNot:
960992 ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction);
961993 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;
9621003 }
9631004 fprintf(irp->f, "\n");
9641005}
std/mem.zig+6-1
......@@ -44,8 +44,13 @@ pub struct Allocator {
4444/// Copy all of source into dest at position 0.
4545/// dest.len must be >= source.len.
4646pub fn copy(inline T: type, dest: []T, source: []const T) {
47 @setDebugSafety(this, false);
4748 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;
4954}
5055
5156/// Return < 0, == 0, or > 0 if memory a is less than, equal to, or greater than,