| ... | @@ -5408,6 +5408,8 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutableGen *executable, Ir | ... | @@ -5408,6 +5408,8 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutableGen *executable, Ir |
| 5408 | } | 5408 | } |
| 5409 | | 5409 | |
| 5410 | static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrInstGenSlice *instruction) { | 5410 | static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrInstGenSlice *instruction) { |
| | 5411 | Error err; |
| | 5412 | |
| 5411 | LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->ptr); | 5413 | LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->ptr); |
| 5412 | ZigType *array_ptr_type = instruction->ptr->value->type; | 5414 | ZigType *array_ptr_type = instruction->ptr->value->type; |
| 5413 | assert(array_ptr_type->id == ZigTypeIdPointer); | 5415 | assert(array_ptr_type->id == ZigTypeIdPointer); |
| ... | @@ -5416,15 +5418,16 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI | ... | @@ -5416,15 +5418,16 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI |
| 5416 | | 5418 | |
| 5417 | bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); | 5419 | bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); |
| 5418 | | 5420 | |
| | 5421 | // The result is either a slice or a pointer to an array |
| 5419 | ZigType *result_type = instruction->base.value->type; | 5422 | ZigType *result_type = instruction->base.value->type; |
| 5420 | if (!type_has_bits(g, result_type)) { | | |
| 5421 | return nullptr; | | |
| 5422 | } | | |
| 5423 | | 5423 | |
| 5424 | // This is not whether the result type has a sentinel, but whether there should be a sentinel check, | 5424 | // This is not whether the result type has a sentinel, but whether there should be a sentinel check, |
| 5425 | // e.g. if they used [a..b :s] syntax. | 5425 | // e.g. if they used [a..b :s] syntax. |
| 5426 | ZigValue *sentinel = instruction->sentinel; | 5426 | ZigValue *sentinel = instruction->sentinel; |
| 5427 | | 5427 | |
| | 5428 | LLVMValueRef slice_start_ptr = nullptr; |
| | 5429 | LLVMValueRef len_value = nullptr; |
| | 5430 | |
| 5428 | if (array_type->id == ZigTypeIdArray || | 5431 | if (array_type->id == ZigTypeIdArray || |
| 5429 | (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle)) | 5432 | (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle)) |
| 5430 | { | 5433 | { |
| ... | @@ -5438,111 +5441,86 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI | ... | @@ -5438,111 +5441,86 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI |
| 5438 | } else { | 5441 | } else { |
| 5439 | end_val = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, array_type->data.array.len, false); | 5442 | end_val = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, array_type->data.array.len, false); |
| 5440 | } | 5443 | } |
| | 5444 | |
| 5441 | if (want_runtime_safety) { | 5445 | if (want_runtime_safety) { |
| | 5446 | // Safety check: start <= end |
| 5442 | if (instruction->start->value->special == ConstValSpecialRuntime || instruction->end) { | 5447 | if (instruction->start->value->special == ConstValSpecialRuntime || instruction->end) { |
| 5443 | add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); | 5448 | add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); |
| 5444 | } | 5449 | } |
| 5445 | if (instruction->end) { | | |
| 5446 | LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, | | |
| 5447 | array_type->data.array.len, false); | | |
| 5448 | add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end); | | |
| 5449 | | 5450 | |
| 5450 | if (sentinel != nullptr) { | 5451 | // Safety check: the last element of the slice (the sentinel if |
| 5451 | LLVMValueRef indices[] = { | 5452 | // requested) must be inside the array |
| 5452 | LLVMConstNull(g->builtin_types.entry_usize->llvm_type), | 5453 | // XXX: Overflow is not checked here... |
| 5453 | end_val, | 5454 | const size_t full_len = array_type->data.array.len + |
| 5454 | }; | 5455 | (array_type->data.array.sentinel != nullptr); |
| 5455 | LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); | 5456 | LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, |
| 5456 | add_sentinel_check(g, sentinel_elem_ptr, sentinel); | 5457 | full_len, false); |
| 5457 | } | | |
| 5458 | } | | |
| 5459 | } | | |
| 5460 | if (!type_has_bits(g, array_type)) { | | |
| 5461 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); | | |
| 5462 | | 5458 | |
| 5463 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); | 5459 | LLVMValueRef check_end_val = end_val; |
| 5464 | | 5460 | if (sentinel != nullptr) { |
| 5465 | // TODO if runtime safety is on, store 0xaaaaaaa in ptr field | 5461 | LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false); |
| 5466 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); | 5462 | check_end_val = LLVMBuildNUWAdd(g->builder, end_val, usize_one, ""); |
| 5467 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | 5463 | } |
| 5468 | return tmp_struct_ptr; | 5464 | add_bounds_check(g, check_end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end); |
| 5469 | } | 5465 | } |
| 5470 | | 5466 | |
| 5471 | LLVMValueRef indices[] = { | 5467 | bool value_has_bits; |
| 5472 | LLVMConstNull(g->builtin_types.entry_usize->llvm_type), | 5468 | if ((err = type_has_bits2(g, array_type, &value_has_bits))) |
| 5473 | start_val, | 5469 | codegen_report_errors_and_exit(g); |
| 5474 | }; | | |
| 5475 | LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); | | |
| 5476 | if (result_type->id == ZigTypeIdPointer) { | | |
| 5477 | ir_assert(instruction->result_loc == nullptr, &instruction->base); | | |
| 5478 | LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); | | |
| 5479 | return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); | | |
| 5480 | } else { | | |
| 5481 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); | | |
| 5482 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, ""); | | |
| 5483 | gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); | | |
| 5484 | | 5470 | |
| 5485 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); | 5471 | if (value_has_bits) { |
| 5486 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); | 5472 | if (want_runtime_safety && sentinel != nullptr) { |
| 5487 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | 5473 | LLVMValueRef indices[] = { |
| | 5474 | LLVMConstNull(g->builtin_types.entry_usize->llvm_type), |
| | 5475 | end_val, |
| | 5476 | }; |
| | 5477 | LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); |
| | 5478 | add_sentinel_check(g, sentinel_elem_ptr, sentinel); |
| | 5479 | } |
| 5488 | | 5480 | |
| 5489 | return tmp_struct_ptr; | 5481 | LLVMValueRef indices[] = { |
| | 5482 | LLVMConstNull(g->builtin_types.entry_usize->llvm_type), |
| | 5483 | start_val, |
| | 5484 | }; |
| | 5485 | slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); |
| 5490 | } | 5486 | } |
| | 5487 | |
| | 5488 | len_value = LLVMBuildNUWSub(g->builder, end_val, start_val, ""); |
| 5491 | } else if (array_type->id == ZigTypeIdPointer) { | 5489 | } else if (array_type->id == ZigTypeIdPointer) { |
| 5492 | assert(array_type->data.pointer.ptr_len != PtrLenSingle); | 5490 | assert(array_type->data.pointer.ptr_len != PtrLenSingle); |
| 5493 | LLVMValueRef start_val = ir_llvm_value(g, instruction->start); | 5491 | LLVMValueRef start_val = ir_llvm_value(g, instruction->start); |
| 5494 | LLVMValueRef end_val = ir_llvm_value(g, instruction->end); | 5492 | LLVMValueRef end_val = ir_llvm_value(g, instruction->end); |
| 5495 | | 5493 | |
| 5496 | if (want_runtime_safety) { | 5494 | if (want_runtime_safety) { |
| | 5495 | // Safety check: start <= end |
| 5497 | add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); | 5496 | add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); |
| 5498 | if (sentinel != nullptr) { | 5497 | } |
| | 5498 | |
| | 5499 | bool value_has_bits; |
| | 5500 | if ((err = type_has_bits2(g, array_type, &value_has_bits))) |
| | 5501 | codegen_report_errors_and_exit(g); |
| | 5502 | |
| | 5503 | if (value_has_bits) { |
| | 5504 | if (want_runtime_safety && sentinel != nullptr) { |
| 5499 | LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &end_val, 1, ""); | 5505 | LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &end_val, 1, ""); |
| 5500 | add_sentinel_check(g, sentinel_elem_ptr, sentinel); | 5506 | add_sentinel_check(g, sentinel_elem_ptr, sentinel); |
| 5501 | } | 5507 | } |
| 5502 | } | | |
| 5503 | | 5508 | |
| 5504 | if (!type_has_bits(g, array_type)) { | 5509 | slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, ""); |
| 5505 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); | | |
| 5506 | size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index; | | |
| 5507 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, ""); | | |
| 5508 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); | | |
| 5509 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | | |
| 5510 | return tmp_struct_ptr; | | |
| 5511 | } | 5510 | } |
| 5512 | | 5511 | |
| 5513 | LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, ""); | 5512 | len_value = LLVMBuildNUWSub(g->builder, end_val, start_val, ""); |
| 5514 | if (result_type->id == ZigTypeIdPointer) { | | |
| 5515 | ir_assert(instruction->result_loc == nullptr, &instruction->base); | | |
| 5516 | LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); | | |
| 5517 | return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); | | |
| 5518 | } | | |
| 5519 | | | |
| 5520 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); | | |
| 5521 | | | |
| 5522 | size_t gen_ptr_index = result_type->data.structure.fields[slice_ptr_index]->gen_index; | | |
| 5523 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, ""); | | |
| 5524 | gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); | | |
| 5525 | | | |
| 5526 | size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index; | | |
| 5527 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, ""); | | |
| 5528 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); | | |
| 5529 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | | |
| 5530 | | | |
| 5531 | return tmp_struct_ptr; | | |
| 5532 | | | |
| 5533 | } else if (array_type->id == ZigTypeIdStruct) { | 5513 | } else if (array_type->id == ZigTypeIdStruct) { |
| 5534 | assert(array_type->data.structure.special == StructSpecialSlice); | 5514 | assert(array_type->data.structure.special == StructSpecialSlice); |
| 5535 | assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); | 5515 | assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); |
| 5536 | assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); | 5516 | assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); |
| 5537 | | 5517 | |
| 5538 | size_t ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index; | 5518 | const size_t gen_len_index = array_type->data.structure.fields[slice_len_index]->gen_index; |
| 5539 | assert(ptr_index != SIZE_MAX); | 5519 | assert(gen_len_index != SIZE_MAX); |
| 5540 | size_t len_index = array_type->data.structure.fields[slice_len_index]->gen_index; | | |
| 5541 | assert(len_index != SIZE_MAX); | | |
| 5542 | | 5520 | |
| 5543 | LLVMValueRef prev_end = nullptr; | 5521 | LLVMValueRef prev_end = nullptr; |
| 5544 | if (!instruction->end || want_runtime_safety) { | 5522 | if (!instruction->end || want_runtime_safety) { |
| 5545 | LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, (unsigned)len_index, ""); | 5523 | LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, gen_len_index, ""); |
| 5546 | prev_end = gen_load_untyped(g, src_len_ptr, 0, false, ""); | 5524 | prev_end = gen_load_untyped(g, src_len_ptr, 0, false, ""); |
| 5547 | } | 5525 | } |
| 5548 | | 5526 | |
| ... | @@ -5554,41 +5532,104 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI | ... | @@ -5554,41 +5532,104 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI |
| 5554 | end_val = prev_end; | 5532 | end_val = prev_end; |
| 5555 | } | 5533 | } |
| 5556 | | 5534 | |
| 5557 | LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, (unsigned)ptr_index, ""); | 5535 | ZigType *ptr_field_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; |
| 5558 | LLVMValueRef src_ptr = gen_load_untyped(g, src_ptr_ptr, 0, false, ""); | | |
| 5559 | | 5536 | |
| 5560 | if (want_runtime_safety) { | 5537 | if (want_runtime_safety) { |
| 5561 | assert(prev_end); | 5538 | assert(prev_end); |
| | 5539 | // Safety check: start <= end |
| 5562 | add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); | 5540 | add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); |
| 5563 | if (instruction->end) { | | |
| 5564 | add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, prev_end); | | |
| 5565 | | 5541 | |
| 5566 | if (sentinel != nullptr) { | 5542 | // Safety check: the sentinel counts as one more element |
| 5567 | LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &end_val, 1, ""); | 5543 | // XXX: Overflow is not checked here... |
| 5568 | add_sentinel_check(g, sentinel_elem_ptr, sentinel); | 5544 | LLVMValueRef check_prev_end = prev_end; |
| 5569 | } | 5545 | if (ptr_field_type->data.pointer.sentinel != nullptr) { |
| | 5546 | LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false); |
| | 5547 | check_prev_end = LLVMBuildNUWAdd(g->builder, prev_end, usize_one, ""); |
| | 5548 | } |
| | 5549 | LLVMValueRef check_end_val = end_val; |
| | 5550 | if (sentinel != nullptr) { |
| | 5551 | LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false); |
| | 5552 | check_end_val = LLVMBuildNUWAdd(g->builder, end_val, usize_one, ""); |
| 5570 | } | 5553 | } |
| | 5554 | |
| | 5555 | add_bounds_check(g, check_end_val, LLVMIntEQ, nullptr, LLVMIntULE, check_prev_end); |
| 5571 | } | 5556 | } |
| 5572 | | 5557 | |
| 5573 | LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, 1, ""); | 5558 | bool ptr_has_bits; |
| 5574 | if (result_type->id == ZigTypeIdPointer) { | 5559 | if ((err = type_has_bits2(g, ptr_field_type, &ptr_has_bits))) |
| 5575 | ir_assert(instruction->result_loc == nullptr, &instruction->base); | 5560 | codegen_report_errors_and_exit(g); |
| 5576 | LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); | 5561 | |
| 5577 | return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); | 5562 | if (ptr_has_bits) { |
| 5578 | } else { | 5563 | const size_t gen_ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index; |
| 5579 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); | 5564 | assert(gen_ptr_index != SIZE_MAX); |
| 5580 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)ptr_index, ""); | | |
| 5581 | gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); | | |
| 5582 | | 5565 | |
| 5583 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)len_index, ""); | 5566 | LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, gen_ptr_index, ""); |
| 5584 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); | 5567 | LLVMValueRef src_ptr = gen_load_untyped(g, src_ptr_ptr, 0, false, ""); |
| 5585 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | | |
| 5586 | | 5568 | |
| 5587 | return tmp_struct_ptr; | 5569 | if (sentinel != nullptr) { |
| | 5570 | LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &end_val, 1, ""); |
| | 5571 | add_sentinel_check(g, sentinel_elem_ptr, sentinel); |
| | 5572 | } |
| | 5573 | |
| | 5574 | slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, 1, ""); |
| 5588 | } | 5575 | } |
| | 5576 | |
| | 5577 | len_value = LLVMBuildNUWSub(g->builder, end_val, start_val, ""); |
| 5589 | } else { | 5578 | } else { |
| 5590 | zig_unreachable(); | 5579 | zig_unreachable(); |
| 5591 | } | 5580 | } |
| | 5581 | |
| | 5582 | bool result_has_bits; |
| | 5583 | if ((err = type_has_bits2(g, result_type, &result_has_bits))) |
| | 5584 | codegen_report_errors_and_exit(g); |
| | 5585 | |
| | 5586 | // Nothing to do, we're only interested in the bound checks emitted above |
| | 5587 | if (!result_has_bits) |
| | 5588 | return nullptr; |
| | 5589 | |
| | 5590 | // The starting pointer for the slice may be null in case of zero-sized |
| | 5591 | // arrays, the length value is always defined. |
| | 5592 | assert(len_value != nullptr); |
| | 5593 | |
| | 5594 | // The slice decays into a pointer to an array, the size is tracked in the |
| | 5595 | // type itself |
| | 5596 | if (result_type->id == ZigTypeIdPointer) { |
| | 5597 | ir_assert(instruction->result_loc == nullptr, &instruction->base); |
| | 5598 | LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); |
| | 5599 | |
| | 5600 | if (slice_start_ptr != nullptr) { |
| | 5601 | return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); |
| | 5602 | } |
| | 5603 | |
| | 5604 | return LLVMGetUndef(result_ptr_type); |
| | 5605 | } |
| | 5606 | |
| | 5607 | ir_assert(instruction->result_loc != nullptr, &instruction->base); |
| | 5608 | // Create a new slice |
| | 5609 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); |
| | 5610 | |
| | 5611 | ZigType *slice_ptr_type = result_type->data.structure.fields[slice_ptr_index]->type_entry; |
| | 5612 | |
| | 5613 | // The slice may not have a pointer at all if it points to a zero-sized type |
| | 5614 | const size_t gen_ptr_index = result_type->data.structure.fields[slice_ptr_index]->gen_index; |
| | 5615 | if (gen_ptr_index != SIZE_MAX) { |
| | 5616 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, ""); |
| | 5617 | if (slice_start_ptr != nullptr) { |
| | 5618 | gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); |
| | 5619 | } else if (want_runtime_safety) { |
| | 5620 | gen_undef_init(g, slice_ptr_type->abi_align, slice_ptr_type, ptr_field_ptr); |
| | 5621 | } else { |
| | 5622 | gen_store_untyped(g, LLVMGetUndef(get_llvm_type(g, slice_ptr_type)), ptr_field_ptr, 0, false); |
| | 5623 | } |
| | 5624 | } |
| | 5625 | |
| | 5626 | const size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index; |
| | 5627 | assert(gen_len_index != SIZE_MAX); |
| | 5628 | |
| | 5629 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, ""); |
| | 5630 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); |
| | 5631 | |
| | 5632 | return tmp_struct_ptr; |
| 5592 | } | 5633 | } |
| 5593 | | 5634 | |
| 5594 | static LLVMValueRef get_trap_fn_val(CodeGen *g) { | 5635 | static LLVMValueRef get_trap_fn_val(CodeGen *g) { |