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