| ... | @@ -5498,6 +5498,8 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutableGen *executable, Ir | ... | @@ -5498,6 +5498,8 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutableGen *executable, Ir |
| 5498 | } | 5498 | } |
| 5499 | | 5499 | |
| 5500 | static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrInstGenSlice *instruction) { | 5500 | static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrInstGenSlice *instruction) { |
| | 5501 | Error err; |
| | 5502 | |
| 5501 | LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->ptr); | 5503 | LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->ptr); |
| 5502 | ZigType *array_ptr_type = instruction->ptr->value->type; | 5504 | ZigType *array_ptr_type = instruction->ptr->value->type; |
| 5503 | assert(array_ptr_type->id == ZigTypeIdPointer); | 5505 | assert(array_ptr_type->id == ZigTypeIdPointer); |
| ... | @@ -5506,15 +5508,16 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI | ... | @@ -5506,15 +5508,16 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI |
| 5506 | | 5508 | |
| 5507 | bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); | 5509 | bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); |
| 5508 | | 5510 | |
| | 5511 | // The result is either a slice or a pointer to an array |
| 5509 | ZigType *result_type = instruction->base.value->type; | 5512 | ZigType *result_type = instruction->base.value->type; |
| 5510 | if (!type_has_bits(g, result_type)) { | | |
| 5511 | return nullptr; | | |
| 5512 | } | | |
| 5513 | | 5513 | |
| 5514 | // This is not whether the result type has a sentinel, but whether there should be a sentinel check, | 5514 | // This is not whether the result type has a sentinel, but whether there should be a sentinel check, |
| 5515 | // e.g. if they used [a..b :s] syntax. | 5515 | // e.g. if they used [a..b :s] syntax. |
| 5516 | ZigValue *sentinel = instruction->sentinel; | 5516 | ZigValue *sentinel = instruction->sentinel; |
| 5517 | | 5517 | |
| | 5518 | LLVMValueRef slice_start_ptr = nullptr; |
| | 5519 | LLVMValueRef len_value = nullptr; |
| | 5520 | |
| 5518 | if (array_type->id == ZigTypeIdArray || | 5521 | if (array_type->id == ZigTypeIdArray || |
| 5519 | (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle)) | 5522 | (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle)) |
| 5520 | { | 5523 | { |
| ... | @@ -5528,111 +5531,86 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI | ... | @@ -5528,111 +5531,86 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI |
| 5528 | } else { | 5531 | } else { |
| 5529 | end_val = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, array_type->data.array.len, false); | 5532 | end_val = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, array_type->data.array.len, false); |
| 5530 | } | 5533 | } |
| | 5534 | |
| 5531 | if (want_runtime_safety) { | 5535 | if (want_runtime_safety) { |
| | 5536 | // Safety check: start <= end |
| 5532 | if (instruction->start->value->special == ConstValSpecialRuntime || instruction->end) { | 5537 | if (instruction->start->value->special == ConstValSpecialRuntime || instruction->end) { |
| 5533 | add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); | 5538 | add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); |
| 5534 | } | 5539 | } |
| 5535 | if (instruction->end) { | | |
| 5536 | LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, | | |
| 5537 | array_type->data.array.len, false); | | |
| 5538 | add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end); | | |
| 5539 | | 5540 | |
| 5540 | if (sentinel != nullptr) { | 5541 | // Safety check: the last element of the slice (the sentinel if |
| 5541 | LLVMValueRef indices[] = { | 5542 | // requested) must be inside the array |
| 5542 | LLVMConstNull(g->builtin_types.entry_usize->llvm_type), | 5543 | // XXX: Overflow is not checked here... |
| 5543 | end_val, | 5544 | const size_t full_len = array_type->data.array.len + |
| 5544 | }; | 5545 | (array_type->data.array.sentinel != nullptr); |
| 5545 | LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); | 5546 | LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, |
| 5546 | add_sentinel_check(g, sentinel_elem_ptr, sentinel); | 5547 | full_len, false); |
| 5547 | } | | |
| 5548 | } | | |
| 5549 | } | | |
| 5550 | if (!type_has_bits(g, array_type)) { | | |
| 5551 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); | | |
| 5552 | | 5548 | |
| 5553 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); | 5549 | LLVMValueRef check_end_val = end_val; |
| 5554 | | 5550 | if (sentinel != nullptr) { |
| 5555 | // TODO if runtime safety is on, store 0xaaaaaaa in ptr field | 5551 | LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false); |
| 5556 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); | 5552 | check_end_val = LLVMBuildNUWAdd(g->builder, end_val, usize_one, ""); |
| 5557 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | 5553 | } |
| 5558 | return tmp_struct_ptr; | 5554 | add_bounds_check(g, check_end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end); |
| 5559 | } | 5555 | } |
| 5560 | | 5556 | |
| 5561 | LLVMValueRef indices[] = { | 5557 | bool value_has_bits; |
| 5562 | LLVMConstNull(g->builtin_types.entry_usize->llvm_type), | 5558 | if ((err = type_has_bits2(g, array_type, &value_has_bits))) |
| 5563 | start_val, | 5559 | codegen_report_errors_and_exit(g); |
| 5564 | }; | | |
| 5565 | LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); | | |
| 5566 | if (result_type->id == ZigTypeIdPointer) { | | |
| 5567 | ir_assert(instruction->result_loc == nullptr, &instruction->base); | | |
| 5568 | LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); | | |
| 5569 | return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); | | |
| 5570 | } else { | | |
| 5571 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); | | |
| 5572 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, ""); | | |
| 5573 | gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); | | |
| 5574 | | 5560 | |
| 5575 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); | 5561 | if (value_has_bits) { |
| 5576 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); | 5562 | if (want_runtime_safety && sentinel != nullptr) { |
| 5577 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | 5563 | LLVMValueRef indices[] = { |
| | 5564 | LLVMConstNull(g->builtin_types.entry_usize->llvm_type), |
| | 5565 | end_val, |
| | 5566 | }; |
| | 5567 | LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); |
| | 5568 | add_sentinel_check(g, sentinel_elem_ptr, sentinel); |
| | 5569 | } |
| 5578 | | 5570 | |
| 5579 | return tmp_struct_ptr; | 5571 | LLVMValueRef indices[] = { |
| | 5572 | LLVMConstNull(g->builtin_types.entry_usize->llvm_type), |
| | 5573 | start_val, |
| | 5574 | }; |
| | 5575 | slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); |
| 5580 | } | 5576 | } |
| | 5577 | |
| | 5578 | len_value = LLVMBuildNUWSub(g->builder, end_val, start_val, ""); |
| 5581 | } else if (array_type->id == ZigTypeIdPointer) { | 5579 | } else if (array_type->id == ZigTypeIdPointer) { |
| 5582 | assert(array_type->data.pointer.ptr_len != PtrLenSingle); | 5580 | assert(array_type->data.pointer.ptr_len != PtrLenSingle); |
| 5583 | LLVMValueRef start_val = ir_llvm_value(g, instruction->start); | 5581 | LLVMValueRef start_val = ir_llvm_value(g, instruction->start); |
| 5584 | LLVMValueRef end_val = ir_llvm_value(g, instruction->end); | 5582 | LLVMValueRef end_val = ir_llvm_value(g, instruction->end); |
| 5585 | | 5583 | |
| 5586 | if (want_runtime_safety) { | 5584 | if (want_runtime_safety) { |
| | 5585 | // Safety check: start <= end |
| 5587 | add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); | 5586 | add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); |
| 5588 | if (sentinel != nullptr) { | 5587 | } |
| | 5588 | |
| | 5589 | bool value_has_bits; |
| | 5590 | if ((err = type_has_bits2(g, array_type, &value_has_bits))) |
| | 5591 | codegen_report_errors_and_exit(g); |
| | 5592 | |
| | 5593 | if (value_has_bits) { |
| | 5594 | if (want_runtime_safety && sentinel != nullptr) { |
| 5589 | LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &end_val, 1, ""); | 5595 | LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &end_val, 1, ""); |
| 5590 | add_sentinel_check(g, sentinel_elem_ptr, sentinel); | 5596 | add_sentinel_check(g, sentinel_elem_ptr, sentinel); |
| 5591 | } | 5597 | } |
| 5592 | } | | |
| 5593 | | 5598 | |
| 5594 | if (!type_has_bits(g, array_type)) { | 5599 | slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, ""); |
| 5595 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); | | |
| 5596 | size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index; | | |
| 5597 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, ""); | | |
| 5598 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); | | |
| 5599 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | | |
| 5600 | return tmp_struct_ptr; | | |
| 5601 | } | 5600 | } |
| 5602 | | 5601 | |
| 5603 | LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, ""); | 5602 | len_value = LLVMBuildNUWSub(g->builder, end_val, start_val, ""); |
| 5604 | if (result_type->id == ZigTypeIdPointer) { | | |
| 5605 | ir_assert(instruction->result_loc == nullptr, &instruction->base); | | |
| 5606 | LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); | | |
| 5607 | return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); | | |
| 5608 | } | | |
| 5609 | | | |
| 5610 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); | | |
| 5611 | | | |
| 5612 | size_t gen_ptr_index = result_type->data.structure.fields[slice_ptr_index]->gen_index; | | |
| 5613 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, ""); | | |
| 5614 | gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); | | |
| 5615 | | | |
| 5616 | size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index; | | |
| 5617 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, ""); | | |
| 5618 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); | | |
| 5619 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | | |
| 5620 | | | |
| 5621 | return tmp_struct_ptr; | | |
| 5622 | | | |
| 5623 | } else if (array_type->id == ZigTypeIdStruct) { | 5603 | } else if (array_type->id == ZigTypeIdStruct) { |
| 5624 | assert(array_type->data.structure.special == StructSpecialSlice); | 5604 | assert(array_type->data.structure.special == StructSpecialSlice); |
| 5625 | assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); | 5605 | assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); |
| 5626 | assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); | 5606 | assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); |
| 5627 | | 5607 | |
| 5628 | size_t ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index; | 5608 | const size_t gen_len_index = array_type->data.structure.fields[slice_len_index]->gen_index; |
| 5629 | assert(ptr_index != SIZE_MAX); | 5609 | assert(gen_len_index != SIZE_MAX); |
| 5630 | size_t len_index = array_type->data.structure.fields[slice_len_index]->gen_index; | | |
| 5631 | assert(len_index != SIZE_MAX); | | |
| 5632 | | 5610 | |
| 5633 | LLVMValueRef prev_end = nullptr; | 5611 | LLVMValueRef prev_end = nullptr; |
| 5634 | if (!instruction->end || want_runtime_safety) { | 5612 | if (!instruction->end || want_runtime_safety) { |
| 5635 | LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, (unsigned)len_index, ""); | 5613 | LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, gen_len_index, ""); |
| 5636 | prev_end = gen_load_untyped(g, src_len_ptr, 0, false, ""); | 5614 | prev_end = gen_load_untyped(g, src_len_ptr, 0, false, ""); |
| 5637 | } | 5615 | } |
| 5638 | | 5616 | |
| ... | @@ -5644,41 +5622,104 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI | ... | @@ -5644,41 +5622,104 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI |
| 5644 | end_val = prev_end; | 5622 | end_val = prev_end; |
| 5645 | } | 5623 | } |
| 5646 | | 5624 | |
| 5647 | LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, (unsigned)ptr_index, ""); | 5625 | ZigType *ptr_field_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; |
| 5648 | LLVMValueRef src_ptr = gen_load_untyped(g, src_ptr_ptr, 0, false, ""); | | |
| 5649 | | 5626 | |
| 5650 | if (want_runtime_safety) { | 5627 | if (want_runtime_safety) { |
| 5651 | assert(prev_end); | 5628 | assert(prev_end); |
| | 5629 | // Safety check: start <= end |
| 5652 | add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); | 5630 | add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); |
| 5653 | if (instruction->end) { | | |
| 5654 | add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, prev_end); | | |
| 5655 | | 5631 | |
| 5656 | if (sentinel != nullptr) { | 5632 | // Safety check: the sentinel counts as one more element |
| 5657 | LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &end_val, 1, ""); | 5633 | // XXX: Overflow is not checked here... |
| 5658 | add_sentinel_check(g, sentinel_elem_ptr, sentinel); | 5634 | LLVMValueRef check_prev_end = prev_end; |
| 5659 | } | 5635 | if (ptr_field_type->data.pointer.sentinel != nullptr) { |
| | 5636 | LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false); |
| | 5637 | check_prev_end = LLVMBuildNUWAdd(g->builder, prev_end, usize_one, ""); |
| | 5638 | } |
| | 5639 | LLVMValueRef check_end_val = end_val; |
| | 5640 | if (sentinel != nullptr) { |
| | 5641 | LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false); |
| | 5642 | check_end_val = LLVMBuildNUWAdd(g->builder, end_val, usize_one, ""); |
| 5660 | } | 5643 | } |
| | 5644 | |
| | 5645 | add_bounds_check(g, check_end_val, LLVMIntEQ, nullptr, LLVMIntULE, check_prev_end); |
| 5661 | } | 5646 | } |
| 5662 | | 5647 | |
| 5663 | LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, 1, ""); | 5648 | bool ptr_has_bits; |
| 5664 | if (result_type->id == ZigTypeIdPointer) { | 5649 | if ((err = type_has_bits2(g, ptr_field_type, &ptr_has_bits))) |
| 5665 | ir_assert(instruction->result_loc == nullptr, &instruction->base); | 5650 | codegen_report_errors_and_exit(g); |
| 5666 | LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); | 5651 | |
| 5667 | return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); | 5652 | if (ptr_has_bits) { |
| 5668 | } else { | 5653 | const size_t gen_ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index; |
| 5669 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); | 5654 | assert(gen_ptr_index != SIZE_MAX); |
| 5670 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)ptr_index, ""); | | |
| 5671 | gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); | | |
| 5672 | | 5655 | |
| 5673 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)len_index, ""); | 5656 | LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, gen_ptr_index, ""); |
| 5674 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); | 5657 | LLVMValueRef src_ptr = gen_load_untyped(g, src_ptr_ptr, 0, false, ""); |
| 5675 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | | |
| 5676 | | 5658 | |
| 5677 | return tmp_struct_ptr; | 5659 | if (sentinel != nullptr) { |
| | 5660 | LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &end_val, 1, ""); |
| | 5661 | add_sentinel_check(g, sentinel_elem_ptr, sentinel); |
| | 5662 | } |
| | 5663 | |
| | 5664 | slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, 1, ""); |
| 5678 | } | 5665 | } |
| | 5666 | |
| | 5667 | len_value = LLVMBuildNUWSub(g->builder, end_val, start_val, ""); |
| 5679 | } else { | 5668 | } else { |
| 5680 | zig_unreachable(); | 5669 | zig_unreachable(); |
| 5681 | } | 5670 | } |
| | 5671 | |
| | 5672 | bool result_has_bits; |
| | 5673 | if ((err = type_has_bits2(g, result_type, &result_has_bits))) |
| | 5674 | codegen_report_errors_and_exit(g); |
| | 5675 | |
| | 5676 | // Nothing to do, we're only interested in the bound checks emitted above |
| | 5677 | if (!result_has_bits) |
| | 5678 | return nullptr; |
| | 5679 | |
| | 5680 | // The starting pointer for the slice may be null in case of zero-sized |
| | 5681 | // arrays, the length value is always defined. |
| | 5682 | assert(len_value != nullptr); |
| | 5683 | |
| | 5684 | // The slice decays into a pointer to an array, the size is tracked in the |
| | 5685 | // type itself |
| | 5686 | if (result_type->id == ZigTypeIdPointer) { |
| | 5687 | ir_assert(instruction->result_loc == nullptr, &instruction->base); |
| | 5688 | LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); |
| | 5689 | |
| | 5690 | if (slice_start_ptr != nullptr) { |
| | 5691 | return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); |
| | 5692 | } |
| | 5693 | |
| | 5694 | return LLVMGetUndef(result_ptr_type); |
| | 5695 | } |
| | 5696 | |
| | 5697 | ir_assert(instruction->result_loc != nullptr, &instruction->base); |
| | 5698 | // Create a new slice |
| | 5699 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); |
| | 5700 | |
| | 5701 | ZigType *slice_ptr_type = result_type->data.structure.fields[slice_ptr_index]->type_entry; |
| | 5702 | |
| | 5703 | // The slice may not have a pointer at all if it points to a zero-sized type |
| | 5704 | const size_t gen_ptr_index = result_type->data.structure.fields[slice_ptr_index]->gen_index; |
| | 5705 | if (gen_ptr_index != SIZE_MAX) { |
| | 5706 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, ""); |
| | 5707 | if (slice_start_ptr != nullptr) { |
| | 5708 | gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); |
| | 5709 | } else if (want_runtime_safety) { |
| | 5710 | gen_undef_init(g, slice_ptr_type->abi_align, slice_ptr_type, ptr_field_ptr); |
| | 5711 | } else { |
| | 5712 | gen_store_untyped(g, LLVMGetUndef(get_llvm_type(g, slice_ptr_type)), ptr_field_ptr, 0, false); |
| | 5713 | } |
| | 5714 | } |
| | 5715 | |
| | 5716 | const size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index; |
| | 5717 | assert(gen_len_index != SIZE_MAX); |
| | 5718 | |
| | 5719 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, ""); |
| | 5720 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); |
| | 5721 | |
| | 5722 | return tmp_struct_ptr; |
| 5682 | } | 5723 | } |
| 5683 | | 5724 | |
| 5684 | static LLVMValueRef get_trap_fn_val(CodeGen *g) { | 5725 | static LLVMValueRef get_trap_fn_val(CodeGen *g) { |