authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-19 01:39:51-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-19 01:39:51-05:00
log8a81f8aa1388331624e4c073e2534d3a987a7d9a
tree9bb160113429cf46e40cca3ea17337edfccdb974
parent19037014e5a25eaac9564d22cc04cf12fb6ef98e

IR: implement compileVar builtin and more

* implicit array to slice cast * fix if statements at global scope * implement array type IR

7 files changed, 357 insertions(+), 416 deletions(-)

src/all_types.hpp+7
...@@ -1451,6 +1451,7 @@ enum IrInstructionId {...@@ -1451,6 +1451,7 @@ enum IrInstructionId {
1451 IrInstructionIdArrayType,1451 IrInstructionIdArrayType,
1452 IrInstructionIdSliceType,1452 IrInstructionIdSliceType,
1453 IrInstructionIdAsm,1453 IrInstructionIdAsm,
1454 IrInstructionIdCompileVar,
1454};1455};
14551456
1456struct IrInstruction {1457struct IrInstruction {
...@@ -1735,6 +1736,12 @@ struct IrInstructionAsm {...@@ -1735,6 +1736,12 @@ struct IrInstructionAsm {
1735 bool has_side_effects;1736 bool has_side_effects;
1736};1737};
17371738
1739struct IrInstructionCompileVar {
1740 IrInstruction base;
1741
1742 IrInstruction *name;
1743};
1744
1738enum LValPurpose {1745enum LValPurpose {
1739 LValPurposeNone,1746 LValPurposeNone,
1740 LValPurposeAssign,1747 LValPurposeAssign,
src/analyze.cpp+2-12
...@@ -869,12 +869,9 @@ static IrInstruction *analyze_const_value(CodeGen *g, BlockContext *scope, AstNo...@@ -869,12 +869,9 @@ static IrInstruction *analyze_const_value(CodeGen *g, BlockContext *scope, AstNo
869 return result;869 return result;
870}870}
871871
872static TypeTableEntry *analyze_type_expr_pointer_only(CodeGen *g, ImportTableEntry *import,872static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
873 BlockContext *context, AstNode *node, bool pointer_only)873 AstNode *node)
874{874{
875 if (pointer_only)
876 zig_panic("TODO");
877
878 IrInstruction *result = analyze_const_value(g, context, node, g->builtin_types.entry_type);875 IrInstruction *result = analyze_const_value(g, context, node, g->builtin_types.entry_type);
879 if (result->type_entry->id == TypeTableEntryIdInvalid)876 if (result->type_entry->id == TypeTableEntryIdInvalid)
880 return g->builtin_types.entry_invalid;877 return g->builtin_types.entry_invalid;
...@@ -883,13 +880,6 @@ static TypeTableEntry *analyze_type_expr_pointer_only(CodeGen *g, ImportTableEnt...@@ -883,13 +880,6 @@ static TypeTableEntry *analyze_type_expr_pointer_only(CodeGen *g, ImportTableEnt
883 return result->static_value.data.x_type;880 return result->static_value.data.x_type;
884}881}
885882
886// Calls analyze_expression on node, and then resolve_type.
887static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
888 AstNode *node)
889{
890 return analyze_type_expr_pointer_only(g, import, context, node, false);
891}
892
893static bool fn_wants_full_static_eval(FnTableEntry *fn_table_entry) {883static bool fn_wants_full_static_eval(FnTableEntry *fn_table_entry) {
894 assert(fn_table_entry);884 assert(fn_table_entry);
895 AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto;885 AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto;
src/ast_render.cpp+1-1
...@@ -696,7 +696,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -696,7 +696,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
696 fprintf(ar->f, ") ");696 fprintf(ar->f, ") ");
697 render_node_grouped(ar, node->data.if_bool_expr.then_block);697 render_node_grouped(ar, node->data.if_bool_expr.then_block);
698 if (node->data.if_bool_expr.else_node) {698 if (node->data.if_bool_expr.else_node) {
699 fprintf(ar->f, "else ");699 fprintf(ar->f, " else ");
700 render_node_grouped(ar, node->data.if_bool_expr.else_node);700 render_node_grouped(ar, node->data.if_bool_expr.else_node);
701 }701 }
702 break;702 break;
src/codegen.cpp+5-246
...@@ -526,240 +526,6 @@ static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddS...@@ -526,240 +526,6 @@ static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddS
526 return result;526 return result;
527}527}
528528
529static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
530 LLVMValueRef val1, LLVMValueRef val2)
531{
532 // for unsigned left shifting, we do the wrapping shift, then logically shift
533 // right the same number of bits
534 // if the values don't match, we have an overflow
535 // for signed left shifting we do the same except arithmetic shift right
536
537 assert(type_entry->id == TypeTableEntryIdInt);
538
539 LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, "");
540 LLVMValueRef orig_val;
541 if (type_entry->data.integral.is_signed) {
542 orig_val = LLVMBuildAShr(g->builder, result, val2, "");
543 } else {
544 orig_val = LLVMBuildLShr(g->builder, result, val2, "");
545 }
546 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, "");
547
548 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk");
549 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail");
550 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
551
552 LLVMPositionBuilderAtEnd(g->builder, fail_block);
553 gen_debug_safety_crash(g);
554
555 LLVMPositionBuilderAtEnd(g->builder, ok_block);
556 return result;
557}
558
559static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, LLVMValueRef val2,
560 TypeTableEntry *type_entry, bool exact)
561{
562
563 if (want_debug_safety(g, source_node)) {
564 LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
565 LLVMValueRef is_zero_bit;
566 if (type_entry->id == TypeTableEntryIdInt) {
567 is_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, zero, "");
568 } else if (type_entry->id == TypeTableEntryIdFloat) {
569 is_zero_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, val2, zero, "");
570 } else {
571 zig_unreachable();
572 }
573 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroOk");
574 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroFail");
575 LLVMBuildCondBr(g->builder, is_zero_bit, fail_block, ok_block);
576
577 LLVMPositionBuilderAtEnd(g->builder, fail_block);
578 gen_debug_safety_crash(g);
579
580 LLVMPositionBuilderAtEnd(g->builder, ok_block);
581 }
582
583 if (type_entry->id == TypeTableEntryIdFloat) {
584 assert(!exact);
585 return LLVMBuildFDiv(g->builder, val1, val2, "");
586 }
587
588 assert(type_entry->id == TypeTableEntryIdInt);
589
590 if (exact) {
591 if (want_debug_safety(g, source_node)) {
592 LLVMValueRef remainder_val;
593 if (type_entry->data.integral.is_signed) {
594 remainder_val = LLVMBuildSRem(g->builder, val1, val2, "");
595 } else {
596 remainder_val = LLVMBuildURem(g->builder, val1, val2, "");
597 }
598 LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
599 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
600
601 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactOk");
602 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactFail");
603 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
604
605 LLVMPositionBuilderAtEnd(g->builder, fail_block);
606 gen_debug_safety_crash(g);
607
608 LLVMPositionBuilderAtEnd(g->builder, ok_block);
609 }
610 if (type_entry->data.integral.is_signed) {
611 return LLVMBuildExactSDiv(g->builder, val1, val2, "");
612 } else {
613 return ZigLLVMBuildExactUDiv(g->builder, val1, val2, "");
614 }
615 } else {
616 if (type_entry->data.integral.is_signed) {
617 return LLVMBuildSDiv(g->builder, val1, val2, "");
618 } else {
619 return LLVMBuildUDiv(g->builder, val1, val2, "");
620 }
621 }
622}
623
624static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
625 LLVMValueRef val1, LLVMValueRef val2,
626 TypeTableEntry *op1_type, TypeTableEntry *op2_type,
627 BinOpType bin_op)
628{
629 assert(op1_type == op2_type);
630
631 switch (bin_op) {
632 case BinOpTypeBinOr:
633 case BinOpTypeAssignBitOr:
634 return LLVMBuildOr(g->builder, val1, val2, "");
635 case BinOpTypeBinXor:
636 case BinOpTypeAssignBitXor:
637 return LLVMBuildXor(g->builder, val1, val2, "");
638 case BinOpTypeBinAnd:
639 case BinOpTypeAssignBitAnd:
640 return LLVMBuildAnd(g->builder, val1, val2, "");
641 case BinOpTypeBitShiftLeft:
642 case BinOpTypeBitShiftLeftWrap:
643 case BinOpTypeAssignBitShiftLeft:
644 case BinOpTypeAssignBitShiftLeftWrap:
645 {
646 assert(op1_type->id == TypeTableEntryIdInt);
647 bool is_wrapping = (bin_op == BinOpTypeBitShiftLeftWrap) ||
648 (bin_op == BinOpTypeAssignBitShiftLeftWrap);
649 if (is_wrapping) {
650 return LLVMBuildShl(g->builder, val1, val2, "");
651 } else if (want_debug_safety(g, source_node)) {
652 return gen_overflow_shl_op(g, op1_type, val1, val2);
653 } else if (op1_type->data.integral.is_signed) {
654 return ZigLLVMBuildNSWShl(g->builder, val1, val2, "");
655 } else {
656 return ZigLLVMBuildNUWShl(g->builder, val1, val2, "");
657 }
658 }
659 case BinOpTypeBitShiftRight:
660 case BinOpTypeAssignBitShiftRight:
661 assert(op1_type->id == TypeTableEntryIdInt);
662 assert(op2_type->id == TypeTableEntryIdInt);
663
664 if (op1_type->data.integral.is_signed) {
665 return LLVMBuildAShr(g->builder, val1, val2, "");
666 } else {
667 return LLVMBuildLShr(g->builder, val1, val2, "");
668 }
669 case BinOpTypeAdd:
670 case BinOpTypeAddWrap:
671 case BinOpTypeAssignPlus:
672 case BinOpTypeAssignPlusWrap:
673 if (op1_type->id == TypeTableEntryIdFloat) {
674 return LLVMBuildFAdd(g->builder, val1, val2, "");
675 } else if (op1_type->id == TypeTableEntryIdInt) {
676 bool is_wrapping = (bin_op == BinOpTypeAddWrap) || (bin_op == BinOpTypeAssignPlusWrap);
677 if (is_wrapping) {
678 return LLVMBuildAdd(g->builder, val1, val2, "");
679 } else if (want_debug_safety(g, source_node)) {
680 return gen_overflow_op(g, op1_type, AddSubMulAdd, val1, val2);
681 } else if (op1_type->data.integral.is_signed) {
682 return LLVMBuildNSWAdd(g->builder, val1, val2, "");
683 } else {
684 return LLVMBuildNUWAdd(g->builder, val1, val2, "");
685 }
686 } else {
687 zig_unreachable();
688 }
689 case BinOpTypeSub:
690 case BinOpTypeSubWrap:
691 case BinOpTypeAssignMinus:
692 case BinOpTypeAssignMinusWrap:
693 if (op1_type->id == TypeTableEntryIdFloat) {
694 return LLVMBuildFSub(g->builder, val1, val2, "");
695 } else if (op1_type->id == TypeTableEntryIdInt) {
696 bool is_wrapping = (bin_op == BinOpTypeSubWrap || bin_op == BinOpTypeAssignMinusWrap);
697 if (is_wrapping) {
698 return LLVMBuildSub(g->builder, val1, val2, "");
699 } else if (want_debug_safety(g, source_node)) {
700 return gen_overflow_op(g, op1_type, AddSubMulSub, val1, val2);
701 } else if (op1_type->data.integral.is_signed) {
702 return LLVMBuildNSWSub(g->builder, val1, val2, "");
703 } else {
704 return LLVMBuildNUWSub(g->builder, val1, val2, "");
705 }
706 } else {
707 zig_unreachable();
708 }
709 case BinOpTypeMult:
710 case BinOpTypeMultWrap:
711 case BinOpTypeAssignTimes:
712 case BinOpTypeAssignTimesWrap:
713 if (op1_type->id == TypeTableEntryIdFloat) {
714 return LLVMBuildFMul(g->builder, val1, val2, "");
715 } else if (op1_type->id == TypeTableEntryIdInt) {
716 bool is_wrapping = (bin_op == BinOpTypeMultWrap || bin_op == BinOpTypeAssignTimesWrap);
717 if (is_wrapping) {
718 return LLVMBuildMul(g->builder, val1, val2, "");
719 } else if (want_debug_safety(g, source_node)) {
720 return gen_overflow_op(g, op1_type, AddSubMulMul, val1, val2);
721 } else if (op1_type->data.integral.is_signed) {
722 return LLVMBuildNSWMul(g->builder, val1, val2, "");
723 } else {
724 return LLVMBuildNUWMul(g->builder, val1, val2, "");
725 }
726 } else {
727 zig_unreachable();
728 }
729 case BinOpTypeDiv:
730 case BinOpTypeAssignDiv:
731 return gen_div(g, source_node, val1, val2, op1_type, false);
732 case BinOpTypeMod:
733 case BinOpTypeAssignMod:
734 if (op1_type->id == TypeTableEntryIdFloat) {
735 return LLVMBuildFRem(g->builder, val1, val2, "");
736 } else {
737 assert(op1_type->id == TypeTableEntryIdInt);
738 if (op1_type->data.integral.is_signed) {
739 return LLVMBuildSRem(g->builder, val1, val2, "");
740 } else {
741 return LLVMBuildURem(g->builder, val1, val2, "");
742 }
743 }
744 case BinOpTypeBoolOr:
745 case BinOpTypeBoolAnd:
746 case BinOpTypeCmpEq:
747 case BinOpTypeCmpNotEq:
748 case BinOpTypeCmpLessThan:
749 case BinOpTypeCmpGreaterThan:
750 case BinOpTypeCmpLessOrEq:
751 case BinOpTypeCmpGreaterOrEq:
752 case BinOpTypeInvalid:
753 case BinOpTypeAssign:
754 case BinOpTypeAssignBoolAnd:
755 case BinOpTypeAssignBoolOr:
756 case BinOpTypeUnwrapMaybe:
757 case BinOpTypeArrayCat:
758 case BinOpTypeArrayMult:
759 zig_unreachable();
760 }
761 zig_unreachable();
762}
763static LLVMIntPredicate cmp_op_to_int_predicate(IrBinOp cmp_op, bool is_signed) {529static LLVMIntPredicate cmp_op_to_int_predicate(IrBinOp cmp_op, bool is_signed) {
764 switch (cmp_op) {530 switch (cmp_op) {
765 case IrBinOpCmpEq:531 case IrBinOpCmpEq:
...@@ -825,7 +591,7 @@ static LLVMValueRef gen_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef...@@ -825,7 +591,7 @@ static LLVMValueRef gen_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef
825 return LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");591 return LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");
826}592}
827593
828static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op,594static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node,
829 LLVMValueRef target_ref, LLVMValueRef value,595 LLVMValueRef target_ref, LLVMValueRef value,
830 TypeTableEntry *op1_type, TypeTableEntry *op2_type)596 TypeTableEntry *op1_type, TypeTableEntry *op2_type)
831{597{
...@@ -834,18 +600,10 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b...@@ -834,18 +600,10 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b
834 }600 }
835 if (handle_is_ptr(op1_type)) {601 if (handle_is_ptr(op1_type)) {
836 assert(op1_type == op2_type);602 assert(op1_type == op2_type);
837 assert(bin_op == BinOpTypeAssign);
838603
839 return gen_struct_memcpy(g, value, target_ref, op1_type);604 return gen_struct_memcpy(g, value, target_ref, op1_type);
840 }605 }
841606
842 if (bin_op != BinOpTypeAssign) {
843 assert(source_node->type == NodeTypeBinOpExpr);
844 LLVMValueRef left_value = LLVMBuildLoad(g->builder, target_ref, "");
845
846 value = gen_arithmetic_bin_op(g, source_node, left_value, value, op1_type, op2_type, bin_op);
847 }
848
849 LLVMBuildStore(g->builder, value, target_ref);607 LLVMBuildStore(g->builder, value, target_ref);
850 return nullptr;608 return nullptr;
851}609}
...@@ -1036,7 +794,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,...@@ -1036,7 +794,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
1036 return expr_val;794 return expr_val;
1037 } else {795 } else {
1038 LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 0, "");796 LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 0, "");
1039 gen_assign_raw(g, cast_instruction->base.source_node, BinOpTypeAssign,797 gen_assign_raw(g, cast_instruction->base.source_node,
1040 val_ptr, expr_val, child_type, actual_type);798 val_ptr, expr_val, child_type, actual_type);
1041799
1042 LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 1, "");800 LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 1, "");
...@@ -1065,7 +823,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,...@@ -1065,7 +823,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
1065 LLVMBuildStore(g->builder, ok_err_val, err_tag_ptr);823 LLVMBuildStore(g->builder, ok_err_val, err_tag_ptr);
1066824
1067 LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 1, "");825 LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 1, "");
1068 gen_assign_raw(g, cast_instruction->base.source_node, BinOpTypeAssign,826 gen_assign_raw(g, cast_instruction->base.source_node,
1069 payload_ptr, expr_val, child_type, actual_type);827 payload_ptr, expr_val, child_type, actual_type);
1070828
1071 return cast_instruction->tmp_ptr;829 return cast_instruction->tmp_ptr;
...@@ -1414,7 +1172,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,...@@ -1414,7 +1172,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
1414 want_zeroes = true;1172 want_zeroes = true;
14151173
1416 if (have_init_expr) {1174 if (have_init_expr) {
1417 gen_assign_raw(g, init_value->source_node, BinOpTypeAssign, var->value_ref,1175 gen_assign_raw(g, init_value->source_node, var->value_ref,
1418 ir_llvm_value(g, init_value), var->type, init_value->type_entry);1176 ir_llvm_value(g, init_value), var->type, init_value->type_entry);
1419 } else {1177 } else {
1420 bool ignore_uninit = false;1178 bool ignore_uninit = false;
...@@ -1685,6 +1443,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -1685,6 +1443,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
1685 case IrInstructionIdSetDebugSafety:1443 case IrInstructionIdSetDebugSafety:
1686 case IrInstructionIdArrayType:1444 case IrInstructionIdArrayType:
1687 case IrInstructionIdSliceType:1445 case IrInstructionIdSliceType:
1446 case IrInstructionIdCompileVar:
1688 zig_unreachable();1447 zig_unreachable();
1689 case IrInstructionIdReturn:1448 case IrInstructionIdReturn:
1690 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);1449 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
src/eval.cpp+17-2
...@@ -318,8 +318,23 @@ void eval_const_expr_implicit_cast(CastOp cast_op,...@@ -318,8 +318,23 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
318 // can't do it318 // can't do it
319 break;319 break;
320 case CastOpToUnknownSizeArray:320 case CastOpToUnknownSizeArray:
321 zig_panic("TODO compile time implicit to unknown size array");321 {
322 break;322 assert(other_type->id == TypeTableEntryIdArray);
323 assert(other_val->data.x_array.size == other_type->data.array.len);
324
325 const_val->data.x_struct.fields = allocate<ConstExprValue>(2);
326 ConstExprValue *ptr_field = &const_val->data.x_struct.fields[slice_ptr_index];
327 ConstExprValue *len_field = &const_val->data.x_struct.fields[slice_len_index];
328
329 ptr_field->special = ConstValSpecialStatic;
330 ptr_field->data.x_ptr.base_ptr = other_val;
331
332 len_field->special = ConstValSpecialStatic;
333 bignum_init_unsigned(&len_field->data.x_bignum, other_type->data.array.len);
334
335 const_val->special = ConstValSpecialStatic;
336 break;
337 }
323 case CastOpMaybeWrap:338 case CastOpMaybeWrap:
324 const_val->data.x_maybe = other_val;339 const_val->data.x_maybe = other_val;
325 const_val->special = ConstValSpecialStatic;340 const_val->special = ConstValSpecialStatic;
src/ir.cpp+316-155
...@@ -218,6 +218,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAsm *) {...@@ -218,6 +218,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAsm *) {
218 return IrInstructionIdAsm;218 return IrInstructionIdAsm;
219}219}
220220
221static constexpr IrInstructionId ir_instruction_id(IrInstructionCompileVar *) {
222 return IrInstructionIdCompileVar;
223}
224
221template<typename T>225template<typename T>
222static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) {226static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) {
223 T *special_instruction = allocate<T>(1);227 T *special_instruction = allocate<T>(1);
...@@ -507,14 +511,6 @@ static IrInstruction *ir_build_field_ptr(IrBuilder *irb, AstNode *source_node,...@@ -507,14 +511,6 @@ static IrInstruction *ir_build_field_ptr(IrBuilder *irb, AstNode *source_node,
507 return &instruction->base;511 return &instruction->base;
508}512}
509513
510//static IrInstruction *ir_build_field_ptr_from(IrBuilder *irb, IrInstruction *old_instruction,
511// IrInstruction *container_ptr, Buf *field_name)
512//{
513// IrInstruction *new_instruction = ir_build_field_ptr(irb, old_instruction->source_node, container_ptr, field_name);
514// ir_link_new_instruction(new_instruction, old_instruction);
515// return new_instruction;
516//}
517
518static IrInstruction *ir_build_read_field(IrBuilder *irb, AstNode *source_node,514static IrInstruction *ir_build_read_field(IrBuilder *irb, AstNode *source_node,
519 IrInstruction *container_ptr, Buf *field_name)515 IrInstruction *container_ptr, Buf *field_name)
520{516{
...@@ -527,14 +523,6 @@ static IrInstruction *ir_build_read_field(IrBuilder *irb, AstNode *source_node,...@@ -527,14 +523,6 @@ static IrInstruction *ir_build_read_field(IrBuilder *irb, AstNode *source_node,
527 return &instruction->base;523 return &instruction->base;
528}524}
529525
530//static IrInstruction *ir_build_read_field_from(IrBuilder *irb, IrInstruction *old_instruction,
531// IrInstruction *container_ptr, Buf *field_name)
532//{
533// IrInstruction *new_instruction = ir_build_read_field(irb, old_instruction->source_node, container_ptr, field_name);
534// ir_link_new_instruction(new_instruction, old_instruction);
535// return new_instruction;
536//}
537
538static IrInstruction *ir_build_struct_field_ptr(IrBuilder *irb, AstNode *source_node,526static IrInstruction *ir_build_struct_field_ptr(IrBuilder *irb, AstNode *source_node,
539 IrInstruction *struct_ptr, TypeStructField *field)527 IrInstruction *struct_ptr, TypeStructField *field)
540{528{
...@@ -861,6 +849,15 @@ static IrInstruction *ir_build_asm_from(IrBuilder *irb, IrInstruction *old_instr...@@ -861,6 +849,15 @@ static IrInstruction *ir_build_asm_from(IrBuilder *irb, IrInstruction *old_instr
861 return new_instruction;849 return new_instruction;
862}850}
863851
852static IrInstruction *ir_build_compile_var(IrBuilder *irb, AstNode *source_node, IrInstruction *name) {
853 IrInstructionCompileVar *instruction = ir_build_instruction<IrInstructionCompileVar>(irb, source_node);
854 instruction->name = name;
855
856 ir_ref_instruction(name);
857
858 return &instruction->base;
859}
860
864static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block,861static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block,
865 bool gen_error_defers, bool gen_maybe_defers)862 bool gen_error_defers, bool gen_maybe_defers)
866{863{
...@@ -1336,6 +1333,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {...@@ -1336,6 +1333,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {
13361333
1337 return ir_build_set_debug_safety(irb, node, arg0_value, arg1_value);1334 return ir_build_set_debug_safety(irb, node, arg0_value, arg1_value);
1338 }1335 }
1336 case BuiltinFnIdCompileVar:
1337 {
1338 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
1339 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, node->block_context);
1340 if (arg0_value == irb->codegen->invalid_instruction)
1341 return arg0_value;
1342
1343 return ir_build_compile_var(irb, node, arg0_value);
1344 }
1339 case BuiltinFnIdMemcpy:1345 case BuiltinFnIdMemcpy:
1340 case BuiltinFnIdMemset:1346 case BuiltinFnIdMemset:
1341 case BuiltinFnIdSizeof:1347 case BuiltinFnIdSizeof:
...@@ -1350,7 +1356,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {...@@ -1350,7 +1356,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {
1350 case BuiltinFnIdCInclude:1356 case BuiltinFnIdCInclude:
1351 case BuiltinFnIdCDefine:1357 case BuiltinFnIdCDefine:
1352 case BuiltinFnIdCUndef:1358 case BuiltinFnIdCUndef:
1353 case BuiltinFnIdCompileVar:
1354 case BuiltinFnIdCompileErr:1359 case BuiltinFnIdCompileErr:
1355 case BuiltinFnIdConstEval:1360 case BuiltinFnIdConstEval:
1356 case BuiltinFnIdCtz:1361 case BuiltinFnIdCtz:
...@@ -1410,14 +1415,15 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, AstNode *node) {...@@ -1410,14 +1415,15 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, AstNode *node) {
1410 IrBasicBlock *else_block = ir_build_basic_block(irb, "Else");1415 IrBasicBlock *else_block = ir_build_basic_block(irb, "Else");
1411 IrBasicBlock *endif_block = ir_build_basic_block(irb, "EndIf");1416 IrBasicBlock *endif_block = ir_build_basic_block(irb, "EndIf");
14121417
1413 ir_build_cond_br(irb, condition->source_node, condition, then_block, else_block, false);1418 bool is_inline = (node->block_context->fn_entry == nullptr);
1419 ir_build_cond_br(irb, condition->source_node, condition, then_block, else_block, is_inline);
14141420
1415 ir_set_cursor_at_end(irb, then_block);1421 ir_set_cursor_at_end(irb, then_block);
1416 IrInstruction *then_expr_result = ir_gen_node(irb, then_node, node->block_context);1422 IrInstruction *then_expr_result = ir_gen_node(irb, then_node, node->block_context);
1417 if (then_expr_result == irb->codegen->invalid_instruction)1423 if (then_expr_result == irb->codegen->invalid_instruction)
1418 return then_expr_result;1424 return then_expr_result;
1419 IrBasicBlock *after_then_block = irb->current_basic_block;1425 IrBasicBlock *after_then_block = irb->current_basic_block;
1420 ir_build_br(irb, node, endif_block, false);1426 ir_build_br(irb, node, endif_block, is_inline);
14211427
1422 ir_set_cursor_at_end(irb, else_block);1428 ir_set_cursor_at_end(irb, else_block);
1423 IrInstruction *else_expr_result;1429 IrInstruction *else_expr_result;
...@@ -1429,7 +1435,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, AstNode *node) {...@@ -1429,7 +1435,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, AstNode *node) {
1429 else_expr_result = ir_build_const_void(irb, node);1435 else_expr_result = ir_build_const_void(irb, node);
1430 }1436 }
1431 IrBasicBlock *after_else_block = irb->current_basic_block;1437 IrBasicBlock *after_else_block = irb->current_basic_block;
1432 ir_build_br(irb, node, endif_block, false);1438 ir_build_br(irb, node, endif_block, is_inline);
14331439
1434 ir_set_cursor_at_end(irb, endif_block);1440 ir_set_cursor_at_end(irb, endif_block);
1435 IrInstruction **incoming_values = allocate<IrInstruction *>(2);1441 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
...@@ -2281,7 +2287,19 @@ static TypeTableEntry *ir_analyze_const_usize(IrAnalyze *ira, IrInstruction *ins...@@ -2281,7 +2287,19 @@ static TypeTableEntry *ir_analyze_const_usize(IrAnalyze *ira, IrInstruction *ins
2281 return ira->codegen->builtin_types.entry_usize;2287 return ira->codegen->builtin_types.entry_usize;
2282}2288}
22832289
2284static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) {2290static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value) {
2291 if (value->static_value.special != ConstValSpecialStatic) {
2292 add_node_error(ira->codegen, value->source_node,
2293 buf_sprintf("unable to evaluate constant expression"));
2294 return nullptr;
2295 }
2296 return &value->static_value;
2297}
2298
2299static TypeTableEntry *ir_resolve_type_lval(IrAnalyze *ira, IrInstruction *type_value, LValPurpose lval) {
2300 if (lval != LValPurposeNone)
2301 zig_panic("TODO");
2302
2285 if (type_value == ira->codegen->invalid_instruction)2303 if (type_value == ira->codegen->invalid_instruction)
2286 return ira->codegen->builtin_types.entry_invalid;2304 return ira->codegen->builtin_types.entry_invalid;
22872305
...@@ -2294,44 +2312,15 @@ static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value...@@ -2294,44 +2312,15 @@ static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value
2294 return ira->codegen->builtin_types.entry_invalid;2312 return ira->codegen->builtin_types.entry_invalid;
2295 }2313 }
22962314
2297 ConstExprValue *const_val = &type_value->static_value;2315 ConstExprValue *const_val = ir_resolve_const(ira, type_value);
2298 if (const_val->special == ConstValSpecialRuntime) {2316 if (!const_val)
2299 add_node_error(ira->codegen, type_value->source_node,
2300 buf_sprintf("unable to evaluate constant expression"));
2301 return ira->codegen->builtin_types.entry_invalid;2317 return ira->codegen->builtin_types.entry_invalid;
2302 }
23032318
2304 return const_val->data.x_type;2319 return const_val->data.x_type;
2305}2320}
23062321
2307static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value) {2322static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) {
2308 if (value->static_value.special != ConstValSpecialStatic) {2323 return ir_resolve_type_lval(ira, type_value, LValPurposeNone);
2309 add_node_error(ira->codegen, value->source_node,
2310 buf_sprintf("unable to evaluate constant expression"));
2311 return nullptr;
2312 }
2313 return &value->static_value;
2314}
2315
2316static bool ir_resolve_bool(IrAnalyze *ira, IrInstruction *bool_value, bool *out) {
2317 if (bool_value == ira->codegen->invalid_instruction)
2318 return false;
2319
2320 if (bool_value->type_entry->id == TypeTableEntryIdInvalid)
2321 return false;
2322
2323 if (bool_value->type_entry->id != TypeTableEntryIdBool) {
2324 add_node_error(ira->codegen, bool_value->source_node,
2325 buf_sprintf("expected type 'bool', found '%s'", buf_ptr(&bool_value->type_entry->name)));
2326 return false;
2327 }
2328
2329 ConstExprValue *const_val = ir_resolve_const(ira, bool_value);
2330 if (!const_val)
2331 return false;
2332
2333 *out = const_val->data.x_bool;
2334 return true;
2335}2324}
23362325
2337static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {2326static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {
...@@ -2347,12 +2336,9 @@ static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {...@@ -2347,12 +2336,9 @@ static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {
2347 return nullptr;2336 return nullptr;
2348 }2337 }
23492338
2350 ConstExprValue *const_val = &fn_value->static_value;2339 ConstExprValue *const_val = ir_resolve_const(ira, fn_value);
2351 if (const_val->special == ConstValSpecialRuntime) {2340 if (!const_val)
2352 add_node_error(ira->codegen, fn_value->source_node,
2353 buf_sprintf("unable to evaluate constant expression"));
2354 return nullptr;2341 return nullptr;
2355 }
23562342
2357 return const_val->data.x_fn;2343 return const_val->data.x_fn;
2358}2344}
...@@ -2654,6 +2640,69 @@ static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value,...@@ -2654,6 +2640,69 @@ static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value,
2654 zig_unreachable();2640 zig_unreachable();
2655}2641}
26562642
2643static bool ir_resolve_usize(IrAnalyze *ira, IrInstruction *value, uint64_t *out) {
2644 if (value->type_entry->id == TypeTableEntryIdInvalid)
2645 return false;
2646
2647 IrInstruction *casted_value = ir_get_casted_value(ira, value, ira->codegen->builtin_types.entry_usize);
2648 if (casted_value->type_entry->id == TypeTableEntryIdInvalid)
2649 return false;
2650
2651 ConstExprValue *const_val = ir_resolve_const(ira, casted_value);
2652 if (!const_val)
2653 return false;
2654
2655 *out = const_val->data.x_bignum.data.x_uint;
2656 return true;
2657}
2658
2659static bool ir_resolve_bool(IrAnalyze *ira, IrInstruction *value, bool *out) {
2660 if (value->type_entry->id == TypeTableEntryIdInvalid)
2661 return false;
2662
2663 IrInstruction *casted_value = ir_get_casted_value(ira, value, ira->codegen->builtin_types.entry_bool);
2664 if (casted_value->type_entry->id == TypeTableEntryIdInvalid)
2665 return false;
2666
2667 ConstExprValue *const_val = ir_resolve_const(ira, casted_value);
2668 if (!const_val)
2669 return false;
2670
2671 *out = const_val->data.x_bool;
2672 return true;
2673}
2674
2675static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {
2676 if (value->type_entry->id == TypeTableEntryIdInvalid)
2677 return nullptr;
2678
2679 TypeTableEntry *str_type = get_slice_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
2680 IrInstruction *casted_value = ir_get_casted_value(ira, value, str_type);
2681 if (casted_value->type_entry->id == TypeTableEntryIdInvalid)
2682 return nullptr;
2683
2684 ConstExprValue *const_val = ir_resolve_const(ira, casted_value);
2685 if (!const_val)
2686 return nullptr;
2687
2688 ConstExprValue *ptr_field = &const_val->data.x_struct.fields[slice_ptr_index];
2689 ConstExprValue *len_field = &const_val->data.x_struct.fields[slice_len_index];
2690 ConstExprValue *array_val = ptr_field->data.x_ptr.base_ptr;
2691 assert(ptr_field->data.x_ptr.index != SIZE_MAX);
2692 size_t len = len_field->data.x_bignum.data.x_uint;
2693 Buf *result = buf_alloc();
2694 buf_resize(result, len);
2695 for (size_t i = 0; i < len; i += 1) {
2696 size_t new_index = ptr_field->data.x_ptr.index + i;
2697 ConstExprValue *char_val = &array_val->data.x_array.elements[new_index];
2698 uint64_t big_c = char_val->data.x_bignum.data.x_uint;
2699 assert(big_c <= UINT8_MAX);
2700 uint8_t c = big_c;
2701 buf_ptr(result)[i] = c;
2702 }
2703 return result;
2704}
2705
2657static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,2706static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,
2658 IrInstructionReturn *return_instruction)2707 IrInstructionReturn *return_instruction)
2659{2708{
...@@ -3528,29 +3577,33 @@ static TypeTableEntry *ir_analyze_instruction_br(IrAnalyze *ira, IrInstructionBr...@@ -3528,29 +3577,33 @@ static TypeTableEntry *ir_analyze_instruction_br(IrAnalyze *ira, IrInstructionBr
3528}3577}
35293578
3530static TypeTableEntry *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructionCondBr *cond_br_instruction) {3579static TypeTableEntry *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructionCondBr *cond_br_instruction) {
3531 TypeTableEntry *bool_type = ira->codegen->builtin_types.entry_bool;3580 IrInstruction *condition = cond_br_instruction->condition->other;
3532 IrInstruction *condition = ir_get_casted_value(ira, cond_br_instruction->condition->other, bool_type);
3533 if (condition == ira->codegen->invalid_instruction)
3534 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
35353581
3536 // TODO detect backward jumps3582 // TODO detect backward jumps
3537 if (condition->static_value.special != ConstValSpecialRuntime) {3583
3538 IrBasicBlock *old_dest_block = condition->static_value.data.x_bool ?3584 if (cond_br_instruction->is_inline || condition->static_value.special != ConstValSpecialRuntime) {
3585 bool cond_is_true;
3586 if (!ir_resolve_bool(ira, condition, &cond_is_true))
3587 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
3588
3589 IrBasicBlock *old_dest_block = cond_is_true ?
3539 cond_br_instruction->then_block : cond_br_instruction->else_block;3590 cond_br_instruction->then_block : cond_br_instruction->else_block;
35403591
3541 if (cond_br_instruction->is_inline || old_dest_block->ref_count == 1) {3592 if (cond_br_instruction->is_inline || old_dest_block->ref_count == 1) {
3542 ir_inline_bb(ira, old_dest_block);3593 ir_inline_bb(ira, old_dest_block);
3543 return ira->codegen->builtin_types.entry_unreachable;3594 return ira->codegen->builtin_types.entry_unreachable;
3544 }3595 }
3545 } else if (cond_br_instruction->is_inline) {
3546 add_node_error(ira->codegen, condition->source_node,
3547 buf_sprintf("unable to evaluate constant expression"));
3548 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
3549 }3596 }
35503597
3598 TypeTableEntry *bool_type = ira->codegen->builtin_types.entry_bool;
3599 IrInstruction *casted_condition = ir_get_casted_value(ira, condition, bool_type);
3600 if (casted_condition == ira->codegen->invalid_instruction)
3601 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
3602
3551 IrBasicBlock *new_then_block = ir_get_new_bb(ira, cond_br_instruction->then_block);3603 IrBasicBlock *new_then_block = ir_get_new_bb(ira, cond_br_instruction->then_block);
3552 IrBasicBlock *new_else_block = ir_get_new_bb(ira, cond_br_instruction->else_block);3604 IrBasicBlock *new_else_block = ir_get_new_bb(ira, cond_br_instruction->else_block);
3553 ir_build_cond_br_from(&ira->new_irb, &cond_br_instruction->base, condition, new_then_block, new_else_block, false);3605 ir_build_cond_br_from(&ira->new_irb, &cond_br_instruction->base,
3606 casted_condition, new_then_block, new_else_block, false);
3554 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);3607 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
3555}3608}
35563609
...@@ -4255,6 +4308,100 @@ static TypeTableEntry *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionA...@@ -4255,6 +4308,100 @@ static TypeTableEntry *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionA
4255 return return_type;4308 return return_type;
4256}4309}
42574310
4311static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
4312 IrInstructionArrayType *array_type_instruction)
4313{
4314 IrInstruction *size_value = array_type_instruction->size->other;
4315 uint64_t size;
4316 if (!ir_resolve_usize(ira, size_value, &size))
4317 return ira->codegen->builtin_types.entry_invalid;
4318
4319 IrInstruction *child_type_value = array_type_instruction->child_type->other;
4320 TypeTableEntry *child_type = ir_resolve_type(ira, child_type_value);
4321 TypeTableEntry *canon_child_type = get_underlying_type(child_type);
4322 switch (canon_child_type->id) {
4323 case TypeTableEntryIdTypeDecl:
4324 zig_unreachable();
4325 case TypeTableEntryIdInvalid:
4326 return ira->codegen->builtin_types.entry_invalid;
4327 case TypeTableEntryIdVar:
4328 case TypeTableEntryIdUnreachable:
4329 case TypeTableEntryIdUndefLit:
4330 case TypeTableEntryIdNullLit:
4331 case TypeTableEntryIdBlock:
4332 add_node_error(ira->codegen, array_type_instruction->base.source_node,
4333 buf_sprintf("array of type '%s' not allowed", buf_ptr(&child_type->name)));
4334 // TODO if this is a typedecl, add error note showing the declaration of the type decl
4335 return ira->codegen->builtin_types.entry_invalid;
4336 case TypeTableEntryIdMetaType:
4337 case TypeTableEntryIdVoid:
4338 case TypeTableEntryIdBool:
4339 case TypeTableEntryIdInt:
4340 case TypeTableEntryIdFloat:
4341 case TypeTableEntryIdPointer:
4342 case TypeTableEntryIdArray:
4343 case TypeTableEntryIdStruct:
4344 case TypeTableEntryIdNumLitFloat:
4345 case TypeTableEntryIdNumLitInt:
4346 case TypeTableEntryIdMaybe:
4347 case TypeTableEntryIdErrorUnion:
4348 case TypeTableEntryIdPureError:
4349 case TypeTableEntryIdEnum:
4350 case TypeTableEntryIdUnion:
4351 case TypeTableEntryIdFn:
4352 case TypeTableEntryIdNamespace:
4353 case TypeTableEntryIdGenericFn:
4354 {
4355 TypeTableEntry *result_type = get_array_type(ira->codegen, child_type, size);
4356 bool depends_on_compile_var = child_type_value->static_value.depends_on_compile_var ||
4357 size_value->static_value.depends_on_compile_var;
4358 ConstExprValue *out_val = ir_build_const_from(ira, &array_type_instruction->base,
4359 depends_on_compile_var);
4360 out_val->data.x_type = result_type;
4361 return ira->codegen->builtin_types.entry_type;
4362 }
4363 }
4364 zig_unreachable();
4365}
4366
4367static TypeTableEntry *ir_analyze_instruction_compile_var(IrAnalyze *ira,
4368 IrInstructionCompileVar *compile_var_instruction)
4369{
4370 IrInstruction *name_value = compile_var_instruction->name->other;
4371 Buf *var_name = ir_resolve_str(ira, name_value);
4372 if (!var_name)
4373 return ira->codegen->builtin_types.entry_invalid;
4374
4375 ConstExprValue *out_val = ir_build_const_from(ira, &compile_var_instruction->base, true);
4376 if (buf_eql_str(var_name, "is_big_endian")) {
4377 out_val->data.x_bool = ira->codegen->is_big_endian;
4378 return ira->codegen->builtin_types.entry_bool;
4379 } else if (buf_eql_str(var_name, "is_release")) {
4380 out_val->data.x_bool = ira->codegen->is_release_build;
4381 return ira->codegen->builtin_types.entry_bool;
4382 } else if (buf_eql_str(var_name, "is_test")) {
4383 out_val->data.x_bool = ira->codegen->is_test_build;
4384 return ira->codegen->builtin_types.entry_bool;
4385 } else if (buf_eql_str(var_name, "os")) {
4386 out_val->data.x_enum.tag = ira->codegen->target_os_index;
4387 return ira->codegen->builtin_types.entry_os_enum;
4388 } else if (buf_eql_str(var_name, "arch")) {
4389 out_val->data.x_enum.tag = ira->codegen->target_arch_index;
4390 return ira->codegen->builtin_types.entry_arch_enum;
4391 } else if (buf_eql_str(var_name, "environ")) {
4392 out_val->data.x_enum.tag = ira->codegen->target_environ_index;
4393 return ira->codegen->builtin_types.entry_environ_enum;
4394 } else if (buf_eql_str(var_name, "object_format")) {
4395 out_val->data.x_enum.tag = ira->codegen->target_oformat_index;
4396 return ira->codegen->builtin_types.entry_oformat_enum;
4397 } else {
4398 add_node_error(ira->codegen, name_value->source_node,
4399 buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(var_name)));
4400 return ira->codegen->builtin_types.entry_invalid;
4401 }
4402 zig_unreachable();
4403}
4404
4258static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {4405static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
4259 switch (instruction->id) {4406 switch (instruction->id) {
4260 case IrInstructionIdInvalid:4407 case IrInstructionIdInvalid:
...@@ -4305,12 +4452,15 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -4305,12 +4452,15 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
4305 return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction);4452 return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction);
4306 case IrInstructionIdAsm:4453 case IrInstructionIdAsm:
4307 return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction);4454 return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction);
4455 case IrInstructionIdArrayType:
4456 return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction);
4457 case IrInstructionIdCompileVar:
4458 return ir_analyze_instruction_compile_var(ira, (IrInstructionCompileVar *)instruction);
4308 case IrInstructionIdSwitchBr:4459 case IrInstructionIdSwitchBr:
4309 case IrInstructionIdCast:4460 case IrInstructionIdCast:
4310 case IrInstructionIdContainerInitList:4461 case IrInstructionIdContainerInitList:
4311 case IrInstructionIdContainerInitFields:4462 case IrInstructionIdContainerInitFields:
4312 case IrInstructionIdStructFieldPtr:4463 case IrInstructionIdStructFieldPtr:
4313 case IrInstructionIdArrayType:
4314 zig_panic("TODO analyze more instructions");4464 zig_panic("TODO analyze more instructions");
4315 }4465 }
4316 zig_unreachable();4466 zig_unreachable();
...@@ -4414,6 +4564,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -4414,6 +4564,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
4414 case IrInstructionIdStructFieldPtr:4564 case IrInstructionIdStructFieldPtr:
4415 case IrInstructionIdArrayType:4565 case IrInstructionIdArrayType:
4416 case IrInstructionIdSliceType:4566 case IrInstructionIdSliceType:
4567 case IrInstructionIdCompileVar:
4417 return false;4568 return false;
4418 case IrInstructionIdAsm:4569 case IrInstructionIdAsm:
4419 {4570 {
...@@ -5180,43 +5331,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {...@@ -5180,43 +5331,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
5180// case BuiltinFnIdCUndef:5331// case BuiltinFnIdCUndef:
5181// zig_panic("TODO");5332// zig_panic("TODO");
5182//5333//
5183// case BuiltinFnIdCompileVar:
5184// {
5185// AstNode **str_node = node->data.fn_call_expr.params.at(0)->parent_field;
5186//
5187// Buf *var_name = resolve_const_expr_str(g, import, context, str_node);
5188// if (!var_name) {
5189// return g->builtin_types.entry_invalid;
5190// }
5191//
5192// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
5193// const_val->ok = true;
5194// const_val->depends_on_compile_var = true;
5195//
5196// if (buf_eql_str(var_name, "is_big_endian")) {
5197// return resolve_expr_const_val_as_bool(g, node, g->is_big_endian, true);
5198// } else if (buf_eql_str(var_name, "is_release")) {
5199// return resolve_expr_const_val_as_bool(g, node, g->is_release_build, true);
5200// } else if (buf_eql_str(var_name, "is_test")) {
5201// return resolve_expr_const_val_as_bool(g, node, g->is_test_build, true);
5202// } else if (buf_eql_str(var_name, "os")) {
5203// const_val->data.x_enum.tag = g->target_os_index;
5204// return g->builtin_types.entry_os_enum;
5205// } else if (buf_eql_str(var_name, "arch")) {
5206// const_val->data.x_enum.tag = g->target_arch_index;
5207// return g->builtin_types.entry_arch_enum;
5208// } else if (buf_eql_str(var_name, "environ")) {
5209// const_val->data.x_enum.tag = g->target_environ_index;
5210// return g->builtin_types.entry_environ_enum;
5211// } else if (buf_eql_str(var_name, "object_format")) {
5212// const_val->data.x_enum.tag = g->target_oformat_index;
5213// return g->builtin_types.entry_oformat_enum;
5214// } else {
5215// add_node_error(g, *str_node,
5216// buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(var_name)));
5217// return g->builtin_types.entry_invalid;
5218// }
5219// }
5220// case BuiltinFnIdConstEval:5334// case BuiltinFnIdConstEval:
5221// {5335// {
5222// AstNode **expr_node = node->data.fn_call_expr.params.at(0)->parent_field;5336// AstNode **expr_node = node->data.fn_call_expr.params.at(0)->parent_field;
...@@ -7605,53 +7719,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {...@@ -7605,53 +7719,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
7605// }7719// }
7606//}7720//}
7607//7721//
7608//static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
7609// TypeTableEntry *expected_type, AstNode *node)
7610//{
7611// AstNode *size_node = node->data.array_type.size;
7612//
7613// TypeTableEntry *child_type = analyze_type_expr_pointer_only(g, import, context,
7614// node->data.array_type.child_type, true);
7615//
7616// if (child_type->id == TypeTableEntryIdUnreachable) {
7617// add_node_error(g, node, buf_create_from_str("array of unreachable not allowed"));
7618// return g->builtin_types.entry_invalid;
7619// } else if (child_type->id == TypeTableEntryIdInvalid) {
7620// return g->builtin_types.entry_invalid;
7621// }
7622//
7623// if (size_node) {
7624// child_type = analyze_type_expr(g, import, context, node->data.array_type.child_type);
7625// TypeTableEntry *size_type = analyze_expression(g, import, context,
7626// g->builtin_types.entry_usize, size_node);
7627// if (size_type->id == TypeTableEntryIdInvalid) {
7628// return g->builtin_types.entry_invalid;
7629// }
7630//
7631// ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val;
7632// if (const_val->ok) {
7633// if (const_val->data.x_bignum.is_negative) {
7634// add_node_error(g, size_node,
7635// buf_sprintf("array size %s is negative",
7636// buf_ptr(bignum_to_buf(&const_val->data.x_bignum))));
7637// return g->builtin_types.entry_invalid;
7638// } else {
7639// return resolve_expr_const_val_as_type(g, node,
7640// get_array_type(g, child_type, const_val->data.x_bignum.data.x_uint), false);
7641// }
7642// } else if (context->fn_entry) {
7643// return resolve_expr_const_val_as_type(g, node,
7644// get_slice_type(g, child_type, node->data.array_type.is_const), false);
7645// } else {
7646// add_node_error(g, first_executing_node(size_node),
7647// buf_sprintf("unable to evaluate constant expression"));
7648// return g->builtin_types.entry_invalid;
7649// }
7650// } else {
7651// TypeTableEntry *slice_type = get_slice_type(g, child_type, node->data.array_type.is_const);
7652// return resolve_expr_const_val_as_type(g, node, slice_type, false);
7653// }
7654//}
7655//static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) {7722//static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) {
7656// size_t result = 0;7723// size_t result = 0;
7657// while (inner_block != outer_block) {7724// while (inner_block != outer_block) {
...@@ -9572,3 +9639,97 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no...@@ -9572,3 +9639,97 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
9572// LLVMPositionBuilderAtEnd(g->builder, basic_block);9639// LLVMPositionBuilderAtEnd(g->builder, basic_block);
9573// return nullptr;9640// return nullptr;
9574//}9641//}
9642//static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
9643// LLVMValueRef val1, LLVMValueRef val2)
9644//{
9645// // for unsigned left shifting, we do the wrapping shift, then logically shift
9646// // right the same number of bits
9647// // if the values don't match, we have an overflow
9648// // for signed left shifting we do the same except arithmetic shift right
9649//
9650// assert(type_entry->id == TypeTableEntryIdInt);
9651//
9652// LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, "");
9653// LLVMValueRef orig_val;
9654// if (type_entry->data.integral.is_signed) {
9655// orig_val = LLVMBuildAShr(g->builder, result, val2, "");
9656// } else {
9657// orig_val = LLVMBuildLShr(g->builder, result, val2, "");
9658// }
9659// LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, "");
9660//
9661// LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk");
9662// LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail");
9663// LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
9664//
9665// LLVMPositionBuilderAtEnd(g->builder, fail_block);
9666// gen_debug_safety_crash(g);
9667//
9668// LLVMPositionBuilderAtEnd(g->builder, ok_block);
9669// return result;
9670//}
9671//
9672//static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, LLVMValueRef val2,
9673// TypeTableEntry *type_entry, bool exact)
9674//{
9675//
9676// if (want_debug_safety(g, source_node)) {
9677// LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
9678// LLVMValueRef is_zero_bit;
9679// if (type_entry->id == TypeTableEntryIdInt) {
9680// is_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, zero, "");
9681// } else if (type_entry->id == TypeTableEntryIdFloat) {
9682// is_zero_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, val2, zero, "");
9683// } else {
9684// zig_unreachable();
9685// }
9686// LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroOk");
9687// LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroFail");
9688// LLVMBuildCondBr(g->builder, is_zero_bit, fail_block, ok_block);
9689//
9690// LLVMPositionBuilderAtEnd(g->builder, fail_block);
9691// gen_debug_safety_crash(g);
9692//
9693// LLVMPositionBuilderAtEnd(g->builder, ok_block);
9694// }
9695//
9696// if (type_entry->id == TypeTableEntryIdFloat) {
9697// assert(!exact);
9698// return LLVMBuildFDiv(g->builder, val1, val2, "");
9699// }
9700//
9701// assert(type_entry->id == TypeTableEntryIdInt);
9702//
9703// if (exact) {
9704// if (want_debug_safety(g, source_node)) {
9705// LLVMValueRef remainder_val;
9706// if (type_entry->data.integral.is_signed) {
9707// remainder_val = LLVMBuildSRem(g->builder, val1, val2, "");
9708// } else {
9709// remainder_val = LLVMBuildURem(g->builder, val1, val2, "");
9710// }
9711// LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
9712// LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
9713//
9714// LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactOk");
9715// LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactFail");
9716// LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
9717//
9718// LLVMPositionBuilderAtEnd(g->builder, fail_block);
9719// gen_debug_safety_crash(g);
9720//
9721// LLVMPositionBuilderAtEnd(g->builder, ok_block);
9722// }
9723// if (type_entry->data.integral.is_signed) {
9724// return LLVMBuildExactSDiv(g->builder, val1, val2, "");
9725// } else {
9726// return ZigLLVMBuildExactUDiv(g->builder, val1, val2, "");
9727// }
9728// } else {
9729// if (type_entry->data.integral.is_signed) {
9730// return LLVMBuildSDiv(g->builder, val1, val2, "");
9731// } else {
9732// return LLVMBuildUDiv(g->builder, val1, val2, "");
9733// }
9734// }
9735//}
src/ir_print.cpp+9
...@@ -472,6 +472,12 @@ static void ir_print_asm(IrPrint *irp, IrInstructionAsm *instruction) {...@@ -472,6 +472,12 @@ static void ir_print_asm(IrPrint *irp, IrInstructionAsm *instruction) {
472 fprintf(irp->f, ")");472 fprintf(irp->f, ")");
473}473}
474474
475static void ir_print_compile_var(IrPrint *irp, IrInstructionCompileVar *instruction) {
476 fprintf(irp->f, "@compileVar(");
477 ir_print_other_instruction(irp, instruction->name);
478 fprintf(irp->f, ")");
479}
480
475static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {481static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
476 ir_print_prefix(irp, instruction);482 ir_print_prefix(irp, instruction);
477 switch (instruction->id) {483 switch (instruction->id) {
...@@ -561,6 +567,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -561,6 +567,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
561 case IrInstructionIdAsm:567 case IrInstructionIdAsm:
562 ir_print_asm(irp, (IrInstructionAsm *)instruction);568 ir_print_asm(irp, (IrInstructionAsm *)instruction);
563 break;569 break;
570 case IrInstructionIdCompileVar:
571 ir_print_compile_var(irp, (IrInstructionCompileVar *)instruction);
572 break;
564 case IrInstructionIdSwitchBr:573 case IrInstructionIdSwitchBr:
565 zig_panic("TODO print more IR instructions");574 zig_panic("TODO print more IR instructions");
566 }575 }