| ... | ... | @@ -375,6 +375,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAlloca *) { |
| 375 | 375 | return IrInstructionIdAlloca; |
| 376 | 376 | } |
| 377 | 377 | |
| 378 | static constexpr IrInstructionId ir_instruction_id(IrInstructionMemset *) { |
| 379 | return IrInstructionIdMemset; |
| 380 | } |
| 381 | |
| 382 | static constexpr IrInstructionId ir_instruction_id(IrInstructionMemcpy *) { |
| 383 | return IrInstructionIdMemcpy; |
| 384 | } |
| 385 | |
| 386 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSlice *) { |
| 387 | return IrInstructionIdSlice; |
| 388 | } |
| 389 | |
| 378 | 390 | template<typename T> |
| 379 | 391 | static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { |
| 380 | 392 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -1514,6 +1526,76 @@ static IrInstruction *ir_build_alloca_from(IrBuilder *irb, IrInstruction *old_in |
| 1514 | 1526 | return new_instruction; |
| 1515 | 1527 | } |
| 1516 | 1528 | |
| 1529 | static 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 | |
| 1544 | static 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 | |
| 1552 | static 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 | |
| 1567 | static 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 | |
| 1575 | static 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 | |
| 1591 | static 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 | |
| 1517 | 1599 | static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, |
| 1518 | 1600 | bool gen_error_defers, bool gen_maybe_defers) |
| 1519 | 1601 | { |
| ... | ... | @@ -2350,7 +2432,43 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 2350 | 2432 | return ir_build_alloca(irb, scope, node, arg0_value, arg1_value); |
| 2351 | 2433 | } |
| 2352 | 2434 | case BuiltinFnIdMemcpy: |
| 2435 | { |
| 2436 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| 2437 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); |
| 2438 | if (arg0_value == irb->codegen->invalid_instruction) |
| 2439 | return arg0_value; |
| 2440 | |
| 2441 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); |
| 2442 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); |
| 2443 | if (arg1_value == irb->codegen->invalid_instruction) |
| 2444 | return arg1_value; |
| 2445 | |
| 2446 | AstNode *arg2_node = node->data.fn_call_expr.params.at(2); |
| 2447 | IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope); |
| 2448 | if (arg2_value == irb->codegen->invalid_instruction) |
| 2449 | return arg2_value; |
| 2450 | |
| 2451 | return ir_build_memcpy(irb, scope, node, arg0_value, arg1_value, arg2_value); |
| 2452 | } |
| 2353 | 2453 | case BuiltinFnIdMemset: |
| 2454 | { |
| 2455 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| 2456 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); |
| 2457 | if (arg0_value == irb->codegen->invalid_instruction) |
| 2458 | return arg0_value; |
| 2459 | |
| 2460 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); |
| 2461 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); |
| 2462 | if (arg1_value == irb->codegen->invalid_instruction) |
| 2463 | return arg1_value; |
| 2464 | |
| 2465 | AstNode *arg2_node = node->data.fn_call_expr.params.at(2); |
| 2466 | IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope); |
| 2467 | if (arg2_value == irb->codegen->invalid_instruction) |
| 2468 | return arg2_value; |
| 2469 | |
| 2470 | return ir_build_memset(irb, scope, node, arg0_value, arg1_value, arg2_value); |
| 2471 | } |
| 2354 | 2472 | case BuiltinFnIdAlignof: |
| 2355 | 2473 | case BuiltinFnIdMemberCount: |
| 2356 | 2474 | case BuiltinFnIdAddWithOverflow: |
| ... | ... | @@ -3252,12 +3370,45 @@ static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode |
| 3252 | 3370 | return ir_build_const_void(irb, parent_scope, node); |
| 3253 | 3371 | } |
| 3254 | 3372 | |
| 3373 | static 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 | |
| 3255 | 3401 | static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, |
| 3256 | 3402 | LValPurpose lval) |
| 3257 | 3403 | { |
| 3258 | 3404 | assert(scope); |
| 3259 | 3405 | switch (node->type) { |
| 3260 | 3406 | case NodeTypeStructValueField: |
| 3407 | case NodeTypeRoot: |
| 3408 | case NodeTypeParamDecl: |
| 3409 | case NodeTypeUse: |
| 3410 | case NodeTypeSwitchProng: |
| 3411 | case NodeTypeSwitchRange: |
| 3261 | 3412 | zig_unreachable(); |
| 3262 | 3413 | case NodeTypeBlock: |
| 3263 | 3414 | return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node), lval); |
| ... | ... | @@ -3319,21 +3470,17 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 3319 | 3470 | return ir_lval_wrap(irb, scope, ir_gen_continue(irb, scope, node), lval); |
| 3320 | 3471 | case NodeTypeDefer: |
| 3321 | 3472 | return ir_lval_wrap(irb, scope, ir_gen_defer(irb, scope, node), lval); |
| 3322 | | case NodeTypeUnwrapErrorExpr: |
| 3323 | 3473 | case NodeTypeSliceExpr: |
| 3474 | return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval); |
| 3475 | case NodeTypeUnwrapErrorExpr: |
| 3324 | 3476 | case NodeTypeCharLiteral: |
| 3325 | 3477 | case NodeTypeZeroesLiteral: |
| 3326 | 3478 | case NodeTypeVarLiteral: |
| 3327 | | case NodeTypeRoot: |
| 3328 | 3479 | case NodeTypeFnProto: |
| 3329 | 3480 | case NodeTypeFnDef: |
| 3330 | 3481 | case NodeTypeFnDecl: |
| 3331 | | case NodeTypeParamDecl: |
| 3332 | | case NodeTypeUse: |
| 3333 | 3482 | case NodeTypeContainerDecl: |
| 3334 | 3483 | case NodeTypeStructField: |
| 3335 | | case NodeTypeSwitchProng: |
| 3336 | | case NodeTypeSwitchRange: |
| 3337 | 3484 | case NodeTypeErrorValueDecl: |
| 3338 | 3485 | case NodeTypeTypeDecl: |
| 3339 | 3486 | zig_panic("TODO more IR gen for node types"); |
| ... | ... | @@ -4304,17 +4451,11 @@ static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_inst |
| 4304 | 4451 | } |
| 4305 | 4452 | |
| 4306 | 4453 | 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; |
| 4318 | 4459 | } |
| 4319 | 4460 | |
| 4320 | 4461 | |
| ... | ... | @@ -7978,6 +8119,295 @@ static TypeTableEntry *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructi |
| 7978 | 8119 | zig_unreachable(); |
| 7979 | 8120 | } |
| 7980 | 8121 | |
| 8122 | static 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 | |
| 8191 | static 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 | |
| 8281 | static 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 | |
| 7981 | 8411 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 7982 | 8412 | switch (instruction->id) { |
| 7983 | 8413 | case IrInstructionIdInvalid: |
| ... | ... | @@ -8094,6 +8524,12 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 8094 | 8524 | return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction); |
| 8095 | 8525 | case IrInstructionIdAlloca: |
| 8096 | 8526 | return ir_analyze_instruction_alloca(ira, (IrInstructionAlloca *)instruction); |
| 8527 | case IrInstructionIdMemset: |
| 8528 | return ir_analyze_instruction_memset(ira, (IrInstructionMemset *)instruction); |
| 8529 | case IrInstructionIdMemcpy: |
| 8530 | return ir_analyze_instruction_memcpy(ira, (IrInstructionMemcpy *)instruction); |
| 8531 | case IrInstructionIdSlice: |
| 8532 | return ir_analyze_instruction_slice(ira, (IrInstructionSlice *)instruction); |
| 8097 | 8533 | case IrInstructionIdCast: |
| 8098 | 8534 | case IrInstructionIdStructFieldPtr: |
| 8099 | 8535 | case IrInstructionIdEnumFieldPtr: |
| ... | ... | @@ -8195,6 +8631,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8195 | 8631 | case IrInstructionIdCUndef: |
| 8196 | 8632 | case IrInstructionIdCmpxchg: |
| 8197 | 8633 | case IrInstructionIdFence: |
| 8634 | case IrInstructionIdMemset: |
| 8635 | case IrInstructionIdMemcpy: |
| 8198 | 8636 | return true; |
| 8199 | 8637 | case IrInstructionIdPhi: |
| 8200 | 8638 | case IrInstructionIdUnOp: |
| ... | ... | @@ -8236,6 +8674,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8236 | 8674 | case IrInstructionIdIntType: |
| 8237 | 8675 | case IrInstructionIdBoolNot: |
| 8238 | 8676 | case IrInstructionIdAlloca: |
| 8677 | case IrInstructionIdSlice: |
| 8239 | 8678 | return false; |
| 8240 | 8679 | case IrInstructionIdAsm: |
| 8241 | 8680 | { |
| ... | ... | @@ -8281,62 +8720,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8281 | 8720 | // |
| 8282 | 8721 | // return g->builtin_types.entry_bool; |
| 8283 | 8722 | // } |
| 8284 | | // case BuiltinFnIdMemcpy: |
| 8285 | | // { |
| 8286 | | // AstNode *dest_node = node->data.fn_call_expr.params.at(0); |
| 8287 | | // AstNode *src_node = node->data.fn_call_expr.params.at(1); |
| 8288 | | // AstNode *len_node = node->data.fn_call_expr.params.at(2); |
| 8289 | | // TypeTableEntry *dest_type = analyze_expression(g, import, context, nullptr, dest_node); |
| 8290 | | // TypeTableEntry *src_type = analyze_expression(g, import, context, nullptr, src_node); |
| 8291 | | // analyze_expression(g, import, context, builtin_fn->param_types[2], len_node); |
| 8292 | | // |
| 8293 | | // if (dest_type->id != TypeTableEntryIdInvalid && |
| 8294 | | // dest_type->id != TypeTableEntryIdPointer) |
| 8295 | | // { |
| 8296 | | // add_node_error(g, dest_node, |
| 8297 | | // buf_sprintf("expected pointer argument, found '%s'", buf_ptr(&dest_type->name))); |
| 8298 | | // } |
| 8299 | | // |
| 8300 | | // if (src_type->id != TypeTableEntryIdInvalid && |
| 8301 | | // src_type->id != TypeTableEntryIdPointer) |
| 8302 | | // { |
| 8303 | | // add_node_error(g, src_node, |
| 8304 | | // buf_sprintf("expected pointer argument, found '%s'", buf_ptr(&src_type->name))); |
| 8305 | | // } |
| 8306 | | // |
| 8307 | | // if (dest_type->id == TypeTableEntryIdPointer && |
| 8308 | | // src_type->id == TypeTableEntryIdPointer) |
| 8309 | | // { |
| 8310 | | // uint64_t dest_align = get_memcpy_align(g, dest_type->data.pointer.child_type); |
| 8311 | | // uint64_t src_align = get_memcpy_align(g, src_type->data.pointer.child_type); |
| 8312 | | // if (dest_align != src_align) { |
| 8313 | | // add_node_error(g, dest_node, buf_sprintf( |
| 8314 | | // "misaligned memcpy, '%s' has alignment '%" PRIu64 ", '%s' has alignment %" PRIu64, |
| 8315 | | // buf_ptr(&dest_type->name), dest_align, |
| 8316 | | // buf_ptr(&src_type->name), src_align)); |
| 8317 | | // } |
| 8318 | | // } |
| 8319 | | // |
| 8320 | | // return builtin_fn->return_type; |
| 8321 | | // } |
| 8322 | | // case BuiltinFnIdMemset: |
| 8323 | | // { |
| 8324 | | // AstNode *dest_node = node->data.fn_call_expr.params.at(0); |
| 8325 | | // AstNode *char_node = node->data.fn_call_expr.params.at(1); |
| 8326 | | // AstNode *len_node = node->data.fn_call_expr.params.at(2); |
| 8327 | | // TypeTableEntry *dest_type = analyze_expression(g, import, context, nullptr, dest_node); |
| 8328 | | // analyze_expression(g, import, context, builtin_fn->param_types[1], char_node); |
| 8329 | | // analyze_expression(g, import, context, builtin_fn->param_types[2], len_node); |
| 8330 | | // |
| 8331 | | // if (dest_type->id != TypeTableEntryIdInvalid && |
| 8332 | | // dest_type->id != TypeTableEntryIdPointer) |
| 8333 | | // { |
| 8334 | | // add_node_error(g, dest_node, |
| 8335 | | // buf_sprintf("expected pointer argument, found '%s'", buf_ptr(&dest_type->name))); |
| 8336 | | // } |
| 8337 | | // |
| 8338 | | // return builtin_fn->return_type; |
| 8339 | | // } |
| 8340 | 8723 | // case BuiltinFnIdAlignof: |
| 8341 | 8724 | // { |
| 8342 | 8725 | // AstNode *type_node = node->data.fn_call_expr.params.at(0); |
| ... | ... | @@ -8455,51 +8838,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8455 | 8838 | // } |
| 8456 | 8839 | // zig_unreachable(); |
| 8457 | 8840 | //} |
| 8458 | | //static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 8459 | | // AstNode *node) |
| 8460 | | //{ |
| 8461 | | // assert(node->type == NodeTypeSliceExpr); |
| 8462 | | // |
| 8463 | | // TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr, |
| 8464 | | // node->data.slice_expr.array_ref_expr); |
| 8465 | | // |
| 8466 | | // TypeTableEntry *return_type; |
| 8467 | | // |
| 8468 | | // if (array_type->id == TypeTableEntryIdInvalid) { |
| 8469 | | // return_type = g->builtin_types.entry_invalid; |
| 8470 | | // } else if (array_type->id == TypeTableEntryIdArray) { |
| 8471 | | // return_type = get_slice_type(g, array_type->data.array.child_type, |
| 8472 | | // node->data.slice_expr.is_const); |
| 8473 | | // } else if (array_type->id == TypeTableEntryIdPointer) { |
| 8474 | | // return_type = get_slice_type(g, array_type->data.pointer.child_type, |
| 8475 | | // node->data.slice_expr.is_const); |
| 8476 | | // } else if (array_type->id == TypeTableEntryIdStruct && |
| 8477 | | // array_type->data.structure.is_slice) |
| 8478 | | // { |
| 8479 | | // return_type = get_slice_type(g, |
| 8480 | | // array_type->data.structure.fields[0].type_entry->data.pointer.child_type, |
| 8481 | | // node->data.slice_expr.is_const); |
| 8482 | | // } else { |
| 8483 | | // add_node_error(g, node, |
| 8484 | | // buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name))); |
| 8485 | | // return_type = g->builtin_types.entry_invalid; |
| 8486 | | // } |
| 8487 | | // |
| 8488 | | // if (return_type->id != TypeTableEntryIdInvalid) { |
| 8489 | | // node->data.slice_expr.resolved_struct_val_expr.type_entry = return_type; |
| 8490 | | // node->data.slice_expr.resolved_struct_val_expr.source_node = node; |
| 8491 | | // context->fn_entry->struct_val_expr_alloca_list.append(&node->data.slice_expr.resolved_struct_val_expr); |
| 8492 | | // } |
| 8493 | | // |
| 8494 | | // analyze_expression(g, import, context, g->builtin_types.entry_usize, node->data.slice_expr.start); |
| 8495 | | // |
| 8496 | | // if (node->data.slice_expr.end) { |
| 8497 | | // analyze_expression(g, import, context, g->builtin_types.entry_usize, node->data.slice_expr.end); |
| 8498 | | // } |
| 8499 | | // |
| 8500 | | // return return_type; |
| 8501 | | //} |
| 8502 | | // |
| 8503 | 8841 | //static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 8504 | 8842 | // AstNode *node, LValPurpose purpose) |
| 8505 | 8843 | //{ |
| ... | ... | @@ -8656,65 +8994,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8656 | 8994 | // } |
| 8657 | 8995 | // case BuiltinFnIdShlWithOverflow: |
| 8658 | 8996 | // return gen_shl_with_overflow(g, node); |
| 8659 | | // case BuiltinFnIdMemcpy: |
| 8660 | | // { |
| 8661 | | // size_t fn_call_param_count = node->data.fn_call_expr.params.length; |
| 8662 | | // assert(fn_call_param_count == 3); |
| 8663 | | // |
| 8664 | | // AstNode *dest_node = node->data.fn_call_expr.params.at(0); |
| 8665 | | // TypeTableEntry *dest_type = get_expr_type(dest_node); |
| 8666 | | // |
| 8667 | | // LLVMValueRef dest_ptr = gen_expr(g, dest_node); |
| 8668 | | // LLVMValueRef src_ptr = gen_expr(g, node->data.fn_call_expr.params.at(1)); |
| 8669 | | // LLVMValueRef len_val = gen_expr(g, node->data.fn_call_expr.params.at(2)); |
| 8670 | | // |
| 8671 | | // LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); |
| 8672 | | // |
| 8673 | | // LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, ""); |
| 8674 | | // LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr, ptr_u8, ""); |
| 8675 | | // |
| 8676 | | // uint64_t align_in_bytes = get_memcpy_align(g, dest_type->data.pointer.child_type); |
| 8677 | | // |
| 8678 | | // LLVMValueRef params[] = { |
| 8679 | | // dest_ptr_casted, // dest pointer |
| 8680 | | // src_ptr_casted, // source pointer |
| 8681 | | // len_val, // byte count |
| 8682 | | // LLVMConstInt(LLVMInt32Type(), align_in_bytes, false), // align in bytes |
| 8683 | | // LLVMConstNull(LLVMInt1Type()), // is volatile |
| 8684 | | // }; |
| 8685 | | // |
| 8686 | | // LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, ""); |
| 8687 | | // return nullptr; |
| 8688 | | // } |
| 8689 | | // case BuiltinFnIdMemset: |
| 8690 | | // { |
| 8691 | | // size_t fn_call_param_count = node->data.fn_call_expr.params.length; |
| 8692 | | // assert(fn_call_param_count == 3); |
| 8693 | | // |
| 8694 | | // AstNode *dest_node = node->data.fn_call_expr.params.at(0); |
| 8695 | | // TypeTableEntry *dest_type = get_expr_type(dest_node); |
| 8696 | | // |
| 8697 | | // LLVMValueRef dest_ptr = gen_expr(g, dest_node); |
| 8698 | | // LLVMValueRef char_val = gen_expr(g, node->data.fn_call_expr.params.at(1)); |
| 8699 | | // LLVMValueRef len_val = gen_expr(g, node->data.fn_call_expr.params.at(2)); |
| 8700 | | // |
| 8701 | | // LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); |
| 8702 | | // |
| 8703 | | // LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, ""); |
| 8704 | | // |
| 8705 | | // uint64_t align_in_bytes = get_memcpy_align(g, dest_type->data.pointer.child_type); |
| 8706 | | // |
| 8707 | | // LLVMValueRef params[] = { |
| 8708 | | // dest_ptr_casted, // dest pointer |
| 8709 | | // char_val, // source pointer |
| 8710 | | // len_val, // byte count |
| 8711 | | // LLVMConstInt(LLVMInt32Type(), align_in_bytes, false), // align in bytes |
| 8712 | | // LLVMConstNull(LLVMInt1Type()), // is volatile |
| 8713 | | // }; |
| 8714 | | // |
| 8715 | | // LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, ""); |
| 8716 | | // return nullptr; |
| 8717 | | // } |
| 8718 | 8997 | // case BuiltinFnIdAlignof: |
| 8719 | 8998 | // case BuiltinFnIdMinValue: |
| 8720 | 8999 | // case BuiltinFnIdMaxValue: |
| ... | ... | @@ -8789,25 +9068,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8789 | 9068 | // } |
| 8790 | 9069 | //} |
| 8791 | 9070 | // |
| 8792 | | //static LLVMValueRef gen_array_base_ptr(CodeGen *g, AstNode *node) { |
| 8793 | | // TypeTableEntry *type_entry = get_expr_type(node); |
| 8794 | | // |
| 8795 | | // LLVMValueRef array_ptr; |
| 8796 | | // if (node->type == NodeTypeFieldAccessExpr) { |
| 8797 | | // array_ptr = gen_field_access_expr(g, node, true); |
| 8798 | | // if (type_entry->id == TypeTableEntryIdPointer) { |
| 8799 | | // // we have a double pointer so we must dereference it once |
| 8800 | | // array_ptr = LLVMBuildLoad(g->builder, array_ptr, ""); |
| 8801 | | // } |
| 8802 | | // } else { |
| 8803 | | // array_ptr = gen_expr(g, node); |
| 8804 | | // } |
| 8805 | | // |
| 8806 | | // assert(!array_ptr || LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); |
| 8807 | | // |
| 8808 | | // return array_ptr; |
| 8809 | | //} |
| 8810 | | // |
| 8811 | 9071 | //static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) { |
| 8812 | 9072 | // assert(node->type == NodeTypeArrayAccessExpr); |
| 8813 | 9073 | // |
| ... | ... | @@ -8820,111 +9080,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8820 | 9080 | // return gen_array_elem_ptr(g, node, array_ptr, array_type, subscript_value); |
| 8821 | 9081 | //} |
| 8822 | 9082 | // |
| 8823 | | //static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) { |
| 8824 | | // assert(node->type == NodeTypeSliceExpr); |
| 8825 | | // |
| 8826 | | // AstNode *array_ref_node = node->data.slice_expr.array_ref_expr; |
| 8827 | | // TypeTableEntry *array_type = get_expr_type(array_ref_node); |
| 8828 | | // |
| 8829 | | // LLVMValueRef tmp_struct_ptr = node->data.slice_expr.resolved_struct_val_expr.ptr; |
| 8830 | | // LLVMValueRef array_ptr = gen_array_base_ptr(g, array_ref_node); |
| 8831 | | // |
| 8832 | | // if (array_type->id == TypeTableEntryIdArray) { |
| 8833 | | // LLVMValueRef start_val = gen_expr(g, node->data.slice_expr.start); |
| 8834 | | // LLVMValueRef end_val; |
| 8835 | | // if (node->data.slice_expr.end) { |
| 8836 | | // end_val = gen_expr(g, node->data.slice_expr.end); |
| 8837 | | // } else { |
| 8838 | | // end_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, array_type->data.array.len, false); |
| 8839 | | // } |
| 8840 | | // |
| 8841 | | // if (want_debug_safety(g, node)) { |
| 8842 | | // add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); |
| 8843 | | // if (node->data.slice_expr.end) { |
| 8844 | | // LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->type_ref, |
| 8845 | | // array_type->data.array.len, false); |
| 8846 | | // add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end); |
| 8847 | | // } |
| 8848 | | // } |
| 8849 | | // |
| 8850 | | // LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, ""); |
| 8851 | | // LLVMValueRef indices[] = { |
| 8852 | | // LLVMConstNull(g->builtin_types.entry_usize->type_ref), |
| 8853 | | // start_val, |
| 8854 | | // }; |
| 8855 | | // LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); |
| 8856 | | // LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr); |
| 8857 | | // |
| 8858 | | // LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, ""); |
| 8859 | | // LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); |
| 8860 | | // LLVMBuildStore(g->builder, len_value, len_field_ptr); |
| 8861 | | // |
| 8862 | | // return tmp_struct_ptr; |
| 8863 | | // } else if (array_type->id == TypeTableEntryIdPointer) { |
| 8864 | | // LLVMValueRef start_val = gen_expr(g, node->data.slice_expr.start); |
| 8865 | | // LLVMValueRef end_val = gen_expr(g, node->data.slice_expr.end); |
| 8866 | | // |
| 8867 | | // if (want_debug_safety(g, node)) { |
| 8868 | | // add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); |
| 8869 | | // } |
| 8870 | | // |
| 8871 | | // LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, ""); |
| 8872 | | // LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, ""); |
| 8873 | | // LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr); |
| 8874 | | // |
| 8875 | | // LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, ""); |
| 8876 | | // LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); |
| 8877 | | // LLVMBuildStore(g->builder, len_value, len_field_ptr); |
| 8878 | | // |
| 8879 | | // return tmp_struct_ptr; |
| 8880 | | // } else if (array_type->id == TypeTableEntryIdStruct) { |
| 8881 | | // assert(array_type->data.structure.is_slice); |
| 8882 | | // assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); |
| 8883 | | // assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); |
| 8884 | | // |
| 8885 | | // size_t ptr_index = array_type->data.structure.fields[0].gen_index; |
| 8886 | | // assert(ptr_index != SIZE_MAX); |
| 8887 | | // size_t len_index = array_type->data.structure.fields[1].gen_index; |
| 8888 | | // assert(len_index != SIZE_MAX); |
| 8889 | | // |
| 8890 | | // LLVMValueRef prev_end = nullptr; |
| 8891 | | // if (!node->data.slice_expr.end || want_debug_safety(g, node)) { |
| 8892 | | // LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, len_index, ""); |
| 8893 | | // prev_end = LLVMBuildLoad(g->builder, src_len_ptr, ""); |
| 8894 | | // } |
| 8895 | | // |
| 8896 | | // LLVMValueRef start_val = gen_expr(g, node->data.slice_expr.start); |
| 8897 | | // LLVMValueRef end_val; |
| 8898 | | // if (node->data.slice_expr.end) { |
| 8899 | | // end_val = gen_expr(g, node->data.slice_expr.end); |
| 8900 | | // } else { |
| 8901 | | // end_val = prev_end; |
| 8902 | | // } |
| 8903 | | // |
| 8904 | | // if (want_debug_safety(g, node)) { |
| 8905 | | // assert(prev_end); |
| 8906 | | // add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); |
| 8907 | | // if (node->data.slice_expr.end) { |
| 8908 | | // add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, prev_end); |
| 8909 | | // } |
| 8910 | | // } |
| 8911 | | // |
| 8912 | | // LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, ptr_index, ""); |
| 8913 | | // LLVMValueRef src_ptr = LLVMBuildLoad(g->builder, src_ptr_ptr, ""); |
| 8914 | | // LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, ptr_index, ""); |
| 8915 | | // LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, len_index, ""); |
| 8916 | | // LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr); |
| 8917 | | // |
| 8918 | | // LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, len_index, ""); |
| 8919 | | // LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); |
| 8920 | | // LLVMBuildStore(g->builder, len_value, len_field_ptr); |
| 8921 | | // |
| 8922 | | // return tmp_struct_ptr; |
| 8923 | | // } else { |
| 8924 | | // zig_unreachable(); |
| 8925 | | // } |
| 8926 | | //} |
| 8927 | | // |
| 8928 | 9083 | //static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) { |
| 8929 | 9084 | // assert(node->type == NodeTypeUnwrapErrorExpr); |
| 8930 | 9085 | // |