diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 110b5923d..f8c05128c 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -217,6 +217,63 @@ Decl *decl_new_generated_var(const char *name, Type *type, VarDeclKind kind, Sou return decl; } +bool expr_is_simple(Expr *expr) +{ + RETRY: + switch (expr->expr_kind) + { + case EXPR_GROUP: + expr = expr->inner_expr; + goto RETRY; + case EXPR_OR_ERROR: + case EXPR_TERNARY: + return false; + case EXPR_RETHROW: + expr = expr->rethrow_expr.inner; + goto RETRY; + default: + return true; + case EXPR_BINARY: + switch (expr->binary_expr.operator) + { + case BINARYOP_AND: + case BINARYOP_OR: + case BINARYOP_GT: + case BINARYOP_GE: + case BINARYOP_LT: + case BINARYOP_LE: + case BINARYOP_NE: + case BINARYOP_EQ: + case BINARYOP_ASSIGN: + case BINARYOP_ADD_ASSIGN: + case BINARYOP_BIT_AND_ASSIGN: + case BINARYOP_BIT_OR_ASSIGN: + case BINARYOP_BIT_XOR_ASSIGN: + case BINARYOP_DIV_ASSIGN: + case BINARYOP_MOD_ASSIGN: + case BINARYOP_MULT_ASSIGN: + case BINARYOP_SHR_ASSIGN: + case BINARYOP_SHL_ASSIGN: + case BINARYOP_SUB_ASSIGN: + return true; + default: + return false; + } + UNREACHABLE + case EXPR_UNARY: + switch (expr->unary_expr.operator) + { + case UNARYOP_NEG: + case UNARYOP_BITNEG: + return false; + default: + return true; + } + UNREACHABLE + } + UNREACHABLE +} + Expr *expr_new(ExprKind kind, SourceSpan start) { diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 939d6db48..2edf8d901 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -463,11 +463,6 @@ typedef struct FunctionSignature attr_signature; } AttrDecl; -typedef struct -{ - Decl *import; -} AliasDecl; - typedef struct { bool is_func : 1; @@ -631,6 +626,7 @@ typedef struct Decl_ typedef struct { bool is_jump : 1; + bool widen : 1; Expr *expr; union { @@ -651,19 +647,22 @@ typedef struct Expr *cond; Expr *then_expr; // May be null for elvis! Expr *else_expr; + bool widen : 1; } ExprTernary; typedef struct { Expr *left; Expr *right; - BinaryOp operator; + BinaryOp operator : 8; + bool widen : 1; } ExprBinary; typedef struct { Expr* expr; - UnaryOp operator; + UnaryOp operator : 8; + bool widen : 1; } ExprUnary; @@ -747,8 +746,6 @@ typedef struct { Path *path; TokenId identifier; - bool is_ref : 1; - bool is_rvalue : 1; Decl *decl; } ExprIdentifier; @@ -849,18 +846,6 @@ typedef struct AstId defer; } ExprGuard; -typedef struct -{ - bool is_try; - Expr *expr; -} ExprTryExpr; - -typedef struct -{ - bool is_try : 1; - Expr *expr; - Expr *init; -} ExprTryAssign; typedef struct { @@ -922,37 +907,28 @@ struct Expr_ SourceSpan span; Type *type; union { - Expr *group_expr; ExprLen len_expr; ExprCast cast_expr; - Expr *typeof_expr; TypeInfo *type_expr; ExprConst const_expr; - ExprStructValue struct_value_expr; ExprGuard rethrow_expr; - Expr *trycatch_expr; Decl *decl_expr; ExprOrError or_error_expr; - ExprFlatElement *flatpath_expr; ExprSliceAssign slice_assign_expr; ExprBinary binary_expr; ExprTernary ternary_expr; ExprUnary unary_expr; Expr** try_unwrap_chain_expr; ExprTryUnwrap try_unwrap_expr; - Expr* force_unwrap_expr; ExprCall call_expr; ExprSlice slice_expr; - ExprTryExpr try_expr; - ExprTryAssign try_assign_expr; - ExprTryDecl try_decl_expr; + Expr *inner_expr; ExprCatchUnwrap catch_unwrap_expr; ExprSubscript subscript_expr; ExprAccess access_expr; ExprDesignator designator_expr; ExprIdentifier identifier_expr; ExprPlaceholder placeholder_expr; - ExprIdentifier macro_identifier_expr; ExprIdentifierRaw ct_ident_expr; ExprCtCall ct_call_expr; ExprIdentifierRaw ct_macro_ident_expr; @@ -960,7 +936,6 @@ struct Expr_ ExprIdentifierRaw hash_ident_expr; TypeInfo *typeid_expr; ExprBodyExpansion body_expansion_expr; - Decl *expr_enum; ExprCompoundLiteral expr_compound_literal; Expr** expression_list; Expr** initializer_list; @@ -968,8 +943,6 @@ struct Expr_ ExprScope expr_scope; ExprFuncBlock expr_block; ExprMacroBlock macro_block; - - Expr* failable_expr; Expr** cond_expr; }; }; @@ -1237,7 +1210,6 @@ typedef struct Ast_ Ast** ct_compound_stmt; Decl *declare_stmt; // 8 Expr *expr_stmt; // 8 - Ast *try_stmt; Decl *var_stmt; // 8 Ast *volatile_stmt; // 8 AstReturnStmt return_stmt; // 16 @@ -1625,33 +1597,6 @@ typedef enum CmpRes_ CMP_GT = 1, } CmpRes; -typedef enum -{ - FLOAT_NAN, - FLOAT_INFINITY, - FLOAT_NORMAL, - FLOAT_ZERO -} FloatCategory; - -typedef enum -{ - ROUNDING_TOWARD_ZERO, - ROUNDING_NEAREST_TIES_TO_EVEN, - ROUNDING_TOWARD_POSITIVE, - ROUNDING_TOWARD_NEGATIVE, - ROUNDING_NEAREST_TIES_TO_AWAY -} FloatRounding; - -typedef struct FloatXX -{ - union - { - double f64; - float f32; - }; - TypeKind type; -} FloatXX; - void type_setup(PlatformTarget *target); Float float_add(Float op1, Float op2); Float float_sub(Float op1, Float op2); @@ -1761,12 +1706,12 @@ static inline bool type_may_negate(Type *type) } -bool cast_implicit_ignore_failable(Expr *expr, Type *to_type); bool cast_implicit(Expr *expr, Type *to_type); bool cast(Expr *expr, Type *to_type); -bool cast_may_implicit(Type *from_type, Type *to_type); -bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability); +bool cast_may_implicit(Type *from_type, Type *to_type, bool is_simple_expr, bool failable_allowed); + +bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability, bool is_const); bool cast_implicit_bit_width(Expr *expr, Type *to_type); CastKind cast_to_bool_kind(Type *type); @@ -1849,6 +1794,7 @@ void diag_verror_range(SourceLocation *location, const char *message, va_list ar #define EXPR_NEW_EXPR(kind_, expr_) expr_new(kind_, (expr_)->span) #define EXPR_NEW_TOKEN(kind_, tok_) expr_new(kind_, source_span_from_token_id((tok_).id)) Expr *expr_new(ExprKind kind, SourceSpan start); +bool expr_is_simple(Expr *expr); static inline bool expr_ok(Expr *expr) { return expr == NULL || expr->expr_kind != EXPR_POISONED; } static inline bool expr_poison(Expr *expr) { expr->expr_kind = EXPR_POISONED; expr->resolve_status = RESOLVE_DONE; return false; } static inline void expr_replace(Expr *expr, Expr *replacement) @@ -1934,6 +1880,7 @@ void sema_analysis_pass_ct_assert(Module *module); void sema_analysis_pass_functions(Module *module); void sema_analyze_stage(Module *module, AnalysisStage stage); +bool sema_failed_cast(Expr *expr, Type *from, Type *to); bool sema_add_member(Context *context, Decl *decl); bool sema_add_local(Context *context, Decl *decl); bool sema_unwrap_var(Context *context, Decl *decl); @@ -1941,14 +1888,14 @@ bool sema_rewrap_var(Context *context, Decl *decl); bool sema_erase_var(Context *context, Decl *decl); bool sema_erase_unwrapped(Context *context, Decl *decl); bool sema_analyse_cond_expr(Context *context, Expr *expr); -bool sema_analyse_assigned_expr(Context *context, Type *to, Expr *expr, bool may_be_failable); -bool sema_analyse_expr_of_required_type(Context *context, Type *to, Expr *expr); +bool sema_analyse_expr_rhs(Context *context, Type *to, Expr *expr, bool allow_failable); ArrayIndex sema_get_initializer_const_array_size(Context *context, Expr *initializer, bool *may_be_array, bool *is_const_size); bool sema_analyse_expr(Context *context, Expr *expr); bool sema_analyse_inferred_expr(Context *context, Type *to, Expr *expr); bool sema_analyse_decl(Context *context, Decl *decl); -bool sema_analyse_var_decl(Context *context, Decl *decl); + +bool sema_analyse_var_decl(Context *context, Decl *decl, bool local); bool sema_analyse_ct_assert_stmt(Context *context, Ast *statement); bool sema_analyse_statement(Context *context, Ast *statement); bool sema_expr_analyse_assign_right_side(Context *context, Expr *expr, Type *left_type, Expr *right, bool is_unwrapped_var); @@ -2107,7 +2054,10 @@ static inline Type *type_reduced_from_expr(Expr *expr) static inline Type *type_no_fail(Type *type) { - return type && type->type_kind == TYPE_FAILABLE ? type->failable : type; + if (!type) return NULL; + if (type->type_kind == TYPE_FAILABLE) return type->failable; + if (type->type_kind == TYPE_FAILABLE_ANY) return type_void; + return type; } static inline bool type_is_pointer_sized_or_more(Type *type) @@ -2124,8 +2074,11 @@ static inline bool type_is_pointer_sized(Type *type) TypeKind k_ = (t_)->type_kind; \ if (k_ == TYPE_TYPEDEF) k_ = (t_)->canonical->type_kind; -#define IS_FAILABLE(element_) ((element_)->type->type_kind == TYPE_FAILABLE) -#define TYPE_IS_FAILABLE(type_) (type_->type_kind == TYPE_FAILABLE) +#define IS_FAILABLE(element_) (type_is_failable((element_)->type)) +#define type_is_failable(type_) ((type_)->type_kind == TYPE_FAILABLE || (type_)->canonical->type_kind == TYPE_FAILABLE_ANY) +#define type_is_failable_type(type_) ((type_)->type_kind == TYPE_FAILABLE) +#define type_is_failable_any(type_) ((type_)->canonical->type_kind == TYPE_FAILABLE_ANY) +#define type_is_void(type_) (type_->canonical->type_kind == TYPE_VOID) static inline Type *type_with_added_failability(Expr *expr, bool add_failable) { @@ -2143,13 +2096,13 @@ static inline Type *type_get_opt_fail(Type *type, bool add_failable) static inline bool type_is_integer(Type *type) { DECL_TYPE_KIND_REAL(kind, type); - return kind >= TYPE_INTEGER_FIRST && type->type_kind <= TYPE_INTEGER_LAST; + return kind >= TYPE_INTEGER_FIRST && kind <= TYPE_INTEGER_LAST; } static inline bool type_is_integer_signed(Type *type) { DECL_TYPE_KIND_REAL(kind, type); - return kind >= TYPE_INT_FIRST && type->type_kind <= TYPE_INT_LAST; + return kind >= TYPE_INT_FIRST && kind <= TYPE_INT_LAST; } static inline bool type_is_integer_or_bool_kind(Type *type) @@ -2161,7 +2114,7 @@ static inline bool type_is_integer_or_bool_kind(Type *type) static inline bool type_is_integer_unsigned(Type *type) { DECL_TYPE_KIND_REAL(kind, type); - return kind >= TYPE_UINT_FIRST && type->type_kind <= TYPE_UINT_LAST; + return kind >= TYPE_UINT_FIRST && kind <= TYPE_UINT_LAST; } static inline bool type_info_poison(TypeInfo *type) @@ -2319,9 +2272,12 @@ static inline Type *type_flatten(Type *type) if (type->type_kind == TYPE_FAILABLE) { type = type->failable; - if (!type) type = type_void; continue; } + if (type->type_kind == TYPE_FAILABLE_ANY) + { + return type_void; + } return type; } } diff --git a/src/compiler/copying.c b/src/compiler/copying.c index efad697b3..e2e33194a 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -75,9 +75,6 @@ Expr *copy_expr(Expr *source_expr) case EXPR_UNDEF: case EXPR_NOP: return expr; - case EXPR_FORCE_UNWRAP: - MACRO_COPY_EXPR(expr->force_unwrap_expr); - return expr; case EXPR_DECL: MACRO_COPY_DECL(expr->decl_expr); return expr; @@ -123,19 +120,16 @@ Expr *copy_expr(Expr *source_expr) case EXPR_LEN: MACRO_COPY_EXPR(expr->len_expr.inner); return expr; - case EXPR_TRY_ASSIGN: - MACRO_COPY_EXPR(expr->try_assign_expr.expr); - MACRO_COPY_EXPR(expr->try_assign_expr.init); - return expr; + case EXPR_FORCE_UNWRAP: case EXPR_TRY: - MACRO_COPY_EXPR(expr->try_expr.expr); + case EXPR_CATCH: + case EXPR_FAILABLE: + case EXPR_GROUP: + MACRO_COPY_EXPR(expr->inner_expr); return expr; case EXPR_COND: MACRO_COPY_EXPR_LIST(expr->cond_expr); return expr; - case EXPR_FAILABLE: - MACRO_COPY_EXPR(expr->failable_expr); - return expr; case EXPR_OR_ERROR: MACRO_COPY_EXPR(expr->or_error_expr.expr); if (expr->or_error_expr.is_jump) @@ -149,9 +143,6 @@ Expr *copy_expr(Expr *source_expr) return expr; case EXPR_MACRO_BLOCK: UNREACHABLE - case EXPR_TYPEOF: - MACRO_COPY_EXPR(expr->typeof_expr); - return expr; case EXPR_COMPOUND_LITERAL: MACRO_COPY_EXPR(expr->expr_compound_literal.initializer); MACRO_COPY_TYPE(expr->expr_compound_literal.type_info); @@ -193,9 +184,6 @@ Expr *copy_expr(Expr *source_expr) MACRO_COPY_EXPR(expr->subscript_expr.expr); MACRO_COPY_EXPR(expr->subscript_expr.index); return expr; - case EXPR_GROUP: - MACRO_COPY_EXPR(expr->group_expr); - return expr; case EXPR_ACCESS: MACRO_COPY_EXPR(expr->access_expr.parent); return expr; diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 63ef841ca..ff1834ab3 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -118,16 +118,9 @@ typedef enum CAST_VRPTR, CAST_PTRVR, CAST_VRBOOL, + CAST_VFTOERR, } CastKind; -typedef enum -{ - CAST_TYPE_EXPLICIT, - CAST_TYPE_IMPLICIT, - CAST_TYPE_OPTIONAL_IMPLICIT, -} CastType; - - typedef enum { @@ -182,6 +175,7 @@ typedef enum EXPR_MACRO_BODY_EXPANSION, EXPR_CALL, EXPR_CAST, + EXPR_CATCH, EXPR_CATCH_UNWRAP, EXPR_COMPOUND_LITERAL, EXPR_CONST, @@ -215,10 +209,8 @@ typedef enum EXPR_TRY, EXPR_TRY_UNWRAP, EXPR_TRY_UNWRAP_CHAIN, - EXPR_TRY_ASSIGN, EXPR_TYPEID, EXPR_TYPEINFO, - EXPR_TYPEOF, EXPR_UNARY, EXPR_UNDEF, EXPR_CT_CALL, @@ -557,6 +549,7 @@ typedef enum TYPE_INFERRED_ARRAY, TYPE_UNTYPED_LIST, TYPE_FAILABLE, + TYPE_FAILABLE_ANY, TYPE_TYPEINFO, TYPE_VECTOR, TYPE_VIRTUAL, diff --git a/src/compiler/headers.c b/src/compiler/headers.c index d75d63945..b0be3081c 100644 --- a/src/compiler/headers.c +++ b/src/compiler/headers.c @@ -35,6 +35,7 @@ static void header_print_type(FILE *file, Type *type) case TYPE_BITSTRUCT: TODO case TYPE_FAILABLE: + case TYPE_FAILABLE_ANY: // If this is reachable then we are not doing the proper lowering. UNREACHABLE case TYPE_VOID: diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index f0fac26ce..92d463279 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -300,15 +300,11 @@ void llvm_emit_ptr_from_array(GenContext *c, BEValue *value) case TYPE_SUBARRAY: { // TODO insert trap on overflow. - LLVMTypeRef subarray_type = llvm_get_type(c, value->type); assert(value->kind == BE_ADDRESS); - LLVMValueRef pointer_addr = LLVMBuildStructGEP2(c->builder, subarray_type, value->value, 0, "subarrayptr"); - LLVMTypeRef pointer_type = llvm_get_type(c, type_get_ptr(value->type->array.base)); - AlignSize alignment = type_abi_alignment(type_voidptr); - // We need to pick the worst alignment in case this is packed in an array. - if (value->alignment < alignment) alignment = value->alignment; - llvm_value_set_address_align(value, - llvm_emit_load_aligned(c, pointer_type, pointer_addr, 0, "saptr"), value->type, alignment); + BEValue member; + llvm_emit_subarray_pointer(c, value, &member); + llvm_value_rvalue(c, &member); + llvm_value_set_address_align(value, member.value, type_get_ptr(value->type->array.base), type_abi_alignment(value->type->array.base)); return; } case TYPE_STRLIT: @@ -744,10 +740,11 @@ void gencontext_emit_introspection_type(GenContext *c, Decl *decl) LLVMSetGlobalConstant(enum_elements, 1); llvm_set_linkage(c, decl, enum_elements); LLVMSetInitializer(enum_elements, LLVMConstNull(elements_type)); + AlignSize alignment = type_alloca_alignment(type_voidptr); for (unsigned i = 0; i < elements; i++) { - LLVMValueRef index[2] = { llvm_const_int(c, type_usize, i) }; - decl->enums.values[i]->backend_ref = LLVMConstInBoundsGEP(enum_elements, index, 1); + AlignSize store_align; + decl->enums.values[i]->backend_ref = llvm_emit_array_gep_raw(c, enum_elements, elements_type, i, alignment, &store_align); } } LLVMValueRef global_name = LLVMAddGlobal(c->module, llvm_get_type(c, type_char), decl->name ? decl->name : "anon"); @@ -849,9 +846,7 @@ LLVMValueRef llvm_value_rvalue_store(GenContext *c, BEValue *value) case BE_ADDRESS_FAILABLE: UNREACHABLE case BE_ADDRESS: - return llvm_emit_load_aligned(c, - llvm_get_type(c, value->type), - value->value, + return llvm_emit_load_aligned(c, llvm_get_type(c, value->type), value->value, value->alignment ? value->alignment : type_abi_alignment(value->type), ""); case BE_BOOLEAN: diff --git a/src/compiler/llvm_codegen_c_abi_x64.c b/src/compiler/llvm_codegen_c_abi_x64.c index c44ed4f17..eeb136b44 100644 --- a/src/compiler/llvm_codegen_c_abi_x64.c +++ b/src/compiler/llvm_codegen_c_abi_x64.c @@ -403,6 +403,7 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X case TYPE_ERRTYPE: case TYPE_BITSTRUCT: case TYPE_FAILABLE: + case TYPE_FAILABLE_ANY: case CT_TYPES: UNREACHABLE case TYPE_VOID: @@ -598,6 +599,7 @@ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_ty case TYPE_ERRTYPE: case TYPE_BITSTRUCT: case TYPE_FAILABLE: + case TYPE_FAILABLE_ANY: case CT_TYPES: UNREACHABLE case TYPE_I128: diff --git a/src/compiler/llvm_codegen_c_abi_x86.c b/src/compiler/llvm_codegen_c_abi_x86.c index 72e091461..798754516 100644 --- a/src/compiler/llvm_codegen_c_abi_x86.c +++ b/src/compiler/llvm_codegen_c_abi_x86.c @@ -120,6 +120,7 @@ static bool x86_should_return_type_in_reg(Type *type) case TYPE_BITSTRUCT: case CT_TYPES: case TYPE_FAILABLE: + case TYPE_FAILABLE_ANY: UNREACHABLE case ALL_INTS: case ALL_FLOATS: @@ -596,6 +597,7 @@ static ABIArgInfo *x86_classify_argument(CallABI call, Regs *regs, Type *type) case TYPE_BITSTRUCT: case TYPE_STRLIT: case TYPE_FAILABLE: + case TYPE_FAILABLE_ANY: case CT_TYPES: UNREACHABLE case ALL_FLOATS: diff --git a/src/compiler/llvm_codegen_debug_info.c b/src/compiler/llvm_codegen_debug_info.c index 46068aad4..413d710ea 100644 --- a/src/compiler/llvm_codegen_debug_info.c +++ b/src/compiler/llvm_codegen_debug_info.c @@ -484,6 +484,7 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type * case CT_TYPES: UNREACHABLE case TYPE_FAILABLE: + case TYPE_FAILABLE_ANY: // If this is reachable then we're not doing the proper lowering. UNREACHABLE case TYPE_BOOL: diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 0c609197e..487224c05 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -10,7 +10,7 @@ static inline void llvm_emit_post_inc_dec(GenContext *c, BEValue *value, Expr *e static inline void llvm_emit_pre_inc_dec(GenContext *c, BEValue *value, Expr *expr, int diff, bool use_mod); static inline void llvm_emit_inc_dec_change(GenContext *c, bool use_mod, BEValue *addr, BEValue *after, BEValue *before, Expr *expr, int diff); static void llvm_emit_post_unary_expr(GenContext *context, BEValue *be_value, Expr *expr); -static inline LLVMValueRef llvm_emit_subscript_addr_with_base_new(GenContext *c, BEValue *parent, BEValue *index, SourceLocation *loc); +static inline void llvm_emit_subscript_addr_with_base(GenContext *c, BEValue *result, BEValue *parent, BEValue *index, SourceLocation *loc); static void llvm_emit_initialize_designated(GenContext *c, BEValue *ref, uint64_t offset, DesignatorElement** current, DesignatorElement **last, Expr *expr, BEValue *emitted_value); static inline void llvm_emit_const_initialize_reference(GenContext *c, BEValue *ref, Expr *expr); LLVMValueRef llvm_emit_is_no_error_value(GenContext *c, BEValue *value) @@ -26,6 +26,21 @@ void llvm_convert_vector_comparison(GenContext *c, BEValue *be_value, LLVMValueR llvm_value_set(be_value, val, result_type); } +LLVMValueRef llvm_emit_coerce_alignment(GenContext *c, BEValue *be_value, LLVMTypeRef coerce_type, AlignSize target_alignment, AlignSize *resulting_alignment) +{ + // If we are loading something with greater alignment than what we have, we cannot directly memcpy. + if (!llvm_value_is_addr(be_value) || be_value->alignment < target_alignment) + { + LLVMValueRef cast = llvm_emit_alloca(c, llvm_get_type(c, be_value->type), target_alignment, "coerce"); + LLVMValueRef target = LLVMBuildBitCast(c->builder, cast, LLVMPointerType(coerce_type, 0), ""); + llvm_store_bevalue_aligned(c, target, be_value, target_alignment); + *resulting_alignment = target_alignment; + return cast; + } + *resulting_alignment = be_value->alignment; + return LLVMBuildBitCast(c->builder, be_value->value, LLVMPointerType(coerce_type, 0), ""); +} + LLVMValueRef llvm_emit_aggregate_value(GenContext *c, Type *type, ...) { @@ -111,7 +126,9 @@ void llvm_enter_struct_for_coerce(GenContext *c, LLVMValueRef *struct_ptr, LLVMT { return; } - LLVMValueRef ref = LLVMBuildStructGEP(c->builder, *struct_ptr, 0, "dive"); + AlignSize dummy; + LLVMValueRef ref = llvm_emit_struct_gep_raw(c, *struct_ptr, *type, 0, llvm_abi_alignment(c, *type), &dummy); + *struct_ptr = ref; *type = first_element; } @@ -328,40 +345,6 @@ static inline void llvm_emit_subscript_addr_base(GenContext *context, BEValue *v llvm_emit_ptr_from_array(context, value); } -static inline LLVMValueRef llvm_emit_subscript_addr_with_base(GenContext *c, Type *parent_type, LLVMValueRef parent_value, LLVMValueRef index_value, SourceLocation *loc) -{ - Type *type = parent_type; - switch (type->type_kind) - { - case TYPE_POINTER: - return LLVMBuildInBoundsGEP2(c->builder, - llvm_get_pointee_type(c, type), - parent_value, &index_value, 1, "ptridx"); - case TYPE_ARRAY: - { - // TODO insert trap on overflow. - LLVMValueRef zero = llvm_get_zero(c, type_int); - LLVMValueRef indices[2] = { - zero, - index_value, - }; - return LLVMBuildInBoundsGEP2(c->builder, - llvm_get_type(c, type), - parent_value, indices, 2, "arridx"); - } - case TYPE_SUBARRAY: - { - // TODO insert trap on overflow. - return LLVMBuildInBoundsGEP2(c->builder, - llvm_get_type(c, type->array.base), - parent_value, &index_value, 1, "sarridx"); - } - default: - UNREACHABLE - - } -} - static void llvm_emit_array_bounds_check(GenContext *c, BEValue *index, LLVMValueRef array_max_index, SourceLocation *loc) { BEValue result; @@ -381,43 +364,43 @@ static void llvm_emit_array_bounds_check(GenContext *c, BEValue *index, LLVMValu llvm_emit_panic_if_true(c, &result, "Array index out of bounds", loc); } -static inline LLVMValueRef llvm_emit_subscript_addr_with_base_new(GenContext *c, BEValue *parent, BEValue *index, SourceLocation *loc) +static inline void llvm_emit_subscript_addr_with_base(GenContext *c, BEValue *result, BEValue *parent, BEValue *index, SourceLocation *loc) { assert(llvm_value_is_addr(parent)); Type *type = type_lowering(parent->type); switch (type->type_kind) { case TYPE_POINTER: - return LLVMBuildInBoundsGEP(c->builder, parent->value, &index->value, 1, "ptridx"); + llvm_value_set_address(result, llvm_emit_pointer_inbounds_gep_raw(c, llvm_get_pointee_type(c, parent->type), parent->value, index->value), type->pointer); + return; case TYPE_ARRAY: case TYPE_VECTOR: - { + // TODO vector if (active_target.feature.safe_mode) { llvm_emit_array_bounds_check(c, index, llvm_const_int(c, index->type, type->array.len), loc); } - LLVMValueRef zero = llvm_get_zero(c, index->type); - LLVMValueRef indices[2] = { - zero, - index->value, - }; - return LLVMBuildInBoundsGEP2(c->builder, - llvm_get_type(c, type), - parent->value, indices, 2, "arridx"); - } + { + AlignSize alignment; + LLVMValueRef ptr = llvm_emit_array_gep_raw_index(c, parent->value, llvm_get_type(c, type), index->value, parent->alignment, &alignment); + llvm_value_set_address_align(result, ptr, type->array.base, alignment); + } + return; case TYPE_SUBARRAY: - { if (active_target.feature.safe_mode) { // TODO insert trap on overflow. } - return LLVMBuildInBoundsGEP2(c->builder, - llvm_get_type(c, type->array.base), - parent->value, &index->value, 1, "sarridx"); - } + { + LLVMValueRef ptr = llvm_emit_pointer_inbounds_gep_raw(c, llvm_get_type(c, type->array.base), parent->value, index->value); + llvm_value_set_address_align(result, ptr, type->array.base, type_abi_alignment(type->array.base)); + } + return; case TYPE_STRLIT: // TODO insert trap on overflow. - return LLVMBuildInBoundsGEP(c->builder, parent->value, &index->value, 1, "ptridx"); + llvm_value_set_address_align(result, llvm_emit_pointer_inbounds_gep_raw(c, llvm_get_type(c, type_char), parent->value, index->value), + type_char, type_abi_alignment(type_char)); + return; default: UNREACHABLE @@ -466,8 +449,7 @@ static inline void gencontext_emit_subscript(GenContext *c, BEValue *value, Expr // It needs to be an rvalue. llvm_value_rvalue(c, &index); - // TODO set alignment - llvm_value_set_address(value, llvm_emit_subscript_addr_with_base_new(c, &ref, &index, TOKLOC(expr->subscript_expr.index->span.loc)), expr->type); + llvm_emit_subscript_addr_with_base(c, value, &ref, &index, TOKLOC(expr->subscript_expr.index->span.loc)); } @@ -587,6 +569,8 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_ } break; + case CAST_VFTOERR: + TODO case CAST_VRBOOL: case CAST_VRPTR: case CAST_PTRVR: @@ -636,7 +620,7 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_ llvm_value_fold_failable(c, value); if (llvm_value_is_addr(value)) { - value->value = LLVMBuildStructGEP(c->builder, value->value, 0, ""); + llvm_emit_subarray_pointer(c, value, value); } else { @@ -757,7 +741,12 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_ llvm_value_fold_failable(c, value); if (llvm_value_is_addr(value)) { - value->value = LLVMBuildStructGEP(c->builder, value->value, 1, ""); + value->value = llvm_emit_struct_gep_raw(c, + value->value, + llvm_get_type(c, value->type), + 1, + value->alignment, + &value->alignment); } else { @@ -836,11 +825,6 @@ static LLVMValueRef llvm_recursive_set_value(GenContext *c, DesignatorElement ** UNREACHABLE } } -static LLVMValueRef llvm_recursive_set_const_value(GenContext *context, DesignatorElement **path, LLVMValueRef value, Type *parent_type, Expr *assign) -{ - unsigned path_count = vec_size(path); - return llvm_recursive_set_value(context, path, value, path + (path_count - 1), assign); -} void llvm_emit_initialize_reference_temporary_const(GenContext *c, BEValue *ref, Expr *expr) @@ -900,14 +884,13 @@ static void llvm_emit_inititialize_reference_const(GenContext *c, BEValue *ref, Type *element_type = array_type->array.base; ArrayIndex size = array_type->array.len; LLVMTypeRef array_type_llvm = llvm_get_type(c, array_type); - LLVMTypeRef element_type_llvm = llvm_get_type(c, element_type); assert(size <= UINT32_MAX); for (ArrayIndex i = 0; i < size; i++) { - LLVMValueRef index = llvm_const_int(c, type_uint, i); - LLVMValueRef array_pointer = LLVMBuildInBoundsGEP2(c->builder, element_type_llvm, array_ref, &index, 1, ""); + AlignSize alignment; + LLVMValueRef array_pointer = llvm_emit_array_gep_raw(c, array_ref, array_type_llvm, i, ref->alignment, &alignment); BEValue value; - llvm_value_set_address(&value, array_pointer, element_type); + llvm_value_set_address_align(&value, array_pointer, element_type, alignment); llvm_emit_inititialize_reference_const(c, &value, const_init->init_array_full[i]); } return; @@ -918,9 +901,8 @@ static void llvm_emit_inititialize_reference_const(GenContext *c, BEValue *ref, llvm_emit_memclear(c, ref); Type *array_type = const_init->type; Type *element_type = array_type->array.base; - LLVMTypeRef element_type_llvm = llvm_get_type(c, element_type); + LLVMTypeRef array_type_llvm = llvm_get_type(c, array_type); ConstInitializer **elements = const_init->init_array.elements; - unsigned element_count = vec_size(elements); ArrayIndex current_index = 0; LLVMValueRef *parts = NULL; VECEACH(elements, i) @@ -928,10 +910,10 @@ static void llvm_emit_inititialize_reference_const(GenContext *c, BEValue *ref, ConstInitializer *element = elements[i]; assert(element->kind == CONST_INIT_ARRAY_VALUE); ArrayIndex element_index = element->init_array_value.index; - LLVMValueRef index = llvm_const_int(c, element_index <= UINT32_MAX ? type_uint : type_usize, element_index); - LLVMValueRef array_pointer = LLVMBuildInBoundsGEP2(c->builder, element_type_llvm, array_ref, &index, 1, ""); + AlignSize alignment; + LLVMValueRef array_pointer = llvm_emit_array_gep_raw(c, array_ref, array_type_llvm, element_index, ref->alignment, &alignment); BEValue value; - llvm_value_set_address(&value, array_pointer, element_type); + llvm_value_set_address_align(&value, array_pointer, element_type, alignment); llvm_emit_inititialize_reference_const(c, &value, element->init_array_value.element); } return; @@ -1005,27 +987,20 @@ static inline void llvm_emit_initialize_reference_list(GenContext *c, BEValue *r LLVMTypeRef llvm_type = llvm_get_type(c, real_type); bool is_struct = type_is_structlike(real_type); bool is_array = real_type->type_kind == TYPE_ARRAY; - Type *array_element_type = is_array ? real_type->array.base : NULL; - LLVMTypeRef array_element_type_llvm = is_array ? llvm_get_type(c, real_type->array.base) : NULL; // Now walk through the elements. VECEACH(elements, i) { Expr *element = elements[i]; - unsigned offset = 0; BEValue pointer; if (is_struct) { - Decl *member = real_type->decl->strukt.members[i]; - offset = member->offset; llvm_value_struct_gep(c, &pointer, ref, i); } else if (is_array) { // Todo optimize - offset = i * type_size(array_element_type); - LLVMValueRef index = llvm_const_int(c, type_uint, i); - LLVMValueRef ptr = LLVMBuildInBoundsGEP2(c->builder, array_element_type_llvm, value, &index, 1, ""); - unsigned alignment = type_min_alignment(offset, ref->alignment); + AlignSize alignment; + LLVMValueRef ptr = llvm_emit_array_gep_raw(c, value, llvm_type, i, ref->alignment, &alignment); llvm_value_set_address_align(&pointer, ptr, element->type, alignment); } else @@ -1063,17 +1038,12 @@ static void llvm_emit_initialize_designated_const_range(GenContext *c, BEValue * emitted_value = &emitted_local; } LLVMTypeRef ref_type = llvm_get_type(c, ref->type); - // Assign the index_ptr to the start value. - LLVMValueRef indices[2] = { - llvm_get_zero(c, curr->index_expr->type), - NULL - }; for (unsigned i = curr->index; i <= curr->index_end; i++) { - indices[1] = llvm_const_int(c, curr->index_expr->type, i); BEValue new_ref; - LLVMValueRef ptr = LLVMBuildInBoundsGEP2(c->builder, ref_type, ref->value, indices, 2, ""); - llvm_value_set_address(&new_ref, ptr, type_get_indexed_type(ref->type)); + AlignSize alignment; + LLVMValueRef ptr = llvm_emit_array_gep_raw(c, ref->value, ref_type, i, ref->alignment, &alignment); + llvm_value_set_address_align(&new_ref, ptr, type_get_indexed_type(ref->type), alignment); llvm_emit_initialize_designated(c, &new_ref, offset, current + 1, last, expr, emitted_value); } } @@ -1127,13 +1097,10 @@ static void llvm_emit_initialize_designated(GenContext *c, BEValue *ref, uint64_ case DESIGNATOR_ARRAY: { Type *type = ref->type->array.base; - LLVMValueRef indices[2]; offset += curr->index * type_size(type); - Type *index_type = curr->index > UINT32_MAX ? type_uint : type_ulong; - indices[0] = llvm_const_int(c, index_type, 0); - indices[1] = llvm_const_int(c, index_type, curr->index); - LLVMValueRef ptr = LLVMBuildInBoundsGEP2(c->builder, llvm_get_type(c, ref->type), ref->value, indices, 2, ""); - llvm_value_set_address_align(&value, ptr, type, type_min_alignment(offset, type_abi_alignment(type))); + AlignSize alignment; + LLVMValueRef ptr = llvm_emit_array_gep_raw(c, ref->value, llvm_get_type(c, ref->type), curr->index, ref->alignment, &alignment); + llvm_value_set_address_align(&value, ptr, type, alignment); llvm_emit_initialize_designated(c, &value, offset, current + 1, last, expr, emitted_value); break; } @@ -1236,7 +1203,7 @@ static inline void llvm_emit_inc_dec_change(GenContext *c, bool use_mod, BEValue { // Use byte here, we don't need a big offset. LLVMValueRef add = LLVMConstInt(diff < 0 ? llvm_get_type(c, type_ichar) : llvm_get_type(c, type_char), diff, diff < 0); - after_value = LLVMBuildGEP2(c->builder, llvm_get_pointee_type(c, type), value.value, &add, 1, "ptrincdec"); + after_value = llvm_emit_pointer_gep_raw(c, llvm_get_pointee_type(c, type), value.value, add); break; } case ALL_FLOATS: @@ -1459,8 +1426,14 @@ void llvm_emit_len_for_expr(GenContext *c, BEValue *be_value, BEValue *expr_to_l case TYPE_SUBARRAY: { LLVMTypeRef subarray_type = llvm_get_type(c, expr_to_len->type); - LLVMValueRef len_addr = LLVMBuildStructGEP2(c->builder, subarray_type, expr_to_len->value, 1, "len"); - llvm_value_set_address(be_value, len_addr, type_usize); + AlignSize alignment; + LLVMValueRef len_addr = llvm_emit_struct_gep_raw(c, + expr_to_len->value, + subarray_type, + 1, + expr_to_len->alignment, + &alignment); + llvm_value_set_address_align(be_value, len_addr, type_usize, alignment); break; } case TYPE_ARRAY: @@ -1517,10 +1490,7 @@ static void llvm_emit_trap_invalid_shift(GenContext *c, LLVMValueRef value, Type llvm_emit_panic_on_true(c, equal_or_greater, error, loc); } -static void -llvm_emit_slice_values(GenContext *c, Expr *slice, Type **parent_type_ref, LLVMValueRef *parent_base_ref, - Type **start_type_ref, LLVMValueRef *start_index_ref, Type **end_type_ref, - LLVMValueRef *end_index_ref) +static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_ref, BEValue *start_ref, BEValue *end_ref) { assert(slice->expr_kind == EXPR_SLICE); @@ -1643,53 +1613,42 @@ llvm_emit_slice_values(GenContext *c, Expr *slice, Type **parent_type_ref, LLVMV end_type = type_usize; } - *end_index_ref = end_index.value; - *end_type_ref = end_type; - *start_index_ref = start_index.value; - *start_type_ref = start_type; - *parent_base_ref = parent_base; - *parent_type_ref = parent_type; + llvm_value_set(end_ref, end_index.value, end_type); + llvm_value_set(start_ref, start_index.value, start_type); + llvm_value_set_address_align(parent_ref, parent_base, parent_type, type_abi_alignment(parent_type)); } static void gencontext_emit_slice(GenContext *c, BEValue *be_value, Expr *expr) { - Type *parent_type; - Type *end_type; - LLVMValueRef end_index; - LLVMValueRef parent_base; - Type *start_type; - LLVMValueRef start_index; // Use general function to get all the values we need (a lot!) - llvm_emit_slice_values(c, expr, &parent_type, - &parent_base, - &start_type, &start_index, &end_type, &end_index); + BEValue parent; + BEValue start; + BEValue end; + llvm_emit_slice_values(c, expr, &parent, &start, &end); + llvm_value_rvalue(c, &start); + llvm_value_rvalue(c, &end); // Calculate the size - LLVMValueRef size = LLVMBuildSub(c->builder, LLVMBuildAdd(c->builder, end_index, llvm_const_int(c, start_type, 1), ""), start_index, "size"); + LLVMValueRef size = LLVMBuildSub(c->builder, LLVMBuildAdd(c->builder, end.value, llvm_const_int(c, start.type, 1), ""), start.value, "size"); LLVMValueRef start_pointer; - switch (parent_type->type_kind) + switch (parent.type->type_kind) { case TYPE_ARRAY: { - Type *pointer_type = type_get_ptr(parent_type->array.base); - // Change pointer from Foo[x] to Foo* - parent_base = llvm_emit_bitcast(c, parent_base, pointer_type); + Type *pointer_type = type_get_ptr(parent.type->array.base); // Move pointer - start_pointer = LLVMBuildInBoundsGEP2(c->builder, llvm_get_pointee_type(c, pointer_type), parent_base, &start_index, 1, "offset"); + AlignSize alignment; + start_pointer = llvm_emit_array_gep_raw_index(c, parent.value, llvm_get_type(c, parent.type), start.value, type_abi_alignment(parent.type), &alignment); + start_pointer = llvm_emit_bitcast(c, start_pointer, pointer_type); break; } case TYPE_SUBARRAY: - { - start_pointer = LLVMBuildInBoundsGEP(c->builder, parent_base, &start_index, 1, "offsetsub"); + start_pointer = llvm_emit_pointer_inbounds_gep_raw(c, llvm_get_type(c, parent.type->array.base), parent.value, start.value); break; - } case TYPE_POINTER: - { - // Move pointer - start_pointer = LLVMBuildInBoundsGEP2(c->builder, llvm_get_pointee_type(c, parent_type), parent_base, &start_index, 1, "offset"); + start_pointer = llvm_emit_pointer_inbounds_gep_raw(c, llvm_get_pointee_type(c, parent.type), parent.value, start.value); break; - } default: TODO } @@ -1698,7 +1657,7 @@ static void gencontext_emit_slice(GenContext *c, BEValue *be_value, Expr *expr) llvm_value_set(be_value, llvm_emit_aggregate_value(c, expr->type, start_pointer, size, NULL), expr->type); } -static void gencontext_emit_slice_assign(GenContext *c, BEValue *be_value, Expr *expr) +static void llvm_emit_slice_assign(GenContext *c, BEValue *be_value, Expr *expr) { // We will be replacing the slice assign with code that roughly looks like this: // size_t end = slice_end; @@ -1709,16 +1668,39 @@ static void gencontext_emit_slice_assign(GenContext *c, BEValue *be_value, Expr Expr *assigned_value = expr->slice_assign_expr.right; llvm_emit_expr(c, be_value, assigned_value); - Type *parent_type; - Type *end_type; - LLVMValueRef end_index; - LLVMValueRef parent_base; - Type *start_type; - LLVMValueRef start_index; + BEValue parent; + BEValue start; + BEValue end; // Use general function to get all the values we need (a lot!) - llvm_emit_slice_values(c, expr->slice_assign_expr.left, &parent_type, - &parent_base, - &start_type, &start_index, &end_type, &end_index); + llvm_emit_slice_values(c, expr->slice_assign_expr.left, &parent, &start, &end); + llvm_value_rvalue(c, &start); + llvm_value_rvalue(c, &end); + + if (LLVMIsConstant(start.value) && LLVMIsConstant(end.value)) + { + assert(type_is_integer(start.type) && type_is_integer(end.type)); + bool signed_start = type_is_signed(start.type); + bool signed_end = type_is_signed(end.type); + uint64_t start_val = (uint64_t)(signed_start ? LLVMConstIntGetSExtValue(start.value) : LLVMConstIntGetZExtValue(start.value)); + uint64_t end_val = (uint64_t)(signed_end ? LLVMConstIntGetSExtValue(end.value) : LLVMConstIntGetZExtValue(end.value)); + assert(start_val <= INT64_MAX); + assert(end_val <= INT64_MAX); + if (start_val > end_val) return; + if (end_val - start_val < SLICE_MAX_UNROLL) + { + BEValue addr; + BEValue offset_val; + for (uint64_t i = start_val; i <= end_val; i++) + { + llvm_value_set_int(c, &offset_val, type_usize, i); + llvm_emit_subscript_addr_with_base(c, &addr, &parent, &offset_val, TOKLOC(expr->span.loc)); + + // And store the value. + llvm_store_bevalue(c, &addr, be_value); + } + return; + } + } // We will need to iterate for the general case. LLVMBasicBlockRef start_block = c->current_block; @@ -1733,11 +1715,13 @@ static void gencontext_emit_slice_assign(GenContext *c, BEValue *be_value, Expr // We emit a phi here: value is either the start value (start_offset) or the next value (next_offset) // but we haven't generated the latter yet, so we defer that. EMIT_LOC(c, expr); - LLVMValueRef offset = LLVMBuildPhi(c->builder, llvm_get_type(c, start_type), ""); + LLVMValueRef offset = LLVMBuildPhi(c->builder, llvm_get_type(c, start.type), ""); + BEValue offset_val; + llvm_value_set(&offset_val, offset, start.type); // Check if we're not at the end. BEValue value; - llvm_emit_int_comp(c, &value, start_type, end_type, offset, end_index, BINARYOP_LE); + llvm_emit_int_comp(c, &value, start.type, end.type, offset, end.value, BINARYOP_LE); // If jump to the assign block if we're not at the end index. EMIT_LOC(c, expr); @@ -1746,19 +1730,20 @@ static void gencontext_emit_slice_assign(GenContext *c, BEValue *be_value, Expr // Emit the assign. llvm_emit_block(c, assign_block); // Reuse this calculation - LLVMValueRef target = llvm_emit_subscript_addr_with_base(c, parent_type, parent_base, offset, TOKLOC(expr->span.loc)); + BEValue addr; + llvm_emit_subscript_addr_with_base(c, &addr, &parent, &offset_val, TOKLOC(expr->span.loc)); + // And store the value. - // TODO correct alignment. - llvm_store_bevalue_aligned(c, target, be_value, 0); + llvm_store_bevalue(c, &addr, be_value); // Create the new offset - LLVMValueRef next_offset = llvm_emit_add_int(c, start_type, offset, llvm_const_int(c, start_type, 1), TOKLOC(expr->span.loc)); + LLVMValueRef next_offset = llvm_emit_add_int(c, start.type, offset, llvm_const_int(c, start.type, 1), TOKLOC(expr->span.loc)); // And jump back llvm_emit_br(c, cond_block); // Finally set up our phi - LLVMValueRef logic_values[2] = { start_index, next_offset }; + LLVMValueRef logic_values[2] = { start.value, next_offset }; LLVMBasicBlockRef blocks[2] = { start_block, assign_block }; LLVMAddIncoming(offset, logic_values, blocks, 2); @@ -2147,10 +2132,10 @@ static void llvm_emit_subarray_comp(GenContext *c, BEValue *be_value, BEValue *l BEValue lhs_to_compare; BEValue rhs_to_compare; llvm_value_set_address(&lhs_to_compare, - LLVMBuildInBoundsGEP2(c->builder, llvm_base_type, lhs_value.value, &(current_index.value), 1, "lhs.ptr"), + llvm_emit_pointer_inbounds_gep_raw(c, llvm_base_type, lhs_value.value, current_index.value), array_base_type); llvm_value_set_address(&rhs_to_compare, - LLVMBuildInBoundsGEP2(c->builder, llvm_base_type, rhs_value.value, &(current_index.value), 1, "rhs.ptr"), + llvm_emit_pointer_inbounds_gep_raw(c, llvm_base_type, rhs_value.value, current_index.value), array_base_type); llvm_emit_comparison(c, &cmp, &lhs_to_compare, &rhs_to_compare, BINARYOP_EQ); match_fail_block = c->current_block; @@ -2311,17 +2296,8 @@ void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValu val = LLVMBuildExactSDiv(c->builder, val, llvm_const_int(c, type_iptrdiff, type_abi_alignment(lhs_type->pointer)), ""); break; } - if (is_constant) - { - rhs_value = LLVMConstNeg(rhs_value); - // TODO use GEP2 - val = LLVMConstGEP(lhs_value, &rhs_value, 1); - } - else - { - rhs_value = LLVMBuildNeg(c->builder, rhs_value, ""); - val = LLVMBuildGEP2(c->builder, llvm_get_pointee_type(c, lhs_type), lhs_value, &rhs_value, 1, "ptrsub"); - } + rhs_value = LLVMConstNeg(rhs_value); + val = llvm_emit_pointer_gep_raw(c, llvm_get_pointee_type(c, lhs_type), lhs_value, rhs_value); break; } if (is_float) @@ -2335,16 +2311,7 @@ void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValu if (lhs_type->type_kind == TYPE_POINTER) { assert(type_is_integer(rhs_type)); - if (LLVMIsConstant(lhs_value) && LLVMIsConstant(rhs_value)) - { - // TODO use LLVMConstGEP2 - // val = LLVMConstGEP2(llvm_get_pointee_type(c, lhs_type), lhs_value, &rhs_value, 1); - val = LLVMConstGEP(lhs_value, &rhs_value, 1); - } - else - { - val = LLVMBuildGEP2(c->builder, llvm_get_pointee_type(c, lhs_type), lhs_value, &rhs_value, 1, "ptradd"); - } + val = llvm_emit_pointer_gep_raw(c, llvm_get_pointee_type(c, lhs_type), lhs_value, rhs_value); break; } if (is_float) @@ -2505,25 +2472,25 @@ void llvm_emit_try_assign_try_catch(GenContext *c, bool is_try, BEValue *be_valu } -void llvm_emit_try_assign_expr(GenContext *c, BEValue *be_value, Expr *expr) -{ - // Create the variable reference. - BEValue addr; - llvm_emit_expr(c, &addr, expr->try_assign_expr.expr); - assert(llvm_value_is_addr(&addr)); - - if (expr->try_assign_expr.is_try) - { - llvm_emit_try_assign_try_catch(c, true, be_value, &addr, NULL, expr->try_assign_expr.init); - } - else - { - llvm_emit_try_assign_try_catch(c, false, be_value, NULL, &addr, expr->try_assign_expr.init); - } -} static inline void llvm_emit_catch_expr(GenContext *c, BEValue *value, Expr *expr) { + Expr *inner = expr->inner_expr; + + if (inner->expr_kind == EXPR_IDENTIFIER) + { + Decl *decl = inner->identifier_expr.decl; + assert(IS_FAILABLE(decl)); + llvm_value_set_address(value, decl_failable_ref(decl), type_anyerr); + return; + } + + if (inner->expr_kind == EXPR_FAILABLE) + { + llvm_emit_expr(c, value, inner->inner_expr); + return; + } + LLVMBasicBlockRef end_block = llvm_basic_block_new(c, "noerr_block"); // Store catch/error var @@ -2536,7 +2503,7 @@ static inline void llvm_emit_catch_expr(GenContext *c, BEValue *value, Expr *exp c->catch_block = end_block; BEValue expr_value; - llvm_emit_expr(c, &expr_value, expr->try_expr.expr); + llvm_emit_expr(c, &expr_value, inner); llvm_value_fold_failable(c, &expr_value); // Restore. @@ -2550,11 +2517,7 @@ static inline void llvm_emit_catch_expr(GenContext *c, BEValue *value, Expr *exp } void llvm_emit_try_expr(GenContext *c, BEValue *value, Expr *expr) { - if (!expr->try_expr.is_try) - { - llvm_emit_catch_expr(c, value, expr); - return; - } + LLVMBasicBlockRef error_block = llvm_basic_block_new(c, "error_block"); LLVMBasicBlockRef no_err_block = llvm_basic_block_new(c, "noerr_block"); LLVMBasicBlockRef phi_block = llvm_basic_block_new(c, "phi_trycatch_block"); @@ -2566,7 +2529,7 @@ void llvm_emit_try_expr(GenContext *c, BEValue *value, Expr *expr) c->error_var = NULL; c->catch_block = error_block; - llvm_emit_expr(c, value, expr->try_expr.expr); + llvm_emit_expr(c, value, expr->inner_expr); llvm_value_fold_failable(c, value); // Restore. @@ -2752,7 +2715,7 @@ static inline void llvm_emit_force_unwrap_expr(GenContext *c, BEValue *be_value, c->error_var = error_var; c->catch_block = panic_block; - llvm_emit_expr(c, be_value, expr->force_unwrap_expr); + llvm_emit_expr(c, be_value, expr->inner_expr); llvm_value_rvalue(c, be_value); // Restore. @@ -3088,35 +3051,39 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr) } } -static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVMValueRef expand_ptr, LLVMValueRef **values); +static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVMValueRef expand_ptr, LLVMValueRef **values, AlignSize alignment); -static void gencontext_expand_array_to_args(GenContext *c, Type *param_type, LLVMValueRef expand_ptr, LLVMValueRef **values) +static void llvm_expand_array_to_args(GenContext *c, Type *param_type, LLVMValueRef expand_ptr, LLVMValueRef **values, AlignSize alignment) { - LLVMTypeRef element_type = llvm_get_type(c, param_type->array.base); - LLVMValueRef zero = llvm_get_zero(c, type_int); - LLVMValueRef indices[2] = { zero, zero, }; + LLVMTypeRef array_type = llvm_get_type(c, param_type); for (ByteSize i = 0; i < param_type->array.len; i++) { - indices[1] = llvm_const_int(c, type_int, i); - LLVMValueRef element_ptr = LLVMBuildGEP2(c->builder, element_type, expand_ptr, indices, 2, ""); - llvm_expand_type_to_args(c, param_type->array.base, element_ptr, values); + AlignSize load_align; + LLVMValueRef element_ptr = llvm_emit_array_gep_raw(c, expand_ptr, array_type, i, alignment, &load_align); + llvm_expand_type_to_args(c, param_type->array.base, element_ptr, values, load_align); } } -static void gencontext_expand_struct_to_args(GenContext *context, Type *param_type, LLVMValueRef expand_ptr, LLVMValueRef **values) +static void llvm_expand_struct_to_args(GenContext *context, Type *param_type, LLVMValueRef expand_ptr, LLVMValueRef **values, AlignSize alignment) { Decl **members = param_type->decl->strukt.members; VECEACH(members, i) { Type *member_type = members[i]->type; if (type_is_empty_field(member_type, true)) continue; - LLVMValueRef member_ptr = LLVMBuildStructGEP(context->builder, expand_ptr, i, "expandmember"); - llvm_expand_type_to_args(context, member_type, member_ptr, values); + AlignSize load_align; + LLVMValueRef member_ptr = llvm_emit_struct_gep_raw(context, + expand_ptr, + llvm_get_type(context, param_type), + i, + alignment, + &load_align); + llvm_expand_type_to_args(context, member_type, member_ptr, values, load_align); } } -static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVMValueRef expand_ptr, LLVMValueRef **values) +static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVMValueRef expand_ptr, LLVMValueRef **values, AlignSize alignment) { REDO: switch (type_lowering(param_type)->type_kind) @@ -3132,22 +3099,23 @@ static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVM case TYPE_BITSTRUCT: case TYPE_FAILABLE: case CT_TYPES: + case TYPE_FAILABLE_ANY: UNREACHABLE break; case TYPE_BOOL: case ALL_INTS: case ALL_FLOATS: case TYPE_POINTER: - vec_add(*values, LLVMBuildLoad2(context->builder, llvm_get_type(context, param_type), expand_ptr, "loadexpanded")); + vec_add(*values, llvm_emit_load_aligned(context, llvm_get_type(context, param_type), expand_ptr, alignment, "loadexpanded")); return; case TYPE_TYPEDEF: param_type = param_type->canonical; goto REDO; case TYPE_STRUCT: - gencontext_expand_struct_to_args(context, param_type, expand_ptr, values); + llvm_expand_struct_to_args(context, param_type, expand_ptr, values, alignment); break; case TYPE_ARRAY: - gencontext_expand_array_to_args(context, param_type, expand_ptr, values); + llvm_expand_array_to_args(context, param_type, expand_ptr, values, alignment); break; case TYPE_UNION: case TYPE_SUBARRAY: @@ -3159,46 +3127,88 @@ static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVM } } - -LLVMValueRef llvm_emit_struct_gep_raw(GenContext *context, LLVMValueRef ptr, LLVMTypeRef struct_type, unsigned index, unsigned struct_alignment, unsigned offset, unsigned *alignment) +void llvm_emit_struct_member_ref(GenContext *c, BEValue *struct_ref, BEValue *member_ref, unsigned member_id) { - *alignment = type_min_alignment(offset, struct_alignment); + assert(llvm_value_is_addr(struct_ref)); + llvm_value_fold_failable(c, struct_ref); + assert(struct_ref->type->type_kind == TYPE_STRUCT); + AlignSize align; + LLVMValueRef ptr = llvm_emit_struct_gep_raw(c, struct_ref->value, llvm_get_type(c, struct_ref->type), member_id, struct_ref->alignment, &align); + llvm_value_set_address_align(member_ref, ptr, struct_ref->type->decl->strukt.members[member_id]->type, align); +} + +LLVMValueRef llvm_emit_struct_gep_raw(GenContext *context, LLVMValueRef ptr, LLVMTypeRef struct_type, unsigned index, + unsigned struct_alignment, AlignSize *alignment) +{ + *alignment = type_min_alignment(LLVMOffsetOfElement(context->target_data, struct_type, index), struct_alignment); if (LLVMIsConstant(ptr)) { LLVMValueRef idx[2] = { llvm_get_zero(context, type_int), llvm_const_int(context, type_int, index) }; - return LLVMConstInBoundsGEP(ptr, idx, 2); + return LLVMConstInBoundsGEP2(struct_type, ptr, idx, 2); } return LLVMBuildStructGEP2(context->builder, struct_type, ptr, index, ""); } -LLVMValueRef llvm_emit_array_gep_raw(GenContext *c, LLVMValueRef ptr, LLVMTypeRef array_type, unsigned index, unsigned array_alignment, unsigned *alignment) + +LLVMValueRef llvm_emit_array_gep_raw_index(GenContext *c, LLVMValueRef ptr, LLVMTypeRef array_type, LLVMValueRef index, AlignSize array_alignment, AlignSize *alignment) { *alignment = type_min_alignment(llvm_store_size(c, LLVMGetElementType(array_type)), array_alignment); - LLVMValueRef idx[2] = { llvm_get_zero(c, type_int), llvm_const_int(c, type_int, index) }; + LLVMValueRef idx[2] = { LLVMConstNull(LLVMTypeOf(index)), index }; if (LLVMIsConstant(ptr)) { - return LLVMConstInBoundsGEP(ptr, idx, 2); + return LLVMConstInBoundsGEP2(array_type, ptr, idx, 2); } return LLVMBuildInBoundsGEP2(c->builder, array_type, ptr, idx, 2, ""); } +LLVMValueRef llvm_emit_array_gep_raw(GenContext *c, LLVMValueRef ptr, LLVMTypeRef array_type, unsigned index, AlignSize array_alignment, AlignSize *alignment) +{ + return llvm_emit_array_gep_raw_index(c, ptr, array_type, llvm_const_int(c, type_usize, index), array_alignment, alignment); +} + + +LLVMValueRef llvm_emit_pointer_gep_raw(GenContext *c, LLVMTypeRef pointee_type, LLVMValueRef ptr, LLVMValueRef offset) +{ + if (LLVMIsConstant(ptr) && LLVMIsConstant(offset)) + { + return LLVMConstGEP2(pointee_type, ptr, &offset, 1); + } + return LLVMBuildGEP2(c->builder, pointee_type, ptr, &offset, 1, "ptroffset"); +} + +LLVMValueRef llvm_emit_pointer_inbounds_gep_raw(GenContext *c, LLVMTypeRef pointee_type, LLVMValueRef ptr, LLVMValueRef offset) +{ + if (LLVMIsConstant(ptr) && LLVMIsConstant(offset)) + { + return LLVMConstInBoundsGEP2(pointee_type, ptr, &offset, 1); + } + return LLVMBuildInBoundsGEP2(c->builder, pointee_type, ptr, &offset, 1, "ptroffset"); +} + void llvm_emit_subarray_len(GenContext *c, BEValue *subarray, BEValue *len) { llvm_value_addr(c, subarray); - unsigned alignment = 0; - LLVMValueRef len_addr = llvm_emit_struct_gep_raw(c, subarray->value, llvm_get_type(c, subarray->type), 1, subarray->alignment, - type_abi_alignment(type_voidptr), &alignment); + AlignSize alignment = 0; + LLVMValueRef len_addr = llvm_emit_struct_gep_raw(c, + subarray->value, + llvm_get_type(c, subarray->type), + 1, + subarray->alignment, + &alignment); llvm_value_set_address_align(len, len_addr, type_usize, alignment); } void llvm_emit_subarray_pointer(GenContext *c, BEValue *subarray, BEValue *pointer) { llvm_value_addr(c, subarray); - unsigned alignment = 0; - LLVMValueRef pointer_addr = llvm_emit_struct_gep_raw(c, subarray->value, llvm_get_type(c, subarray->type), 0, subarray->alignment, - 0, &alignment); + AlignSize alignment = 0; + LLVMValueRef pointer_addr = llvm_emit_struct_gep_raw(c, + subarray->value, + llvm_get_type(c, subarray->type), + 0, + subarray->alignment, + &alignment); llvm_value_set_address_align(pointer, pointer_addr, type_get_ptr(subarray->type->array.base), alignment); - } void llvm_value_struct_gep(GenContext *c, BEValue *element, BEValue *struct_pointer, unsigned index) @@ -3215,13 +3225,12 @@ void llvm_value_struct_gep(GenContext *c, BEValue *element, BEValue *struct_poin } actual_index++; } - unsigned alignment; + AlignSize alignment; LLVMValueRef ref = llvm_emit_struct_gep_raw(c, struct_pointer->value, llvm_get_type(c, struct_pointer->type), actual_index, struct_pointer->alignment, - member->offset, &alignment); llvm_value_set_address(element, ref, member->type); element->alignment = alignment; @@ -3297,34 +3306,16 @@ void llvm_emit_parameter(GenContext *c, LLVMValueRef **args, ABIArgInfo *info, B vec_add(*args, llvm_emit_coerce(c, coerce_type, be_value, type)); return; } - LLVMValueRef cast; AlignSize target_alignment = llvm_abi_alignment(c, coerce_type); - AlignSize max_align = MAX((be_value->alignment), llvm_abi_alignment(c, coerce_type)); - // If we are loading something with greater alignment than what we have, we cannot directly memcpy. - if (llvm_value_is_addr(be_value) && be_value->alignment < target_alignment) - { - // So load it instead. - llvm_value_rvalue(c, be_value); - } - - // In this case we have something nicely aligned, so we just do a cast. - if (llvm_value_is_addr(be_value)) - { - cast = LLVMBuildBitCast(c->builder, be_value->value, LLVMPointerType(coerce_type, 0), ""); - } - else - { - cast = llvm_emit_alloca(c, coerce_type, max_align, "coerce"); - LLVMValueRef target = LLVMBuildBitCast(c->builder, cast, llvm_get_ptr_type(c, type), ""); - llvm_store_bevalue_aligned(c, target, be_value, max_align); - } + AlignSize alignment; + LLVMValueRef cast = llvm_emit_coerce_alignment(c, be_value, coerce_type, target_alignment, &alignment); LLVMTypeRef element = llvm_abi_type(c, info->direct_coerce.type); for (unsigned idx = 0; idx < info->direct_coerce.elements; idx++) { - LLVMValueRef element_ptr = LLVMBuildStructGEP2(c->builder, coerce_type, cast, idx, ""); - vec_add(*args, - llvm_emit_load_aligned(c, element, element_ptr, llvm_abi_alignment(c, element), "")); + AlignSize load_align; + LLVMValueRef element_ptr = llvm_emit_struct_gep_raw(c, cast, coerce_type, idx, alignment, &load_align); + vec_add(*args, llvm_emit_load_aligned(c, element, element_ptr, load_align, "")); } return; } @@ -3337,13 +3328,17 @@ void llvm_emit_parameter(GenContext *c, LLVMValueRef **args, ABIArgInfo *info, B LLVMTypeRef lo = llvm_abi_type(c, info->direct_pair.lo); LLVMTypeRef hi = llvm_abi_type(c, info->direct_pair.hi); LLVMTypeRef struct_type = llvm_get_coerce_type(c, info); - LLVMValueRef cast = LLVMBuildBitCast(c->builder, be_value->value, LLVMPointerType(struct_type, 0), "casttemp"); + + AlignSize struct_align; + LLVMValueRef cast = llvm_emit_coerce_alignment(c, be_value, struct_type, llvm_abi_alignment(c, struct_type), &struct_align); // Get the lo value. - LLVMValueRef lo_ptr = LLVMBuildStructGEP2(c->builder, struct_type, cast, 0, "lo"); - vec_add(*args, llvm_emit_load_aligned(c, lo, lo_ptr, llvm_abi_alignment(c, lo), "lo")); + + AlignSize alignment; + LLVMValueRef lo_ptr = llvm_emit_struct_gep_raw(c, cast, struct_type, 0, struct_align, &alignment); + vec_add(*args, llvm_emit_load_aligned(c, lo, lo_ptr, alignment, "lo")); // Get the hi value. - LLVMValueRef hi_ptr = LLVMBuildStructGEP2(c->builder, struct_type, cast, 1, "hi"); - vec_add(*args, llvm_emit_load_aligned(c, hi, hi_ptr, llvm_abi_alignment(c, hi), "hi")); + LLVMValueRef hi_ptr = llvm_emit_struct_gep_raw(c, cast, struct_type, 1, struct_align, &alignment); + vec_add(*args, llvm_emit_load_aligned(c, hi, hi_ptr, alignment, "hi")); return; } case ABI_ARG_EXPAND_COERCE: @@ -3351,13 +3346,16 @@ void llvm_emit_parameter(GenContext *c, LLVMValueRef **args, ABIArgInfo *info, B // Move this to an address (if needed) llvm_value_addr(c, be_value); LLVMTypeRef coerce_type = llvm_get_coerce_type(c, info); - LLVMValueRef temp = LLVMBuildBitCast(c->builder, be_value->value, LLVMPointerType(coerce_type, 0), "coerce"); - LLVMValueRef gep_first = LLVMBuildStructGEP2(c->builder, coerce_type, temp, info->coerce_expand.lo_index, "first"); - vec_add(*args, LLVMBuildLoad2(c->builder, llvm_abi_type(c, info->coerce_expand.lo), gep_first, "")); + AlignSize alignment; + LLVMValueRef temp = llvm_emit_coerce_alignment(c, be_value, coerce_type, llvm_abi_alignment(c, coerce_type), &alignment); + + AlignSize align; + LLVMValueRef gep_first = llvm_emit_struct_gep_raw(c, temp, coerce_type, info->coerce_expand.lo_index, alignment, &align); + vec_add(*args, llvm_emit_load_aligned(c, llvm_abi_type(c, info->coerce_expand.lo), gep_first, align, "")); if (info->coerce_expand.hi) { - LLVMValueRef gep_second = LLVMBuildStructGEP2(c->builder, coerce_type, temp, info->coerce_expand.hi_index, "second"); - vec_add(*args, LLVMBuildLoad2(c->builder, llvm_abi_type(c, info->coerce_expand.hi), gep_second, "")); + LLVMValueRef gep_second = llvm_emit_struct_gep_raw(c, temp, coerce_type, info->coerce_expand.hi_index, alignment, &align); + vec_add(*args, llvm_emit_load_aligned(c, llvm_abi_type(c, info->coerce_expand.hi), gep_second, align, "")); } return; } @@ -3365,7 +3363,7 @@ void llvm_emit_parameter(GenContext *c, LLVMValueRef **args, ABIArgInfo *info, B { // Move this to an address (if needed) llvm_value_addr(c, be_value); - llvm_expand_type_to_args(c, type, be_value->value, args); + llvm_expand_type_to_args(c, type, be_value->value, args, be_value->alignment); // Expand the padding here. if (info->expand.padding_type) { @@ -3562,20 +3560,15 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr) LLVMTypeRef llvm_pointee = llvm_get_type(c, pointee_type); Type *array = type_get_array(pointee_type, arguments - non_variadic_params); LLVMTypeRef llvm_array_type = llvm_get_type(c, array); - LLVMValueRef array_ref = llvm_emit_alloca_aligned(c, array, "varargslots"); - LLVMValueRef zero = llvm_get_zero(c, type_usize); - LLVMValueRef indices[2] = { - zero, - zero, - }; + AlignSize alignment = type_alloca_alignment(array); + LLVMValueRef array_ref = llvm_emit_alloca(c, llvm_array_type, alignment, "varargslots"); for (unsigned i = non_variadic_params; i < arguments; i++) { Expr *arg_expr = expr->call_expr.arguments[i]; - llvm_emit_expr(c, &temp_value, arg_expr); - indices[1] = llvm_const_int(c, type_usize, i - non_variadic_params); - LLVMValueRef slot = LLVMBuildInBoundsGEP2(c->builder, llvm_array_type, array_ref, indices, 2, ""); - llvm_store_bevalue_aligned(c, slot, &temp_value, 0); + AlignSize store_alignment; + LLVMValueRef slot = llvm_emit_array_gep_raw(c, array_ref, llvm_array_type, i - non_variadic_params, alignment, &store_alignment); + llvm_store_bevalue_aligned(c, slot, &temp_value, store_alignment); } BEValue len_addr; llvm_emit_subarray_len(c, &subarray, &len_addr); @@ -3604,6 +3597,10 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr) // 10. Create the actual call (remember to emit a loc, because we might have shifted loc emitting the params) EMIT_LOC(c, expr); LLVMValueRef call_value = LLVMBuildCall2(c->builder, func_type, func, values, vec_size(values), ""); + if (signature->call_abi) + { + LLVMSetInstructionCallConv(call_value, llvm_call_convention_from_call(signature->call_abi, platform_target.arch, platform_target.os)); + } if (expr->call_expr.force_noinline) { llvm_attribute_add_call(c, call_value, attribute_noinline, -1, 0); @@ -3689,14 +3686,10 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr) LLVMTypeRef coerce_type = llvm_get_coerce_type(c, ret_info); LLVMValueRef coerce = LLVMBuildBitCast(c->builder, ret, coerce_type, ""); - // 15c. Find the type of the "lo" element. - LLVMTypeRef lo_type = llvm_abi_type(c, ret_info->coerce_expand.lo); - // 15d. Find the address to the low value - unsigned alignment; + AlignSize alignment; LLVMValueRef lo = llvm_emit_struct_gep_raw(c, coerce, coerce_type, ret_info->coerce_expand.lo_index, - type_abi_alignment(return_type), - ret_info->coerce_expand.offset_lo, &alignment); + type_abi_alignment(return_type), &alignment); // 15e. If there is only a single field, we simply store the value, // so { lo } set into { pad, lo, pad } -> original type. @@ -3704,13 +3697,9 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr) { // Here we do a store to call -> lo (leaving the rest undefined) llvm_store_aligned(c, lo, call_value, alignment); - break; } - // 15f. Calculate the hi type. - LLVMTypeRef hi_type = llvm_abi_type(c, ret_info->coerce_expand.hi); - // 15g. We can now extract { lo, hi } to lo_value and hi_value. LLVMValueRef lo_value = LLVMBuildExtractValue(c->builder, call_value, 0, ""); LLVMValueRef hi_value = LLVMBuildExtractValue(c->builder, call_value, 1, ""); @@ -3720,8 +3709,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr) // 15i. Calculate the address to the high value (like for the low in 15d. LLVMValueRef hi = llvm_emit_struct_gep_raw(c, coerce, coerce_type, ret_info->coerce_expand.hi_index, - type_abi_alignment(return_type), - ret_info->coerce_expand.offset_hi, &alignment); + type_abi_alignment(return_type), &alignment); // 15h. Store the high value. llvm_store_aligned(c, hi, hi_value, alignment); @@ -3984,7 +3972,7 @@ BEValue llvm_emit_assign_expr(GenContext *c, BEValue *ref, Expr *expr, LLVMValue static inline void gencontext_emit_failable(GenContext *context, BEValue *be_value, Expr *expr) { - Expr *fail = expr->failable_expr; + Expr *fail = expr->inner_expr; if (context->error_var) { assert(context->error_var); @@ -4260,7 +4248,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) llvm_emit_local_decl(c, expr->decl_expr); return; case EXPR_SLICE_ASSIGN: - gencontext_emit_slice_assign(c, value, expr); + llvm_emit_slice_assign(c, value, expr); return; case EXPR_SLICE: gencontext_emit_slice(c, value, expr); @@ -4274,8 +4262,8 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) case EXPR_TRY: llvm_emit_try_expr(c, value, expr); return; - case EXPR_TRY_ASSIGN: - llvm_emit_try_assign_expr(c, value, expr); + case EXPR_CATCH: + llvm_emit_catch_expr(c, value, expr); return; case EXPR_NOP: llvm_value_set(value, NULL, type_void); @@ -4322,8 +4310,8 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) case EXPR_RETHROW: gencontext_emit_rethrow_expr(c, value, expr); return; - case EXPR_TYPEOF: case EXPR_TYPEID: + case EXPR_GROUP: // These are folded in the semantic analysis step. UNREACHABLE case EXPR_IDENTIFIER: @@ -4339,9 +4327,6 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) case EXPR_CALL: llvm_emit_call_expr(c, value, expr); return; - case EXPR_GROUP: - expr = expr->group_expr; - return; case EXPR_EXPRESSION_LIST: gencontext_emit_expression_list_expr(c, value, expr); return; diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index 513f97992..06cf7632a 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -7,7 +7,7 @@ static void llvm_emit_param_attributes(GenContext *context, LLVMValueRef function, ABIArgInfo *info, bool is_return, int index, int last_index); static inline void llvm_emit_return_value(GenContext *context, LLVMValueRef value); -static void llvm_expand_from_args(GenContext *c, Type *type, LLVMValueRef ref, unsigned *index); +static void llvm_expand_from_args(GenContext *c, Type *type, LLVMValueRef ref, unsigned *index, AlignSize alignment); static inline void llvm_process_parameter_value(GenContext *c, Decl *decl, unsigned *index); bool llvm_emit_check_block_branch(GenContext *context) @@ -76,28 +76,30 @@ void llvm_emit_block(GenContext *context, LLVMBasicBlockRef next_block) context->current_block_is_target = false; } -static void llvm_expand_from_args(GenContext *c, Type *type, LLVMValueRef ref, unsigned *index) +static void llvm_expand_from_args(GenContext *c, Type *type, LLVMValueRef ref, unsigned *index, AlignSize alignment) { switch (type->type_kind) { case TYPE_ARRAY: + { + LLVMTypeRef array_type = llvm_get_type(c, type); for (unsigned i = 0; i < type->array.len; i++) { - LLVMValueRef indices[2] = { llvm_get_zero(c, type_uint), llvm_const_int(c, type_uint, i) }; - LLVMValueRef target = LLVMBuildInBoundsGEP2(c->builder, llvm_get_type(c, type), ref, indices, 2, ""); - LLVMValueRef cast_addr = llvm_emit_bitcast(c, target, type_get_ptr(type->array.base)); - llvm_expand_from_args(c, type->array.base, cast_addr, index); + AlignSize element_align; + LLVMValueRef target = llvm_emit_array_gep_raw(c, ref, array_type, i, alignment, &element_align); + llvm_expand_from_args(c, type->array.base, target, index, element_align); } return; + } case TYPE_STRUCT: { + LLVMTypeRef struct_type = llvm_get_type(c, type); Decl **members = type->decl->strukt.members; VECEACH(members, i) { - LLVMValueRef indices[2] = { llvm_get_zero(c, type_uint), llvm_const_int(c, type_uint, i) }; - LLVMValueRef target = LLVMBuildInBoundsGEP2(c->builder, llvm_get_type(c, type), ref, indices, 2, ""); - LLVMValueRef cast_addr = llvm_emit_bitcast(c, target, type_get_ptr(members[i]->type)); - llvm_expand_from_args(c, members[i]->type, cast_addr, index); + AlignSize element_align; + LLVMValueRef target = llvm_emit_struct_gep_raw(c, ref, struct_type, i, alignment, &element_align); + llvm_expand_from_args(c, members[i]->type, target, index, element_align); } return; } @@ -105,11 +107,11 @@ static void llvm_expand_from_args(GenContext *c, Type *type, LLVMValueRef ref, u { Type *largest_type = type_find_largest_union_element(type); LLVMValueRef cast_addr = llvm_emit_bitcast(c, ref, type_get_ptr(largest_type)); - llvm_expand_from_args(c, largest_type, cast_addr, index); + llvm_expand_from_args(c, largest_type, cast_addr, index, alignment); return; } default: - LLVMBuildStore(c->builder, llvm_get_next_param(c, index), ref); + llvm_store_aligned(c, ref, llvm_get_next_param(c, index), alignment); return; } } @@ -139,12 +141,15 @@ static inline void llvm_process_parameter_value(GenContext *c, Decl *decl, unsig // Create the expand type: LLVMTypeRef coerce_type = llvm_get_coerce_type(c, info); LLVMValueRef temp = LLVMBuildBitCast(c->builder, decl->backend_ref, LLVMPointerType(coerce_type, 0), "coerce"); - LLVMValueRef gep_first = LLVMBuildStructGEP2(c->builder, coerce_type, temp, info->coerce_expand.lo_index, "first"); - llvm_store_aligned(c, gep_first, llvm_get_next_param(c, index), 0); + + AlignSize alignment = decl->alignment; + AlignSize element_align; + LLVMValueRef gep_first = llvm_emit_struct_gep_raw(c, temp, coerce_type, info->coerce_expand.lo_index, alignment, &element_align); + llvm_store_aligned(c, gep_first, llvm_get_next_param(c, index), element_align); if (info->coerce_expand.hi) { - LLVMValueRef gep_second = LLVMBuildStructGEP2(c->builder, coerce_type, temp, info->coerce_expand.hi_index, "second"); - llvm_store_aligned(c, gep_second, llvm_get_next_param(c, index), 0); + LLVMValueRef gep_second = llvm_emit_struct_gep_raw(c, temp, coerce_type, info->coerce_expand.hi_index, alignment, &element_align); + llvm_store_aligned(c, gep_second, llvm_get_next_param(c, index), element_align); } break; } @@ -159,15 +164,14 @@ static inline void llvm_process_parameter_value(GenContext *c, Decl *decl, unsig // Cast to { lo, hi } LLVMValueRef cast = LLVMBuildBitCast(c->builder, decl->backend_ref, LLVMPointerType(struct_type, 0), "pair"); // Point to the lo value. - LLVMValueRef lo_ptr = LLVMBuildStructGEP2(c->builder, struct_type, cast, 0, "lo"); + AlignSize element_align; + LLVMValueRef lo_ptr = llvm_emit_struct_gep_raw(c, cast, struct_type, 0, decl_alignment, &element_align); // Store it in the struct. - AlignSize lo_alignment = MIN(llvm_abi_alignment(c, lo), decl_alignment); - llvm_store_aligned(c, lo_ptr, llvm_get_next_param(c, index), lo_alignment); + llvm_store_aligned(c, lo_ptr, llvm_get_next_param(c, index), element_align); // Point to the hi value. - LLVMValueRef hi_ptr = LLVMBuildStructGEP2(c->builder, struct_type, cast, 1, "hi"); + LLVMValueRef hi_ptr = llvm_emit_struct_gep_raw(c, cast, struct_type, 1, decl_alignment, &element_align); // Store it in the struct. - AlignSize hi_alignment = MIN(llvm_abi_alignment(c, hi), decl_alignment); - llvm_store_aligned(c, hi_ptr, llvm_get_next_param(c, index), hi_alignment); + llvm_store_aligned(c, hi_ptr, llvm_get_next_param(c, index), element_align); return; } case ABI_ARG_DIRECT_COERCE: @@ -194,19 +198,20 @@ static inline void llvm_process_parameter_value(GenContext *c, Decl *decl, unsig // Cast to the coerce type. LLVMValueRef cast = LLVMBuildBitCast(c->builder, decl->backend_ref, LLVMPointerType(coerce_type, 0), "coerce"); + AlignSize decl_alignment = decl->alignment; // Store each expanded parameter. for (unsigned idx = 0; idx < info->direct_coerce.elements; idx++) { - LLVMValueRef element_ptr = LLVMBuildStructGEP2(c->builder, coerce_type, cast, idx, ""); + AlignSize align; + LLVMValueRef element_ptr = llvm_emit_struct_gep_raw(c, cast, coerce_type, idx, decl_alignment, &align); LLVMValueRef value = llvm_get_next_param(c, index); - - llvm_store_aligned(c, element_ptr, value, MIN(llvm_abi_alignment(c, element_type), decl->alignment)); + llvm_store_aligned(c, element_ptr, value, align); } return; } case ABI_ARG_EXPAND: { - llvm_expand_from_args(c, decl->type, decl->backend_ref, index); + llvm_expand_from_args(c, decl->type, decl->backend_ref, index, decl->alignment); if (info->expand.padding_type) { // Skip the pad. @@ -298,10 +303,9 @@ void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *failabl LLVMValueRef coerce = LLVMBuildBitCast(c->builder, return_value->value, coerce_type, ""); // We might have only one value, in that case, build a GEP to that one. LLVMValueRef lo_val; - unsigned alignment; + AlignSize alignment; LLVMValueRef lo = llvm_emit_struct_gep_raw(c, coerce, coerce_type, info->coerce_expand.lo_index, - return_value->alignment, - info->coerce_expand.offset_lo, &alignment); + return_value->alignment, &alignment); LLVMTypeRef lo_type = llvm_abi_type(c, info->coerce_expand.lo); lo_val = llvm_emit_load_aligned(c, lo_type, lo, alignment, ""); @@ -314,8 +318,7 @@ void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *failabl // Let's make a first class aggregate LLVMValueRef hi = llvm_emit_struct_gep_raw(c, coerce, coerce_type, info->coerce_expand.hi_index, - return_value->alignment, - info->coerce_expand.offset_hi, &alignment); + return_value->alignment, &alignment); LLVMTypeRef hi_type = llvm_abi_type(c, info->coerce_expand.hi); LLVMValueRef hi_val = llvm_emit_load_aligned(c, hi_type, hi, alignment, ""); @@ -354,7 +357,7 @@ void llvm_emit_return_implicit(GenContext *c) LLVMBuildUnreachable(c->builder); return; } - if (rtype_real->type_kind == TYPE_FAILABLE) + if (type_is_failable(rtype_real)) { llvm_emit_return_abi(c, NULL, NULL); return; diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index ccbb83a4b..1b92c0080 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -22,6 +22,7 @@ #include "dwarf.h" +#define SLICE_MAX_UNROLL 4 typedef enum { @@ -265,8 +266,15 @@ void llvm_emit_ptr_from_array(GenContext *c, BEValue *value); void llvm_emit_debug_output(GenContext *c, const char *message, const char *file, const char *func, unsigned line); void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *failable); void llvm_emit_return_implicit(GenContext *c); -LLVMValueRef llvm_emit_struct_gep_raw(GenContext *context, LLVMValueRef ptr, LLVMTypeRef struct_type, unsigned index, unsigned struct_alignment, unsigned offset, unsigned *alignment); -LLVMValueRef llvm_emit_array_gep_raw(GenContext *c, LLVMValueRef ptr, LLVMTypeRef array_type, unsigned index, unsigned array_alignment, unsigned *alignment); +void llvm_emit_struct_member_ref(GenContext *c, BEValue *struct_ref, BEValue *member_ref, unsigned member_id); +LLVMValueRef llvm_emit_struct_gep_raw(GenContext *context, LLVMValueRef ptr, LLVMTypeRef struct_type, unsigned index, + unsigned struct_alignment, AlignSize *alignment); +LLVMValueRef llvm_emit_array_gep_raw(GenContext *c, LLVMValueRef ptr, LLVMTypeRef array_type, unsigned index, AlignSize array_alignment, AlignSize *alignment); +LLVMValueRef llvm_emit_array_gep_raw_index(GenContext *c, LLVMValueRef ptr, LLVMTypeRef array_type, LLVMValueRef index, AlignSize array_alignment, AlignSize *alignment); +LLVMValueRef llvm_emit_pointer_gep_raw(GenContext *c, LLVMTypeRef pointee_type, LLVMValueRef ptr, LLVMValueRef offset); + +LLVMValueRef llvm_emit_pointer_inbounds_gep_raw(GenContext *c, LLVMTypeRef pointee_type, LLVMValueRef ptr, LLVMValueRef offset); + void llvm_emit_subarray_len(GenContext *context, BEValue *subarray, BEValue *len); void llvm_emit_subarray_pointer(GenContext *context, BEValue *subarray, BEValue *pointer); LLVMValueRef llvm_get_next_param(GenContext *context, unsigned *index); diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index 9d1eb45eb..49e5334ff 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -537,7 +537,7 @@ static void llvm_emit_foreach_stmt(GenContext *c, Ast *ast) assert(llvm_value_is_addr(&enum_value)); - LLVMValueRef ref_to_element = LLVMBuildInBoundsGEP2(c->builder, actual_type_llvm, enum_value.value, &(index_value.value), 1, ""); + LLVMValueRef ref_to_element = llvm_emit_pointer_inbounds_gep_raw(c, actual_type_llvm, enum_value.value, index_value.value); BEValue result; if (ast->foreach_stmt.value_by_ref) { @@ -995,7 +995,6 @@ static bool expr_is_pure(Expr *expr) case EXPR_CT_IDENT: case EXPR_TYPEID: case EXPR_CT_CALL: - case EXPR_TYPEOF: UNREACHABLE case EXPR_MACRO_BODY_EXPANSION: case EXPR_CALL: @@ -1020,7 +1019,6 @@ static bool expr_is_pure(Expr *expr) case EXPR_SLICE_ASSIGN: case EXPR_TRY_UNWRAP: case EXPR_TRY_UNWRAP_CHAIN: - case EXPR_TRY_ASSIGN: case EXPR_UNDEF: case EXPR_TYPEINFO: case EXPR_FORCE_UNWRAP: @@ -1036,8 +1034,6 @@ static bool expr_is_pure(Expr *expr) return true; } break; - case EXPR_GROUP: - return expr_is_pure(expr->group_expr); case EXPR_LEN: return expr_is_pure(expr->len_expr.inner); case EXPR_SLICE: @@ -1052,7 +1048,9 @@ static bool expr_is_pure(Expr *expr) && expr_is_pure(expr->ternary_expr.else_expr) && expr_is_pure(expr->ternary_expr.then_expr); case EXPR_TRY: - return expr_is_pure(expr->try_expr.expr); + case EXPR_GROUP: + case EXPR_CATCH: + return expr_is_pure(expr->inner_expr); } UNREACHABLE } @@ -1208,12 +1206,15 @@ static LLVMValueRef llvm_emit_string(GenContext *c, const char *str) { LLVMTypeRef char_type = llvm_get_type(c, type_char); unsigned len = strlen(str); - LLVMValueRef global_string = LLVMAddGlobal(c->module, LLVMArrayType(char_type, len + 1), ""); + LLVMTypeRef char_array_type = LLVMArrayType(char_type, len + 1); + LLVMValueRef global_string = LLVMAddGlobal(c->module, char_array_type, ""); LLVMSetLinkage(global_string, LLVMInternalLinkage); LLVMSetGlobalConstant(global_string, 1); LLVMSetInitializer(global_string, LLVMConstStringInContext(c->context, str, len, 0)); - LLVMValueRef zero = llvm_get_zero(c, type_usize); - LLVMValueRef string = LLVMBuildInBoundsGEP2(c->builder, LLVMTypeOf(global_string), global_string, &zero, 1, ""); + AlignSize alignment; + // TODO alignment + LLVMValueRef string = llvm_emit_array_gep_raw(c, global_string, char_array_type, 0, + 1, &alignment); return LLVMBuildBitCast(c->builder, string, LLVMPointerType(char_type, 0), ""); } void llvm_emit_debug_output(GenContext *c, const char *message, const char *file, const char *func, unsigned line) diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index 2dbd9f634..673fcb7b0 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -235,7 +235,7 @@ LLVMTypeRef llvm_func_type(GenContext *context, Type *type) LLVMTypeRef return_type = NULL; Type *rtype = signature->rtype->type; - bool is_failable = rtype->type_kind == TYPE_FAILABLE; + bool is_failable = type_is_failable(rtype); if (is_failable) rtype = rtype->failable; Type *real_return_type = is_failable ? type_anyerr : rtype; ABIArgInfo *ret_arg_info = is_failable ? signature->failable_abi_info : signature->ret_abi_info; @@ -316,6 +316,7 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type) case CT_TYPES: UNREACHABLE case TYPE_FAILABLE: + case TYPE_FAILABLE_ANY: // If this is reachable, then we're not doing the proper lowering. UNREACHABLE case TYPE_TYPEID: diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index b99db22b7..82b9ccd99 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -472,11 +472,11 @@ static Expr *parse_grouping_expr(Context *context, Expr *left) assert(!left && "Unexpected left hand side"); Expr *expr = EXPR_NEW_TOKEN(EXPR_GROUP, context->tok); advance_and_verify(context, TOKEN_LPAREN); - ASSIGN_EXPR_ELSE(expr->group_expr, parse_expr(context), poisoned_expr); + ASSIGN_EXPR_ELSE(expr->inner_expr, parse_expr(context), poisoned_expr); CONSUME_OR(TOKEN_RPAREN, poisoned_expr); - if (expr->group_expr->expr_kind == EXPR_TYPEINFO && try_consume(context, TOKEN_LPAREN)) + if (expr->inner_expr->expr_kind == EXPR_TYPEINFO && try_consume(context, TOKEN_LPAREN)) { - TypeInfo *info = expr->group_expr->type_expr; + TypeInfo *info = expr->inner_expr->type_expr; if (TOKEN_IS(TOKEN_LBRACE) && info->resolve_status != RESOLVE_DONE) { SEMA_TOKEN_ERROR(context->tok, "Unexpected start of a block '{' here. If you intended a compound literal, remove the () around the type."); @@ -579,7 +579,7 @@ static Expr *parse_failable(Context *context, Expr *left_side) { Expr *failable = expr_new(EXPR_FAILABLE, left_side->span); advance_and_verify(context, TOKEN_BANG); - failable->failable_expr = left_side; + failable->inner_expr = left_side; RANGE_EXTEND_PREV(failable); return failable; } @@ -852,7 +852,7 @@ static Expr *parse_try_expr(Context *context, Expr *left) assert(!left && "Unexpected left hand side"); bool is_try = TOKEN_IS(TOKEN_TRY); advance(context); - Expr *try_expr = expr_new(EXPR_TRY, source_span_from_token_id(context->prev_tok)); + Expr *try_expr = expr_new(is_try ? EXPR_TRY : EXPR_CATCH, source_span_from_token_id(context->prev_tok)); if (!try_consume(context, TOKEN_LPAREN)) { if (is_try) @@ -866,8 +866,7 @@ static Expr *parse_try_expr(Context *context, Expr *left) return poisoned_expr; } } - ASSIGN_EXPR_ELSE(try_expr->try_expr.expr, parse_expr(context), poisoned_expr); - try_expr->try_expr.is_try = is_try; + ASSIGN_EXPR_ELSE(try_expr->inner_expr, parse_expr(context), poisoned_expr); CONSUME_OR(TOKEN_RPAREN, poisoned_expr); RANGE_EXTEND_PREV(try_expr); return try_expr; @@ -886,7 +885,7 @@ static Expr *parse_force_unwrap_expr(Context *context, Expr *left) { Expr *force_unwrap_expr = EXPR_NEW_EXPR(EXPR_FORCE_UNWRAP, left); advance(context); - force_unwrap_expr->force_unwrap_expr = left; + force_unwrap_expr->inner_expr = left; RANGE_EXTEND_PREV(force_unwrap_expr); return force_unwrap_expr; } diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index 786a2570e..7297b237b 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -493,10 +493,10 @@ static inline Ast *parse_decl_or_expr_stmt(Context *context) bool failable = false; // We might be parsing "int!" // If so we need to unwrap this. - if (expr->expr_kind == EXPR_FAILABLE && expr->failable_expr->expr_kind == EXPR_TYPEINFO) + if (expr->expr_kind == EXPR_FAILABLE && expr->inner_expr->expr_kind == EXPR_TYPEINFO) { UNREACHABLE - expr_replace(expr, expr->failable_expr); + expr_replace(expr, expr->inner_expr); } if (expr->expr_kind == EXPR_TYPEINFO) { diff --git a/src/compiler/parser_internal.h b/src/compiler/parser_internal.h index 1d4a2fc0d..d9039f384 100644 --- a/src/compiler/parser_internal.h +++ b/src/compiler/parser_internal.h @@ -23,11 +23,6 @@ do { if (!try_consume(context, TOKEN_COMMA) && !TOKEN_IS(TOKEN_RPAREN)) { \ SEMA_TOKEN_ERROR(context->tok, "Expected ',' or ')'"); return _res; } } while(0) -typedef enum -{ - DECL_PARSE_NORMAL, - DECL_PARSE_UNWRAP -} DeclParse; Decl *parse_top_level_statement(Context *context); Ast *parse_ct_assert_stmt(Context *context); Ast *parse_stmt(Context *context); @@ -35,7 +30,7 @@ Path *parse_path_prefix(Context *context, bool *had_error); Expr *parse_type_expression_with_path(Context *context, Path *path); Expr *parse_expr(Context *context); bool consume_ident(Context *context, const char* name); -Expr *parse_try_expr_after_try(Context *context, bool is_try); + TypeInfo *parse_type(Context *context); TypeInfo *parse_failable_type(Context *context); TypeInfo *parse_type_with_base(Context *context, TypeInfo *type_info); @@ -58,12 +53,12 @@ Decl *parse_decl_after_type(Context *context, TypeInfo *type); bool parse_parameters(Context *context, Visibility visibility, Decl ***params_ref); bool parse_arg_list(Context *context, Expr ***result, TokenType param_end, bool *unsplat); Expr *parse_type_compound_literal_expr_after_type(Context *context, TypeInfo *type_info); -Expr *parse_type_access_expr_after_type(Context *context, TypeInfo *type_info); + bool parse_next_is_decl(Context *context); bool parse_next_is_case_type(Context *context); bool parse_next_is_type(Context *context); bool parse_module(Context *context); -Decl *parse_define_compile_time_variable(Context *context, bool global); + bool try_consume(Context *context, TokenType type); bool consume(Context *context, TokenType type, const char *message, ...); bool consume_const_name(Context *context, const char* type); diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 99c0e7894..926834089 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -24,6 +24,12 @@ static inline bool insert_cast(Expr *expr, CastKind kind, Type *type) return true; } +bool sema_failed_cast(Expr *expr, Type *from, Type *to) +{ + SEMA_ERROR(expr, "The cast %s to %s is not allowed.", type_quoted_error_string(from), type_quoted_error_string(to)); + return false; +} + static inline bool insert_runtime_cast_unless_const(Expr *expr, CastKind kind, Type *type) { if (expr->expr_kind == EXPR_CONST) return false; @@ -121,6 +127,18 @@ bool bool_to_float(Expr *expr, Type *canonical, Type *type) return true; } +/** + * Cast bool to float. + */ +bool voidfail_to_error(Expr *expr, Type *canonical, Type *type) +{ + Expr *inner = expr_copy(expr); + expr->expr_kind = EXPR_CATCH; + expr->inner_expr = inner; + expr->type = type; + return true; +} + /** * Convert from any into to bool. * @return true for any implicit conversion except assign and assign add. @@ -232,14 +250,6 @@ static bool int_to_float(Expr *expr, CastKind kind, Type *canonical, Type *type) } -static bool int_literal_to_float(Expr *expr, Type *canonical, Type *type) -{ - assert(type_is_float(canonical)); - assert(expr->expr_kind == EXPR_CONST); - const_int_to_fp_cast(expr, canonical, type); - return true; -} - /** * Convert a compile time into to a boolean. */ @@ -363,17 +373,23 @@ CastKind cast_to_bool_kind(Type *type) case TYPE_BITSTRUCT: case TYPE_UNTYPED_LIST: case TYPE_FAILABLE: + case TYPE_FAILABLE_ANY: return CAST_ERROR; } UNREACHABLE } -bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability) +bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability, bool is_const) { - // 1. failable -> non-failable can't be cast unless we ignore failability. - if (from_type->type_kind == TYPE_FAILABLE && to_type->type_kind != TYPE_FAILABLE) + // *or* we're converting a void! to an error code + if (type_is_failable(from_type) && !type_is_failable(to_type)) { + if (from_type->failable == type_void || !from_type->failable) + { + // void! x; anyerr y = (anyerr)(x); + if (to_type->type_kind == TYPE_ERRTYPE || to_type->type_kind == TYPE_ANYERR) return true; + } if (!ignore_failability) return false; } @@ -388,9 +404,17 @@ bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability) // 2. Same underlying type, always ok if (from_type == to_type) return true; + if (to_type->type_kind == TYPE_INFERRED_ARRAY) + { + if (from_type->type_kind == TYPE_ARRAY && type_flatten_distinct(from_type->array.base) == type_flatten_distinct(to_type->array.base)) return true; + return false; + } + TypeKind to_kind = to_type->type_kind; switch (from_type->type_kind) { + case TYPE_FAILABLE_ANY: + return true; case TYPE_DISTINCT: case TYPE_TYPEDEF: case TYPE_FAILABLE: @@ -419,6 +443,9 @@ bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability) return to_type == type_bool || to_kind == TYPE_ERRTYPE || type_is_integer(to_type); case ALL_SIGNED_INTS: case ALL_UNSIGNED_INTS: + // We don't have to match pointer size if it's a constant. + if (to_kind == TYPE_POINTER && is_const) return true; + FALLTHROUGH; case TYPE_ENUM: // Allow conversion int/enum -> float/bool/enum int/enum -> pointer is only allowed if the int/enum is pointer sized. if (type_is_integer(to_type) || type_is_float(to_type) || to_type == type_bool || to_kind == TYPE_ENUM) return true; @@ -449,7 +476,7 @@ bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability) case TYPE_STRUCT: if (type_is_substruct(from_type)) { - if (cast_may_explicit(from_type->decl->strukt.members[0]->type, to_type, false)) return true; + if (cast_may_explicit(from_type->decl->strukt.members[0]->type, to_type, false, false)) return true; } FALLTHROUGH; case TYPE_UNION: @@ -506,39 +533,49 @@ static bool may_cast_to_virtual(Type *virtual, Type *from) TODO; } + +bool type_may_convert_to_anyerr(Type *type) +{ + if (type_is_failable_any(type)) return true; + if (!type_is_failable_type(type)) return false; + return type->failable->canonical == type_void; +} /** * Can the conversion occur implicitly? */ -bool cast_may_implicit(Type *from_type, Type *to_type) +bool cast_may_implicit(Type *from_type, Type *to_type, bool is_simple_expr, bool failable_allowed) { - if (from_type == type_anyfail) - { - return to_type->type_kind == TYPE_FAILABLE; - } - - Type *from = from_type->canonical; Type *to = to_type->canonical; - // 1. Same canonical type - we're fine. - if (from == to) return true; + // 1. First handle void! => any error + if (to == type_anyerr && type_may_convert_to_anyerr(from_type)) return true; - if (from->type_kind == TYPE_FAILABLE && to->type_kind != TYPE_FAILABLE) return false; - if (to->type_kind == TYPE_FAILABLE) + // 2. any! => may implicitly to convert to any. + if (type_is_failable_any(from_type)) return failable_allowed; + + Type *from = from_type->canonical; + if (type_is_failable_type(from_type)) { - return cast_may_implicit(type_no_fail(from), type_no_fail(to)); + if (!failable_allowed) return false; + from = from_type->failable->canonical; } + // 4. Same canonical type - we're fine. + if (from == to) return true; + // 2. Handle floats if (type_is_float(to)) { // 2a. Any integer may convert to a float. if (type_is_integer(from)) return true; - // 2b. Any narrower float or FXX may convert to a float. + // 2b. Any narrower float if (type_is_float(from)) { - // This works because the type_size of FXX = 0 - return type_size(to) >= type_size(from); + ByteSize to_size = type_size(to); + ByteSize from_size = type_size(from); + if (to_size == from_size) return true; + return to_size > from_size && is_simple_expr; } return false; } @@ -557,7 +594,10 @@ bool cast_may_implicit(Type *from_type, Type *to_type) // 3a. Any narrower int may convert to a wider or same int, regardless of signedness. if (type_is_integer(from)) { - return type_size(to) >= type_size(from); + ByteSize to_size = type_size(to); + ByteSize from_size = type_size(from); + if (to_size == from_size) return true; + return to_size > from_size && is_simple_expr; } return false; } @@ -597,6 +637,12 @@ bool cast_may_implicit(Type *from_type, Type *to_type) return false; } + if (to_type->type_kind == TYPE_INFERRED_ARRAY) + { + if (from_type->type_kind == TYPE_ARRAY && type_flatten_distinct(from_type->array.base) == type_flatten_distinct(to_type->array.base)) return true; + return false; + } + // 5. Handle sub arrays if (to->type_kind == TYPE_SUBARRAY) { @@ -621,7 +667,7 @@ bool cast_may_implicit(Type *from_type, Type *to_type) { if (from->type_kind == TYPE_STRLIT) { - return cast_may_implicit(from, type_flatten(to)); + return cast_may_implicit(from, type_flatten(to), is_simple_expr, failable_allowed); } } @@ -647,7 +693,7 @@ bool cast_may_implicit(Type *from_type, Type *to_type) // 11. Substruct cast, if the first member is inline, see if we can cast to this member. if (type_is_substruct(from)) { - return cast_may_implicit(from->decl->strukt.members[0]->type, to); + return cast_may_implicit(from->decl->strukt.members[0]->type, to, is_simple_expr, failable_allowed); } return false; @@ -804,9 +850,8 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type) case EXPR_EXPRESSION_LIST: return recursive_may_narrow_float(VECLAST(expr->expression_list), type); case EXPR_GROUP: - return recursive_may_narrow_float(expr->group_expr, type); case EXPR_FORCE_UNWRAP: - return recursive_may_narrow_float(expr->force_unwrap_expr, type); + return recursive_may_narrow_float(expr->inner_expr, type); case EXPR_RETHROW: return recursive_may_narrow_float(expr->rethrow_expr.inner, type); case EXPR_TERNARY: @@ -843,25 +888,22 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type) case EXPR_PLACEHOLDER: case EXPR_TYPEID: case EXPR_TYPEINFO: - case EXPR_TYPEOF: case EXPR_UNDEF: case EXPR_CT_CALL: case EXPR_NOP: case EXPR_LEN: + case EXPR_CATCH: UNREACHABLE case EXPR_POST_UNARY: return recursive_may_narrow_float(expr->unary_expr.expr, type); case EXPR_SCOPED_EXPR: return recursive_may_narrow_float(expr->expr_scope.expr, type); case EXPR_TRY: - assert(expr->try_expr.is_try); - return recursive_may_narrow_float(expr->try_expr.expr, type); + return recursive_may_narrow_float(expr->inner_expr, type); case EXPR_TRY_UNWRAP: TODO case EXPR_TRY_UNWRAP_CHAIN: TODO - case EXPR_TRY_ASSIGN: - return recursive_may_narrow_float(expr->try_assign_expr.expr, type); case EXPR_UNARY: { switch (expr->unary_expr.operator) @@ -959,12 +1001,8 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type) if (expr->or_error_expr.is_jump) return NULL; return recursive_may_narrow_int(expr->or_error_expr.or_error_expr, type); } - case EXPR_FORCE_UNWRAP: - return recursive_may_narrow_int(expr->force_unwrap_expr, type); case EXPR_EXPRESSION_LIST: return recursive_may_narrow_int(VECLAST(expr->expression_list), type); - case EXPR_GROUP: - return recursive_may_narrow_int(expr->group_expr, type); case EXPR_RETHROW: return recursive_may_narrow_int(expr->rethrow_expr.inner, type); case EXPR_TERNARY: @@ -1001,7 +1039,6 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type) case EXPR_PLACEHOLDER: case EXPR_TYPEID: case EXPR_TYPEINFO: - case EXPR_TYPEOF: case EXPR_UNDEF: case EXPR_CT_CALL: case EXPR_NOP: @@ -1011,14 +1048,14 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type) case EXPR_SCOPED_EXPR: return recursive_may_narrow_int(expr->expr_scope.expr, type); case EXPR_TRY: - assert(expr->try_expr.is_try); - return recursive_may_narrow_int(expr->try_expr.expr, type); + case EXPR_CATCH: + case EXPR_GROUP: + case EXPR_FORCE_UNWRAP: + return recursive_may_narrow_int(expr->inner_expr, type); case EXPR_TRY_UNWRAP: TODO case EXPR_TRY_UNWRAP_CHAIN: TODO - case EXPR_TRY_ASSIGN: - return recursive_may_narrow_int(expr->try_assign_expr.expr, type); case EXPR_UNARY: { switch (expr->unary_expr.operator) @@ -1039,35 +1076,18 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type) } UNREACHABLE } -bool cast_implicit_ignore_failable(Expr *expr, Type *to_type) -{ - if (expr->type->type_kind == TYPE_FAILABLE && to_type->type_kind != TYPE_FAILABLE) - { - to_type = type_get_failable(to_type); - } - return cast_implicit(expr, to_type); -} bool cast_implicit(Expr *expr, Type *to_type) { + assert(!type_is_failable(to_type)); Type *expr_type = expr->type; - if (expr_type == type_anyfail) - { - if (to_type->type_kind != TYPE_FAILABLE) - { - SEMA_ERROR(expr, "Cannot cast %s to a non-failable type %s.", type_quoted_error_string(expr_type), - type_quoted_error_string(to_type)); - return false; - } - expr->type = to_type; - return true; - } Type *expr_canonical = expr_type->canonical; Type *to_canonical = to_type->canonical; if (expr_canonical == to_canonical) return true; - if (!cast_may_implicit(expr_canonical, to_canonical)) + bool is_simple = expr_is_simple(expr); + if (!cast_may_implicit(expr_canonical, to_canonical, is_simple, true)) { - if (!cast_may_explicit(expr_canonical, to_canonical, false)) + if (!cast_may_explicit(expr_canonical, to_canonical, false, expr->expr_kind == EXPR_CONST)) { if (expr_canonical->type_kind == TYPE_FAILABLE && to_canonical->type_kind != TYPE_FAILABLE) { @@ -1077,7 +1097,8 @@ bool cast_implicit(Expr *expr, Type *to_type) SEMA_ERROR(expr, "You cannot cast %s into %s even with an explicit cast, so this looks like an error.", type_quoted_error_string(expr->type), type_quoted_error_string(to_type)); return false; } - if (expr->expr_kind == EXPR_CONST && expr->const_expr.narrowable) + bool is_narrowing = type_size(expr_canonical) >= type_size(to_canonical); + if (expr->expr_kind == EXPR_CONST && expr->const_expr.narrowable && is_narrowing) { Type *expr_flatten = type_flatten_distinct(expr_canonical); Type *to_flatten = type_flatten_distinct(to_canonical); @@ -1104,9 +1125,8 @@ bool cast_implicit(Expr *expr, Type *to_type) goto OK; } } - if (type_is_integer(expr_canonical) && type_is_integer(to_canonical)) + if (type_is_integer(expr_canonical) && type_is_integer(to_canonical) && is_narrowing) { - assert(type_size(expr_canonical) > type_size(to_canonical)); Expr *problem = recursive_may_narrow_int(expr, to_canonical); if (problem) { @@ -1116,7 +1136,7 @@ bool cast_implicit(Expr *expr, Type *to_type) } goto OK; } - if (type_is_float(expr_canonical) && type_is_float(to_canonical)) + if (type_is_float(expr_canonical) && type_is_float(to_canonical) && is_narrowing) { Expr *problem = recursive_may_narrow_float(expr, to_canonical); if (problem) @@ -1221,39 +1241,24 @@ static inline bool subarray_to_bool(Expr *expr) return insert_cast(expr, CAST_SABOOL, type_bool); } -bool cast(Expr *expr, Type *to_type) +static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type, bool from_is_failable) { - Type *from_type = type_flatten_distinct(expr->type->canonical); - bool from_is_failable = false; - if (from_type->type_kind == TYPE_FAILABLE) - { - from_type = from_type->failable; - from_is_failable = true; - } - - Type *to = type_flatten(to_type); - if (from_type == to) - { - if (!from_is_failable && to_type->type_kind == TYPE_FAILABLE) - { - to_type = type_no_fail(to_type); - } - expr->type = to_type; - if (expr->expr_kind == EXPR_CONST) expr->const_expr.narrowable = false; - return true; - } switch (from_type->type_kind) { + case TYPE_FAILABLE_ANY: + UNREACHABLE case TYPE_VOID: + UNREACHABLE case TYPE_TYPEID: case TYPE_DISTINCT: case TYPE_FUNC: case TYPE_TYPEDEF: case CT_TYPES: - case TYPE_FAILABLE: UNREACHABLE case TYPE_BITSTRUCT: UNREACHABLE + case TYPE_FAILABLE: + TODO case TYPE_BOOL: // Bool may convert into integers and floats but only explicitly. if (type_is_integer(to)) return bool_to_int(expr, to, to_type); @@ -1303,7 +1308,7 @@ bool cast(Expr *expr, Type *to_type) case TYPE_ERRTYPE: if (to->type_kind == TYPE_ANYERR) return err_to_anyerr(expr, to_type); if (to == type_bool) return err_to_bool(expr, to_type); - if (type_is_integer(to_type)) return insert_cast(expr, CAST_ERINT, to_type); + if (type_is_integer(to)) return insert_cast(expr, CAST_ERINT, to_type); break; case TYPE_STRUCT: case TYPE_UNION: @@ -1327,5 +1332,49 @@ bool cast(Expr *expr, Type *to_type) } UNREACHABLE } +bool cast(Expr *expr, Type *to_type) +{ + assert(!type_is_failable(to_type)); + Type *from_type = expr->type; + bool from_is_failable = false; + Type *to = type_flatten(to_type); + + // Special case *! => error + if (to == type_anyerr || to->type_kind == TYPE_ERRTYPE) + { + if (type_is_failable(from_type)) return voidfail_to_error(expr, to, to_type); + } + + if (type_is_failable_any(from_type)) + { + expr->type = type_get_failable(to_type); + return true; + } + + if (type_is_failable_type(from_type)) + { + from_type = from_type->failable; + from_is_failable = true; + } + from_type = type_flatten_distinct(from_type); + if (to_type->type_kind == TYPE_INFERRED_ARRAY) + { + to_type = from_type; + to = type_flatten(from_type); + } + if (from_type == to) + { + expr->type = type_get_opt_fail(to_type, from_is_failable); + if (expr->expr_kind == EXPR_CONST) expr->const_expr.narrowable = false; + return true; + } + if (!cast_inner(expr, from_type, to, to_type, from_is_failable)) return false; + Type *result_type = expr->type; + if (from_is_failable && !type_is_failable(result_type)) + { + expr->type = type_get_failable(result_type); + } + return true; +} #pragma clang diagnostic pop \ No newline at end of file diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index f76c51330..bcd3ac09a 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -480,10 +480,8 @@ static inline bool sema_analyse_function_param(Context *context, Decl *param, bo SEMA_ERROR(param, "Only typed parameters are allowed for functions."); return false; } - if (!sema_resolve_type_info(context, param->var.type_info)) - { - return false; - } + if (!sema_resolve_type_info(context, param->var.type_info)) return false; + if (param->var.vararg) { param->var.type_info->type = type_get_subarray(param->var.type_info->type); @@ -497,10 +495,14 @@ static inline bool sema_analyse_function_param(Context *context, Decl *param, bo if (param->var.init_expr) { Expr *expr = param->var.init_expr; - if (!sema_analyse_assigned_expr(context, param->type, expr, false)) return false; - Expr *inner = expr; - while (inner->expr_kind == EXPR_CAST) inner = expr->cast_expr.expr; - if (inner->expr_kind != EXPR_CONST) + + if (!sema_analyse_expr_rhs(context, param->type, expr, true)) return false; + if (IS_FAILABLE(expr)) + { + SEMA_ERROR(expr, "Default arguments may not be failable."); + return false; + } + if (!expr_is_constant_eval(expr, CONSTANT_EVAL_ANY)) { SEMA_ERROR(expr, "Only constant expressions may be used as default values."); return false; @@ -593,6 +595,7 @@ static inline bool sema_analyse_distinct(Context *context, Decl *decl) case CT_TYPES: UNREACHABLE return false; + case TYPE_FAILABLE_ANY: case TYPE_FAILABLE: SEMA_ERROR(decl, "You cannot create a distinct type from a failable."); return false; @@ -676,7 +679,7 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl) } // We try to convert to the desired type. - if (!sema_analyse_expr_of_required_type(context, type, expr)) + if (!sema_analyse_expr_rhs(context, type, expr, false)) { success = false; enum_value->resolve_status = RESOLVE_DONE; @@ -988,28 +991,7 @@ static inline bool sema_update_call_convention(Decl *decl, CallABI abi) static inline bool sema_analyse_func(Context *context, Decl *decl) { DEBUG_LOG("----Analysing function %s", decl->name); - Type *func_type = sema_analyse_function_signature(context, &decl->func_decl.function_signature, true); - - decl->type = func_type; - if (!func_type) return decl_poison(decl); - if (decl->func_decl.type_parent) - { - if (!sema_analyse_method(context, decl)) return decl_poison(decl); - } - else - { - if (decl->name == kw_main) - { - if (decl->visibility == VISIBLE_LOCAL) - { - SEMA_ERROR(decl, "'main' cannot have local visibility."); - return false; - } - decl->visibility = VISIBLE_EXTERN; - } - decl_set_external_name(decl); - } - if (!sema_analyse_doc_header(decl->docs, decl->func_decl.function_signature.params, NULL)) return decl_poison(decl); + VECEACH(decl->attributes, i) { Attr *attr = decl->attributes[i]; @@ -1067,14 +1049,14 @@ static inline bool sema_analyse_func(Context *context, Decl *decl) } break; case ATTRIBUTE_FASTCALL: - if (platform_target.arch == ARCH_TYPE_X86) + if (platform_target.arch == ARCH_TYPE_X86 || (platform_target.arch == ARCH_TYPE_X86_64 && platform_target.os == OS_TYPE_WIN32)) { had = sema_update_call_convention(decl, CALL_X86_FAST); } break; case ATTRIBUTE_REGCALL: had = decl->func_decl.function_signature.call_abi > 0; - if (platform_target.arch == ARCH_TYPE_X86) + if (platform_target.arch == ARCH_TYPE_X86 || (platform_target.arch == ARCH_TYPE_X86_64 && platform_target.os == OS_TYPE_WIN32)) { had = sema_update_call_convention(decl, CALL_X86_REG); } @@ -1098,6 +1080,29 @@ static inline bool sema_analyse_func(Context *context, Decl *decl) return decl_poison(decl); } } + + Type *func_type = sema_analyse_function_signature(context, &decl->func_decl.function_signature, true); + + decl->type = func_type; + if (!func_type) return decl_poison(decl); + if (decl->func_decl.type_parent) + { + if (!sema_analyse_method(context, decl)) return decl_poison(decl); + } + else + { + if (decl->name == kw_main) + { + if (decl->visibility == VISIBLE_LOCAL) + { + SEMA_ERROR(decl, "'main' cannot have local visibility."); + return false; + } + decl->visibility = VISIBLE_EXTERN; + } + decl_set_external_name(decl); + } + if (!sema_analyse_doc_header(decl->docs, decl->func_decl.function_signature.params, NULL)) return decl_poison(decl); DEBUG_LOG("Function analysis done."); return true; } @@ -1287,10 +1292,27 @@ bool sema_analyse_attributes_for_var(Context *context, Decl *decl) return true; } +bool sema_analyse_decl_type(Context *context, Type *type, SourceSpan span) +{ + if (type == type_void) + { + sema_error_range(span, "The use of 'void' as a variable type is not permitted."); + return false; + } + + if (!type_is_failable(type)) return true; + if (type_is_failable_any(type) || type_flatten_distinct(type->failable) == type_void) + { + sema_error_range(span, "The use of 'void!' as a variable type is not permitted, use %s instead.", + type_quoted_error_string(type_anyerr)); + return false; + } + return true; +} /** * Analyse a regular global or local declaration, e.g. int x = 123 */ -bool sema_analyse_var_decl(Context *context, Decl *decl) +bool sema_analyse_var_decl(Context *context, Decl *decl, bool local) { assert(decl->decl_kind == DECL_VAR && "Unexpected declaration type"); @@ -1298,7 +1320,7 @@ bool sema_analyse_var_decl(Context *context, Decl *decl) // this should always be true. assert(decl->var.type_info || decl->var.kind == VARDECL_CONST); - bool is_global = decl->var.kind == VARDECL_GLOBAL || decl->var.kind == VARDECL_CONST; + bool is_global = decl->var.kind == VARDECL_GLOBAL || !local; if (!sema_analyse_attributes_for_var(context, decl)) return false; @@ -1333,15 +1355,16 @@ bool sema_analyse_var_decl(Context *context, Decl *decl) if (!sema_analyse_expr(context, init_expr)) return false; decl->type = init_expr->type; if (!decl->alignment) decl->alignment = type_alloca_alignment(decl->type); - + if (!sema_analyse_decl_type(context, decl->type, init_expr->span)) return false; // Skip further evaluation. goto EXIT_OK; } } if (!sema_resolve_type_info_maybe_inferred(context, decl->var.type_info, decl->var.init_expr != NULL)) return decl_poison(decl); - decl->type = decl->var.type_info->type; + decl->type = decl->var.type_info->type; + if (!sema_analyse_decl_type(context, decl->type, decl->var.type_info->span)) return false; if (decl->var.is_static) { scratch_buffer_clear(); @@ -1381,16 +1404,9 @@ bool sema_analyse_var_decl(Context *context, Decl *decl) assert(right_side_type->type_kind == TYPE_ARRAY); decl->type = type_get_array(decl->type->array.base, right_side_type->array.len); } - else if (decl->type) - { - decl->var.init_expr->type = decl->type; - } Expr *init_expr = decl->var.init_expr; - // 1. Check type. - if (!sema_analyse_assigned_expr(context, decl->type, init_expr, false)) return false; - // 2. Check const-ness if ((is_global || decl->var.is_static) && !expr_is_constant_eval(init_expr, CONSTANT_EVAL_ANY)) { @@ -1398,7 +1414,7 @@ bool sema_analyse_var_decl(Context *context, Decl *decl) } else { - if (decl->var.unwrap && init->type->type_kind != TYPE_FAILABLE) + if (decl->var.unwrap && IS_FAILABLE(init)) { SEMA_ERROR(decl->var.init_expr, "A failable expression was expected here."); return decl_poison(decl); @@ -1534,13 +1550,6 @@ static bool sema_analyse_parameterized_define(Context *c, Decl *decl) UNREACHABLE } } -static void decl_define_type(Decl *decl, Type *actual_type) -{ - Type *type = type_new(TYPE_TYPEDEF, decl->name); - type->decl = decl; - type->canonical = actual_type->canonical; - decl->type = type; -} static inline bool sema_analyse_define(Context *c, Decl *decl) { @@ -1599,7 +1608,7 @@ bool sema_analyse_decl(Context *context, Decl *decl) if (!sema_analyse_macro(context, decl)) return decl_poison(decl); break; case DECL_VAR: - if (!sema_analyse_var_decl(context, decl)) return decl_poison(decl); + if (!sema_analyse_var_decl(context, decl, false)) return decl_poison(decl); decl_set_external_name(decl); break; case DECL_DISTINCT: diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index a9fdad7a9..3ad2ee32f 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -150,6 +150,7 @@ bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) { switch (expr->cast_expr.kind) { + case CAST_VFTOERR: case CAST_ERROR: return false; case CAST_ERBOOL: @@ -267,7 +268,6 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) case EXPR_MACRO_BODY_EXPANSION: case EXPR_TRY_UNWRAP: case EXPR_TRY_UNWRAP_CHAIN: - case EXPR_TRY_ASSIGN: case EXPR_POST_UNARY: case EXPR_SCOPED_EXPR: case EXPR_SLICE_ASSIGN: @@ -279,10 +279,8 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) case EXPR_EXPRESSION_LIST: return expr_list_is_constant_eval(expr->expression_list, eval_kind); case EXPR_FAILABLE: - expr = expr->failable_expr; - goto RETRY; case EXPR_GROUP: - expr = expr->group_expr; + expr = expr->inner_expr; goto RETRY; case EXPR_INITIALIZER_LIST: return expr_list_is_constant_eval(expr->initializer_list, eval_kind); @@ -303,10 +301,9 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) assert(!expr_is_constant_eval(expr->ternary_expr.cond, eval_kind)); return false; case EXPR_FORCE_UNWRAP: - expr = expr->force_unwrap_expr; - goto RETRY; case EXPR_TRY: - expr = expr->try_expr.expr; + case EXPR_CATCH: + expr = expr->inner_expr; goto RETRY; case EXPR_TYPEID: return eval_kind == CONSTANT_EVAL_ANY; @@ -330,7 +327,6 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) } UNREACHABLE case EXPR_CT_CALL: - case EXPR_TYPEOF: case EXPR_TYPEINFO: case EXPR_HASH_IDENT: case EXPR_CT_IDENT: @@ -404,7 +400,7 @@ static inline Ast **context_push_returns(Context *context) int sema_check_comp_time_bool(Context *context, Expr *expr) { - if (!sema_analyse_assigned_expr(context, type_bool, expr, false)) return -1; + if (!sema_analyse_cond_expr(context, expr)) return -1; if (expr->expr_kind != EXPR_CONST) { SEMA_ERROR(expr, "Compile time evaluation requires a compile time constant value."); @@ -452,7 +448,7 @@ bool expr_is_ltype(Expr *expr) case EXPR_ACCESS: return expr_is_ltype(expr->access_expr.parent); case EXPR_GROUP: - return expr_is_ltype(expr->group_expr); + return expr_is_ltype(expr->inner_expr); case EXPR_SUBSCRIPT: case EXPR_SLICE: return true; @@ -465,7 +461,6 @@ static inline bool sema_cast_ident_rvalue(Context *context, Expr *expr) { Decl *decl = expr->identifier_expr.decl; decl = decl_flatten(decl); - expr->identifier_expr.is_rvalue = true; switch (decl->decl_kind) { @@ -614,8 +609,7 @@ static inline bool sema_expr_analyse_ternary(Context *context, Expr *expr) // Normal if (left) { - if (!sema_analyse_expr(context, cond)) return expr_poison(expr); - if (!cast_implicit(cond, type_bool)) return expr_poison(expr); + if (!sema_analyse_cond_expr(context, cond)) return expr_poison(expr); if (!sema_analyse_expr(context, left)) return expr_poison(expr); if (cond->expr_kind == EXPR_CONST) { @@ -656,7 +650,8 @@ static inline bool sema_expr_analyse_ternary(Context *context, Expr *expr) type_to_error_string(left_canonical), type_to_error_string(right_canonical)); return false; } - if (!cast_implicit(left, max) || !cast_implicit(right, max)) return false; + Type *no_fail_max = type_no_fail(max); + if (!cast_implicit(left, no_fail_max) || !cast_implicit(right, max)) return false; } if (path > -1) @@ -879,7 +874,35 @@ static inline bool sema_expr_analyse_hash_identifier(Context *context, Expr *exp return sema_analyse_expr(context, expr); } -static inline bool sema_expr_analyse_binary_subexpr(Context *context, Expr *left, Expr *right) +static inline bool sema_widen_top_down(Expr *expr, Type *type) +{ + Type *to = type; + Type *from = expr->type; + RETRY: + if (type_is_integer(from) && type_is_integer(to)) goto CONVERT_IF_BIGGER; + if (type_is_float(from) && type_is_float(to)) goto CONVERT_IF_BIGGER; + if (type_is_integer(from) && type_is_float(to)) goto CONVERT; + if (type_is_vector(from) && type_is_vector(to)) + { + to = type_vector_type(to); + from = type_vector_type(from); + goto RETRY; + } + return true; + CONVERT_IF_BIGGER: + if (type_size(to) <= type_size(from)) return true; + CONVERT: + return cast_implicit(expr, type); +} + +static inline bool sema_promote_binary_top_down(Context *context, Expr *binary, Expr *left, Expr *right) +{ + if (!binary->binary_expr.widen) return true; + Type *to = binary->type; + return sema_widen_top_down(left, to) && sema_widen_top_down(right, to); +} + +static inline bool sema_expr_analyse_binary_subexpr(Context *context, Expr *binary, Expr *left, Expr *right) { return (int)sema_analyse_expr(context, left) & (int)sema_analyse_expr(context, right); } @@ -890,7 +913,9 @@ static inline bool sema_expr_analyse_binary_arithmetic_subexpr(Context *context, Expr *right = expr->binary_expr.right; // 1. Analyse both sides. - if (!sema_expr_analyse_binary_subexpr(context, left, right)) return false; + if (!sema_expr_analyse_binary_subexpr(context, expr, left, right)) return false; + + if (!sema_promote_binary_top_down(context, expr, left, right)) return false; Type *left_type = type_no_fail(left->type)->canonical; Type *right_type = type_no_fail(right->type)->canonical; @@ -1054,6 +1079,7 @@ static inline bool sema_check_invalid_body_arguments(Context *context, Expr *cal return true; } + static inline bool sema_expand_call_arguments(Context *context, CalledDecl *callee, Expr *call, Decl **params, Expr **args, unsigned func_param_count, bool variadic, bool *failable) { unsigned num_args = vec_size(args); @@ -1262,7 +1288,7 @@ static inline bool sema_expr_analyse_call_invocation(Context *context, Expr *cal else { // 11e. A simple variadic value: - if (!sema_analyse_assigned_expr(context, variadic_type, arg, true)) return false; + if (!sema_analyse_expr_rhs(context, variadic_type, arg, true)) return false; } // Set the argument at the location. *failable |= IS_FAILABLE(arg); @@ -1304,7 +1330,7 @@ static inline bool sema_expr_analyse_call_invocation(Context *context, Expr *cal break; case VARDECL_PARAM: // foo - if (!sema_analyse_assigned_expr(context, param->type, arg, true)) return false; + if (!sema_analyse_expr_rhs(context, param->type, arg, true)) return false; if (IS_FAILABLE(arg)) *failable = true; if (callee.macro) { @@ -1317,14 +1343,14 @@ static inline bool sema_expr_analyse_call_invocation(Context *context, Expr *cal // compile time variables during evaluation: assert(callee.macro); SCOPE_START - if (!sema_analyse_assigned_expr(context, param->type, arg, true)) return SCOPE_POP_ERROR(); + if (!sema_analyse_expr_rhs(context, param->type, arg, true)) return SCOPE_POP_ERROR(); SCOPE_END; if (IS_FAILABLE(arg)) *failable = true; break; case VARDECL_PARAM_CT: // $foo assert(callee.macro); - if (!sema_analyse_assigned_expr(context, param->type, arg, false)) return false; + if (!sema_analyse_expr_rhs(context, param->type, arg, true)) return false; if (!expr_is_constant_eval(arg, CONSTANT_EVAL_ANY)) { SEMA_ERROR(arg, "A compile time parameter must always be a constant, did you mistake it for a normal paramter?"); @@ -1448,7 +1474,7 @@ static inline Type *unify_returns(Context *context) Ast *return_stmt = context->returns[i]; Expr *ret_expr = return_stmt->return_stmt.expr; // 8. All casts should work. - if (!cast_implicit(ret_expr, common_type)) + if (!cast_implicit(ret_expr, type_no_fail(common_type))) { assert(false); return NULL; @@ -1648,14 +1674,14 @@ static bool sema_expr_analyse_macro_call(Context *context, Expr *call_expr, Expr goto EXIT; } Type *type = ret_expr->type; - if (!cast_may_implicit(type, rtype)) + if (!cast_may_implicit(type, rtype, true, true)) { SEMA_ERROR(ret_expr, "Expected %s, not %s.", type_quoted_error_string(rtype), type_quoted_error_string(type)); ok = false; goto EXIT; } - bool success = cast_implicit_ignore_failable(ret_expr, rtype); + bool success = cast_implicit(ret_expr, rtype); assert(success); } call_expr->type = type_get_opt_fail(rtype, failable); @@ -1749,7 +1775,7 @@ static inline bool sema_expr_analyse_generic_call(Context *context, Expr *call_e } if (param->var.type_info) { - if (!sema_analyse_assigned_expr(context, param->var.type_info->type, arg, true)) return false; + if (!sema_analyse_expr_rhs(context, param->var.type_info->type, arg, true)) return false; } else { @@ -2234,8 +2260,8 @@ static inline bool sema_expr_analyse_slice(Context *context, Expr *expr) static inline bool sema_expr_analyse_group(Context *context, Expr *expr) { - if (!sema_analyse_expr(context, expr->group_expr)) return false; - *expr = *expr->group_expr; + if (!sema_analyse_expr(context, expr->inner_expr)) return false; + *expr = *expr->inner_expr; return true; } @@ -3162,8 +3188,9 @@ static bool sema_expr_analyse_designated_initializer(Context *context, Type *ass Expr *expr = init_expressions[i]; Type *result = sema_expr_analyse_designator(context, original, expr, &max_index); if (!result) return false; - if (!sema_analyse_assigned_expr(context, result, expr->designator_expr.value, true)) return false; - failable = failable || IS_FAILABLE(expr->designator_expr.value); + Expr *value = expr->designator_expr.value; + if (!sema_analyse_expr_rhs(context, result, value, true)) return false; + failable = failable || IS_FAILABLE(value); expr->resolve_status = RESOLVE_DONE; } @@ -3222,7 +3249,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(Context *context, return false; } // 5. We know the required type, so resolve the expression. - if (!sema_analyse_assigned_expr(context, members[i]->type, elements[i], true)) return false; + if (!sema_analyse_expr_rhs(context, members[i]->type, element, true)) return false; failable = failable || IS_FAILABLE(element); } assert(initializer->type); @@ -3294,7 +3321,8 @@ static inline bool sema_expr_analyse_array_plain_initializer(Context *context, T SEMA_ERROR(element, "Too many elements in initializer, expected only %d.", expected_members); return false; } - if (!sema_analyse_assigned_expr(context, inner_type, element, true)) return false; + + if (!sema_analyse_expr_rhs(context, inner_type, element, true)) return false; failable = failable || IS_FAILABLE(element); } assert(initializer->type); @@ -3483,18 +3511,16 @@ static inline bool sema_expr_analyse_cast(Context *context, Expr *expr) if (!sema_analyse_expr(context, inner) || !success) return false; Type *target_type = expr->cast_expr.type_info->type; - Type *inner_no_fail = type_no_fail(inner->type); - if (!cast_may_explicit(inner_no_fail, target_type, false)) + if (type_is_failable(target_type)) { - if (inner->expr_kind == EXPR_CONST && type_is_integer(inner_no_fail->canonical) && target_type->canonical->type_kind == TYPE_POINTER) - { - goto OK; - } - SEMA_ERROR(expr, "Cannot cast %s to %s.", type_quoted_error_string(inner->type), type_quoted_error_string(target_type)); + SEMA_ERROR(expr->cast_expr.type_info, "Casting to a failable type is not allowed."); return false; } - OK: - cast(inner, type_get_opt_fail(target_type, IS_FAILABLE(inner))); + if (!cast_may_explicit(inner->type, target_type, true, inner->expr_kind == EXPR_CONST)) + { + return sema_failed_cast(expr, type_no_fail(inner->type), target_type); + } + cast(inner, target_type); expr_replace(expr, inner); return true; } @@ -3502,8 +3528,7 @@ static inline bool sema_expr_analyse_cast(Context *context, Expr *expr) static inline bool sema_expr_analyse_slice_assign(Context *context, Expr *expr, Type *left_type, Expr *right, bool is_unwrapped) { // 1. Evaluate right side to required type. - Type *left_no_fail = type_no_fail(left_type); - if (!sema_analyse_assigned_expr(context, left_no_fail->array.base, right, TYPE_IS_FAILABLE(left_type))) return false; + if (!sema_analyse_expr_rhs(context, left_type->array.base, right, false)) return false; Expr *left = expr->binary_expr.left; expr->type = right->type; @@ -3522,9 +3547,8 @@ bool sema_expr_analyse_assign_right_side(Context *context, Expr *expr, Type *lef } // 1. Evaluate right side to required type. - Type *no_fail_left_type = type_no_fail(left_type); - if (!sema_analyse_inferred_expr(context, no_fail_left_type, right)) return false; - if (IS_FAILABLE(right) && !TYPE_IS_FAILABLE(left_type)) + if (!sema_analyse_expr_rhs(context, left_type, right, true)) return false; + if (IS_FAILABLE(right) && !type_is_failable(left_type)) { if (is_unwrapped) { @@ -3532,21 +3556,9 @@ bool sema_expr_analyse_assign_right_side(Context *context, Expr *expr, Type *lef return false; } if (!left_type) left_type = type_no_fail(right->type); - SEMA_ERROR(right, "%s cannot be converted to %s.", type_quoted_error_string(right->type), type_quoted_error_string(left_type)); - return false; + return sema_failed_cast(right, right->type, left_type); } - Type *right_type = type_no_fail(right->type)->canonical; - // 2. Evaluate right hand side, making special concession for inferred arrays. - if (!no_fail_left_type) goto DONE; - - if (no_fail_left_type->canonical->type_kind == TYPE_INFERRED_ARRAY && right_type->type_kind == TYPE_ARRAY) - { - if (no_fail_left_type->canonical->array.base == right_type->array.base) goto DONE; - } - if (!cast_implicit_ignore_failable(right, no_fail_left_type)) return false; - - DONE: // 3. Set the result to the type on the right side. if (expr) expr->type = right->type; @@ -3763,8 +3775,13 @@ static bool sema_expr_analyse_common_assign(Context *context, Expr *expr, Expr * } // 5. Cast the right hand side to the one on the left - if (!sema_analyse_assigned_expr(context, no_fail, right, IS_FAILABLE(left))) return false; - + if (!sema_analyse_expr(context, right)) return false; + if (!cast_implicit(right, no_fail)) return false; + if (IS_FAILABLE(right) && !IS_FAILABLE(left)) + { + SEMA_ERROR(right, "This expression cannot be failable, since the assigned variable isn't."); + return false; + } // 6. Check for zero in case of div or mod. if (right->expr_kind == EXPR_CONST) { @@ -3841,6 +3858,11 @@ static bool sema_expr_analyse_add_sub_assign(Context *context, Expr *expr, Expr if (!sema_analyse_expr(context, right)) return false; // 3. Copy type & set properties. + if (IS_FAILABLE(right) && !IS_FAILABLE(left)) + { + SEMA_ERROR(right, "Cannot assign a failable value to a non-failable."); + return false; + } expr->type = left->type; bool failable = IS_FAILABLE(left) || IS_FAILABLE(right); @@ -3907,20 +3929,7 @@ static bool binary_arithmetic_promotion(Context *context, Expr *left, Expr *righ SEMA_ERROR(parent, error_message, type_quoted_error_string(left->type), type_quoted_error_string(right->type)); return false; } - return cast_implicit_ignore_failable(left, max) && cast_implicit_ignore_failable(right, max); -} - -static bool sema_check_int_type_fit(Expr *expr, Type *target_type) -{ - if (!target_type) return true; - Type *type = expr->type->canonical; - if (!type_is_integer(target_type->canonical) || !type_is_integer(type)) return true; - if (type_size(type) > type_size(target_type)) - { - SEMA_ERROR(expr, "A '%s' cannot implicitly convert into '%s'.", type_to_error_string(expr->type), type_to_error_string(target_type)); - return false; - } - return true; + return cast_implicit(left, max) && cast_implicit(right, max); } static void unify_voidptr(Expr *left, Expr *right, Type **left_type_ref, Type **right_type_ref) @@ -3945,7 +3954,7 @@ static Type *defer_iptr_cast(Expr *maybe_pointer, Expr *maybe_diff) if (maybe_pointer->expr_kind == EXPR_CAST && maybe_pointer->cast_expr.kind == CAST_PTRXI && type_flatten(maybe_pointer->type) == type_flatten(type_iptr) - && cast_may_implicit(maybe_diff->type, maybe_diff->type)) + && cast_may_implicit(maybe_diff->type, maybe_diff->type, true, true)) { Type *cast_to_iptr = maybe_pointer->type; maybe_pointer->cast_expr.kind = CAST_PTRPTR; @@ -3962,7 +3971,7 @@ static Type *defer_iptr_cast(Expr *maybe_pointer, Expr *maybe_diff) static bool sema_expr_analyse_sub(Context *context, Expr *expr, Expr *left, Expr *right) { // 1. Analyse a and b. - if (!sema_expr_analyse_binary_subexpr(context, left, right)) return false; + if (!sema_expr_analyse_binary_subexpr(context, expr, left, right)) return false; // Do we have (iptr)(ptr) - rhs? If so we change it to // (iptr)((char*)(ptr) - 1) @@ -4020,6 +4029,11 @@ static bool sema_expr_analyse_sub(Context *context, Expr *expr, Expr *left, Expr return true; } + if (!sema_promote_binary_top_down(context, expr, left, right)) return false; + + left_type = type_no_fail(left->type)->canonical; + right_type = type_no_fail(right->type)->canonical; + // 7. Attempt arithmetic promotion, to promote both to a common type. if (!binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, "The subtraction %s - %s is not possible.")) { @@ -4059,7 +4073,7 @@ static bool sema_expr_analyse_add(Context *context, Expr *expr, Expr *left, Expr { // 1. Promote everything to the recipient type – if possible // this is safe in the pointer case actually. - if (!sema_expr_analyse_binary_subexpr(context, left, right)) return false; + if (!sema_expr_analyse_binary_subexpr(context, expr, left, right)) return false; Type *cast_to_iptr = defer_iptr_cast(left, right); if (!cast_to_iptr) cast_to_iptr = defer_iptr_cast(right, left); @@ -4111,6 +4125,11 @@ static bool sema_expr_analyse_add(Context *context, Expr *expr, Expr *left, Expr return true; } + if (!sema_promote_binary_top_down(context, expr, left, right)) return false; + + left_type = type_no_fail(left->type)->canonical; + right_type = type_no_fail(right->type)->canonical; + assert(!cast_to_iptr); // 4. Do an binary arithmetic promotion if (!binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, "Cannot do the addition %s + %s.")) @@ -4156,6 +4175,7 @@ static bool sema_expr_analyse_mult(Context *context, Expr *expr, Expr *left, Exp // 1. Analyse the sub expressions and promote to a common type if (!sema_expr_analyse_binary_arithmetic_subexpr(context, expr, "It is not possible to multiply %s by %s.")) return false; + // 2. Handle constant folding. if (expr_both_const(left, right)) { @@ -4306,7 +4326,7 @@ static bool sema_expr_analyse_bit(Context *context, Expr *expr, Expr *left, Expr static bool sema_expr_analyse_shift(Context *context, Expr *expr, Expr *left, Expr *right) { // 1. Analyze both sides. - if (!sema_expr_analyse_binary_subexpr(context, left, right)) return false; + if (!sema_expr_analyse_binary_subexpr(context, expr, left, right)) return false; // 2. Only integers or integer vectors may be shifted. if (!both_any_integer_or_integer_vector(left, right)) @@ -4314,8 +4334,10 @@ static bool sema_expr_analyse_shift(Context *context, Expr *expr, Expr *left, Ex return sema_type_error_on_binop(expr); } + if (expr->binary_expr.widen && !sema_widen_top_down(left, expr->type)) return false; + // 3. Promote lhs using the usual numeric promotion. - if (!cast_implicit_ignore_failable(left, numeric_arithmetic_promotion(type_no_fail(left->type)))) return false; + if (!cast_implicit(left, numeric_arithmetic_promotion(type_no_fail(left->type)))) return false; // 4. For a constant rhs side we will make a series of checks. if (IS_CONST(right)) @@ -4366,7 +4388,7 @@ static bool sema_expr_analyse_shift_assign(Context *context, Expr *expr, Expr *l { // 1. Analyze the two sub lhs & rhs *without coercion* - if (!sema_expr_analyse_binary_subexpr(context, left, right)) return false; + if (!sema_expr_analyse_binary_subexpr(context, expr, left, right)) return false; bool failable = IS_FAILABLE(left) || IS_FAILABLE(right); @@ -4408,7 +4430,7 @@ static bool sema_expr_analyse_shift_assign(Context *context, Expr *expr, Expr *l static bool sema_expr_analyse_and_or(Context *context, Expr *expr, Expr *left, Expr *right) { - if (!sema_expr_analyse_binary_subexpr(context, left, right)) return false; + if (!sema_expr_analyse_binary_subexpr(context, expr, left, right)) return false; if (!cast_implicit(left, type_bool) || !cast_implicit(right, type_bool)) return false; if (expr_both_const(left, right)) @@ -4441,14 +4463,14 @@ static void cast_to_max_bit_size(Context *context, Expr *left, Expr *right, Type Type *to = left->type->type_kind < TYPE_U8 ? type_int_signed_by_bitsize(bit_size_right) : type_int_unsigned_by_bitsize(bit_size_right); - bool success = cast_implicit_ignore_failable(left, to); + bool success = cast_implicit(left, to); assert(success); return; } Type *to = right->type->type_kind < TYPE_U8 ? type_int_signed_by_bitsize(bit_size_left) : type_int_unsigned_by_bitsize(bit_size_left); - bool success = cast_implicit_ignore_failable(right, to); + bool success = cast_implicit(right, to); assert(success); } @@ -4510,7 +4532,7 @@ static bool sema_is_unsigned_always_false_comparison(Context *context, Expr *exp static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Expr *right) { // 1. Analyse left and right side without any conversions. - if (!sema_expr_analyse_binary_subexpr(context, left, right)) return false; + if (!sema_expr_analyse_binary_subexpr(context, expr, left, right)) return false; bool is_equality_type_op = expr->binary_expr.operator == BINARYOP_NE || expr->binary_expr.operator == BINARYOP_EQ; @@ -4583,7 +4605,7 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp } // 6. Do the implicit cast. - bool success = cast_implicit_ignore_failable(left, max) && cast_implicit_ignore_failable(right, max); + bool success = cast_implicit(left, max) && cast_implicit(right, max); assert(success); DONE: @@ -4745,7 +4767,7 @@ static bool sema_take_addr_of(Expr *inner) case EXPR_ACCESS: return sema_take_addr_of(inner->access_expr.parent); case EXPR_GROUP: - return sema_take_addr_of(inner->group_expr); + return sema_take_addr_of(inner->inner_expr); case EXPR_SUBSCRIPT: return sema_take_addr_of(inner->subscript_expr.expr); case EXPR_TYPEINFO: @@ -4773,7 +4795,7 @@ static bool sema_expr_analyse_addr(Context *context, Expr *expr) return false; case EXPR_GROUP: // We want to collapse any grouping here. - expr_replace(inner, inner->group_expr); + expr_replace(inner, inner->inner_expr); goto REDO; default: { @@ -4798,6 +4820,7 @@ static bool sema_expr_analyse_neg(Context *context, Expr *expr) // 1. Check the inner expression Expr *inner = expr->unary_expr.expr; if (!sema_analyse_expr(context, inner)) return false; + if (expr->unary_expr.widen && !sema_widen_top_down(inner, expr->type)) return false; // 2. Check if it's possible to negate this (i.e. is it an int, float or vector) Type *no_fail = type_no_fail(inner->type); @@ -4808,7 +4831,7 @@ static bool sema_expr_analyse_neg(Context *context, Expr *expr) } // 3. Promote the type Type *result_type = numeric_arithmetic_promotion(no_fail); - if (!cast_implicit_ignore_failable(inner, result_type)) return false; + if (!cast_implicit(inner, result_type)) return false; // 4. If it's non-const, we're done. if (inner->expr_kind != EXPR_CONST) @@ -4844,6 +4867,8 @@ static bool sema_expr_analyse_bit_not(Context *context, Expr *expr) Expr *inner = expr->unary_expr.expr; if (!sema_analyse_expr(context, inner)) return false; + if (expr->unary_expr.widen && !sema_widen_top_down(inner, expr->type)) return false; + // 2. Check that it's a vector, bool Type *canonical = type_no_fail(inner->type)->canonical; if (!type_is_integer_or_bool_kind(type_flatten_distinct(canonical))) @@ -4895,7 +4920,7 @@ static bool sema_expr_analyse_not(Context *context, Expr *expr) } // 4. Let's see if it's possible to cast it implicitly - if (!cast_may_implicit(type, type_bool)) + if (!cast_may_implicit(type, type_bool, true, true)) { SEMA_ERROR(expr, "The use of '!' on %s is not allowed as it can't be converted to a boolean value.", type_quoted_error_string(inner->type)); return false; @@ -5123,101 +5148,39 @@ static inline bool sema_expr_analyse_unary(Context *context, Expr *expr) } - - -static inline bool sema_expr_analyse_try_assign(Context *context, Expr *expr, bool implicitly_create_variable) -{ - - Expr *init = expr->try_assign_expr.init; - Expr *lhs = expr->try_assign_expr.expr; - - Type *lhs_type; - - // If we have: - // a. In a context where implicit declaration of variables occur - // b. The LHS is an identifier without PATH - // c. And this variable does not exist in the scope. - // Create it (when we know the type) - bool create_variable; - if (implicitly_create_variable && lhs->expr_kind == EXPR_IDENTIFIER && !lhs->identifier_expr.path - && !sema_resolve_normal_symbol(context, lhs->identifier_expr.identifier, NULL, false)) - { - create_variable = true; - lhs_type = NULL; - } - else - { - // Otherwise we just analyse it. - create_variable = false; - if (expr->try_assign_expr.is_try) - { - if (!sema_analyse_expr_lvalue(context, lhs)) return false; - } - else - { - if (!sema_analyse_assigned_expr(context, type_anyerr, lhs, true)) return false; - } - if (!expr_is_ltype(lhs)) - { - SEMA_ERROR(lhs, "This expression is not assignable, did you make a mistake?"); - return false; - } - if (IS_FAILABLE(lhs)) - { - SEMA_ERROR(lhs, "A 'try' assignment is not possible with failable on the left hand side, did you intend 'try (variable = expr)'?"); - return false; - } - lhs_type = lhs->type; - } - - lhs_type = type_no_fail(lhs_type); - if (expr->try_assign_expr.is_try) - { - if (!sema_analyse_assigned_expr(context, lhs_type, init, true)) return false; - } - else - { - if (!sema_analyse_assigned_expr(context, NULL, init, true)) return false; - } - - if (!IS_FAILABLE(init)) - { - SEMA_ERROR(init, "Expected a failable expression to '%s'.", expr->try_assign_expr.is_try ? "try" : "catch"); - return false; - } - - if (create_variable) - { - lhs_type = init->type; - Decl *decl = decl_new_var(lhs->identifier_expr.identifier, type_info_new_base(lhs_type, lhs->span), VARDECL_LOCAL, VISIBLE_LOCAL); - TODO - // try_expr->try_expr.implicit_decl = decl; - if (!sema_add_local(context, decl)) return false; - if (!sema_analyse_expr_lvalue(context, lhs)) return false; - } - - expr->type = type_bool; - return true; -} static inline bool sema_expr_analyse_try(Context *context, Expr *expr) { - Expr *inner = expr->try_expr.expr; + Expr *inner = expr->inner_expr; if (!sema_analyse_expr(context, inner)) return false; if (!IS_FAILABLE(inner)) { - SEMA_ERROR(expr->try_expr.expr, "Expected a failable expression to '%s'.", expr->expr_kind == EXPR_TRY ? "try" : "catch"); + SEMA_ERROR(inner, "Expected a failable expression to 'try'."); return false; } - expr->type = expr->try_expr.is_try ? type_bool : type_anyerr; + expr->type = type_bool; + return true; +} + +static inline bool sema_expr_analyse_catch(Context *context, Expr *expr) +{ + Expr *inner = expr->inner_expr; + if (!sema_analyse_expr(context, inner)) return false; + if (!IS_FAILABLE(inner)) + { + SEMA_ERROR(inner, "Expected a failable expression to 'catch'."); + return false; + } + expr->type = type_anyerr; return true; } static inline bool sema_expr_analyse_or_error(Context *context, Expr *expr) { Expr *inner = expr->or_error_expr.expr; - bool success = sema_analyse_expr(context, inner); + if (!sema_analyse_expr(context, inner)) return false; + + if (expr->or_error_expr.widen && !sema_widen_top_down(inner, expr->type)) return false; - if (!success) return false; Type *type = inner->type; if (type->type_kind != TYPE_FAILABLE) { @@ -5235,6 +5198,8 @@ static inline bool sema_expr_analyse_or_error(Context *context, Expr *expr) // First we analyse the "else" and try to implictly cast. Expr *else_expr = expr->or_error_expr.or_error_expr; if (!sema_analyse_expr(context, else_expr)) return false; + if (expr->or_error_expr.widen && !sema_widen_top_down(else_expr, expr->type)) return false; + // Here we might need to insert casts. Type *else_type = else_expr->type; if (else_type->type_kind == TYPE_FAILABLE) @@ -5249,9 +5214,13 @@ static inline bool sema_expr_analyse_or_error(Context *context, Expr *expr) type_quoted_error_string(else_type)); return false; } - if (!cast_implicit(inner, type_get_failable(common))) return false; + if (!cast_implicit(inner, common)) return false; if (!cast_implicit(else_expr, common)) return false; - + if (IS_FAILABLE(else_expr)) + { + SEMA_ERROR(else_expr, "The expression must be a non-failable."); + return false; + } expr->type = common; return true; @@ -5287,7 +5256,7 @@ static inline bool sema_expr_analyse_rethrow(Context *context, Expr *expr) static inline bool sema_expr_analyse_force_unwrap(Context *context, Expr *expr) { - Expr *inner = expr->force_unwrap_expr; + Expr *inner = expr->inner_expr; if (!sema_analyse_expr(context, inner)) return false; if (inner->type == type_anyfail) { @@ -5375,7 +5344,7 @@ static inline bool sema_expr_analyse_compound_literal(Context *context, Expr *ex { if (!sema_resolve_type_info(context, expr->expr_compound_literal.type_info)) return false; Type *type = expr->expr_compound_literal.type_info->type; - if (TYPE_IS_FAILABLE(type)) + if (type_is_failable(type)) { SEMA_ERROR(expr->expr_compound_literal.type_info, "The type here should always be written as a plain type and not a failable, please remove the '!'."); @@ -5386,22 +5355,11 @@ static inline bool sema_expr_analyse_compound_literal(Context *context, Expr *ex return true; } -static inline bool sema_expr_analyse_typeof(Context *context, Expr *expr) -{ - TODO - if (!sema_analyse_expr(context, expr->typeof_expr)) return false; - - Type *type = expr->typeof_expr->type->canonical; - expr->expr_kind = EXPR_TYPEID; - expr->typeid_expr = type_info_new_base(type, expr->typeof_expr->span); - expr->type = type_typeid; - return true; -} static inline bool sema_expr_analyse_failable(Context *context, Expr *expr) { - Expr *inner = expr->failable_expr; + Expr *inner = expr->inner_expr; if (!sema_analyse_expr(context, inner)) return false; if (IS_FAILABLE(inner)) @@ -5970,51 +5928,6 @@ static inline bool sema_expr_analyse_ct_nameof(Context *context, Expr *expr) return true; } -static inline bool sema_expr_resolve_maybe_identifier(Context *c, Expr *expr, Decl **decl_ref, Type **type_ref, ExprFlatElement **flatpath) -{ - switch (expr->expr_kind) - { - case EXPR_CONST_IDENTIFIER: - case EXPR_IDENTIFIER: - { - ASSIGN_DECL_ELSE(*decl_ref, sema_resolve_normal_symbol(c, expr->identifier_expr.identifier, expr->identifier_expr.path, false), false); - return true; - } - case EXPR_TYPEINFO: - if (expr->resolve_status == RESOLVE_DONE) - { - *type_ref = expr->type_expr->type; - return true; - } - if (expr->type_expr->kind != TYPE_INFO_IDENTIFIER) - { - SEMA_ERROR(expr, "Expected a plain type name here."); - return false; - } - ASSIGN_DECL_ELSE(*decl_ref, sema_resolve_normal_symbol(c, expr->type_expr->unresolved.name_loc, - expr->type_expr->unresolved.path, false), false); - return true; - case EXPR_CONST: - switch (expr->const_expr.const_kind) - { - case CONST_STRING: - return sema_analyse_identifier_path_string(c, expr->span, expr, decl_ref, type_ref, flatpath, false); - case CONST_ERR: - case CONST_ENUM: - // This should not be possible, they should only be found after analysing access. - UNREACHABLE - default: - SEMA_ERROR(expr, "You can only do $define on identifiers and types."); - break; - } - case EXPR_ACCESS: - TODO // This will handle enum and errs - default: - return false; - } - -} - static Type *sema_expr_check_type_exists(Context *context, TypeInfo *type_info) { @@ -6279,7 +6192,7 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Expr *expr) case EXPR_CATCH_UNWRAP: UNREACHABLE case EXPR_DECL: - if (!sema_analyse_var_decl(context, expr->decl_expr)) return false; + if (!sema_analyse_var_decl(context, expr->decl_expr, true)) return false; expr->type = expr->decl_expr->type; return true; case EXPR_CT_CALL: @@ -6310,10 +6223,8 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Expr *expr) return sema_expr_analyse_force_unwrap(context, expr); case EXPR_TRY: return sema_expr_analyse_try(context, expr); - case EXPR_TRY_ASSIGN: - return sema_expr_analyse_try_assign(context, expr, false); - case EXPR_TYPEOF: - return sema_expr_analyse_typeof(context, expr); + case EXPR_CATCH: + return sema_expr_analyse_catch(context, expr); case EXPR_OR_ERROR: return sema_expr_analyse_or_error(context, expr); case EXPR_COMPOUND_LITERAL: @@ -6357,50 +6268,41 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Expr *expr) UNREACHABLE } -bool sema_analyse_assigned_expr(Context *context, Type *to, Expr *expr, bool may_be_failable) -{ - if (!sema_analyse_inferred_expr(context, to, expr)) return false; - if (IS_FAILABLE(expr)) - { - if (!may_be_failable) - { - if (!to) to = expr->type; - SEMA_ERROR(expr, "%s cannot be converted to %s.", type_quoted_error_string(type_no_fail(expr->type)), type_quoted_error_string(to)); - return false; - } - if (to && to->type_kind != TYPE_FAILABLE) - { - to = type_get_failable(to); - } - } - return to ? cast_implicit(expr, to) : true; -} bool sema_analyse_cond_expr(Context *context, Expr *expr) { + if (expr->expr_kind == EXPR_BINARY && expr->binary_expr.operator == BINARYOP_ASSIGN) + { + SEMA_ERROR(expr, "Assignment expressions must be enclosed in an extra () in conditionals."); + return false; + } if (!sema_analyse_expr(context, expr)) return false; if (IS_FAILABLE(expr)) { - SEMA_ERROR(expr, "%s cannot be converted to %s.", type_quoted_error_string(expr->type), type_quoted_error_string(type_bool)); + SEMA_ERROR(expr, "A failable %s cannot be implicitly converted to a regular boolean value, use 'try()' " + "and 'catch()' to conditionally execute on success or failure.", + type_quoted_error_string(expr->type)); return false; } return cast_implicit(expr, type_bool); } -bool sema_analyse_expr_of_required_type(Context *context, Type *to, Expr *expr) + +bool sema_analyse_expr_rhs(Context *context, Type *to, Expr *expr, bool allow_failable) { - Type *no_fail_type = type_no_fail(to); - if (!sema_analyse_inferred_expr(context, no_fail_type, expr)) return false; - if (IS_FAILABLE(expr)) + if (to && type_is_failable_type(to)) { - if (no_fail_type && to->type_kind != TYPE_FAILABLE) - { - if (!to) to = expr->type; - SEMA_ERROR(expr, "%s cannot be converted to %s.", type_quoted_error_string(expr->type), type_quoted_error_string(to)); - return false; - } + to = to->failable; + assert(allow_failable); } - return to ? cast_implicit(expr, to) : true; + if (!sema_analyse_inferred_expr(context, to, expr)) return false; + if (to && !cast_implicit(expr, to)) return false; + if (!allow_failable && IS_FAILABLE(expr)) + { + SEMA_ERROR(expr, "You cannot have a failable here."); + return false; + } + return true; } @@ -6573,8 +6475,66 @@ bool sema_analyse_expr(Context *context, Expr *expr) return sema_analyse_expr_lvalue(context, expr) && sema_cast_rvalue(context, expr); } +void insert_widening_type(Expr *expr, Type *infer_type) +{ + if (!infer_type) return; + switch (expr->expr_kind) + { + case EXPR_BINARY: + switch (expr->binary_expr.operator) + { + case BINARYOP_MULT: + case BINARYOP_SUB: + case BINARYOP_ADD: + case BINARYOP_DIV: + case BINARYOP_MOD: + case BINARYOP_SHR: + case BINARYOP_SHL: + case BINARYOP_BIT_OR: + case BINARYOP_BIT_XOR: + case BINARYOP_BIT_AND: + if (!expr_is_simple(expr->binary_expr.left) || !expr_is_simple(expr->binary_expr.right)) return; + expr->type = infer_type; + expr->binary_expr.widen = true; + return; + default: + return; + } + case EXPR_OR_ERROR: + if (!expr_is_simple(expr->or_error_expr.expr)) return; + if (!expr->or_error_expr.is_jump && !expr_is_simple(expr->or_error_expr.or_error_expr)) return; + expr->type = infer_type; + expr->or_error_expr.widen = true; + return; + case EXPR_GROUP: + insert_widening_type(expr->inner_expr, infer_type); + return; + case EXPR_TERNARY: + if (!expr_is_simple(expr->ternary_expr.else_expr)) return; + if (expr->ternary_expr.then_expr && !expr_is_simple(expr->ternary_expr.else_expr)) return; + expr->type = infer_type; + expr->ternary_expr.widen = true; + return; + case EXPR_UNARY: + switch (expr->unary_expr.operator) + { + case UNARYOP_NEG: + case UNARYOP_BITNEG: + if (!expr_is_simple(expr->unary_expr.expr)) return; + expr->type = infer_type; + expr->unary_expr.widen = true; + return; + default: + return; + } + default: + return; + } + UNREACHABLE +} bool sema_analyse_inferred_expr(Context *context, Type *infer_type, Expr *expr) { + infer_type = type_no_fail(infer_type); switch (expr->resolve_status) { case RESOLVE_NOT_DONE: @@ -6600,6 +6560,7 @@ bool sema_analyse_inferred_expr(Context *context, Type *infer_type, Expr *expr) if (!sema_expr_analyse_identifier(context, infer_type, expr)) return expr_poison(expr); break; default: + insert_widening_type(expr, infer_type); if (!sema_analyse_expr_dispatch(context, expr)) return expr_poison(expr); break; } diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 8e3f7165b..b78f94edf 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -103,7 +103,7 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement) } // 3. Evaluate the return value to be the expected return type. - if (!sema_analyse_expr_of_required_type(context, expected_rtype, return_expr)) return false; + if (!sema_analyse_expr_rhs(context, expected_rtype, return_expr, type_is_failable(expected_rtype))) return false; assert(type_no_fail(statement->return_stmt.expr->type)->canonical == type_no_fail(expected_rtype)->canonical); @@ -212,7 +212,7 @@ static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr) return false; } - if (!cast_implicit_ignore_failable(failable, ident->type)) return false; + if (!cast_implicit(failable, ident->type)) return false; expr->try_unwrap_expr.assign_existing = true; expr->try_unwrap_expr.lhs = ident; @@ -253,7 +253,7 @@ static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr) if (var_type) { - if (!cast_implicit_ignore_failable(failable, var_type->type)) return false; + if (!cast_implicit(failable, var_type->type)) return false; } // 4c. Create a type_info if needed. @@ -266,7 +266,7 @@ static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr) Decl *decl = decl_new_var(ident_token, var_type, VARDECL_LOCAL, VISIBLE_LOCAL); // 4e. Analyse it - if (!sema_analyse_var_decl(context, decl)) return false; + if (!sema_analyse_var_decl(context, decl, true)) return false; expr->try_unwrap_expr.decl = decl; } @@ -369,7 +369,7 @@ static inline bool sema_analyse_catch_unwrap(Context *context, Expr *expr) decl->var.init_expr = expr_new(EXPR_UNDEF, decl->span); // 4e. Analyse it - if (!sema_analyse_var_decl(context, decl)) return false; + if (!sema_analyse_var_decl(context, decl, true)) return false; expr->catch_unwrap_expr.decl = decl; expr->catch_unwrap_expr.lhs = NULL; @@ -380,7 +380,7 @@ RESOLVE_EXPRS:; { Expr *fail = exprs[i]; if (!sema_analyse_expr(context, fail)) return false; - if (fail->type->type_kind != TYPE_FAILABLE) + if (!type_is_failable(fail->type)) { SEMA_ERROR(fail, "This expression is not failable, did you add it by mistake?"); return false; @@ -515,9 +515,7 @@ static inline bool sema_analyse_cond(Context *context, Expr *expr, bool cast_to_ // 3e. Expect that it isn't a failable if (IS_FAILABLE(init) && !decl->var.unwrap) { - SEMA_ERROR(last, "%s cannot be converted to %s.", - type_quoted_error_string(last->type), - cast_to_bool ? "'bool'" : type_quoted_error_string(init->type)); + return sema_failed_cast(last, last->type, cast_to_bool ? type_bool : init->type); return false; } // TODO document @@ -531,9 +529,7 @@ static inline bool sema_analyse_cond(Context *context, Expr *expr, bool cast_to_ // 3a. Check for failables in case of an expression. if (IS_FAILABLE(last)) { - SEMA_ERROR(last, "%s cannot be converted to %s.", - type_quoted_error_string(last->type), - cast_to_bool ? "'bool'" : type_quoted_error_string(type_no_fail(last->type))); + sema_failed_cast(last, last->type, cast_to_bool ? type_bool : type_no_fail(last->type)); return false; } // 3b. Cast to bool if that is needed @@ -660,98 +656,9 @@ static inline bool sema_analyse_do_stmt(Context *context, Ast *statement) } -/** - * Analyse a regular local declaration, e.g. int x = 123 - */ -bool sema_analyse_local_decl(Context *context, Decl *decl) -{ - assert(decl->decl_kind == DECL_VAR && "Unexpected declaration type"); - - // TODO unify with global decl analysis - // Add a local to the current context, will throw error on shadowing. - if (!sema_add_local(context, decl)) return decl_poison(decl); - - // 1. Local constants: const int FOO = 123. - if (decl->var.kind == VARDECL_CONST) - { - Expr *init_expr = decl->var.init_expr; - // 1a. We require an init expression. - if (!init_expr) - { - SEMA_ERROR(decl, "Constants need to have an initial value."); - return false; - } - // 1b. We require defined constants - if (init_expr->expr_kind == EXPR_UNDEF) - { - SEMA_ERROR(decl, "Constants cannot be undefined."); - return false; - } - if (!decl->var.type_info) - { - if (!sema_analyse_expr(context, init_expr)) return false; - decl->type = init_expr->type; - // Skip further evaluation. - goto EXIT_OK; - } - } - if (!sema_resolve_type_info_maybe_inferred(context, decl->var.type_info, decl->var.init_expr != NULL)) return decl_poison(decl); - decl->type = decl->var.type_info->type; - if (decl->var.init_expr) - { - bool type_is_inferred = decl->type->type_kind == TYPE_INFERRED_ARRAY; - Expr *init = decl->var.init_expr; - // Handle explicit undef - if (init->expr_kind == EXPR_UNDEF) - { - if (type_is_inferred) - { - SEMA_ERROR(decl->var.type_info, "Size of the array cannot be inferred with explicit undef."); - return false; - } - goto EXIT_OK; - } - - if (!sema_expr_analyse_assign_right_side(context, NULL, decl->type, init, false)) return decl_poison(decl); - - if (type_is_inferred) - { - Type *right_side_type = init->type->canonical; - assert(right_side_type->type_kind == TYPE_ARRAY); - decl->type = type_get_array(decl->type->array.base, right_side_type->array.len); - } - - if (decl->var.unwrap && init->type->type_kind != TYPE_FAILABLE) - { - SEMA_ERROR(decl->var.init_expr, "A failable expression was expected here."); - return decl_poison(decl); - } - if (init->expr_kind == EXPR_CONST) init->const_expr.narrowable = false; - } - EXIT_OK: - if (decl->var.is_static) - { - scratch_buffer_clear(); - scratch_buffer_append(context->active_function_for_analysis->name); - scratch_buffer_append_char('.'); - scratch_buffer_append(decl->name); - decl->external_name = scratch_buffer_interned(); - } - if (decl->var.init_expr && decl->var.is_static) - { - if (!expr_is_constant_eval(decl->var.init_expr, CONSTANT_EVAL_ANY)) - { - SEMA_ERROR(decl->var.init_expr, "Static variable initialization must be constant."); - return false; - } - } - if (!decl->alignment) decl->alignment = type_alloca_alignment(decl->type); - return true; -} - static inline bool sema_analyse_declare_stmt(Context *context, Ast *statement) { - return sema_analyse_local_decl(context, statement->declare_stmt); + return sema_analyse_var_decl(context, statement->declare_stmt, true); } /** @@ -798,7 +705,7 @@ static inline bool sema_analyse_var_stmt(Context *context, Ast *statement) } if (decl->var.init_expr) { - if (!sema_analyse_expr_of_required_type(context, decl->type, decl->var.init_expr)) return false; + if (!sema_analyse_expr_rhs(context, decl->type, decl->var.init_expr, false)) return false; if (!expr_is_constant_eval(decl->var.init_expr, CONSTANT_EVAL_ANY)) { SEMA_ERROR(decl->var.init_expr, "Expected a constant expression assigned to %s.", decl->name); @@ -1174,7 +1081,7 @@ static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement) Type *indexed_type; // First fold the enumerator expression, removing any () around it. - while (enumerator->expr_kind == EXPR_GROUP) enumerator = enumerator->group_expr; + while (enumerator->expr_kind == EXPR_GROUP) enumerator = enumerator->inner_expr; bool iterator_based = false; @@ -1283,9 +1190,9 @@ static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement) index->var.type_info = type_info_new_base(type_isize, index->span); } // Analyse the declaration. - if (!sema_analyse_local_decl(context, index)) return SCOPE_POP_ERROR(); + if (!sema_analyse_var_decl(context, index, true)) return SCOPE_POP_ERROR(); - if (index->type->type_kind == TYPE_FAILABLE) + if (type_is_failable(index->type)) { SEMA_ERROR(index->var.type_info, "The index may not be a failable."); return SCOPE_POP_ERROR(); @@ -1314,7 +1221,7 @@ static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement) } // Analyse the value declaration. - if (!sema_analyse_local_decl(context, var)) return SCOPE_POP_ERROR(); + if (!sema_analyse_var_decl(context, var, true)) return SCOPE_POP_ERROR(); if (IS_FAILABLE(var)) { @@ -1333,7 +1240,11 @@ static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement) Expr dummy = { .resolve_status = RESOLVE_DONE, .span = { var->var.type_info->span.loc, var->span.end_loc }, .expr_kind = EXPR_IDENTIFIER, .type = expected_var_type }; if (!cast_implicit(&dummy, var->type)) return SCOPE_POP_ERROR(); - + if (IS_FAILABLE(&dummy)) + { + SEMA_ERROR(var, "The variable may not be failable."); + return false; + } assert(dummy.expr_kind == EXPR_CAST); statement->foreach_stmt.cast = dummy.cast_expr.kind; } @@ -1638,7 +1549,7 @@ static bool sema_analyse_nextcase_stmt(Context *context, Ast *statement) Type *expected_type = parent->ast_kind == AST_SWITCH_STMT ? parent->switch_stmt.cond->type : type_anyerr; - if (!sema_analyse_expr_of_required_type(context, expected_type, target)) return false; + if (!sema_analyse_expr_rhs(context, expected_type, target, false)) return false; if (target->expr_kind == EXPR_CONST) { @@ -1753,35 +1664,6 @@ static bool sema_analyse_ct_if_stmt(Context *context, Ast *statement) } } -/** - * Cast the case expression to the switch type and ensure it is constant. - * - * @return true if the analysis succeeds. - */ -static bool sema_analyse_case_expr(Context *context, Type* to_type, Ast *case_stmt, bool *is_const) -{ - assert(to_type); - Expr *case_expr = case_stmt->case_stmt.expr; - - // 1. Try to do implicit conversion to the correct type. - if (!sema_analyse_inferred_expr(context, to_type, case_expr)) return false; - - Type *case_type = case_expr->type->canonical; - Type *to_type_canonical = to_type->canonical; - - // 3. If we already have the same type we're done. - if (to_type_canonical == case_type) return true; - - // 4. Otherwise check if we have an enum receiving type and a number on - // in the case. In that case we do an implicit conversion. - if (to_type_canonical->type_kind == TYPE_ENUM && type_is_integer(case_type)) - { - return cast(case_expr, to_type); - } - - return cast_implicit(case_expr, to_type); -} - static inline bool sema_analyse_compound_statement_no_scope(Context *context, Ast *compound_statement) { @@ -1802,7 +1684,7 @@ static inline bool sema_analyse_compound_statement_no_scope(Context *context, As static inline bool sema_check_type_case(Context *context, Type *switch_type, Ast *case_stmt, Ast **cases, unsigned index) { Expr *expr = case_stmt->case_stmt.expr; - if (!sema_analyse_expr_of_required_type(context, type_typeid, expr)) return false; + if (!sema_analyse_expr_rhs(context, type_typeid, expr, false)) return false; if (expr->expr_kind == EXPR_CONST) { @@ -1825,8 +1707,12 @@ static inline bool sema_check_type_case(Context *context, Type *switch_type, Ast static inline bool sema_check_value_case(Context *context, Type *switch_type, Ast *case_stmt, Ast **cases, unsigned index, bool *if_chained) { - if (!sema_analyse_case_expr(context, switch_type, case_stmt, if_chained)) return false; + assert(switch_type); Expr *expr = case_stmt->case_stmt.expr; + + // 1. Try to do implicit conversion to the correct type. + if (!sema_analyse_expr_rhs(context, switch_type, expr, false)) return false; + if (expr->expr_kind != EXPR_CONST) { *if_chained = true; @@ -1950,8 +1836,7 @@ static bool sema_analyse_ct_switch_body(Context *context, Ast *statement) } else { - if (!sema_analyse_inferred_expr(context, type, expr)) return false; - if (!cast_implicit(expr, type)) return false; + if (!sema_analyse_expr_rhs(context, type, expr, false)) return false; } if (expr->expr_kind != EXPR_CONST) { @@ -2117,7 +2002,7 @@ bool sema_analyse_assert_stmt(Context *context, Ast *statement) } else { - if (!sema_analyse_assigned_expr(context, type_bool, expr, false)) return false; + if (!sema_analyse_cond_expr(context, expr)) return false; } return true; } diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index 8a92774bb..4f2a1a7fe 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -195,6 +195,7 @@ bool sema_resolve_type(Context *context, Type *type) case TYPE_VECTOR: case TYPE_TYPEINFO: case TYPE_UNTYPED_LIST: + case TYPE_FAILABLE_ANY: return true; case TYPE_POINTER: return sema_resolve_type(context, type->pointer); diff --git a/src/compiler/types.c b/src/compiler/types.c index 129738d30..d9f4ed26a 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -42,8 +42,6 @@ Type *type_u128 = &t.u128; Type *type_uptr = &t.uptr; Type *type_uptrdiff = &t.uptrdiff; Type *type_usize = &t.usz; -Type *type_compint = &t.ixx; -Type *type_compfloat = &t.fxx; Type *type_compstr = &t.str; Type *type_anyerr = &t.anyerr; Type *type_complist = &t.ctlist; @@ -51,8 +49,6 @@ Type *type_anyfail = &t.anyfail; static unsigned size_subarray; static AlignSize alignment_subarray; -unsigned size_error_code; -unsigned alignment_error_code; static AlignSize max_alignment_vector; #define PTR_OFFSET 0 @@ -139,6 +135,8 @@ const char *type_to_error_string(Type *type) return "typeinfo"; case TYPE_TYPEID: return "typeid"; + case TYPE_FAILABLE_ANY: + return "void!"; case TYPE_POINTER: if (type->pointer->type_kind == TYPE_FUNC) { @@ -216,7 +214,6 @@ RETRY: UNREACHABLE; case TYPE_FAILABLE: type = type->failable; - if (!type) return 1; goto RETRY; case TYPE_TYPEDEF: type = type->canonical; @@ -231,6 +228,7 @@ RETRY: assert(type->decl->resolve_status == RESOLVE_DONE); return type->decl->strukt.size; case TYPE_VOID: + case TYPE_FAILABLE_ANY: return 1; case TYPE_BOOL: case TYPE_TYPEID: @@ -354,7 +352,6 @@ bool type_is_abi_aggregate(Type *type) return false; case TYPE_FAILABLE: type = type->failable; - if (!type) return false; goto RETRY; case TYPE_DISTINCT: type = type->decl->distinct_decl.base_type; @@ -365,6 +362,7 @@ bool type_is_abi_aggregate(Type *type) case TYPE_BITSTRUCT: case ALL_FLOATS: case TYPE_VOID: + case TYPE_FAILABLE_ANY: case ALL_INTS: case TYPE_BOOL: case TYPE_TYPEID: @@ -518,7 +516,6 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements) { case TYPE_FAILABLE: type = type->failable; - if (!type) return false; goto RETRY; case TYPE_DISTINCT: type = type->decl->distinct_decl.base_type; @@ -532,6 +529,7 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements) case TYPE_STRLIT: case TYPE_SUBARRAY: case CT_TYPES: + case TYPE_FAILABLE_ANY: return false; case TYPE_VIRTUAL: case TYPE_VIRTUAL_ANY: @@ -745,10 +743,10 @@ AlignSize type_abi_alignment(Type *type) return alignment; } case TYPE_VOID: + case TYPE_FAILABLE_ANY: return 1; case TYPE_FAILABLE: type = type->failable; - if (!type) return 1; goto RETRY; case TYPE_DISTINCT: type = type->decl->distinct_decl.base_type; @@ -900,6 +898,7 @@ static Type *type_generate_inferred_array(Type *arr_type, bool canonical) Type *type_get_ptr_recurse(Type *ptr_type) { + assert(ptr_type->type_kind != TYPE_FAILABLE_ANY); if (ptr_type->type_kind == TYPE_FAILABLE) { ptr_type = ptr_type->failable; @@ -910,13 +909,13 @@ Type *type_get_ptr_recurse(Type *ptr_type) } Type *type_get_ptr(Type *ptr_type) { - assert(ptr_type->type_kind != TYPE_FAILABLE); + assert(!type_is_failable(ptr_type)); return type_generate_ptr(ptr_type, false); } Type *type_get_failable(Type *failable_type) { - assert(failable_type->type_kind != TYPE_FAILABLE); + assert(!type_is_failable(failable_type)); return type_generate_failable(failable_type, false); } @@ -967,8 +966,6 @@ bool type_is_structurally_equivalent(Type *type1, Type *type2) if (type1 == type2) return true; - if (type_size(type1) != type_size(type2)) return false; - // If the other type is a union, we check against every member // noting that there is only structural equivalence if it fills out the if (type2->type_kind == TYPE_UNION) @@ -1213,6 +1210,9 @@ static void type_append_name_to_scratch(Type *type) type_append_name_to_scratch(type->pointer); scratch_buffer_append_char('*'); break; + case TYPE_FAILABLE_ANY: + scratch_buffer_append("void!"); + break; case TYPE_FAILABLE: if (type->failable) { @@ -1349,7 +1349,7 @@ void type_setup(PlatformTarget *target) type_create("typeinfo", &t.typeinfo, TYPE_TYPEINFO, 1, 1, 1); type_create("complist", &t.ctlist, TYPE_UNTYPED_LIST, 1, 1, 1); - t.anyfail = (Type){ .type_kind = TYPE_FAILABLE, .failable = type_void }; + type_create("void!", &t.anyfail, TYPE_FAILABLE_ANY, 1, 1, 1); type_init("typeid", &t.typeid, TYPE_TYPEID, target->width_pointer, target->align_pointer); type_init("void*", &t.voidstar, TYPE_POINTER, target->width_pointer, target->align_pointer); @@ -1415,6 +1415,7 @@ bool type_is_scalar(Type *type) case TYPE_ARRAY: case TYPE_SUBARRAY: case TYPE_VECTOR: + case TYPE_FAILABLE_ANY: return false; case TYPE_BOOL: case ALL_INTS: @@ -1653,7 +1654,7 @@ Type *type_find_max_type(Type *type, Type *other) type = type->canonical; other = other->canonical; - assert(type->type_kind != TYPE_FAILABLE && other->type_kind != TYPE_FAILABLE); + assert(!type_is_failable(type) && !type_is_failable(other)); if (type == other) return type; @@ -1670,6 +1671,7 @@ Type *type_find_max_type(Type *type, Type *other) case TYPE_INFERRED_ARRAY: case TYPE_POISONED: case TYPE_FAILABLE: + case TYPE_FAILABLE_ANY: UNREACHABLE case TYPE_VOID: case TYPE_BOOL: diff --git a/test/test_suite/abi/literal_load.c3t b/test/test_suite/abi/literal_load.c3t index 9ee9ec911..b1bb284b2 100644 --- a/test/test_suite/abi/literal_load.c3t +++ b/test/test_suite/abi/literal_load.c3t @@ -17,15 +17,15 @@ func Test creator() // #expect: literal_load.ll - %literal = alloca %Test, align 4 - %literal1 = alloca %Test, align 4 - %0 = bitcast %Test* %literal to i32* - store i32 0, i32* %0, align 4 - %dive = getelementptr inbounds %Test, %Test* %literal, i32 0, i32 0 - %1 = load i32, i32* %dive, align 4 - call void @blorg(i32 %1) - %2 = bitcast %Test* %literal1 to i32* - store i32 0, i32* %2, align 4 - %dive2 = getelementptr inbounds %Test, %Test* %literal1, i32 0, i32 0 - %3 = load i32, i32* %dive2, align 4 - ret i32 %3 \ No newline at end of file + %literal = alloca %Test, align 4 + %literal1 = alloca %Test, align 4 + %0 = bitcast %Test* %literal to i32* + store i32 0, i32* %0, align 4 + %1 = getelementptr inbounds %Test, %Test* %literal, i32 0, i32 0 + %2 = load i32, i32* %1, align 4 + call void @blorg(i32 %2) + %3 = bitcast %Test* %literal1 to i32* + store i32 0, i32* %3, align 4 + %4 = getelementptr inbounds %Test, %Test* %literal1, i32 0, i32 0 + %5 = load i32, i32* %4, align 4 + ret i32 %5 \ No newline at end of file diff --git a/test/test_suite/abi/literal_load_aarch64.c3t b/test/test_suite/abi/literal_load_aarch64.c3t index 95a0994e4..5c98595be 100644 --- a/test/test_suite/abi/literal_load_aarch64.c3t +++ b/test/test_suite/abi/literal_load_aarch64.c3t @@ -20,17 +20,17 @@ func Test creator() declare void @blorg(i64) - %literal = alloca %Test, align 4 - %literal1 = alloca %Test, align 4 - %0 = bitcast %Test* %literal to i32* - store i32 0, i32* %0, align 4 - %dive = getelementptr inbounds %Test, %Test* %literal, i32 0, i32 0 - %1 = load i32, i32* %dive, align 4 - %2 = zext i32 %1 to i64 - call void @blorg(i64 %2) - %3 = bitcast %Test* %literal1 to i32* - store i32 0, i32* %3, align 4 - %dive2 = getelementptr inbounds %Test, %Test* %literal1, i32 0, i32 0 - %4 = load i32, i32* %dive2, align 4 - %5 = zext i32 %4 to i64 - ret i64 %5 \ No newline at end of file + %literal = alloca %Test, align 4 + %literal1 = alloca %Test, align 4 + %0 = bitcast %Test* %literal to i32* + store i32 0, i32* %0, align 4 + %1 = getelementptr inbounds %Test, %Test* %literal, i32 0, i32 0 + %2 = load i32, i32* %1, align 4 + %3 = zext i32 %2 to i64 + call void @blorg(i64 %3) + %4 = bitcast %Test* %literal1 to i32* + store i32 0, i32* %4, align 4 + %5 = getelementptr inbounds %Test, %Test* %literal1, i32 0, i32 0 + %6 = load i32, i32* %5, align 4 + %7 = zext i32 %6 to i64 + ret i64 %7 \ No newline at end of file diff --git a/test/test_suite/abi/literal_load_mingw.c3t b/test/test_suite/abi/literal_load_mingw.c3t index aecadf19d..a2c10c7bd 100644 --- a/test/test_suite/abi/literal_load_mingw.c3t +++ b/test/test_suite/abi/literal_load_mingw.c3t @@ -19,14 +19,14 @@ func Test creator() // #expect: literal_load.ll %literal = alloca %Test, align 4 - %literal1 = alloca %Test, align 4 - %0 = bitcast %Test* %literal to i32* - store i32 0, i32* %0, align 4 - %dive = getelementptr inbounds %Test, %Test* %literal, i32 0, i32 0 - %1 = load i32, i32* %dive, align 4 - call void @blorg(i32 %1) - %2 = bitcast %Test* %literal1 to i32* - store i32 0, i32* %2, align 4 - %dive2 = getelementptr inbounds %Test, %Test* %literal1, i32 0, i32 0 - %3 = load i32, i32* %dive2, align 4 - ret i32 %3 \ No newline at end of file + %literal1 = alloca %Test, align 4 + %0 = bitcast %Test* %literal to i32* + store i32 0, i32* %0, align 4 + %1 = getelementptr inbounds %Test, %Test* %literal, i32 0, i32 0 + %2 = load i32, i32* %1, align 4 + call void @blorg(i32 %2) + %3 = bitcast %Test* %literal1 to i32* + store i32 0, i32* %3, align 4 + %4 = getelementptr inbounds %Test, %Test* %literal1, i32 0, i32 0 + %5 = load i32, i32* %4, align 4 + ret i32 %5 \ No newline at end of file diff --git a/test/test_suite/abi/regcall_expand.c3t b/test/test_suite/abi/regcall_expand.c3t new file mode 100644 index 000000000..001ee9f60 --- /dev/null +++ b/test/test_suite/abi/regcall_expand.c3t @@ -0,0 +1,53 @@ +// #target: x64-mingw +module test; + +extern fn void printf(char*, ...); + +struct Foo +{ + float[2] x; +} +fn void test(Foo x) @regcall +{ +} + +fn void main() +{ + test(Foo { }); +} + +/* #expect: test.ll + +%Foo = type { [2 x float] } + +@Foo = linkonce_odr constant i8 1 + +; Function Attrs: nounwind +declare void @printf(i8*, ...) #0 + +; Function Attrs: nounwind +define x86_regcallcc void @test.test(float %0, float %1) #0 { +entry: + %x = alloca %Foo, align 4 + %2 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + %3 = getelementptr inbounds [2 x float], [2 x float]* %2, i64 0, i64 0 + store float %0, float* %3, align 4 + %4 = getelementptr inbounds [2 x float], [2 x float]* %2, i64 0, i64 1 + store float %1, float* %4, align 4 + ret void +} + +; Function Attrs: nounwind +define void @main() #0 { +entry: + %literal = alloca %Foo, align 4 + %0 = bitcast %Foo* %literal to i8* + call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 0, i64 8, i1 false) + %1 = getelementptr inbounds %Foo, %Foo* %literal, i32 0, i32 0 + %2 = getelementptr inbounds [2 x float], [2 x float]* %1, i64 0, i64 0 + %loadexpanded = load float, float* %2, align 4 + %3 = getelementptr inbounds [2 x float], [2 x float]* %1, i64 0, i64 1 + %loadexpanded1 = load float, float* %3, align 4 + call x86_regcallcc void @test.test(float %loadexpanded, float %loadexpanded1) + ret void +} diff --git a/test/test_suite/abi/union_x64.c3t b/test/test_suite/abi/union_x64.c3t index 8899e4b9e..5ecdc0374 100644 --- a/test/test_suite/abi/union_x64.c3t +++ b/test/test_suite/abi/union_x64.c3t @@ -20,17 +20,19 @@ func void hello(Foo f) declare void @hello2(i64, i64) #0 -define void @unionx64.hello(i64 %0, i64 %1) - +define void @unionx64.hello(i64 %0, i64 %1) #0 { +entry: %f = alloca %Foo, align 8 %pair = bitcast %Foo* %f to { i64, i64 }* - %lo = getelementptr inbounds { i64, i64 }, { i64, i64 }* %pair, i32 0, i32 0 - store i64 %0, i64* %lo, align 8 - %hi = getelementptr inbounds { i64, i64 }, { i64, i64 }* %pair, i32 0, i32 1 - store i64 %1, i64* %hi, align 8 - %casttemp = bitcast %Foo* %f to { i64, i64 }* - %lo1 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %casttemp, i32 0, i32 0 - %lo2 = load i64, i64* %lo1, align 8 - %hi3 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %casttemp, i32 0, i32 1 - %hi4 = load i64, i64* %hi3, align 8 - call void @hello2(i64 %lo2, i64 %hi4) + %2 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %pair, i32 0, i32 0 + store i64 %0, i64* %2, align 8 + %3 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %pair, i32 0, i32 1 + store i64 %1, i64* %3, align 8 + %4 = bitcast %Foo* %f to { i64, i64 }* + %5 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %4, i32 0, i32 0 + %lo = load i64, i64* %5, align 8 + %6 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %4, i32 0, i32 1 + %hi = load i64, i64* %6, align 8 + call void @hello2(i64 %lo, i64 %hi) + ret void +} diff --git a/test/test_suite/arrays/array_literal.c3t b/test/test_suite/arrays/array_literal.c3t index 38381c637..53933cfb4 100644 --- a/test/test_suite/arrays/array_literal.c3t +++ b/test/test_suite/arrays/array_literal.c3t @@ -24,6 +24,6 @@ entry: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 16 %1, i8* align 16 bitcast ([30 x double]* @.__const to i8*), i32 240, i1 false) %2 = load i32, i32* %x, align 4 %uiuiext = zext i32 %2 to i64 - %arridx = getelementptr inbounds [30 x double], [30 x double]* %student_t, i64 0, i64 %uiuiext - %3 = load double, double* %arridx, align 8 - ret double %3 + %3 = getelementptr inbounds [30 x double], [30 x double]* %student_t, i64 0, i64 %uiuiext + %4 = load double, double* %3, align 8 + ret double %4 diff --git a/test/test_suite/arrays/inferred_array_err.c3 b/test/test_suite/arrays/inferred_array_err.c3 new file mode 100644 index 000000000..0e7dabd0b --- /dev/null +++ b/test/test_suite/arrays/inferred_array_err.c3 @@ -0,0 +1,7 @@ +fn int[*] hello() // #error: Inferred array types can only be used in declarations with initializers +{ + return int[3] { 1, 2, 3}; +} + +int[*] c; // #error: Inferred array types can only be used in declarations with initializers + diff --git a/test/test_suite/arrays/inferred_array_err2.c3 b/test/test_suite/arrays/inferred_array_err2.c3 new file mode 100644 index 000000000..b3c4ebf9e --- /dev/null +++ b/test/test_suite/arrays/inferred_array_err2.c3 @@ -0,0 +1,5 @@ +fn void test() +{ + int[3] z; + (int[*])(z); // #error: Inferred array types can only be used in declarations with initializers +} \ No newline at end of file diff --git a/test/test_suite/cast/cast_struct_fails.c3 b/test/test_suite/cast/cast_struct_fails.c3 index d6114b65b..9749d7b8c 100644 --- a/test/test_suite/cast/cast_struct_fails.c3 +++ b/test/test_suite/cast/cast_struct_fails.c3 @@ -25,11 +25,11 @@ struct BazTwo func void test1() { Foo x; - Bar z = (Baz)(x); // #error: Cannot cast 'Foo' to 'Baz' + Bar z = (Baz)(x); // #error: cast 'Foo' to 'Baz' } func void test2() { Baz x; - BazTwo z = (BazTwo)(x); // #error: Cannot cast 'Baz' to 'BazTwo' + BazTwo z = (BazTwo)(x); // #error: cast 'Baz' to 'BazTwo' } diff --git a/test/test_suite/cast/cast_to_failable.c3 b/test/test_suite/cast/cast_to_failable.c3 new file mode 100644 index 000000000..99d18f6d5 --- /dev/null +++ b/test/test_suite/cast/cast_to_failable.c3 @@ -0,0 +1,12 @@ +errtype MyErr +{ + FOO +} + +func void test() +{ + int! x; + int! d = ($typeof(MyErr.FOO!))(x); // #error: Casting to a failable type is not allowed +} + + diff --git a/test/test_suite/cast/top_down_cast_fails.c3 b/test/test_suite/cast/top_down_cast_fails.c3 new file mode 100644 index 000000000..092c9cbf5 --- /dev/null +++ b/test/test_suite/cast/top_down_cast_fails.c3 @@ -0,0 +1,29 @@ +fn void test() +{ + int x; + int y; + long z = x * y; + z = x * y + z; // #error: 'int' to 'long' + z = x * y + x; // #error: 'int' to 'long' + z = x / y; + z = x + y; + z = x - y; + z = x % y; + z = x / y + z; // #error: 'int' to 'long' + z = x + y + z; // #error: 'int' to 'long' + z = x - y + z; // #error: 'int' to 'long' + z = x % y + z; // #error: 'int' to 'long' + z = x / y + x; // #error: 'int' to 'long' + z = x + y + x; // #error: 'int' to 'long' + z = x - y + x; // #error: 'int' to 'long' + z = x % y + x; // #error: 'int' to 'long' + + z = x << y + x; // #error: 'int' to 'long' + z = x >> y + x; // #error: 'int' to 'long' + z = x << y + z; // #error: 'int' to 'long' + z = x >> y + z; // #error: 'int' to 'long' + z = ~x + x; // #error: 'int' to 'long' + z = ~x + z; // #error: 'int' to 'long' + z = -x + z; // #error: 'int' to 'long' + z = x + z; +} \ No newline at end of file diff --git a/test/test_suite/cast/top_down_casts.c3t b/test/test_suite/cast/top_down_casts.c3t new file mode 100644 index 000000000..77744b176 --- /dev/null +++ b/test/test_suite/cast/top_down_casts.c3t @@ -0,0 +1,101 @@ +fn void test() +{ + int x; + int y; + long z = x * y; + z = x / y; + z = x + y; + z = x - y; + z = x % y; + z = x << y; + z = x >> y; + z = ~x; + z = -x; + int! w; + z = w ?? 1; +} + +// #expect: top_down_casts.ll + +define void @top_down_casts.test() #0 { +entry: + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %z = alloca i64, align 8 + %w = alloca i32, align 4 + %w.f = alloca i64, align 8 + store i32 0, i32* %x, align 4 + store i32 0, i32* %y, align 4 + %0 = load i32, i32* %x, align 4 + %sisiext = sext i32 %0 to i64 + %1 = load i32, i32* %y, align 4 + %sisiext1 = sext i32 %1 to i64 + %mul = mul i64 %sisiext, %sisiext1 + store i64 %mul, i64* %z, align 8 + %2 = load i32, i32* %x, align 4 + %sisiext2 = sext i32 %2 to i64 + %3 = load i32, i32* %y, align 4 + %sisiext3 = sext i32 %3 to i64 + %sdiv = sdiv i64 %sisiext2, %sisiext3 + store i64 %sdiv, i64* %z, align 8 + %4 = load i32, i32* %x, align 4 + %sisiext4 = sext i32 %4 to i64 + %5 = load i32, i32* %y, align 4 + %sisiext5 = sext i32 %5 to i64 + %add = add i64 %sisiext4, %sisiext5 + store i64 %add, i64* %z, align 8 + %6 = load i32, i32* %x, align 4 + %sisiext6 = sext i32 %6 to i64 + %7 = load i32, i32* %y, align 4 + %sisiext7 = sext i32 %7 to i64 + %sub = sub i64 %sisiext6, %sisiext7 + store i64 %sub, i64* %z, align 8 + %8 = load i32, i32* %x, align 4 + %sisiext8 = sext i32 %8 to i64 + %9 = load i32, i32* %y, align 4 + %sisiext9 = sext i32 %9 to i64 + %smod = srem i64 %sisiext8, %sisiext9 + store i64 %smod, i64* %z, align 8 + %10 = load i32, i32* %x, align 4 + %sisiext10 = sext i32 %10 to i64 + %11 = load i32, i32* %y, align 4 + %12 = zext i32 %11 to i64 + %shl = shl i64 %sisiext10, %12 + %13 = freeze i64 %shl + store i64 %13, i64* %z, align 8 + %14 = load i32, i32* %x, align 4 + %sisiext11 = sext i32 %14 to i64 + %15 = load i32, i32* %y, align 4 + %16 = zext i32 %15 to i64 + %ashr = ashr i64 %sisiext11, %16 + %17 = freeze i64 %ashr + store i64 %17, i64* %z, align 8 + %18 = load i32, i32* %x, align 4 + %sisiext12 = sext i32 %18 to i64 + %bnot = xor i64 %sisiext12, -1 + store i64 %bnot, i64* %z, align 8 + %19 = load i32, i32* %x, align 4 + %sisiext13 = sext i32 %19 to i64 + %20 = load i32, i32* %x, align 4 + %sisiext14 = sext i32 %20 to i64 + %neg = sub i64 0, %sisiext14 + store i64 %neg, i64* %z, align 8 + store i64 0, i64* %w.f, align 8 + store i32 0, i32* %w, align 4 + %21 = load i64, i64* %w.f, align 8 + %not_err = icmp eq i64 %21, 0 + br i1 %not_err, label %after_check, label %else_block + +after_check: ; preds = %entry + %22 = load i32, i32* %w, align 4 + %sisiext15 = sext i32 %22 to i64 + br label %phi_block + +else_block: ; preds = %entry + br label %phi_block + +phi_block: ; preds = %else_block, %after_check + %val = phi i64 [ %sisiext15, %after_check ], [ 1, %else_block ] + store i64 %val, i64* %z, align 8 + ret void +} \ No newline at end of file diff --git a/test/test_suite/errors/anyerr_void.c3t b/test/test_suite/errors/anyerr_void.c3t new file mode 100644 index 000000000..d67856710 --- /dev/null +++ b/test/test_suite/errors/anyerr_void.c3t @@ -0,0 +1,97 @@ +errtype MyError +{ + FOO, + BAR +} +fn void! errorThing() +{ + return MyError.BAR!; +} + +fn void! errorThing2() +{ + return; +} + +extern fn void printf(char*, ...); +func void main() +{ + anyerr z = errorThing(); + printf("Z; %llx\n", (iptr)(z)); + printf("BAR: %llx\n", (iptr)(MyError.BAR)); + printf("FOO: %llx\n", (iptr)(MyError.FOO)); + z = errorThing2(); + printf("Z2: %llx\n", (iptr)(z)); +} + +/* #expect: anyerr_void.ll + +; Function Attrs: nounwind +define i64 @anyerr_void.errorThing() #0 { +entry: + %reterr = alloca i64, align 8 + store i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"anyerr_void.MyError$elements", i64 0, i64 1) to i64), i64* %reterr, align 8 + br label %err_retblock + +postfailed: ; No predecessors! + ret i64 0 + +err_retblock: ; preds = %entry + %0 = load i64, i64* %reterr, align 8 + ret i64 %0 +} + +; Function Attrs: nounwind +define i64 @anyerr_void.errorThing2() #0 { +entry: + %reterr = alloca i64, align 8 + ret i64 0 +} + +; Function Attrs: nounwind +declare void @printf(i8*, ...) #0 + +; Function Attrs: nounwind +define void @main() #0 { +entry: + %z = alloca i64, align 8 + %error_var = alloca i64, align 8 + %error_var1 = alloca i64, align 8 + store i64 0, i64* %error_var, align 8 + %0 = call i64 @anyerr_void.errorThing() + %not_err = icmp eq i64 %0, 0 + br i1 %not_err, label %after.errcheck, label %error + +error: ; preds = %entry + store i64 %0, i64* %error_var, align 8 + br label %noerr_block + +after.errcheck: ; preds = %entry + br label %noerr_block + +noerr_block: ; preds = %after.errcheck, %error + %1 = load i64, i64* %error_var, align 8 + store i64 %1, i64* %z, align 8 + %2 = load i64, i64* %z, align 8 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i32 0, i32 0), i64 %2) + call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.1, i32 0, i32 0), i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"anyerr_void.MyError$elements", i64 0, i64 1) to i64)) + call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.2, i32 0, i32 0), i64 ptrtoint ([2 x i8*]* @"anyerr_void.MyError$elements" to i64)) + store i64 0, i64* %error_var1, align 8 + %3 = call i64 @anyerr_void.errorThing2() + %not_err2 = icmp eq i64 %3, 0 + br i1 %not_err2, label %after.errcheck4, label %error3 + +error3: ; preds = %noerr_block + store i64 %3, i64* %error_var1, align 8 + br label %noerr_block5 + +after.errcheck4: ; preds = %noerr_block + br label %noerr_block5 + +noerr_block5: ; preds = %after.errcheck4, %error3 + %4 = load i64, i64* %error_var1, align 8 + store i64 %4, i64* %z, align 8 + %5 = load i64, i64* %z, align 8 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.3, i32 0, i32 0), i64 %5) + ret void +} \ No newline at end of file diff --git a/test/test_suite/errors/failable_untyped_list.c3 b/test/test_suite/errors/failable_untyped_list.c3 index b8d061007..54245c1c3 100644 --- a/test/test_suite/errors/failable_untyped_list.c3 +++ b/test/test_suite/errors/failable_untyped_list.c3 @@ -14,7 +14,7 @@ extern func int printf(char *c, ...); func void main() { int! z = 2; - Foo*! w = &&{ z, 0 }; // #error: casting 'int[2]*' to 'Foo*' is not permitted + Foo*! w = &&{ z, 0 }; // #error: A failable 'int[2]*!' cannot be converted to 'Foo*' } func void test() diff --git a/test/test_suite/errors/general_error_regression.c3t b/test/test_suite/errors/general_error_regression.c3t index 2ce1e5cb3..6a9e08295 100644 --- a/test/test_suite/errors/general_error_regression.c3t +++ b/test/test_suite/errors/general_error_regression.c3t @@ -104,7 +104,7 @@ entry: %b = alloca i32, align 4 %a = alloca i32, align 4 store i64 ptrtoint ([5 x i8*]* @"foo.Foo$elements" to i64), i64* %f, align 8 - store i64 ptrtoint ([5 x i8*]* getelementptr inbounds ([5 x i8*], [5 x i8*]* @"foo.Foo$elements", i64 1) to i64), i64* %ef, align 8 + store i64 ptrtoint (i8** getelementptr inbounds ([5 x i8*], [5 x i8*]* @"foo.Foo$elements", i64 0, i64 1) to i64), i64* %ef, align 8 %0 = load i64, i64* %f, align 8 store i64 %0, i64* %x, align 8 %1 = load i64, i64* %x, align 8 @@ -117,12 +117,12 @@ entry: store i64 %5, i64* %z, align 8 %6 = load i64, i64* %z, align 8 %7 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.1, i32 0, i32 0), i64 %6) - store i64 ptrtoint ([5 x i8*]* getelementptr inbounds ([5 x i8*], [5 x i8*]* @"foo.Foo$elements", i64 3) to i64), i64* %x, align 8 + store i64 ptrtoint (i8** getelementptr inbounds ([5 x i8*], [5 x i8*]* @"foo.Foo$elements", i64 0, i64 3) to i64), i64* %x, align 8 %8 = load i64, i64* %x, align 8 store i64 %8, i64* %z, align 8 %9 = load i64, i64* %z, align 8 %10 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.2, i32 0, i32 0), i64 %9) - store i64 ptrtoint ([5 x i8*]* getelementptr inbounds ([5 x i8*], [5 x i8*]* @"foo.Foo$elements", i64 4) to i64), i64* %x, align 8 + store i64 ptrtoint (i8** getelementptr inbounds ([5 x i8*], [5 x i8*]* @"foo.Foo$elements", i64 0, i64 4) to i64), i64* %x, align 8 %11 = load i64, i64* %x, align 8 store i64 %11, i64* %z, align 8 %12 = load i64, i64* %z, align 8 @@ -132,7 +132,7 @@ entry: store i64 %14, i64* %z, align 8 %15 = load i64, i64* %z, align 8 %16 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.4, i32 0, i32 0), i64 %15) - store i64 ptrtoint ([2 x i8*]* getelementptr inbounds ([2 x i8*], [2 x i8*]* @"foo.Foob$elements", i64 1) to i64), i64* %x, align 8 + store i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"foo.Foob$elements", i64 0, i64 1) to i64), i64* %x, align 8 %17 = load i64, i64* %x, align 8 store i64 %17, i64* %z, align 8 %18 = load i64, i64* %z, align 8 @@ -143,5 +143,4 @@ entry: call void @foo.Bar__hello(i32* %b) call void @foo.MyEnum__hello(i32* %a) ret void -} - +} \ No newline at end of file diff --git a/test/test_suite/errors/illegal_use_of_failable.c3 b/test/test_suite/errors/illegal_use_of_failable.c3 index 202389bf3..b944a7a10 100644 --- a/test/test_suite/errors/illegal_use_of_failable.c3 +++ b/test/test_suite/errors/illegal_use_of_failable.c3 @@ -1,12 +1,12 @@ func void syntaxErrors() { int! i = 0; - while (i + 1) {} // #error: 'int!' cannot be converted to 'bool' - if (i + 1) {} // #error: 'int!' cannot be converted to 'bool' - for (int x = i;;) {} // #error: 'int!' cannot be converted to 'int'. - for (int x = 0; x < i + 1;) {} // #error: 'bool!' cannot be converted to 'bool' - for (int x = 0; x < 10; x += i + 1) {} // #error: 'int!' cannot be converted to 'int' - switch (i + 1) // #error: 'int!' cannot be converted to 'int' + while (i + 1) {} // #error: 'int!' to 'bool' + if (i + 1) {} // #error: 'int!' to 'bool' + for (int x = i;;) {} // #error: 'int!' to 'int' + for (int x = 0; x < i + 1;) {} // #error: A failable 'bool!' cannot be implicitly converted to a regular boolean + for (int x = 0; x < 10; x += i + 1) {} // #error: Cannot assign a failable value to a non-failable + switch (i + 1) // #error: 'int!' to 'int' { default: i + 1; diff --git a/test/test_suite/errors/try_with_chained_unwrap_errors.c3 b/test/test_suite/errors/try_with_chained_unwrap_errors.c3 index 9e08c6718..35cb3dd48 100644 --- a/test/test_suite/errors/try_with_chained_unwrap_errors.c3 +++ b/test/test_suite/errors/try_with_chained_unwrap_errors.c3 @@ -88,6 +88,6 @@ func void test10() } else { - int g = a; // #error: 'int!' cannot be converted to 'int' + int g = a; // #error: 'int!' to 'int' } } \ No newline at end of file diff --git a/test/test_suite/expressions/addr_compiles.c3t b/test/test_suite/expressions/addr_compiles.c3t index 67ed4c528..8c2395920 100644 --- a/test/test_suite/expressions/addr_compiles.c3t +++ b/test/test_suite/expressions/addr_compiles.c3t @@ -113,33 +113,32 @@ entry: %6 = load i32*, i32** %zy, align 8 %7 = load i32, i32* %6, align 8 call void (i8*, ...) @printf(i8* getelementptr inbounds ([29 x i8], [29 x i8]* @.str.3, i32 0, i32 0), i32 %5, i32 %7) - %arridx = getelementptr inbounds [3 x i32], [3 x i32]* %arr, i64 0, i64 0 - %8 = load i32, i32* %arridx, align 4 - %sub = sub i32 %8, 1 - store i32 %sub, i32* %arridx, align 4 - %arridx1 = getelementptr inbounds [3 x i32], [3 x i32]* %arr, i64 0, i64 1 - %9 = load i32, i32* %arridx1, align 4 - %sub2 = sub i32 %9, 1 - store i32 %sub2, i32* %arridx1, align 4 - %arridx3 = getelementptr inbounds [3 x i32], [3 x i32]* %arr, i64 0, i64 2 - %10 = load i32, i32* %arridx3, align 4 - %sub4 = sub i32 %10, 1 - store i32 %sub4, i32* %arridx3, align 4 - %arridx5 = getelementptr inbounds [3 x i32], [3 x i32]* %arr, i64 0, i64 2 - store i32* %arridx5, i32** %d, align 8 - %11 = bitcast [3 x i32]* %arr to i32* - %offset = getelementptr inbounds i32, i32* %11, i64 1 - %12 = insertvalue %"int[]" undef, i32* %offset, 0 - %13 = insertvalue %"int[]" %12, i64 2, 1 - store %"int[]" %13, %"int[]"* %taddr, align 8 + %8 = getelementptr inbounds [3 x i32], [3 x i32]* %arr, i64 0, i64 0 + %9 = load i32, i32* %8, align 4 + %sub = sub i32 %9, 1 + store i32 %sub, i32* %8, align 4 + %10 = getelementptr inbounds [3 x i32], [3 x i32]* %arr, i64 0, i64 1 + %11 = load i32, i32* %10, align 4 + %sub1 = sub i32 %11, 1 + store i32 %sub1, i32* %10, align 4 + %12 = getelementptr inbounds [3 x i32], [3 x i32]* %arr, i64 0, i64 2 + %13 = load i32, i32* %12, align 4 + %sub2 = sub i32 %13, 1 + store i32 %sub2, i32* %12, align 4 + %14 = getelementptr inbounds [3 x i32], [3 x i32]* %arr, i64 0, i64 2 + store i32* %14, i32** %d, align 8 + %15 = getelementptr inbounds [3 x i32], [3 x i32]* %arr, i64 0, i64 1 + %16 = insertvalue %"int[]" undef, i32* %15, 0 + %17 = insertvalue %"int[]" %16, i64 2, 1 + store %"int[]" %17, %"int[]"* %taddr, align 8 store %"int[]"* %taddr, %"int[]"** %e, align 8 - %14 = load i32*, i32** %d, align 8 - %15 = load i32, i32* %14, align 8 - %16 = load %"int[]"*, %"int[]"** %e, align 8 - %subarrayptr = getelementptr inbounds %"int[]", %"int[]"* %16, i32 0, i32 0 - %saptr = load i32*, i32** %subarrayptr, align 8 - %sarridx = getelementptr inbounds i32, i32* %saptr, i64 0 - %17 = load i32, i32* %sarridx, align 4 - call void (i8*, ...) @printf(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.str.4, i32 0, i32 0), i32 %15, i32 %17) + %18 = load i32*, i32** %d, align 8 + %19 = load i32, i32* %18, align 8 + %20 = load %"int[]"*, %"int[]"** %e, align 8 + %21 = getelementptr inbounds %"int[]", %"int[]"* %20, i32 0, i32 0 + %22 = load i32*, i32** %21, align 8 + %ptroffset = getelementptr inbounds i32, i32* %22, i64 0 + %23 = load i32, i32* %ptroffset, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.str.4, i32 0, i32 0), i32 %19, i32 %23) ret void } \ No newline at end of file diff --git a/test/test_suite/expressions/casts/cast_failable.c3 b/test/test_suite/expressions/casts/cast_failable.c3 new file mode 100644 index 000000000..0dfb5dee3 --- /dev/null +++ b/test/test_suite/expressions/casts/cast_failable.c3 @@ -0,0 +1,10 @@ +errtype MyErr +{ + FOO +} + +func void test() +{ + int! x = (int!)(MyErr.FOO!); // #error: Casting to a failable type is not allowed + int! y = MyErr.FOO!; +} \ No newline at end of file diff --git a/test/test_suite/expressions/casts/cast_func_to_various.c3 b/test/test_suite/expressions/casts/cast_func_to_various.c3 index 887a689f7..6507922c8 100644 --- a/test/test_suite/expressions/casts/cast_func_to_various.c3 +++ b/test/test_suite/expressions/casts/cast_func_to_various.c3 @@ -21,17 +21,17 @@ func void test1(Func arg) func void test2(Func arg) { - ichar b = (ichar)(arg); // #error: Cannot cast 'Func' (func void(int)) to 'ichar'. + ichar b = (ichar)(arg); // #error: 'Func' (func void(int)) to 'ichar' } func void test3(Func arg) { - uint c = (uint)(arg); // #error: Cannot cast 'Func' (func void(int)) to 'uint'. + uint c = (uint)(arg); // #error: 'Func' (func void(int)) to 'uint' } func void test4(Func arg) { - float d = (float)(arg); // #error: Cannot cast 'Func' (func void(int)) to 'float'. + float d = (float)(arg); // #error: 'Func' (func void(int)) to 'float' } func void test7(Func arg) @@ -41,5 +41,5 @@ func void test7(Func arg) FuncSame l = (FuncSame)(arg); FuncOther ke = arg; // #error: 'Func' (func void(int)) to 'FuncOther' (func bool(char*)) FuncSame fe = arg; - Enum j = (Enum)(arg); // #error: Cannot cast 'Func' (func void(int)) to 'Enum'. + Enum j = (Enum)(arg); // #error: 'Func' (func void(int)) to 'Enum' } diff --git a/test/test_suite/expressions/casts/cast_to_nonscalar.c3 b/test/test_suite/expressions/casts/cast_to_nonscalar.c3 index 87bb7209e..e3ecbed12 100644 --- a/test/test_suite/expressions/casts/cast_to_nonscalar.c3 +++ b/test/test_suite/expressions/casts/cast_to_nonscalar.c3 @@ -5,5 +5,5 @@ struct Struct func void test1() { - int a = (Struct)(200); // #error: Cannot cast 'int' to 'Struct' + int a = (Struct)(200); // #error: 'int' to 'Struct' } diff --git a/test/test_suite/expressions/incdec.c3t b/test/test_suite/expressions/incdec.c3t index 72bb7227d..0e33cda13 100644 --- a/test/test_suite/expressions/incdec.c3t +++ b/test/test_suite/expressions/incdec.c3t @@ -18,11 +18,11 @@ func void test(int* foo) %z = alloca float, align 4 store i32* %0, i32** %foo %1 = load i32*, i32** %foo, align 8 - %ptrincdec = getelementptr i32, i32* %1, i8 1 - store i32* %ptrincdec, i32** %foo, align 8 + %ptroffset = getelementptr i32, i32* %1, i8 1 + store i32* %ptroffset, i32** %foo, align 8 %2 = load i32*, i32** %foo, align 8 - %ptrincdec1 = getelementptr i32, i32* %2, i8 -1 - store i32* %ptrincdec1, i32** %foo, align 8 + %ptroffset1 = getelementptr i32, i32* %2, i8 -1 + store i32* %ptroffset1, i32** %foo, align 8 store i32 10, i32* %y, align 4 %3 = load i32, i32* %y, align 4 %add = add i32 %3, 1 diff --git a/test/test_suite/expressions/negate_int.c3 b/test/test_suite/expressions/negate_int.c3 index 8139edda5..3c9f52dc4 100644 --- a/test/test_suite/expressions/negate_int.c3 +++ b/test/test_suite/expressions/negate_int.c3 @@ -2,40 +2,40 @@ func void test1() { short! a = 1; try(-a); - short b = -a; // #error: 'int!' cannot be converted to 'short'. + short b = -a; // #error: 'int!' cannot be converted to 'short' } func void test2() { int! a = 1; try(-a); - int b = -a; // #error: 'int!' cannot be converted to 'int' + int b = -a; // #error: 'int!' to 'int' } func void test3() { long! a = 1; try(-a); - long b = -a; // #error: 'long!' cannot be converted to 'long' + long b = -a; // #error: 'long!' to 'long' } func void test4() { short! a = 1; try(~a); - short b = ~a; // #error: 'short!' cannot be converted to 'short' + short b = ~a; // #error: 'short!' to 'short' } func void test5() { int! a = 1; try(~a); - int b = ~a; // #error: 'int!' cannot be converted to 'int' + int b = ~a; // #error: 'int!' to 'int' } func void test6() { long! a = 1; try(~a); - long b = ~a; // #error: 'long!' cannot be converted to 'long' + long b = ~a; // #error: 'long!' to 'long' } diff --git a/test/test_suite/failable_catch.c3t b/test/test_suite/failable_catch.c3t index b7c843b48..4b21e6540 100644 --- a/test/test_suite/failable_catch.c3t +++ b/test/test_suite/failable_catch.c3t @@ -32,158 +32,144 @@ func void main() define void @main() #0 { entry: %a = alloca i32, align 4 - %a.f = alloca i64, align 8 - %x = alloca i32, align 4 - %blockret = alloca i32, align 4 - %b = alloca i32, align 4 - %b.f = alloca i64, align 8 - %x1 = alloca i32, align 4 - %blockret2 = alloca i32, align 4 - %c = alloca i32, align 4 - %c.f = alloca i64, align 8 - %x8 = alloca i32, align 4 - %blockret9 = alloca i32, align 4 - %error_var = alloca i64, align 8 - store i32 1, i32* %x, align 4 - %0 = load i32, i32* %x, align 4 - %intbool = icmp ne i32 %0, 0 - br i1 %intbool, label %if.then, label %if.exit + %a.f = alloca i64, align 8 + %x = alloca i32, align 4 + %blockret = alloca i32, align 4 + %b = alloca i32, align 4 + %b.f = alloca i64, align 8 + %x1 = alloca i32, align 4 + %blockret2 = alloca i32, align 4 + %c = alloca i32, align 4 + %c.f = alloca i64, align 8 + %x8 = alloca i32, align 4 + %blockret9 = alloca i32, align 4 + store i32 1, i32* %x, align 4 + %0 = load i32, i32* %x, align 4 + %intbool = icmp ne i32 %0, 0 + br i1 %intbool, label %if.then, label %if.exit -if.then: ; preds = %entry - %1 = load i32, i32* %x, align 4 - store i32 %1, i32* %blockret, align 4 - br label %expr_block.exit + if.then: ; preds = %entry + %1 = load i32, i32* %x, align 4 + store i32 %1, i32* %blockret, align 4 + br label %expr_block.exit -if.exit: ; preds = %entry - store i64 ptrtoint ([1 x i8*]* @"failable_catch.MyErr$elements" to i64), i64* %a.f, align 8 - br label %after_assign + if.exit: ; preds = %entry + store i64 ptrtoint ([1 x i8*]* @"failable_catch.MyErr$elements" to i64), i64* %a.f, align 8 + br label %after_assign -expr_block.exit: ; preds = %if.then - %2 = load i32, i32* %blockret, align 4 - store i32 %2, i32* %a, align 4 - store i64 0, i64* %a.f, align 8 - br label %after_assign + expr_block.exit: ; preds = %if.then + %2 = load i32, i32* %blockret, align 4 + store i32 %2, i32* %a, align 4 + store i64 0, i64* %a.f, align 8 + br label %after_assign -after_assign: ; preds = %expr_block.exit, %if.exit - %3 = load i64, i64* %a.f, align 8 - %not_err = icmp eq i64 %3, 0 - br i1 %not_err, label %after_check, label %else_block + after_assign: ; preds = %expr_block.exit, %if.exit + %3 = load i64, i64* %a.f, align 8 + %not_err = icmp eq i64 %3, 0 + br i1 %not_err, label %after_check, label %else_block -after_check: ; preds = %after_assign - %4 = load i32, i32* %a, align 4 - %add = add i32 %4, 3 - br label %phi_block + after_check: ; preds = %after_assign + %4 = load i32, i32* %a, align 4 + %add = add i32 %4, 3 + br label %phi_block -else_block: ; preds = %after_assign - br label %phi_block + else_block: ; preds = %after_assign + br label %phi_block -phi_block: ; preds = %else_block, %after_check - %val = phi i32 [ %add, %after_check ], [ 2, %else_block ] - store i32 %val, i32* %x1, align 4 - %5 = load i32, i32* %x1, align 4 - %intbool3 = icmp ne i32 %5, 0 - br i1 %intbool3, label %if.then4, label %if.exit5 + phi_block: ; preds = %else_block, %after_check + %val = phi i32 [ %add, %after_check ], [ 2, %else_block ] + store i32 %val, i32* %x1, align 4 + %5 = load i32, i32* %x1, align 4 + %intbool3 = icmp ne i32 %5, 0 + br i1 %intbool3, label %if.then4, label %if.exit5 -if.then4: ; preds = %phi_block - %6 = load i32, i32* %x1, align 4 - store i32 %6, i32* %blockret2, align 4 - br label %expr_block.exit6 + if.then4: ; preds = %phi_block + %6 = load i32, i32* %x1, align 4 + store i32 %6, i32* %blockret2, align 4 + br label %expr_block.exit6 -if.exit5: ; preds = %phi_block - store i64 ptrtoint ([1 x i8*]* @"failable_catch.MyErr$elements" to i64), i64* %b.f, align 8 - br label %after_assign7 + if.exit5: ; preds = %phi_block + store i64 ptrtoint ([1 x i8*]* @"failable_catch.MyErr$elements" to i64), i64* %b.f, align 8 + br label %after_assign7 -expr_block.exit6: ; preds = %if.then4 - %7 = load i32, i32* %blockret2, align 4 - store i32 %7, i32* %b, align 4 - store i64 0, i64* %b.f, align 8 - br label %after_assign7 + expr_block.exit6: ; preds = %if.then4 + %7 = load i32, i32* %blockret2, align 4 + store i32 %7, i32* %b, align 4 + store i64 0, i64* %b.f, align 8 + br label %after_assign7 -after_assign7: ; preds = %expr_block.exit6, %if.exit5 - store i32 0, i32* %x8, align 4 - %8 = load i32, i32* %x8, align 4 - %intbool10 = icmp ne i32 %8, 0 - br i1 %intbool10, label %if.then11, label %if.exit12 + after_assign7: ; preds = %expr_block.exit6, %if.exit5 + store i32 0, i32* %x8, align 4 + %8 = load i32, i32* %x8, align 4 + %intbool10 = icmp ne i32 %8, 0 + br i1 %intbool10, label %if.then11, label %if.exit12 -if.then11: ; preds = %after_assign7 - %9 = load i32, i32* %x8, align 4 - store i32 %9, i32* %blockret9, align 4 - br label %expr_block.exit13 + if.then11: ; preds = %after_assign7 + %9 = load i32, i32* %x8, align 4 + store i32 %9, i32* %blockret9, align 4 + br label %expr_block.exit13 -if.exit12: ; preds = %after_assign7 - store i64 ptrtoint ([1 x i8*]* @"failable_catch.MyErr$elements" to i64), i64* %c.f, align 8 - br label %after_assign14 + if.exit12: ; preds = %after_assign7 + store i64 ptrtoint ([1 x i8*]* @"failable_catch.MyErr$elements" to i64), i64* %c.f, align 8 + br label %after_assign14 -expr_block.exit13: ; preds = %if.then11 - %10 = load i32, i32* %blockret9, align 4 - store i32 %10, i32* %c, align 4 - store i64 0, i64* %c.f, align 8 - br label %after_assign14 + expr_block.exit13: ; preds = %if.then11 + %10 = load i32, i32* %blockret9, align 4 + store i32 %10, i32* %c, align 4 + store i64 0, i64* %c.f, align 8 + br label %after_assign14 -after_assign14: ; preds = %expr_block.exit13, %if.exit12 - %11 = load i64, i64* %a.f, align 8 - %not_err15 = icmp eq i64 %11, 0 - br i1 %not_err15, label %after_check16, label %voiderr + after_assign14: ; preds = %expr_block.exit13, %if.exit12 + %11 = load i64, i64* %a.f, align 8 + %not_err15 = icmp eq i64 %11, 0 + br i1 %not_err15, label %after_check16, label %voiderr -after_check16: ; preds = %after_assign14 - %12 = load i32, i32* %a, align 4 - call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i32 0, i32 0), i32 %12) - br label %voiderr + after_check16: ; preds = %after_assign14 + %12 = load i32, i32* %a, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i32 0, i32 0), i32 %12) + br label %voiderr -voiderr: ; preds = %after_check16, %after_assign14 - %13 = load i64, i64* %b.f, align 8 - %not_err17 = icmp eq i64 %13, 0 - br i1 %not_err17, label %after_check18, label %voiderr19 + voiderr: ; preds = %after_check16, %after_assign14 + %13 = load i64, i64* %b.f, align 8 + %not_err17 = icmp eq i64 %13, 0 + br i1 %not_err17, label %after_check18, label %voiderr19 -after_check18: ; preds = %voiderr - %14 = load i32, i32* %b, align 4 - call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.1, i32 0, i32 0), i32 %14) - br label %voiderr19 + after_check18: ; preds = %voiderr + %14 = load i32, i32* %b, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.1, i32 0, i32 0), i32 %14) + br label %voiderr19 -voiderr19: ; preds = %after_check18, %voiderr - %15 = load i64, i64* %c.f, align 8 - %not_err20 = icmp eq i64 %15, 0 - br i1 %not_err20, label %after_check21, label %voiderr22 + voiderr19: ; preds = %after_check18, %voiderr + %15 = load i64, i64* %c.f, align 8 + %not_err20 = icmp eq i64 %15, 0 + br i1 %not_err20, label %after_check21, label %voiderr22 -after_check21: ; preds = %voiderr19 - %16 = load i32, i32* %c, align 4 - call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.2, i32 0, i32 0), i32 %16) - br label %voiderr22 + after_check21: ; preds = %voiderr19 + %16 = load i32, i32* %c, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.2, i32 0, i32 0), i32 %16) + br label %voiderr22 -voiderr22: ; preds = %after_check21, %voiderr19 - store i64 0, i64* %error_var, align 8 - %17 = load i64, i64* %c.f, align 8 - %not_err23 = icmp eq i64 %17, 0 - br i1 %not_err23, label %after_check24, label %error + voiderr22: ; preds = %after_check21, %voiderr19 + %17 = load i64, i64* %c.f, align 8 + %neq = icmp ne i64 %17, 0 + br i1 %neq, label %if.then23, label %if.exit24 -error: ; preds = %voiderr22 - store i64 %17, i64* %error_var, align 8 - br label %noerr_block + if.then23: ; preds = %voiderr22 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.3, i32 0, i32 0)) + br label %if.exit24 -after_check24: ; preds = %voiderr22 - br label %noerr_block + if.exit24: ; preds = %if.then23, %voiderr22 + store i32 3, i32* %c, align 4 + store i64 0, i64* %c.f, align 8 + %18 = load i64, i64* %c.f, align 8 + %not_err25 = icmp eq i64 %18, 0 + br i1 %not_err25, label %after_check26, label %voiderr27 -noerr_block: ; preds = %after_check24, %error - %18 = load i64, i64* %error_var, align 8 - %neq = icmp ne i64 %18, 0 - br i1 %neq, label %if.then25, label %if.exit26 + after_check26: ; preds = %if.exit24 + %19 = load i32, i32* %c, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.4, i32 0, i32 0), i32 %19) + br label %voiderr27 -if.then25: ; preds = %noerr_block - call void (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.3, i32 0, i32 0)) - br label %if.exit26 - -if.exit26: ; preds = %if.then25, %noerr_block - store i32 3, i32* %c, align 4 - store i64 0, i64* %c.f, align 8 - %19 = load i64, i64* %c.f, align 8 - %not_err27 = icmp eq i64 %19, 0 - br i1 %not_err27, label %after_check28, label %voiderr29 - -after_check28: ; preds = %if.exit26 - %20 = load i32, i32* %c, align 4 - call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.4, i32 0, i32 0), i32 %20) - br label %voiderr29 - -voiderr29: ; preds = %after_check28, %if.exit26 - ret void -} \ No newline at end of file + voiderr27: ; preds = %after_check26, %if.exit24 + ret void + } diff --git a/test/test_suite/functions/default_param_fail.c3 b/test/test_suite/functions/default_param_fail.c3 new file mode 100644 index 000000000..8872acfca --- /dev/null +++ b/test/test_suite/functions/default_param_fail.c3 @@ -0,0 +1,11 @@ + +int z; + +errtype MyError +{ + FOO, +} + +fn void test(int a = z) {} // #error: Only constant expressions may be used as default values + +fn void test2(int b = MyError.FOO!) {} // #error: Default arguments may not be failable \ No newline at end of file diff --git a/test/test_suite/functions/splat.c3t b/test/test_suite/functions/splat.c3t index acc3e6502..d8fe48781 100644 --- a/test/test_suite/functions/splat.c3t +++ b/test/test_suite/functions/splat.c3t @@ -19,9 +19,9 @@ func void test() %varargslots = alloca [3 x i32], align 4 %x = alloca [3 x i32], align 4 %z = alloca %"int[]", align 8 - %vararg3 = alloca %"int[]", align 8 - %vararg9 = alloca %"int[]", align 8 - %vararg15 = alloca %"int[]", align 8 + %vararg1 = alloca %"int[]", align 8 + %vararg4 = alloca %"int[]", align 8 + %vararg7 = alloca %"int[]", align 8 %0 = getelementptr inbounds [3 x i32], [3 x i32]* %varargslots, i64 0, i64 0 store i32 1, i32* %0, align 4 %1 = getelementptr inbounds [3 x i32], [3 x i32]* %varargslots, i64 0, i64 1 @@ -33,43 +33,43 @@ func void test() %4 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 0 %5 = bitcast [3 x i32]* %varargslots to i32* store i32* %5, i32** %4, align 8 - %casttemp = bitcast %"int[]"* %vararg to { i8*, i64 }* - %lo = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp, i32 0, i32 0 - %lo1 = load i8*, i8** %lo, align 8 - %hi = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp, i32 0, i32 1 - %hi2 = load i64, i64* %hi, align 8 - %6 = call i32 @sum_us(i8* %lo1, i64 %hi2) - %7 = bitcast [3 x i32]* %x to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %7, i8* align 4 bitcast ([3 x i32]* @.__const to i8*), i32 12, i1 false) - %8 = bitcast [3 x i32]* %x to i32* - %9 = insertvalue %"int[]" undef, i32* %8, 0 - %10 = insertvalue %"int[]" %9, i64 3, 1 - store %"int[]" %10, %"int[]"* %z, align 8 - %11 = getelementptr inbounds %"int[]", %"int[]"* %vararg3, i32 0, i32 1 - %12 = getelementptr inbounds %"int[]", %"int[]"* %vararg3, i32 0, i32 0 - store i64 3, i64* %11, align 8 - %13 = bitcast [3 x i32]* %x to i32* - store i32* %13, i32** %12, align 8 - %casttemp4 = bitcast %"int[]"* %vararg3 to { i8*, i64 }* - %lo5 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp4, i32 0, i32 0 - %lo6 = load i8*, i8** %lo5, align 8 - %hi7 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp4, i32 0, i32 1 - %hi8 = load i64, i64* %hi7, align 8 - %14 = call i32 @sum_us(i8* %lo6, i64 %hi8) - %15 = getelementptr inbounds %"int[]", %"int[]"* %vararg9, i32 0, i32 1 - %16 = getelementptr inbounds %"int[]", %"int[]"* %vararg9, i32 0, i32 0 - %casttemp10 = bitcast %"int[]"* %z to { i8*, i64 }* - %lo11 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp10, i32 0, i32 0 - %lo12 = load i8*, i8** %lo11, align 8 - %hi13 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp10, i32 0, i32 1 - %hi14 = load i64, i64* %hi13, align 8 - %17 = call i32 @sum_us(i8* %lo12, i64 %hi14) - %18 = getelementptr inbounds %"int[]", %"int[]"* %vararg15, i32 0, i32 1 - store i64 0, i64* %18, align 8 - %casttemp16 = bitcast %"int[]"* %vararg15 to { i8*, i64 }* - %lo17 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp16, i32 0, i32 0 - %lo18 = load i8*, i8** %lo17, align 8 - %hi19 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp16, i32 0, i32 1 - %hi20 = load i64, i64* %hi19, align 8 - %19 = call i32 @sum_us(i8* %lo18, i64 %hi20) + %6 = bitcast %"int[]"* %vararg to { i8*, i64 }* + %7 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %6, i32 0, i32 0 + %lo = load i8*, i8** %7, align 8 + %8 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %6, i32 0, i32 1 + %hi = load i64, i64* %8, align 8 + %9 = call i32 @sum_us(i8* %lo, i64 %hi) + %10 = bitcast [3 x i32]* %x to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %10, i8* align 4 bitcast ([3 x i32]* @.__const to i8*), i32 12, i1 false) + %11 = bitcast [3 x i32]* %x to i32* + %12 = insertvalue %"int[]" undef, i32* %11, 0 + %13 = insertvalue %"int[]" %12, i64 3, 1 + store %"int[]" %13, %"int[]"* %z, align 8 + %14 = getelementptr inbounds %"int[]", %"int[]"* %vararg1, i32 0, i32 1 + %15 = getelementptr inbounds %"int[]", %"int[]"* %vararg1, i32 0, i32 0 + store i64 3, i64* %14, align 8 + %16 = bitcast [3 x i32]* %x to i32* + store i32* %16, i32** %15, align 8 + %17 = bitcast %"int[]"* %vararg1 to { i8*, i64 }* + %18 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %17, i32 0, i32 0 + %lo2 = load i8*, i8** %18, align 8 + %19 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %17, i32 0, i32 1 + %hi3 = load i64, i64* %19, align 8 + %20 = call i32 @sum_us(i8* %lo2, i64 %hi3) + %21 = getelementptr inbounds %"int[]", %"int[]"* %vararg4, i32 0, i32 1 + %22 = getelementptr inbounds %"int[]", %"int[]"* %vararg4, i32 0, i32 0 + %23 = bitcast %"int[]"* %z to { i8*, i64 }* + %24 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %23, i32 0, i32 0 + %lo5 = load i8*, i8** %24, align 8 + %25 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %23, i32 0, i32 1 + %hi6 = load i64, i64* %25, align 8 + %26 = call i32 @sum_us(i8* %lo5, i64 %hi6) + %27 = getelementptr inbounds %"int[]", %"int[]"* %vararg7, i32 0, i32 1 + store i64 0, i64* %27, align 8 + %28 = bitcast %"int[]"* %vararg7 to { i8*, i64 }* + %29 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %28, i32 0, i32 0 + %lo8 = load i8*, i8** %29, align 8 + %30 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %28, i32 0, i32 1 + %hi9 = load i64, i64* %30, align 8 + %31 = call i32 @sum_us(i8* %lo8, i64 %hi9) ret void diff --git a/test/test_suite/functions/test_regression.c3t b/test/test_suite/functions/test_regression.c3t index 4687989d6..a4c43579e 100644 --- a/test/test_suite/functions/test_regression.c3t +++ b/test/test_suite/functions/test_regression.c3t @@ -268,6 +268,7 @@ entry: ret void } +; Function Attrs: nounwind define i32 @test.Foo2__mutate(%Foo2* %0) #0 { entry: %foo = alloca %Foo2*, align 8 @@ -281,14 +282,17 @@ entry: ret i32 %add } +; Function Attrs: nounwind declare i32 @printf(i8*, ...) #0 +; Function Attrs: nounwind define void @test.helloWorld() #0 { entry: %0 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str, i32 0, i32 0)) ret void } +; Function Attrs: nounwind define i32 @test.test_static() #0 { entry: %0 = load i32, i32* @test_static.x, align 4 @@ -300,6 +304,7 @@ entry: ret i32 %3 } +; Function Attrs: nounwind define i32 @test.helo(double %0, %Bobo* byval(%Bobo) align 8 %1) #0 { entry: %d = alloca double, align 8 @@ -323,6 +328,7 @@ entry: ret i32 1 } +; Function Attrs: nounwind define i32 @test.test1(i32 %0, i32 %1) #0 { entry: %a = alloca i32, align 4 @@ -346,10 +352,13 @@ if.exit: ; preds = %entry ret i32 %6 } +; Function Attrs: nounwind declare void @test_virtual3(i64, i8*) #0 +; Function Attrs: nounwind declare void @test_virtual2(i8*, i8*) #0 +; Function Attrs: nounwind define i32 @test.sum_us(i8* %0, i64 %1) #0 { entry: %x = alloca %"int[]", align 8 @@ -357,97 +366,99 @@ entry: %vararg = alloca %"int[]", align 8 %taddr = alloca %"int[]", align 8 %pair = bitcast %"int[]"* %x to { i8*, i64 }* - %lo = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 0 - store i8* %0, i8** %lo, align 8 - %hi = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 1 - store i64 %1, i64* %hi, align 8 + %2 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 0 + store i8* %0, i8** %2, align 8 + %3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 1 + store i64 %1, i64* %3, align 8 store i32 0, i32* %sum, align 4 - %len = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1 - %2 = load i64, i64* %len, align 8 - %eq = icmp eq i64 0, %2 + %4 = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1 + %5 = load i64, i64* %4, align 8 + %eq = icmp eq i64 0, %5 br i1 %eq, label %if.then, label %if.exit if.then: ; preds = %entry ret i32 0 if.exit: ; preds = %entry - %3 = load i32, i32* %sum, align 4 - %subarrayptr = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 0 - %saptr = load i32*, i32** %subarrayptr, align 8 - %sarridx = getelementptr inbounds i32, i32* %saptr, i64 0 - %4 = load i32, i32* %sarridx, align 4 - %5 = load %"int[]", %"int[]"* %x, align 8 - %6 = extractvalue %"int[]" %5, 0 - %7 = extractvalue %"int[]" %5, 1 - %sub = sub i64 %7, 1 - %8 = add i64 %sub, 1 - %size = sub i64 %8, 1 - %offsetsub = getelementptr inbounds i32, i32* %6, i64 1 - %9 = insertvalue %"int[]" undef, i32* %offsetsub, 0 - %10 = insertvalue %"int[]" %9, i64 %size, 1 - %11 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 1 - %12 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 0 - store %"int[]" %10, %"int[]"* %taddr, align 8 - %casttemp = bitcast %"int[]"* %taddr to { i8*, i64 }* - %lo1 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp, i32 0, i32 0 - %lo2 = load i8*, i8** %lo1, align 8 - %hi3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp, i32 0, i32 1 - %hi4 = load i64, i64* %hi3, align 8 - %13 = call i32 @test.sum_us(i8* %lo2, i64 %hi4) - %add = add i32 %4, %13 - %add5 = add i32 %3, %add - store i32 %add5, i32* %sum, align 4 - %14 = load i32, i32* %sum, align 4 - ret i32 %14 + %6 = load i32, i32* %sum, align 4 + %7 = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 0 + %8 = load i32*, i32** %7, align 8 + %ptroffset = getelementptr inbounds i32, i32* %8, i64 0 + %9 = load i32, i32* %ptroffset, align 4 + %10 = load %"int[]", %"int[]"* %x, align 8 + %11 = extractvalue %"int[]" %10, 0 + %12 = extractvalue %"int[]" %10, 1 + %sub = sub i64 %12, 1 + %13 = add i64 %sub, 1 + %size = sub i64 %13, 1 + %ptroffset1 = getelementptr inbounds i32, i32* %11, i64 1 + %14 = insertvalue %"int[]" undef, i32* %ptroffset1, 0 + %15 = insertvalue %"int[]" %14, i64 %size, 1 + %16 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 1 + %17 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 0 + store %"int[]" %15, %"int[]"* %taddr, align 8 + %18 = bitcast %"int[]"* %taddr to { i8*, i64 }* + %19 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %18, i32 0, i32 0 + %lo = load i8*, i8** %19, align 8 + %20 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %18, i32 0, i32 1 + %hi = load i64, i64* %20, align 8 + %21 = call i32 @test.sum_us(i8* %lo, i64 %hi) + %add = add i32 %9, %21 + %add2 = add i32 %6, %add + store i32 %add2, i32* %sum, align 4 + %22 = load i32, i32* %sum, align 4 + ret i32 %22 } +; Function Attrs: nounwind define i32 @test.sumd(i8* %0, i64 %1) #0 { entry: %x = alloca %"int[]", align 8 %sum = alloca i32, align 4 %i = alloca i32, align 4 %pair = bitcast %"int[]"* %x to { i8*, i64 }* - %lo = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 0 - store i8* %0, i8** %lo, align 8 - %hi = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 1 - store i64 %1, i64* %hi, align 8 + %2 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 0 + store i8* %0, i8** %2, align 8 + %3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 1 + store i64 %1, i64* %3, align 8 store i32 0, i32* %sum, align 4 store i32 0, i32* %i, align 4 br label %for.cond for.cond: ; preds = %for.inc, %entry - %2 = load i32, i32* %i, align 4 - %sisiext = sext i32 %2 to i64 - %len = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1 - %3 = load i64, i64* %len, align 8 - %lt = icmp slt i64 %sisiext, %3 - %check = icmp slt i64 %3, 0 + %4 = load i32, i32* %i, align 4 + %sisiext = sext i32 %4 to i64 + %5 = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1 + %6 = load i64, i64* %5, align 8 + %lt = icmp slt i64 %sisiext, %6 + %check = icmp slt i64 %6, 0 %siui-lt = or i1 %check, %lt br i1 %siui-lt, label %for.body, label %for.exit for.body: ; preds = %for.cond - %4 = load i32, i32* %sum, align 4 - %subarrayptr = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 0 - %saptr = load i32*, i32** %subarrayptr, align 8 - %5 = load i32, i32* %i, align 4 - %sisiext1 = sext i32 %5 to i64 - %sarridx = getelementptr inbounds i32, i32* %saptr, i64 %sisiext1 - %6 = load i32, i32* %sarridx, align 4 - %add = add i32 %4, %6 + %7 = load i32, i32* %sum, align 4 + %8 = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 0 + %9 = load i32*, i32** %8, align 8 + %10 = load i32, i32* %i, align 4 + %sisiext1 = sext i32 %10 to i64 + %ptroffset = getelementptr inbounds i32, i32* %9, i64 %sisiext1 + %11 = load i32, i32* %ptroffset, align 4 + %add = add i32 %7, %11 store i32 %add, i32* %sum, align 4 br label %for.inc for.inc: ; preds = %for.body - %7 = load i32, i32* %i, align 4 - %add2 = add i32 %7, 1 + %12 = load i32, i32* %i, align 4 + %add2 = add i32 %12, 1 store i32 %add2, i32* %i, align 4 br label %for.cond for.exit: ; preds = %for.cond - %8 = load i32, i32* %sum, align 4 - ret i32 %8 + %13 = load i32, i32* %sum, align 4 + ret i32 %13 } +; Function Attrs: nounwind define void @main() #0 { entry: %list = alloca %LinkedList, align 8 @@ -466,13 +477,13 @@ entry: %vararg = alloca %"int[]", align 8 %z = alloca %"int[]", align 8 %de = alloca [3 x i32], align 4 + %vararg11 = alloca %"int[]", align 8 %vararg14 = alloca %"int[]", align 8 - %vararg20 = alloca %"int[]", align 8 - %vararg26 = alloca %"int[]", align 8 + %vararg17 = alloca %"int[]", align 8 %varargslots = alloca [4 x i32], align 16 - %vararg32 = alloca %"int[]", align 8 - %varargslots33 = alloca [1 x i32], align 4 - %vararg39 = alloca %"int[]", align 8 + %vararg20 = alloca %"int[]", align 8 + %varargslots21 = alloca [1 x i32], align 4 + %vararg24 = alloca %"int[]", align 8 %a1 = alloca i32 (double, %Bobo*)*, align 8 %b2 = alloca i32 (double, %Bobo*)*, align 8 %0 = call i32 @test.test_static() @@ -552,114 +563,114 @@ for.exit9: ; preds = %for.cond2 call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %21, i8* align 4 bitcast (%Blob* @.__const.6 to i8*), i32 4, i1 false) %22 = bitcast %Blob.0* %b to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %22, i8* align 8 bitcast (%Blob.0* @.__const.7 to i8*), i32 8, i1 false) - %dive = getelementptr inbounds %Blob, %Blob* %a, i32 0, i32 0 - %23 = load i32, i32* %dive, align 4 - %24 = call i32 @test2.int.getValue(i32 %23) - %25 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.8, i32 0, i32 0), i32 %24) - %dive10 = getelementptr inbounds %Blob.0, %Blob.0* %b, i32 0, i32 0 - %26 = bitcast double* %tempcoerce to i8* - %27 = bitcast double* %dive10 to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %26, i8* align 8 %27, i32 8, i1 false) - %28 = load double, double* %tempcoerce, align 8 - %29 = call double @test2.double.getValue(double %28) - %30 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.9, i32 0, i32 0), double %29) - %31 = call i32 @test2.int.getMult(i32 25) - %32 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.10, i32 0, i32 0), i32 %31) - %33 = call double @test2.double.getMult(double 3.300000e+00) - %34 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @.str.11, i32 0, i32 0), double %33) + %23 = getelementptr inbounds %Blob, %Blob* %a, i32 0, i32 0 + %24 = load i32, i32* %23, align 4 + %25 = call i32 @test2.int.getValue(i32 %24) + %26 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.8, i32 0, i32 0), i32 %25) + %27 = getelementptr inbounds %Blob.0, %Blob.0* %b, i32 0, i32 0 + %28 = bitcast double* %tempcoerce to i8* + %29 = bitcast double* %27 to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %28, i8* align 8 %29, i32 8, i1 false) + %30 = load double, double* %tempcoerce, align 8 + %31 = call double @test2.double.getValue(double %30) + %32 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.9, i32 0, i32 0), double %31) + %33 = call i32 @test2.int.getMult(i32 25) + %34 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.10, i32 0, i32 0), i32 %33) + %35 = call double @test2.double.getMult(double 3.300000e+00) + %36 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @.str.11, i32 0, i32 0), double %35) call void @test.helloWorld() - %35 = bitcast %Foo* %ddx to i8* - call void @llvm.memset.p0i8.i64(i8* align 4 %35, i8 0, i64 8, i1 false) + %37 = bitcast %Foo* %ddx to i8* + call void @llvm.memset.p0i8.i64(i8* align 4 %37, i8 0, i64 8, i1 false) store i32 3, i32* %fro, align 4 - %36 = bitcast [4 x i32]* %x to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 16 %36, i8* align 16 bitcast ([4 x i32]* @.__const.12 to i8*), i32 16, i1 false) - %37 = load i32, i32* %fro, align 4 - %38 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 1 - %39 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 0 - store i64 4, i64* %38, align 8 - %40 = bitcast [4 x i32]* %x to i32* - store i32* %40, i32** %39, align 8 - %casttemp = bitcast %"int[]"* %vararg to { i8*, i64 }* - %lo = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp, i32 0, i32 0 - %lo11 = load i8*, i8** %lo, align 8 - %hi = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp, i32 0, i32 1 - %hi12 = load i64, i64* %hi, align 8 - %41 = call i32 @test.sum_us(i8* %lo11, i64 %hi12) - %42 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* @.str.13, i32 0, i32 0), i32 %41) - %add13 = add i32 %37, %42 - store i32 %add13, i32* %fro, align 4 - %43 = load i32, i32* %fro, align 4 - %44 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.14, i32 0, i32 0), i32 %43) - %45 = bitcast [4 x i32]* %x to i32* - %46 = insertvalue %"int[]" undef, i32* %45, 0 - %47 = insertvalue %"int[]" %46, i64 4, 1 - store %"int[]" %47, %"int[]"* %z, align 8 - %48 = bitcast [3 x i32]* %de to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %48, i8* align 4 bitcast ([3 x i32]* @.__const.15 to i8*), i32 12, i1 false) - %49 = getelementptr inbounds %"int[]", %"int[]"* %vararg14, i32 0, i32 1 - %50 = getelementptr inbounds %"int[]", %"int[]"* %vararg14, i32 0, i32 0 - store i64 4, i64* %49, align 8 - %51 = bitcast [4 x i32]* %x to i32* - store i32* %51, i32** %50, align 8 - %casttemp15 = bitcast %"int[]"* %vararg14 to { i8*, i64 }* - %lo16 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp15, i32 0, i32 0 - %lo17 = load i8*, i8** %lo16, align 8 - %hi18 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp15, i32 0, i32 1 - %hi19 = load i64, i64* %hi18, align 8 - %52 = call i32 @test.sum_us(i8* %lo17, i64 %hi19) - %53 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.str.16, i32 0, i32 0), i32 %52) - %54 = getelementptr inbounds %"int[]", %"int[]"* %vararg20, i32 0, i32 1 - %55 = getelementptr inbounds %"int[]", %"int[]"* %vararg20, i32 0, i32 0 - %casttemp21 = bitcast %"int[]"* %z to { i8*, i64 }* - %lo22 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp21, i32 0, i32 0 - %lo23 = load i8*, i8** %lo22, align 8 - %hi24 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp21, i32 0, i32 1 - %hi25 = load i64, i64* %hi24, align 8 - %56 = call i32 @test.sum_us(i8* %lo23, i64 %hi25) - %57 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.str.17, i32 0, i32 0), i32 %56) - %58 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 0 - store i32 1, i32* %58, align 4 - %59 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 1 - store i32 2, i32* %59, align 4 - %60 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 2 - store i32 4, i32* %60, align 4 - %61 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 3 - store i32 5, i32* %61, align 4 - %62 = getelementptr inbounds %"int[]", %"int[]"* %vararg26, i32 0, i32 1 - store i64 4, i64* %62, align 8 - %63 = getelementptr inbounds %"int[]", %"int[]"* %vararg26, i32 0, i32 0 - %64 = bitcast [4 x i32]* %varargslots to i32* - store i32* %64, i32** %63, align 8 - %casttemp27 = bitcast %"int[]"* %vararg26 to { i8*, i64 }* - %lo28 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp27, i32 0, i32 0 - %lo29 = load i8*, i8** %lo28, align 8 - %hi30 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp27, i32 0, i32 1 - %hi31 = load i64, i64* %hi30, align 8 - %65 = call i32 @test.sum_us(i8* %lo29, i64 %hi31) - %66 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.18, i32 0, i32 0), i32 %65) - %67 = getelementptr inbounds [1 x i32], [1 x i32]* %varargslots33, i64 0, i64 0 - store i32 1, i32* %67, align 4 - %68 = getelementptr inbounds %"int[]", %"int[]"* %vararg32, i32 0, i32 1 - store i64 1, i64* %68, align 8 - %69 = getelementptr inbounds %"int[]", %"int[]"* %vararg32, i32 0, i32 0 - %70 = bitcast [1 x i32]* %varargslots33 to i32* - store i32* %70, i32** %69, align 8 - %casttemp34 = bitcast %"int[]"* %vararg32 to { i8*, i64 }* - %lo35 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp34, i32 0, i32 0 - %lo36 = load i8*, i8** %lo35, align 8 - %hi37 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp34, i32 0, i32 1 - %hi38 = load i64, i64* %hi37, align 8 - %71 = call i32 @test.sum_us(i8* %lo36, i64 %hi38) - %72 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.19, i32 0, i32 0), i32 %71) - %73 = getelementptr inbounds %"int[]", %"int[]"* %vararg39, i32 0, i32 1 - store i64 0, i64* %73, align 8 - %casttemp40 = bitcast %"int[]"* %vararg39 to { i8*, i64 }* - %lo41 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp40, i32 0, i32 0 - %lo42 = load i8*, i8** %lo41, align 8 - %hi43 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp40, i32 0, i32 1 - %hi44 = load i64, i64* %hi43, align 8 - %74 = call i32 @test.sum_us(i8* %lo42, i64 %hi44) - %75 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.20, i32 0, i32 0), i32 %74) + %38 = bitcast [4 x i32]* %x to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 16 %38, i8* align 16 bitcast ([4 x i32]* @.__const.12 to i8*), i32 16, i1 false) + %39 = load i32, i32* %fro, align 4 + %40 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 1 + %41 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 0 + store i64 4, i64* %40, align 8 + %42 = bitcast [4 x i32]* %x to i32* + store i32* %42, i32** %41, align 8 + %43 = bitcast %"int[]"* %vararg to { i8*, i64 }* + %44 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %43, i32 0, i32 0 + %lo = load i8*, i8** %44, align 8 + %45 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %43, i32 0, i32 1 + %hi = load i64, i64* %45, align 8 + %46 = call i32 @test.sum_us(i8* %lo, i64 %hi) + %47 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* @.str.13, i32 0, i32 0), i32 %46) + %add10 = add i32 %39, %47 + store i32 %add10, i32* %fro, align 4 + %48 = load i32, i32* %fro, align 4 + %49 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.14, i32 0, i32 0), i32 %48) + %50 = bitcast [4 x i32]* %x to i32* + %51 = insertvalue %"int[]" undef, i32* %50, 0 + %52 = insertvalue %"int[]" %51, i64 4, 1 + store %"int[]" %52, %"int[]"* %z, align 8 + %53 = bitcast [3 x i32]* %de to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %53, i8* align 4 bitcast ([3 x i32]* @.__const.15 to i8*), i32 12, i1 false) + %54 = getelementptr inbounds %"int[]", %"int[]"* %vararg11, i32 0, i32 1 + %55 = getelementptr inbounds %"int[]", %"int[]"* %vararg11, i32 0, i32 0 + store i64 4, i64* %54, align 8 + %56 = bitcast [4 x i32]* %x to i32* + store i32* %56, i32** %55, align 8 + %57 = bitcast %"int[]"* %vararg11 to { i8*, i64 }* + %58 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %57, i32 0, i32 0 + %lo12 = load i8*, i8** %58, align 8 + %59 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %57, i32 0, i32 1 + %hi13 = load i64, i64* %59, align 8 + %60 = call i32 @test.sum_us(i8* %lo12, i64 %hi13) + %61 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.str.16, i32 0, i32 0), i32 %60) + %62 = getelementptr inbounds %"int[]", %"int[]"* %vararg14, i32 0, i32 1 + %63 = getelementptr inbounds %"int[]", %"int[]"* %vararg14, i32 0, i32 0 + %64 = bitcast %"int[]"* %z to { i8*, i64 }* + %65 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %64, i32 0, i32 0 + %lo15 = load i8*, i8** %65, align 8 + %66 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %64, i32 0, i32 1 + %hi16 = load i64, i64* %66, align 8 + %67 = call i32 @test.sum_us(i8* %lo15, i64 %hi16) + %68 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.str.17, i32 0, i32 0), i32 %67) + %69 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 0 + store i32 1, i32* %69, align 4 + %70 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 1 + store i32 2, i32* %70, align 4 + %71 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 2 + store i32 4, i32* %71, align 4 + %72 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 3 + store i32 5, i32* %72, align 4 + %73 = getelementptr inbounds %"int[]", %"int[]"* %vararg17, i32 0, i32 1 + store i64 4, i64* %73, align 8 + %74 = getelementptr inbounds %"int[]", %"int[]"* %vararg17, i32 0, i32 0 + %75 = bitcast [4 x i32]* %varargslots to i32* + store i32* %75, i32** %74, align 8 + %76 = bitcast %"int[]"* %vararg17 to { i8*, i64 }* + %77 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %76, i32 0, i32 0 + %lo18 = load i8*, i8** %77, align 8 + %78 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %76, i32 0, i32 1 + %hi19 = load i64, i64* %78, align 8 + %79 = call i32 @test.sum_us(i8* %lo18, i64 %hi19) + %80 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.18, i32 0, i32 0), i32 %79) + %81 = getelementptr inbounds [1 x i32], [1 x i32]* %varargslots21, i64 0, i64 0 + store i32 1, i32* %81, align 4 + %82 = getelementptr inbounds %"int[]", %"int[]"* %vararg20, i32 0, i32 1 + store i64 1, i64* %82, align 8 + %83 = getelementptr inbounds %"int[]", %"int[]"* %vararg20, i32 0, i32 0 + %84 = bitcast [1 x i32]* %varargslots21 to i32* + store i32* %84, i32** %83, align 8 + %85 = bitcast %"int[]"* %vararg20 to { i8*, i64 }* + %86 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %85, i32 0, i32 0 + %lo22 = load i8*, i8** %86, align 8 + %87 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %85, i32 0, i32 1 + %hi23 = load i64, i64* %87, align 8 + %88 = call i32 @test.sum_us(i8* %lo22, i64 %hi23) + %89 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.19, i32 0, i32 0), i32 %88) + %90 = getelementptr inbounds %"int[]", %"int[]"* %vararg24, i32 0, i32 1 + store i64 0, i64* %90, align 8 + %91 = bitcast %"int[]"* %vararg24 to { i8*, i64 }* + %92 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %91, i32 0, i32 0 + %lo25 = load i8*, i8** %92, align 8 + %93 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %91, i32 0, i32 1 + %hi26 = load i64, i64* %93, align 8 + %94 = call i32 @test.sum_us(i8* %lo25, i64 %hi26) + %95 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.20, i32 0, i32 0), i32 %94) store i32 (double, %Bobo*)* null, i32 (double, %Bobo*)** %a1, align 8 store i32 (double, %Bobo*)* null, i32 (double, %Bobo*)** %b2, align 8 ret void @@ -708,11 +719,11 @@ entry: define i32 @test2.int.getValue(i32 %0) entry: %blob = alloca %Blob, align 4 - %dive = getelementptr inbounds %Blob, %Blob* %blob, i32 0, i32 0 - store i32 %0, i32* %dive, align 4 %1 = getelementptr inbounds %Blob, %Blob* %blob, i32 0, i32 0 - %2 = load i32, i32* %1, align 4 - ret i32 %2 + store i32 %0, i32* %1, align 4 + %2 = getelementptr inbounds %Blob, %Blob* %blob, i32 0, i32 0 + %3 = load i32, i32* %2, align 4 + ret i32 %3 // #expect: test2.double.ll @@ -736,8 +747,8 @@ entry: define double @test2.double.getValue(double %0) entry: %blob = alloca %Blob, align 8 - %dive = getelementptr inbounds %Blob, %Blob* %blob, i32 0, i32 0 - store double %0, double* %dive, align 8 %1 = getelementptr inbounds %Blob, %Blob* %blob, i32 0, i32 0 - %2 = load double, double* %1, align 8 - ret double %2 \ No newline at end of file + store double %0, double* %1, align 8 + %2 = getelementptr inbounds %Blob, %Blob* %blob, i32 0, i32 0 + %3 = load double, double* %2, align 8 + ret double %3 \ No newline at end of file diff --git a/test/test_suite/functions/test_regression_mingw.c3t b/test/test_suite/functions/test_regression_mingw.c3t index 46abfa5d2..da081127a 100644 --- a/test/test_suite/functions/test_regression_mingw.c3t +++ b/test/test_suite/functions/test_regression_mingw.c3t @@ -245,7 +245,7 @@ func Type getValue(Blob blob) return blob.a; } -// #expect: test.ll +/* #expect: test.ll %Blob = type { i32 } %Blob.0 = type { double } @@ -259,7 +259,125 @@ func Type getValue(Blob blob) %"int[]" = type { i32*, i64 } %Foo = type { i32, i32 } -define void @test.Foo2__printme(%Foo2* %0) +@test2.int.argh = external global i32 +@Bobo = linkonce_odr constant i8 1 +@Blob = linkonce_odr constant i8 1 +@Foor = linkonce_odr constant i8 1 +@Foo2 = linkonce_odr constant i8 1 +@Foo = linkonce_odr constant i8 1 +@.str = private constant [13 x i8] c"helloWorld!\0A\00", align 1 +@test_static.x = hidden global i32 1, align 4 +@.str.1 = private constant [16 x i8] c"Test static %d\0A\00", align 1 +@.__const = private constant [3 x i32] [i32 1, i32 2, i32 3], align 4 +@.str.2 = private constant [17 x i8] c"Element[%d]: %d\0A\00", align 1 +@.str.3 = private constant [28 x i8] c"Min %d Max %d Elements: %d\0A\00", align 1 +@.str.4 = private constant [7 x i8] c"Hello\0A\00", align 1 +@.str.5 = private constant [17 x i8] c"Element[%d]: %d\0A\00", align 1 +@.__const.6 = private constant %Blob { i32 42 }, align 4 +@.__const.7 = private constant %Blob.0 { double 3.330000e+01 }, align 8 +@.str.8 = private constant [10 x i8] c"a was %d\0A\00", align 1 +@.str.9 = private constant [10 x i8] c"b was %f\0A\00", align 1 +@.str.10 = private constant [17 x i8] c"Mult int was %d\0A\00", align 1 +@.str.11 = private constant [20 x i8] c"Mult double was %f\0A\00", align 1 +@.__const.12 = private constant [4 x i32] [i32 1, i32 2, i32 3, i32 3], align 4 +@.str.13 = private constant [22 x i8] c"1Vararg4unsplatA: %d\0A\00", align 1 +@.str.14 = private constant [4 x i8] c"%d\0A\00", align 1 +@.__const.15 = private constant [3 x i32] [i32 1, i32 2, i32 3], align 4 +@.str.16 = private constant [21 x i8] c"Vararg4unsplatB: %d\0A\00", align 1 +@.str.17 = private constant [21 x i8] c"Vararg4unsplatC: %d\0A\00", align 1 +@.str.18 = private constant [13 x i8] c"Vararg4: %d\0A\00", align 1 +@.str.19 = private constant [13 x i8] c"Vararg1: %d\0A\00", align 1 +@.str.20 = private constant [13 x i8] c"Vararg0: %d\0A\00", align 1 +@.str.21 = private constant [12 x i8] c"Foo is: %d\0A\00", align 1 +@.str.22 = private constant [9 x i8] c"Mutating\00", align 1 + +declare i32 @test2.int.getValue(i32) + +declare double @test2.double.getValue(i64) + +declare i32 @test2.int.getMult(i32) + +declare double @test2.double.getMult(double) + +; Function Attrs: nounwind +declare void @List.ensureCapacity(%List*) #0 + +; Function Attrs: nounwind +declare void @"std::array::list.int.List__push"(%List*, i32) #0 + +; Function Attrs: nounwind +declare void @"std::array::list.int.List__append"(%List*, i32) #0 + +; Function Attrs: nounwind +declare i32 @"std::array::list.int.List__pop"(%List*) #0 + +; Function Attrs: nounwind +declare i32 @"std::array::list.int.List__popFirst"(%List*) #0 + +; Function Attrs: nounwind +declare void @"std::array::list.int.List__removeAt"(%List*, i64) #0 + +; Function Attrs: nounwind +declare void @"std::array::list.int.List__pushFront"(%List*, i32) #0 + +; Function Attrs: nounwind +declare void @"std::array::list.int.List__insertAt"(%List*, i64, i32) #0 + +; Function Attrs: nounwind +declare void @"std::array::list.int.List__removeLast"(%List*) #0 + +; Function Attrs: nounwind +declare void @"std::array::list.int.List__removeFirst"(%List*) #0 + +; Function Attrs: nounwind +declare i32* @"std::array::list.int.List__first"(%List*) #0 + +; Function Attrs: nounwind +declare i32* @"std::array::list.int.List__last"(%List*) #0 + +; Function Attrs: nounwind +declare zeroext i8 @"std::array::list.int.List__isEmpty"(%List*) #0 + +; Function Attrs: nounwind +declare i64 @"std::array::list.int.List__len"(%List*) #0 + +; Function Attrs: nounwind +declare i32 @"std::array::list.int.List__get"(%List*, i64) #0 + +; Function Attrs: nounwind +declare void @"std::array::list.int.List__free"(%List*) #0 + +; Function Attrs: nounwind +declare void @"std::array::linkedlist.int.LinkedList__push"(%LinkedList*, i32) #0 + +; Function Attrs: nounwind +declare void @LinkedList.linkFirst(%LinkedList*, i32) #0 + +; Function Attrs: nounwind +declare void @LinkedList.linkLast(%LinkedList*, i32) #0 + +; Function Attrs: nounwind +declare void @"std::array::linkedlist.int.LinkedList__free"(%LinkedList*) #0 + +; Function Attrs: nounwind +declare i64 @"std::array::linkedlist.int.LinkedList__len"(%LinkedList*) #0 + +; Function Attrs: nounwind +declare i32 @"std::array::linkedlist.int.LinkedList__get"(%LinkedList*, i64) #0 + +; Function Attrs: nounwind +declare void @LinkedList.linkBefore(%LinkedList*, %Node*, i32) #0 + +; Function Attrs: nounwind +declare void @LinkedList.unlinkLast(%LinkedList*, %Node*) #0 + +; Function Attrs: nounwind +declare void @LinkedList.unlink(%LinkedList*, %Node*) #0 + +declare void @hello_world.hello() + +; Function Attrs: nounwind +define void @test.Foo2__printme(%Foo2* %0) #0 { entry: %foo = alloca %Foo2*, align 8 store %Foo2* %0, %Foo2** %foo, align 8 @@ -270,7 +388,8 @@ entry: ret void } -define i32 @test.Foo2__mutate(%Foo2* %0) +; Function Attrs: nounwind +define i32 @test.Foo2__mutate(%Foo2* %0) #0 { entry: %foo = alloca %Foo2*, align 8 store %Foo2* %0, %Foo2** %foo, align 8 @@ -283,13 +402,18 @@ entry: ret i32 %add } -define void @test.helloWorld() +; Function Attrs: nounwind +declare i32 @printf(i8*, ...) #0 + +; Function Attrs: nounwind +define void @test.helloWorld() #0 { entry: %0 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str, i32 0, i32 0)) ret void } -define i32 @test.test_static() +; Function Attrs: nounwind +define i32 @test.test_static() #0 { entry: %0 = load i32, i32* @test_static.x, align 4 %add = add i32 %0, 1 @@ -300,7 +424,9 @@ entry: ret i32 %3 } -define i32 @test.helo(double %0, %Bobo* align 4 %1) +; Function Attrs: nounwind +define i32 @test.helo(double %0, %Bobo* align 4 %1) #0 { +entry: %d = alloca double, align 8 %b = alloca %Bobo, align 4 %de = alloca [3 x i32], align 4 @@ -322,7 +448,9 @@ define i32 @test.helo(double %0, %Bobo* align 4 %1) ret i32 1 } -define i32 @test.test1(i32 %0, i32 %1) +; Function Attrs: nounwind +define i32 @test.test1(i32 %0, i32 %1) #0 { +entry: %a = alloca i32, align 4 %b = alloca i32, align 4 store i32 %0, i32* %a, align 4 @@ -336,17 +464,22 @@ define i32 @test.test1(i32 %0, i32 %1) %gt = icmp sgt i32 %5, 128 br i1 %gt, label %if.then, label %if.exit +if.then: ; preds = %entry ret i32 -1 +if.exit: ; preds = %entry %6 = load i32, i32* %a, align 4 ret i32 %6 } -declare void @test_virtual3(%"virtual*"* align 8) +; Function Attrs: nounwind +declare void @test_virtual3(%"virtual*"* align 8) #0 -declare void @test_virtual2(%"virtual$"* align 8) +; Function Attrs: nounwind +declare void @test_virtual2(%"virtual$"* align 8) #0 -define i32 @test.sum_us(%"int[]"* align 8 %0) +; Function Attrs: nounwind +define i32 @test.sum_us(%"int[]"* align 8 %0) #0 { entry: %x = alloca %"int[]", align 8 %sum = alloca i32, align 4 @@ -356,41 +489,42 @@ entry: %2 = bitcast %"int[]"* %0 to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %1, i8* align 8 %2, i32 16, i1 false) store i32 0, i32* %sum, align 4 - %len = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1 - %3 = load i64, i64* %len, align 8 - %eq = icmp eq i64 0, %3 + %3 = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1 + %4 = load i64, i64* %3, align 8 + %eq = icmp eq i64 0, %4 br i1 %eq, label %if.then, label %if.exit -if.then: +if.then: ; preds = %entry ret i32 0 -if.exit: - %4 = load i32, i32* %sum, align 4 - %subarrayptr = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 0 - %saptr = load i32*, i32** %subarrayptr, align 8 - %sarridx = getelementptr inbounds i32, i32* %saptr, i64 0 - %5 = load i32, i32* %sarridx, align 4 - %6 = load %"int[]", %"int[]"* %x, align 8 - %7 = extractvalue %"int[]" %6, 0 - %8 = extractvalue %"int[]" %6, 1 - %sub = sub i64 %8, 1 - %9 = add i64 %sub, 1 - %size = sub i64 %9, 1 - %offsetsub = getelementptr inbounds i32, i32* %7, i64 1 - %10 = insertvalue %"int[]" undef, i32* %offsetsub, 0 - %11 = insertvalue %"int[]" %10, i64 %size, 1 - %12 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 1 - %13 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 0 - store %"int[]" %11, %"int[]"* %indirectarg, align 8 - %14 = call i32 @test.sum_us(%"int[]"* %indirectarg) - %add = add i32 %5, %14 - %add1 = add i32 %4, %add - store i32 %add1, i32* %sum, align 4 - %15 = load i32, i32* %sum, align 4 - ret i32 %15 +if.exit: ; preds = %entry + %5 = load i32, i32* %sum, align 4 + %6 = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 0 + %7 = load i32*, i32** %6, align 8 + %ptroffset = getelementptr inbounds i32, i32* %7, i64 0 + %8 = load i32, i32* %ptroffset, align 4 + %9 = load %"int[]", %"int[]"* %x, align 8 + %10 = extractvalue %"int[]" %9, 0 + %11 = extractvalue %"int[]" %9, 1 + %sub = sub i64 %11, 1 + %12 = add i64 %sub, 1 + %size = sub i64 %12, 1 + %ptroffset1 = getelementptr inbounds i32, i32* %10, i64 1 + %13 = insertvalue %"int[]" undef, i32* %ptroffset1, 0 + %14 = insertvalue %"int[]" %13, i64 %size, 1 + %15 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 1 + %16 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 0 + store %"int[]" %14, %"int[]"* %indirectarg, align 8 + %17 = call i32 @test.sum_us(%"int[]"* %indirectarg) + %add = add i32 %8, %17 + %add2 = add i32 %5, %add + store i32 %add2, i32* %sum, align 4 + %18 = load i32, i32* %sum, align 4 + ret i32 %18 } -define i32 @test.sumd(%"int[]"* align 8 %0) +; Function Attrs: nounwind +define i32 @test.sumd(%"int[]"* align 8 %0) #0 { entry: %x = alloca %"int[]", align 8 %sum = alloca i32, align 4 @@ -402,40 +536,41 @@ entry: store i32 0, i32* %i, align 4 br label %for.cond -for.cond: +for.cond: ; preds = %for.inc, %entry %3 = load i32, i32* %i, align 4 %sisiext = sext i32 %3 to i64 - %len = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1 - %4 = load i64, i64* %len, align 8 - %lt = icmp slt i64 %sisiext, %4 - %check = icmp slt i64 %4, 0 + %4 = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1 + %5 = load i64, i64* %4, align 8 + %lt = icmp slt i64 %sisiext, %5 + %check = icmp slt i64 %5, 0 %siui-lt = or i1 %check, %lt br i1 %siui-lt, label %for.body, label %for.exit -for.body: - %5 = load i32, i32* %sum, align 4 - %subarrayptr = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 0 - %saptr = load i32*, i32** %subarrayptr, align 8 - %6 = load i32, i32* %i, align 4 - %sisiext1 = sext i32 %6 to i64 - %sarridx = getelementptr inbounds i32, i32* %saptr, i64 %sisiext1 - %7 = load i32, i32* %sarridx, align 4 - %add = add i32 %5, %7 +for.body: ; preds = %for.cond + %6 = load i32, i32* %sum, align 4 + %7 = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 0 + %8 = load i32*, i32** %7, align 8 + %9 = load i32, i32* %i, align 4 + %sisiext1 = sext i32 %9 to i64 + %ptroffset = getelementptr inbounds i32, i32* %8, i64 %sisiext1 + %10 = load i32, i32* %ptroffset, align 4 + %add = add i32 %6, %10 store i32 %add, i32* %sum, align 4 br label %for.inc -for.inc: - %8 = load i32, i32* %i, align 4 - %add2 = add i32 %8, 1 +for.inc: ; preds = %for.body + %11 = load i32, i32* %i, align 4 + %add2 = add i32 %11, 1 store i32 %add2, i32* %i, align 4 br label %for.cond -for.exit: - %9 = load i32, i32* %sum, align 4 - ret i32 %9 +for.exit: ; preds = %for.cond + %12 = load i32, i32* %sum, align 4 + ret i32 %12 } -define void @main() +; Function Attrs: nounwind +define void @main() #0 { entry: %list = alloca %LinkedList, align 8 %i = alloca i32, align 4 @@ -454,18 +589,18 @@ entry: %indirectarg = alloca %"int[]", align 8 %z = alloca %"int[]", align 8 %de = alloca [3 x i32], align 4 - %vararg12 = alloca %"int[]", align 8 - %indirectarg13 = alloca %"int[]", align 8 - %vararg14 = alloca %"int[]", align 8 - %indirectarg15 = alloca %"int[]", align 8 - %vararg16 = alloca %"int[]", align 8 + %vararg11 = alloca %"int[]", align 8 + %indirectarg12 = alloca %"int[]", align 8 + %vararg13 = alloca %"int[]", align 8 + %indirectarg14 = alloca %"int[]", align 8 + %vararg15 = alloca %"int[]", align 8 %varargslots = alloca [4 x i32], align 4 - %indirectarg17 = alloca %"int[]", align 8 - %vararg18 = alloca %"int[]", align 8 - %varargslots19 = alloca [1 x i32], align 4 - %indirectarg20 = alloca %"int[]", align 8 - %vararg21 = alloca %"int[]", align 8 - %indirectarg22 = alloca %"int[]", align 8 + %indirectarg16 = alloca %"int[]", align 8 + %vararg17 = alloca %"int[]", align 8 + %varargslots18 = alloca [1 x i32], align 4 + %indirectarg19 = alloca %"int[]", align 8 + %vararg20 = alloca %"int[]", align 8 + %indirectarg21 = alloca %"int[]", align 8 %a1 = alloca i32 (double, %Bobo*)*, align 8 %b2 = alloca i32 (double, %Bobo*)*, align 8 %0 = call i32 @test.test_static() @@ -480,14 +615,14 @@ entry: store i32 0, i32* %i, align 4 br label %for.cond -for.cond: +for.cond: ; preds = %for.inc, %entry %4 = load i32, i32* %i, align 4 - %5 = call i64 @"std::array::linkedlist.int.LinkedList__len"(%LinkedList* %list) + %5 = call i64 @"std::array::linkedlist.int.LinkedList__len"(%LinkedList* %list) #3 %uisitrunc = trunc i64 %5 to i32 %lt = icmp slt i32 %4, %uisitrunc br i1 %lt, label %for.body, label %for.exit -for.body: +for.body: ; preds = %for.cond %6 = load i32, i32* %i, align 4 %7 = load i32, i32* %i, align 4 %siuiext = zext i32 %7 to i64 @@ -495,13 +630,13 @@ for.body: %9 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.2, i32 0, i32 0), i32 %6, i32 %8) br label %for.inc -for.inc: +for.inc: ; preds = %for.body %10 = load i32, i32* %i, align 4 %add = add i32 %10, 1 store i32 %add, i32* %i, align 4 br label %for.cond -for.exit: +for.exit: ; preds = %for.cond call void @"std::array::linkedlist.int.LinkedList__free"(%LinkedList* %list) %11 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([28 x i8], [28 x i8]* @.str.3, i32 0, i32 0), i32 -5, i32 14, i32 3) store i32 14, i32* %max, align 4 @@ -513,19 +648,19 @@ for.exit: call void @"std::array::list.int.List__append"(%List* %array, i32 100) call void @"std::array::list.int.List__append"(%List* %array, i32 200) call void @"std::array::list.int.List__append"(%List* %array, i32 400) - call void @"std::array::list.int.List__push"(%List* %array, i32 600) + call void @"std::array::list.int.List__push"(%List* %array, i32 600) #3 call void @"std::array::list.int.List__insertAt"(%List* %array, i64 2, i32 300) store i32 0, i32* %i1, align 4 br label %for.cond2 -for.cond2: +for.cond2: ; preds = %for.inc7, %for.exit %14 = load i32, i32* %i1, align 4 %15 = call i64 @"std::array::list.int.List__len"(%List* %array) %uisitrunc3 = trunc i64 %15 to i32 %lt4 = icmp slt i32 %14, %uisitrunc3 br i1 %lt4, label %for.body5, label %for.exit9 -for.body5: +for.body5: ; preds = %for.cond2 %16 = load i32, i32* %i1, align 4 %17 = load i32, i32* %i1, align 4 %siuiext6 = zext i32 %17 to i64 @@ -533,114 +668,114 @@ for.body5: %19 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.5, i32 0, i32 0), i32 %16, i32 %18) br label %for.inc7 -for.inc7: +for.inc7: ; preds = %for.body5 %20 = load i32, i32* %i1, align 4 %add8 = add i32 %20, 1 store i32 %add8, i32* %i1, align 4 br label %for.cond2 -for.exit9: +for.exit9: ; preds = %for.cond2 call void @"std::array::list.int.List__free"(%List* %array) %21 = bitcast %Blob* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %21, i8* align 4 bitcast (%Blob* @.__const.6 to i8*), i32 4, i1 false) %22 = bitcast %Blob.0* %b to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %22, i8* align 8 bitcast (%Blob.0* @.__const.7 to i8*), i32 8, i1 false) - %dive = getelementptr inbounds %Blob, %Blob* %a, i32 0, i32 0 - %23 = load i32, i32* %dive, align 4 - %24 = call i32 @test2.int.getValue(i32 %23) - %25 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.8, i32 0, i32 0), i32 %24) - %dive10 = getelementptr inbounds %Blob.0, %Blob.0* %b, i32 0, i32 0 - %26 = bitcast i64* %tempcoerce to i8* - %27 = bitcast double* %dive10 to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %26, i8* align 8 %27, i32 8, i1 false) - %28 = load i64, i64* %tempcoerce, align 8 - %29 = call double @test2.double.getValue(i64 %28) - %30 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.9, i32 0, i32 0), double %29) - %31 = call i32 @test2.int.getMult(i32 25) - %32 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.10, i32 0, i32 0), i32 %31) - %33 = call double @test2.double.getMult(double 3.300000e+00) - %34 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @.str.11, i32 0, i32 0), double %33) + %23 = getelementptr inbounds %Blob, %Blob* %a, i32 0, i32 0 + %24 = load i32, i32* %23, align 4 + %25 = call i32 @test2.int.getValue(i32 %24) + %26 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.8, i32 0, i32 0), i32 %25) + %27 = getelementptr inbounds %Blob.0, %Blob.0* %b, i32 0, i32 0 + %28 = bitcast i64* %tempcoerce to i8* + %29 = bitcast double* %27 to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %28, i8* align 8 %29, i32 8, i1 false) + %30 = load i64, i64* %tempcoerce, align 8 + %31 = call double @test2.double.getValue(i64 %30) + %32 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.9, i32 0, i32 0), double %31) + %33 = call i32 @test2.int.getMult(i32 25) + %34 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.10, i32 0, i32 0), i32 %33) + %35 = call double @test2.double.getMult(double 3.300000e+00) + %36 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @.str.11, i32 0, i32 0), double %35) call void @test.helloWorld() - %35 = bitcast %Foo* %ddx to i8* - call void @llvm.memset.p0i8.i64(i8* align 4 %35, i8 0, i64 8, i1 false) + %37 = bitcast %Foo* %ddx to i8* + call void @llvm.memset.p0i8.i64(i8* align 4 %37, i8 0, i64 8, i1 false) store i32 3, i32* %fro, align 4 - %36 = bitcast [4 x i32]* %x to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %36, i8* align 4 bitcast ([4 x i32]* @.__const.12 to i8*), i32 16, i1 false) - %37 = load i32, i32* %fro, align 4 - %38 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 1 - %39 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 0 - store i64 4, i64* %38, align 8 - %40 = bitcast [4 x i32]* %x to i32* - store i32* %40, i32** %39, align 8 - %41 = bitcast %"int[]"* %indirectarg to i8* - %42 = bitcast %"int[]"* %vararg to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %41, i8* align 8 %42, i32 16, i1 false) - %43 = call i32 @test.sum_us(%"int[]"* %indirectarg) - %44 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* @.str.13, i32 0, i32 0), i32 %43) - %add11 = add i32 %37, %44 - store i32 %add11, i32* %fro, align 4 - %45 = load i32, i32* %fro, align 4 - %46 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.14, i32 0, i32 0), i32 %45) - %47 = bitcast [4 x i32]* %x to i32* - %48 = insertvalue %"int[]" undef, i32* %47, 0 - %49 = insertvalue %"int[]" %48, i64 4, 1 - store %"int[]" %49, %"int[]"* %z, align 8 - %50 = bitcast [3 x i32]* %de to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %50, i8* align 4 bitcast ([3 x i32]* @.__const.15 to i8*), i32 12, i1 false) - %51 = getelementptr inbounds %"int[]", %"int[]"* %vararg12, i32 0, i32 1 - %52 = getelementptr inbounds %"int[]", %"int[]"* %vararg12, i32 0, i32 0 - store i64 4, i64* %51, align 8 - %53 = bitcast [4 x i32]* %x to i32* - store i32* %53, i32** %52, align 8 - %54 = bitcast %"int[]"* %indirectarg13 to i8* - %55 = bitcast %"int[]"* %vararg12 to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %54, i8* align 8 %55, i32 16, i1 false) - %56 = call i32 @test.sum_us(%"int[]"* %indirectarg13) - %57 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.str.16, i32 0, i32 0), i32 %56) - %58 = getelementptr inbounds %"int[]", %"int[]"* %vararg14, i32 0, i32 1 - %59 = getelementptr inbounds %"int[]", %"int[]"* %vararg14, i32 0, i32 0 - %60 = bitcast %"int[]"* %indirectarg15 to i8* - %61 = bitcast %"int[]"* %z to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %60, i8* align 8 %61, i32 16, i1 false) - %62 = call i32 @test.sum_us(%"int[]"* %indirectarg15) - %63 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.str.17, i32 0, i32 0), i32 %62) - %64 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 0 - store i32 1, i32* %64, align 4 - %65 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 1 - store i32 2, i32* %65, align 4 - %66 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 2 - store i32 4, i32* %66, align 4 - %67 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 3 - store i32 5, i32* %67, align 4 - %68 = getelementptr inbounds %"int[]", %"int[]"* %vararg16, i32 0, i32 1 - store i64 4, i64* %68, align 8 - %69 = getelementptr inbounds %"int[]", %"int[]"* %vararg16, i32 0, i32 0 - %70 = bitcast [4 x i32]* %varargslots to i32* - store i32* %70, i32** %69, align 8 - %71 = bitcast %"int[]"* %indirectarg17 to i8* - %72 = bitcast %"int[]"* %vararg16 to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %71, i8* align 8 %72, i32 16, i1 false) - %73 = call i32 @test.sum_us(%"int[]"* %indirectarg17) - %74 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.18, i32 0, i32 0), i32 %73) - %75 = getelementptr inbounds [1 x i32], [1 x i32]* %varargslots19, i64 0, i64 0 - store i32 1, i32* %75, align 4 - %76 = getelementptr inbounds %"int[]", %"int[]"* %vararg18, i32 0, i32 1 - store i64 1, i64* %76, align 8 - %77 = getelementptr inbounds %"int[]", %"int[]"* %vararg18, i32 0, i32 0 - %78 = bitcast [1 x i32]* %varargslots19 to i32* - store i32* %78, i32** %77, align 8 - %79 = bitcast %"int[]"* %indirectarg20 to i8* - %80 = bitcast %"int[]"* %vararg18 to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %79, i8* align 8 %80, i32 16, i1 false) - %81 = call i32 @test.sum_us(%"int[]"* %indirectarg20) - %82 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.19, i32 0, i32 0), i32 %81) - %83 = getelementptr inbounds %"int[]", %"int[]"* %vararg21, i32 0, i32 1 - store i64 0, i64* %83, align 8 - %84 = bitcast %"int[]"* %indirectarg22 to i8* - %85 = bitcast %"int[]"* %vararg21 to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %84, i8* align 8 %85, i32 16, i1 false) - %86 = call i32 @test.sum_us(%"int[]"* %indirectarg22) - %87 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.20, i32 0, i32 0), i32 %86) + %38 = bitcast [4 x i32]* %x to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %38, i8* align 4 bitcast ([4 x i32]* @.__const.12 to i8*), i32 16, i1 false) + %39 = load i32, i32* %fro, align 4 + %40 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 1 + %41 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 0 + store i64 4, i64* %40, align 8 + %42 = bitcast [4 x i32]* %x to i32* + store i32* %42, i32** %41, align 8 + %43 = bitcast %"int[]"* %indirectarg to i8* + %44 = bitcast %"int[]"* %vararg to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %43, i8* align 8 %44, i32 16, i1 false) + %45 = call i32 @test.sum_us(%"int[]"* %indirectarg) + %46 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* @.str.13, i32 0, i32 0), i32 %45) + %add10 = add i32 %39, %46 + store i32 %add10, i32* %fro, align 4 + %47 = load i32, i32* %fro, align 4 + %48 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.14, i32 0, i32 0), i32 %47) + %49 = bitcast [4 x i32]* %x to i32* + %50 = insertvalue %"int[]" undef, i32* %49, 0 + %51 = insertvalue %"int[]" %50, i64 4, 1 + store %"int[]" %51, %"int[]"* %z, align 8 + %52 = bitcast [3 x i32]* %de to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %52, i8* align 4 bitcast ([3 x i32]* @.__const.15 to i8*), i32 12, i1 false) + %53 = getelementptr inbounds %"int[]", %"int[]"* %vararg11, i32 0, i32 1 + %54 = getelementptr inbounds %"int[]", %"int[]"* %vararg11, i32 0, i32 0 + store i64 4, i64* %53, align 8 + %55 = bitcast [4 x i32]* %x to i32* + store i32* %55, i32** %54, align 8 + %56 = bitcast %"int[]"* %indirectarg12 to i8* + %57 = bitcast %"int[]"* %vararg11 to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %56, i8* align 8 %57, i32 16, i1 false) + %58 = call i32 @test.sum_us(%"int[]"* %indirectarg12) + %59 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.str.16, i32 0, i32 0), i32 %58) + %60 = getelementptr inbounds %"int[]", %"int[]"* %vararg13, i32 0, i32 1 + %61 = getelementptr inbounds %"int[]", %"int[]"* %vararg13, i32 0, i32 0 + %62 = bitcast %"int[]"* %indirectarg14 to i8* + %63 = bitcast %"int[]"* %z to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %62, i8* align 8 %63, i32 16, i1 false) + %64 = call i32 @test.sum_us(%"int[]"* %indirectarg14) + %65 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.str.17, i32 0, i32 0), i32 %64) + %66 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 0 + store i32 1, i32* %66, align 4 + %67 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 1 + store i32 2, i32* %67, align 4 + %68 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 2 + store i32 4, i32* %68, align 4 + %69 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 3 + store i32 5, i32* %69, align 4 + %70 = getelementptr inbounds %"int[]", %"int[]"* %vararg15, i32 0, i32 1 + store i64 4, i64* %70, align 8 + %71 = getelementptr inbounds %"int[]", %"int[]"* %vararg15, i32 0, i32 0 + %72 = bitcast [4 x i32]* %varargslots to i32* + store i32* %72, i32** %71, align 8 + %73 = bitcast %"int[]"* %indirectarg16 to i8* + %74 = bitcast %"int[]"* %vararg15 to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %73, i8* align 8 %74, i32 16, i1 false) + %75 = call i32 @test.sum_us(%"int[]"* %indirectarg16) + %76 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.18, i32 0, i32 0), i32 %75) + %77 = getelementptr inbounds [1 x i32], [1 x i32]* %varargslots18, i64 0, i64 0 + store i32 1, i32* %77, align 4 + %78 = getelementptr inbounds %"int[]", %"int[]"* %vararg17, i32 0, i32 1 + store i64 1, i64* %78, align 8 + %79 = getelementptr inbounds %"int[]", %"int[]"* %vararg17, i32 0, i32 0 + %80 = bitcast [1 x i32]* %varargslots18 to i32* + store i32* %80, i32** %79, align 8 + %81 = bitcast %"int[]"* %indirectarg19 to i8* + %82 = bitcast %"int[]"* %vararg17 to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %81, i8* align 8 %82, i32 16, i1 false) + %83 = call i32 @test.sum_us(%"int[]"* %indirectarg19) + %84 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.19, i32 0, i32 0), i32 %83) + %85 = getelementptr inbounds %"int[]", %"int[]"* %vararg20, i32 0, i32 1 + store i64 0, i64* %85, align 8 + %86 = bitcast %"int[]"* %indirectarg21 to i8* + %87 = bitcast %"int[]"* %vararg20 to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %86, i8* align 8 %87, i32 16, i1 false) + %88 = call i32 @test.sum_us(%"int[]"* %indirectarg21) + %89 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.20, i32 0, i32 0), i32 %88) store i32 (double, %Bobo*)* null, i32 (double, %Bobo*)** %a1, align 8 store i32 (double, %Bobo*)* null, i32 (double, %Bobo*)** %b2, align 8 ret void @@ -689,11 +824,11 @@ entry: define i32 @test2.int.getValue(i32 %0) entry: %blob = alloca %Blob, align 4 - %dive = getelementptr inbounds %Blob, %Blob* %blob, i32 0, i32 0 - store i32 %0, i32* %dive, align 4 %1 = getelementptr inbounds %Blob, %Blob* %blob, i32 0, i32 0 - %2 = load i32, i32* %1, align 4 - ret i32 %2 + store i32 %0, i32* %1, align 4 + %2 = getelementptr inbounds %Blob, %Blob* %blob, i32 0, i32 0 + %3 = load i32, i32* %2, align 4 + ret i32 %3 // #expect: test2.double.ll @@ -718,10 +853,10 @@ entry: define double @test2.double.getValue(i64 %0) entry: %blob = alloca %Blob, align 8 - %dive = getelementptr inbounds %Blob, %Blob* %blob, i32 0, i32 0 - %1 = bitcast double* %dive to i64* - store i64 %0, i64* %1, align 8 - %2 = getelementptr inbounds %Blob, %Blob* %blob, i32 0, i32 0 - %3 = load double, double* %2, align 8 - ret double %3 + %1 = getelementptr inbounds %Blob, %Blob* %blob, i32 0, i32 0 + %2 = bitcast double* %1 to i64* + store i64 %0, i64* %2, align 8 + %3 = getelementptr inbounds %Blob, %Blob* %blob, i32 0, i32 0 + %4 = load double, double* %3, align 8 + ret double %4 diff --git a/test/test_suite/initializer_lists/fasta.c3t b/test/test_suite/initializer_lists/fasta.c3t index ec0bc00bf..8e289fb8c 100644 --- a/test/test_suite/initializer_lists/fasta.c3t +++ b/test/test_suite/initializer_lists/fasta.c3t @@ -164,37 +164,37 @@ entry: %len = alloca i64, align 8 %i = alloca i32, align 4 %pair = bitcast %"char[]"* %seq to { i8*, i64 }* - %lo = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 0 - store i8* %0, i8** %lo, align 8 - %hi = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 1 - store i64 %1, i64* %hi, align 8 + %3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 0 + store i8* %0, i8** %3, align 8 + %4 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 1 + store i64 %1, i64* %4, align 8 store i32 %2, i32* %n, align 4 - %len1 = getelementptr inbounds %"char[]", %"char[]"* %seq, i32 0, i32 1 - %3 = load i64, i64* %len1, align 8 - store i64 %3, i64* %len, align 8 + %5 = getelementptr inbounds %"char[]", %"char[]"* %seq, i32 0, i32 1 + %6 = load i64, i64* %5, align 8 + store i64 %6, i64* %len, align 8 store i32 0, i32* %i, align 4 br label %for.cond for.cond: ; preds = %for.inc, %entry - %4 = load i32, i32* %i, align 4 - %5 = load i32, i32* %n, align 4 - %lt = icmp slt i32 %4, %5 + %7 = load i32, i32* %i, align 4 + %8 = load i32, i32* %n, align 4 + %lt = icmp slt i32 %7, %8 br i1 %lt, label %for.body, label %for.exit for.body: ; preds = %for.cond - %subarrayptr = getelementptr inbounds %"char[]", %"char[]"* %seq, i32 0, i32 0 - %saptr = load i8*, i8** %subarrayptr, align 8 - %6 = load i32, i32* %i, align 4 - %sisiext = sext i32 %6 to i64 - %7 = load i64, i64* %len, align 8 - %smod = srem i64 %sisiext, %7 - %sarridx = getelementptr inbounds i8, i8* %saptr, i64 %smod - %8 = load i8, i8* %sarridx, align 1 - %uisiext = zext i8 %8 to i32 + %9 = getelementptr inbounds %"char[]", %"char[]"* %seq, i32 0, i32 0 + %10 = load i8*, i8** %9, align 8 + %11 = load i32, i32* %i, align 4 + %sisiext = sext i32 %11 to i64 + %12 = load i64, i64* %len, align 8 + %smod = srem i64 %sisiext, %12 + %ptroffset = getelementptr inbounds i8, i8* %10, i64 %smod + %13 = load i8, i8* %ptroffset, align 1 + %uisiext = zext i8 %13 to i32 call void @putchar(i32 %uisiext) - %9 = load i32, i32* %i, align 4 - %smod2 = srem i32 %9, 60 - %eq = icmp eq i32 %smod2, 59 + %14 = load i32, i32* %i, align 4 + %smod1 = srem i32 %14, 60 + %eq = icmp eq i32 %smod1, 59 br i1 %eq, label %if.then, label %if.exit if.then: ; preds = %for.body @@ -205,22 +205,22 @@ if.exit: ; preds = %if.then, %for.body br label %for.inc for.inc: ; preds = %if.exit - %10 = load i32, i32* %i, align 4 - %add = add i32 %10, 1 + %15 = load i32, i32* %i, align 4 + %add = add i32 %15, 1 store i32 %add, i32* %i, align 4 br label %for.cond for.exit: ; preds = %for.cond - %11 = load i32, i32* %i, align 4 - %smod3 = srem i32 %11, 60 - %neq = icmp ne i32 %smod3, 0 - br i1 %neq, label %if.then4, label %if.exit5 + %16 = load i32, i32* %i, align 4 + %smod2 = srem i32 %16, 60 + %neq = icmp ne i32 %smod2, 0 + br i1 %neq, label %if.then3, label %if.exit4 -if.then4: ; preds = %for.exit +if.then3: ; preds = %for.exit call void @putchar(i32 10) - br label %if.exit5 + br label %if.exit4 -if.exit5: ; preds = %if.then4, %for.exit +if.exit4: ; preds = %if.then3, %for.exit ret void } @@ -230,118 +230,118 @@ entry: %symb = alloca %"char[]", align 8 %probability = alloca %"double[]", align 8 %n = alloca i32, align 4 - %len5 = alloca i32, align 4 + %len = alloca i32, align 4 %i = alloca i32, align 4 %v = alloca double, align 8 %j = alloca i32, align 4 %pair = bitcast %"char[]"* %symb to { i8*, i64 }* - %lo = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 0 - store i8* %0, i8** %lo, align 8 - %hi = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 1 - store i64 %1, i64* %hi, align 8 + %5 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 0 + store i8* %0, i8** %5, align 8 + %6 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 1 + store i64 %1, i64* %6, align 8 %pair1 = bitcast %"double[]"* %probability to { i8*, i64 }* - %lo2 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair1, i32 0, i32 0 - store i8* %2, i8** %lo2, align 8 - %hi3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair1, i32 0, i32 1 - store i64 %3, i64* %hi3, align 8 + %7 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair1, i32 0, i32 0 + store i8* %2, i8** %7, align 8 + %8 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair1, i32 0, i32 1 + store i64 %3, i64* %8, align 8 store i32 %4, i32* %n, align 4 - %len = getelementptr inbounds %"char[]", %"char[]"* %symb, i32 0, i32 1 - %5 = load i64, i64* %len, align 8 - %len4 = getelementptr inbounds %"double[]", %"double[]"* %probability, i32 0, i32 1 - %6 = load i64, i64* %len4, align 8 - %eq = icmp eq i64 %5, %6 + %9 = getelementptr inbounds %"char[]", %"char[]"* %symb, i32 0, i32 1 + %10 = load i64, i64* %9, align 8 + %11 = getelementptr inbounds %"double[]", %"double[]"* %probability, i32 0, i32 1 + %12 = load i64, i64* %11, align 8 + %eq = icmp eq i64 %10, %12 call void @llvm.assume(i1 %eq) - %len6 = getelementptr inbounds %"double[]", %"double[]"* %probability, i32 0, i32 1 - %7 = load i64, i64* %len6, align 8 - %uisitrunc = trunc i64 %7 to i32 - store i32 %uisitrunc, i32* %len5, align 4 + %13 = getelementptr inbounds %"double[]", %"double[]"* %probability, i32 0, i32 1 + %14 = load i64, i64* %13, align 8 + %uisitrunc = trunc i64 %14 to i32 + store i32 %uisitrunc, i32* %len, align 4 store i32 0, i32* %i, align 4 br label %for.cond -for.cond: ; preds = %for.inc18, %entry - %8 = load i32, i32* %i, align 4 - %9 = load i32, i32* %n, align 4 - %lt = icmp slt i32 %8, %9 - br i1 %lt, label %for.body, label %for.exit20 +for.cond: ; preds = %for.inc11, %entry + %15 = load i32, i32* %i, align 4 + %16 = load i32, i32* %n, align 4 + %lt = icmp slt i32 %15, %16 + br i1 %lt, label %for.body, label %for.exit13 for.body: ; preds = %for.cond - %10 = call float @fasta.fasta_rand(float 1.000000e+00) - %fpfpext = fpext float %10 to double + %17 = call float @fasta.fasta_rand(float 1.000000e+00) + %fpfpext = fpext float %17 to double store double %fpfpext, double* %v, align 8 store i32 0, i32* %j, align 4 - br label %for.cond7 + br label %for.cond2 -for.cond7: ; preds = %for.inc, %for.body - %11 = load i32, i32* %j, align 4 - %12 = load i32, i32* %len5, align 4 - %sub = sub i32 %12, 1 - %lt8 = icmp slt i32 %11, %sub - br i1 %lt8, label %for.body9, label %for.exit +for.cond2: ; preds = %for.inc, %for.body + %18 = load i32, i32* %j, align 4 + %19 = load i32, i32* %len, align 4 + %sub = sub i32 %19, 1 + %lt3 = icmp slt i32 %18, %sub + br i1 %lt3, label %for.body4, label %for.exit -for.body9: ; preds = %for.cond7 - %13 = load double, double* %v, align 8 - %subarrayptr = getelementptr inbounds %"double[]", %"double[]"* %probability, i32 0, i32 0 - %saptr = load double*, double** %subarrayptr, align 8 - %14 = load i32, i32* %j, align 4 - %sisiext = sext i32 %14 to i64 - %sarridx = getelementptr inbounds double, double* %saptr, i64 %sisiext - %15 = load double, double* %sarridx, align 8 - %fsub = fsub double %13, %15 +for.body4: ; preds = %for.cond2 + %20 = load double, double* %v, align 8 + %21 = getelementptr inbounds %"double[]", %"double[]"* %probability, i32 0, i32 0 + %22 = load double*, double** %21, align 8 + %23 = load i32, i32* %j, align 4 + %sisiext = sext i32 %23 to i64 + %ptroffset = getelementptr inbounds double, double* %22, i64 %sisiext + %24 = load double, double* %ptroffset, align 8 + %fsub = fsub double %20, %24 store double %fsub, double* %v, align 8 - %16 = load double, double* %v, align 8 - %lt10 = fcmp olt double %16, 0.000000e+00 - br i1 %lt10, label %if.then, label %if.exit + %25 = load double, double* %v, align 8 + %lt5 = fcmp olt double %25, 0.000000e+00 + br i1 %lt5, label %if.then, label %if.exit -if.then: ; preds = %for.body9 +if.then: ; preds = %for.body4 br label %for.exit -if.exit: ; preds = %for.body9 +if.exit: ; preds = %for.body4 br label %for.inc for.inc: ; preds = %if.exit - %17 = load i32, i32* %j, align 4 - %add = add i32 %17, 1 + %26 = load i32, i32* %j, align 4 + %add = add i32 %26, 1 store i32 %add, i32* %j, align 4 - br label %for.cond7 + br label %for.cond2 -for.exit: ; preds = %if.then, %for.cond7 - %subarrayptr11 = getelementptr inbounds %"char[]", %"char[]"* %symb, i32 0, i32 0 - %saptr12 = load i8*, i8** %subarrayptr11, align 8 - %18 = load i32, i32* %j, align 4 - %sisiext13 = sext i32 %18 to i64 - %sarridx14 = getelementptr inbounds i8, i8* %saptr12, i64 %sisiext13 - %19 = load i8, i8* %sarridx14, align 1 - %uisiext = zext i8 %19 to i32 +for.exit: ; preds = %if.then, %for.cond2 + %27 = getelementptr inbounds %"char[]", %"char[]"* %symb, i32 0, i32 0 + %28 = load i8*, i8** %27, align 8 + %29 = load i32, i32* %j, align 4 + %sisiext6 = sext i32 %29 to i64 + %ptroffset7 = getelementptr inbounds i8, i8* %28, i64 %sisiext6 + %30 = load i8, i8* %ptroffset7, align 1 + %uisiext = zext i8 %30 to i32 call void @putchar(i32 %uisiext) - %20 = load i32, i32* %i, align 4 - %smod = srem i32 %20, 60 - %eq15 = icmp eq i32 %smod, 59 - br i1 %eq15, label %if.then16, label %if.exit17 + %31 = load i32, i32* %i, align 4 + %smod = srem i32 %31, 60 + %eq8 = icmp eq i32 %smod, 59 + br i1 %eq8, label %if.then9, label %if.exit10 -if.then16: ; preds = %for.exit +if.then9: ; preds = %for.exit call void @putchar(i32 10) - br label %if.exit17 + br label %if.exit10 -if.exit17: ; preds = %if.then16, %for.exit - br label %for.inc18 +if.exit10: ; preds = %if.then9, %for.exit + br label %for.inc11 -for.inc18: ; preds = %if.exit17 - %21 = load i32, i32* %i, align 4 - %add19 = add i32 %21, 1 - store i32 %add19, i32* %i, align 4 +for.inc11: ; preds = %if.exit10 + %32 = load i32, i32* %i, align 4 + %add12 = add i32 %32, 1 + store i32 %add12, i32* %i, align 4 br label %for.cond -for.exit20: ; preds = %for.cond - %22 = load i32, i32* %i, align 4 - %smod21 = srem i32 %22, 60 - %neq = icmp ne i32 %smod21, 0 - br i1 %neq, label %if.then22, label %if.exit23 +for.exit13: ; preds = %for.cond + %33 = load i32, i32* %i, align 4 + %smod14 = srem i32 %33, 60 + %neq = icmp ne i32 %smod14, 0 + br i1 %neq, label %if.then15, label %if.exit16 -if.then22: ; preds = %for.exit20 +if.then15: ; preds = %for.exit13 call void @putchar(i32 10) - br label %if.exit23 + br label %if.exit16 -if.exit23: ; preds = %if.then22, %for.exit20 +if.exit16: ; preds = %if.then15, %for.exit13 ret void } @@ -360,8 +360,8 @@ entry: if.then: ; preds = %entry %3 = load i8**, i8*** %argv, align 8 - %ptridx = getelementptr inbounds i8*, i8** %3, i64 1 - %4 = load i8*, i8** %ptridx, align 8 + %ptroffset = getelementptr inbounds i8*, i8** %3, i64 1 + %4 = load i8*, i8** %ptroffset, align 8 %5 = call i32 @atoi(i8* %4) store i32 %5, i32* %n, align 4 br label %if.exit @@ -390,4 +390,4 @@ if.exit: ; preds = %if.then, %entry %mul10 = mul i32 %11, 5 call void @fasta.random_fasta(i8* %lo6, i64 %hi7, i8* %lo8, i64 %hi9, i32 %mul10) ret void -} \ No newline at end of file +} diff --git a/test/test_suite/initializer_lists/general_tests.c3t b/test/test_suite/initializer_lists/general_tests.c3t index f3d443546..898adf128 100644 --- a/test/test_suite/initializer_lists/general_tests.c3t +++ b/test/test_suite/initializer_lists/general_tests.c3t @@ -69,11 +69,11 @@ entry: call void @llvm.memset.p0i8.i64(i8* align 4 %2, i8 0, i64 0, i1 false) store i32 33, i32* %foo2, align 4 store i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i32 0, i32 0), i8** %str, align 8 - %3 = getelementptr inbounds i32, [3 x i32]* %literal, i32 0 + %3 = getelementptr inbounds [3 x i32], [3 x i32]* %literal, i64 0, i64 0 store i32 1, i32* %3, align 4 - %4 = getelementptr inbounds i32, [3 x i32]* %literal, i32 1 + %4 = getelementptr inbounds [3 x i32], [3 x i32]* %literal, i64 0, i64 1 store i32 2, i32* %4, align 4 - %5 = getelementptr inbounds i32, [3 x i32]* %literal, i32 2 + %5 = getelementptr inbounds [3 x i32], [3 x i32]* %literal, i64 0, i64 2 store i32 3, i32* %5, align 4 %6 = bitcast [3 x i32]* %literal to i32* %7 = insertvalue %"int[]" undef, i32* %6, 0 diff --git a/test/test_suite/initializer_lists/ranges_to_dynamic.c3t b/test/test_suite/initializer_lists/ranges_to_dynamic.c3t new file mode 100644 index 000000000..b253a064e --- /dev/null +++ b/test/test_suite/initializer_lists/ranges_to_dynamic.c3t @@ -0,0 +1,69 @@ +module test; + +extern fn void printf(char*, ...); + +fn void test(int x) +{ + int[10] y = { [0..3] = 4, [6..8] = x }; + foreach (int v : y) + { + printf("%d\n", v); + } +} + +fn void main() +{ + test(101); +} + +/* #expect: test.ll + +define void @test.test(i32 %0) #0 { +entry: + %x = alloca i32, align 4 + %y = alloca [10 x i32], align 16 + %idx = alloca i64, align 8 + %v = alloca i32, align 4 + store i32 %0, i32* %x, align 4 + %1 = bitcast [10 x i32]* %y to i8* + call void @llvm.memset.p0i8.i64(i8* align 16 %1, i8 0, i64 40, i1 false) + %2 = getelementptr inbounds [10 x i32], [10 x i32]* %y, i64 0, i64 0 + store i32 4, i32* %2, align 4 + %3 = getelementptr inbounds [10 x i32], [10 x i32]* %y, i64 0, i64 1 + store i32 4, i32* %3, align 4 + %4 = getelementptr inbounds [10 x i32], [10 x i32]* %y, i64 0, i64 2 + store i32 4, i32* %4, align 4 + %5 = getelementptr inbounds [10 x i32], [10 x i32]* %y, i64 0, i64 3 + store i32 4, i32* %5, align 4 + %6 = getelementptr inbounds [10 x i32], [10 x i32]* %y, i64 0, i64 6 + %7 = load i32, i32* %x, align 4 + store i32 %7, i32* %6, align 4 + %8 = getelementptr inbounds [10 x i32], [10 x i32]* %y, i64 0, i64 7 + store i32 %7, i32* %8, align 4 + %9 = getelementptr inbounds [10 x i32], [10 x i32]* %y, i64 0, i64 8 + store i32 %7, i32* %9, align 4 + store i64 0, i64* %idx, align 8 + br label %foreach.cond + +foreach.cond: ; preds = %foreach.inc, %entry + %10 = load i64, i64* %idx, align 8 + %lt = icmp ult i64 %10, 10 + br i1 %lt, label %foreach.body, label %foreach.exit + +foreach.body: ; preds = %foreach.cond + %ptroffset = getelementptr inbounds i32, [10 x i32]* %y, i64 %10 + %11 = load i32, i32* %ptroffset, align 4 + store i32 %11, i32* %v, align 4 + %12 = load i32, i32* %v, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %12) + br label %foreach.inc + +foreach.inc: ; preds = %foreach.body + %13 = load i64, i64* %idx, align 8 + %14 = add i64 %13, 1 + store i64 %14, i64* %idx, align 8 + br label %foreach.cond + +foreach.exit: ; preds = %foreach.cond + ret void +} diff --git a/test/test_suite/initializer_lists/statics.c3t b/test/test_suite/initializer_lists/statics.c3t index 5f00bd4ae..11491de23 100644 --- a/test/test_suite/initializer_lists/statics.c3t +++ b/test/test_suite/initializer_lists/statics.c3t @@ -48,7 +48,7 @@ define void @statics.test() #0 { entry: %b = alloca %"Bar[]", align 8 %literal = alloca [1 x %Bar], align 4 - %0 = getelementptr inbounds %Bar, [1 x %Bar]* %literal, i32 0 + %0 = getelementptr inbounds [1 x %Bar], [1 x %Bar]* %literal, i64 0, i64 0 %1 = getelementptr inbounds %Bar, %Bar* %0, i32 0, i32 0 store i32 1, i32* %1, align 4 %2 = getelementptr inbounds %Bar, %Bar* %0, i32 0, i32 1 @@ -57,29 +57,29 @@ entry: %4 = insertvalue %"Bar[]" undef, %Bar* %3, 0 %5 = insertvalue %"Bar[]" %4, i64 1, 1 store %"Bar[]" %5, %"Bar[]"* %b, align 8 - %subarrayptr = getelementptr inbounds %"Bar[]", %"Bar[]"* %b, i32 0, i32 0 - %saptr = load %Bar*, %Bar** %subarrayptr, align 8 - %sarridx = getelementptr inbounds %Bar, %Bar* %saptr, i64 0 - %6 = getelementptr inbounds %Bar, %Bar* %sarridx, i32 0, i32 1 - %7 = load i32, i32* %6, align 4 - %saptr1 = load %Bar*, %Bar** getelementptr inbounds (%"Bar[]", %"Bar[]"* @test.c, i32 0, i32 0), align 8 - %sarridx2 = getelementptr inbounds %Bar, %Bar* %saptr1, i64 0 - %8 = getelementptr inbounds %Bar, %Bar* %sarridx2, i32 0, i32 1 + %6 = getelementptr inbounds %"Bar[]", %"Bar[]"* %b, i32 0, i32 0 + %7 = load %Bar*, %Bar** %6, align 8 + %ptroffset = getelementptr inbounds %Bar, %Bar* %7, i64 0 + %8 = getelementptr inbounds %Bar, %Bar* %ptroffset, i32 0, i32 1 %9 = load i32, i32* %8, align 4 - %10 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i32 0, i32 0), i32 %7, i32 %9) - %subarrayptr3 = getelementptr inbounds %"Bar[]", %"Bar[]"* %b, i32 0, i32 0 - %saptr4 = load %Bar*, %Bar** %subarrayptr3, align 8 - %sarridx5 = getelementptr inbounds %Bar, %Bar* %saptr4, i64 0 - %11 = getelementptr inbounds %Bar, %Bar* %sarridx5, i32 0, i32 1 + %10 = load %Bar*, %Bar** getelementptr inbounds (%"Bar[]", %"Bar[]"* @test.c, i32 0, i32 0), align 8 + %ptroffset1 = getelementptr inbounds %Bar, %Bar* %10, i64 0 + %11 = getelementptr inbounds %Bar, %Bar* %ptroffset1, i32 0, i32 1 %12 = load i32, i32* %11, align 4 - %add = add i32 %12, 1 - store i32 %add, i32* %11, align 4 - %saptr6 = load %Bar*, %Bar** getelementptr inbounds (%"Bar[]", %"Bar[]"* @test.c, i32 0, i32 0), align 8 - %sarridx7 = getelementptr inbounds %Bar, %Bar* %saptr6, i64 0 - %13 = getelementptr inbounds %Bar, %Bar* %sarridx7, i32 0, i32 1 - %14 = load i32, i32* %13, align 4 - %add8 = add i32 %14, 1 - store i32 %add8, i32* %13, align 4 + %13 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i32 0, i32 0), i32 %9, i32 %12) + %14 = getelementptr inbounds %"Bar[]", %"Bar[]"* %b, i32 0, i32 0 + %15 = load %Bar*, %Bar** %14, align 8 + %ptroffset2 = getelementptr inbounds %Bar, %Bar* %15, i64 0 + %16 = getelementptr inbounds %Bar, %Bar* %ptroffset2, i32 0, i32 1 + %17 = load i32, i32* %16, align 4 + %add = add i32 %17, 1 + store i32 %add, i32* %16, align 4 + %18 = load %Bar*, %Bar** getelementptr inbounds (%"Bar[]", %"Bar[]"* @test.c, i32 0, i32 0), align 8 + %ptroffset3 = getelementptr inbounds %Bar, %Bar* %18, i64 0 + %19 = getelementptr inbounds %Bar, %Bar* %ptroffset3, i32 0, i32 1 + %20 = load i32, i32* %19, align 4 + %add4 = add i32 %20, 1 + store i32 %add4, i32* %19, align 4 ret void } @@ -91,3 +91,4 @@ entry: call void @statics.test() ret i32 1 } + diff --git a/test/test_suite/initializer_lists/subarrays.c3t b/test/test_suite/initializer_lists/subarrays.c3t index 0302ef0da..f42851bcc 100644 --- a/test/test_suite/initializer_lists/subarrays.c3t +++ b/test/test_suite/initializer_lists/subarrays.c3t @@ -72,108 +72,108 @@ entry: %x = alloca %"int[]", align 8 %literal = alloca [3 x i32], align 4 %y = alloca i32*, align 8 - %literal3 = alloca [3 x i32], align 4 + %literal2 = alloca [3 x i32], align 4 %ffe = alloca %Baz, align 8 %azz = alloca [1 x i32], align 4 %a = alloca [0 x i32], align 4 %xy = alloca i8, align 1 - %literal7 = alloca [3 x i32], align 4 + %literal6 = alloca [3 x i32], align 4 %b = alloca %Bar, align 4 %z = alloca %Baz, align 8 %sub = alloca %"int[]", align 8 - %literal10 = alloca [0 x i32], align 4 + %literal8 = alloca [0 x i32], align 4 %foo = alloca %"Bar[]", align 8 - %literal11 = alloca [0 x %Bar], align 4 + %literal9 = alloca [0 x %Bar], align 4 %baz = alloca [3 x %Baz], align 16 - %saptr = load %Bar*, %Bar** getelementptr inbounds (%"Bar[]", %"Bar[]"* @subarrays.arrbar, i32 0, i32 0), align 8 - %sarridx = getelementptr inbounds %Bar, %Bar* %saptr, i64 1 - %0 = bitcast %Bar* %w to i8* - %1 = bitcast %Bar* %sarridx to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 %1, i32 8, i1 false) - %saptr1 = load %Bar*, %Bar** getelementptr inbounds (%"Bar[]", %"Bar[]"* @subarrays.arrbar, i32 0, i32 0), align 8 - %sarridx2 = getelementptr inbounds %Bar, %Bar* %saptr1, i64 1 - %2 = getelementptr inbounds %Bar, %Bar* %sarridx2, i32 0, i32 0 - %3 = load i32, i32* %2, align 4 - %4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %3) - %5 = getelementptr inbounds i32, [3 x i32]* %literal, i32 0 - store i32 1, i32* %5, align 4 - %6 = getelementptr inbounds i32, [3 x i32]* %literal, i32 1 - store i32 2, i32* %6, align 4 - %7 = getelementptr inbounds i32, [3 x i32]* %literal, i32 2 - store i32 3, i32* %7, align 4 - %8 = bitcast [3 x i32]* %literal to i32* - %9 = insertvalue %"int[]" undef, i32* %8, 0 - %10 = insertvalue %"int[]" %9, i64 3, 1 - store %"int[]" %10, %"int[]"* %x, align 8 - %11 = getelementptr inbounds i32, [3 x i32]* %literal3, i32 0 - store i32 123, i32* %11, align 4 - %12 = getelementptr inbounds i32, [3 x i32]* %literal3, i32 1 - store i32 234, i32* %12, align 4 - %13 = getelementptr inbounds i32, [3 x i32]* %literal3, i32 2 - store i32 567, i32* %13, align 4 - %ptrptr = bitcast [3 x i32]* %literal3 to i32* + %0 = load %Bar*, %Bar** getelementptr inbounds (%"Bar[]", %"Bar[]"* @subarrays.arrbar, i32 0, i32 0), align 8 + %ptroffset = getelementptr inbounds %Bar, %Bar* %0, i64 1 + %1 = bitcast %Bar* %w to i8* + %2 = bitcast %Bar* %ptroffset to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %1, i8* align 4 %2, i32 8, i1 false) + %3 = load %Bar*, %Bar** getelementptr inbounds (%"Bar[]", %"Bar[]"* @subarrays.arrbar, i32 0, i32 0), align 8 + %ptroffset1 = getelementptr inbounds %Bar, %Bar* %3, i64 1 + %4 = getelementptr inbounds %Bar, %Bar* %ptroffset1, i32 0, i32 0 + %5 = load i32, i32* %4, align 4 + %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %5) + %7 = getelementptr inbounds [3 x i32], [3 x i32]* %literal, i64 0, i64 0 + store i32 1, i32* %7, align 4 + %8 = getelementptr inbounds [3 x i32], [3 x i32]* %literal, i64 0, i64 1 + store i32 2, i32* %8, align 4 + %9 = getelementptr inbounds [3 x i32], [3 x i32]* %literal, i64 0, i64 2 + store i32 3, i32* %9, align 4 + %10 = bitcast [3 x i32]* %literal to i32* + %11 = insertvalue %"int[]" undef, i32* %10, 0 + %12 = insertvalue %"int[]" %11, i64 3, 1 + store %"int[]" %12, %"int[]"* %x, align 8 + %13 = getelementptr inbounds [3 x i32], [3 x i32]* %literal2, i64 0, i64 0 + store i32 123, i32* %13, align 4 + %14 = getelementptr inbounds [3 x i32], [3 x i32]* %literal2, i64 0, i64 1 + store i32 234, i32* %14, align 4 + %15 = getelementptr inbounds [3 x i32], [3 x i32]* %literal2, i64 0, i64 2 + store i32 567, i32* %15, align 4 + %ptrptr = bitcast [3 x i32]* %literal2 to i32* store i32* %ptrptr, i32** %y, align 8 - %14 = call i32 @"std::io.println"(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.5, i32 0, i32 0)) #3 - %len = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1 - %15 = load i64, i64* %len, align 8 - %uisitrunc = trunc i64 %15 to i32 - %subarrayptr = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 0 - %saptr4 = load i32*, i32** %subarrayptr, align 8 - %sarridx5 = getelementptr inbounds i32, i32* %saptr4, i64 1 - %16 = load i32, i32* %sarridx5, align 4 - %17 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([26 x i8], [26 x i8]* @.str.6, i32 0, i32 0), i32 %uisitrunc, i32 %16) - %18 = load i32*, i32** %y, align 8 - %ptridx = getelementptr inbounds i32, i32* %18, i64 1 - %19 = load i32, i32* %ptridx, align 4 - %20 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.7, i32 0, i32 0), i32 %19) - %21 = load i32*, i32** @subarrays.fofeo, align 8 - %ptridx6 = getelementptr inbounds i32, i32* %21, i64 1 - %22 = load i32, i32* %ptridx6, align 4 - %23 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @.str.8, i32 0, i32 0), i32 %22) - %24 = bitcast %Baz* %ffe to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %24, i8* align 8 bitcast ({ i32, [4 x i8] }* @.__const to i8*), i32 8, i1 false) - %25 = bitcast [1 x i32]* %azz to i8* - call void @llvm.memset.p0i8.i64(i8* align 4 %25, i8 0, i64 4, i1 false) - %26 = bitcast [0 x i32]* %a to i8* - call void @llvm.memset.p0i8.i64(i8* align 4 %26, i8 0, i64 0, i1 false) - %27 = getelementptr inbounds i32, [3 x i32]* %literal7, i32 0 - store i32 1, i32* %27, align 4 - %28 = getelementptr inbounds i32, [3 x i32]* %literal7, i32 1 - store i32 2, i32* %28, align 4 - %29 = getelementptr inbounds i32, [3 x i32]* %literal7, i32 2 - store i32 3, i32* %29, align 4 - %30 = bitcast [3 x i32]* %literal7 to i32* - %31 = insertvalue %"int[]" undef, i32* %30, 0 - %32 = insertvalue %"int[]" %31, i64 3, 1 - %len8 = extractvalue %"int[]" %32, 1 - %not = icmp eq i64 %len8, 0 - %33 = zext i1 %not to i8 - store i8 %33, i8* %xy, align 1 - %34 = load i8, i8* %xy, align 1 - %35 = trunc i8 %34 to i1 - %not9 = xor i1 %35, true - br i1 %not9, label %if.then, label %if.exit + %16 = call i32 @"std::io.println"(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.5, i32 0, i32 0)) #3 + %17 = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1 + %18 = load i64, i64* %17, align 8 + %uisitrunc = trunc i64 %18 to i32 + %19 = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 0 + %20 = load i32*, i32** %19, align 8 + %ptroffset3 = getelementptr inbounds i32, i32* %20, i64 1 + %21 = load i32, i32* %ptroffset3, align 4 + %22 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([26 x i8], [26 x i8]* @.str.6, i32 0, i32 0), i32 %uisitrunc, i32 %21) + %23 = load i32*, i32** %y, align 8 + %ptroffset4 = getelementptr inbounds i32, i32* %23, i64 1 + %24 = load i32, i32* %ptroffset4, align 4 + %25 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.7, i32 0, i32 0), i32 %24) + %26 = load i32*, i32** @subarrays.fofeo, align 8 + %ptroffset5 = getelementptr inbounds i32, i32* %26, i64 1 + %27 = load i32, i32* %ptroffset5, align 4 + %28 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @.str.8, i32 0, i32 0), i32 %27) + %29 = bitcast %Baz* %ffe to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %29, i8* align 8 bitcast ({ i32, [4 x i8] }* @.__const to i8*), i32 8, i1 false) + %30 = bitcast [1 x i32]* %azz to i8* + call void @llvm.memset.p0i8.i64(i8* align 4 %30, i8 0, i64 4, i1 false) + %31 = bitcast [0 x i32]* %a to i8* + call void @llvm.memset.p0i8.i64(i8* align 4 %31, i8 0, i64 0, i1 false) + %32 = getelementptr inbounds [3 x i32], [3 x i32]* %literal6, i64 0, i64 0 + store i32 1, i32* %32, align 4 + %33 = getelementptr inbounds [3 x i32], [3 x i32]* %literal6, i64 0, i64 1 + store i32 2, i32* %33, align 4 + %34 = getelementptr inbounds [3 x i32], [3 x i32]* %literal6, i64 0, i64 2 + store i32 3, i32* %34, align 4 + %35 = bitcast [3 x i32]* %literal6 to i32* + %36 = insertvalue %"int[]" undef, i32* %35, 0 + %37 = insertvalue %"int[]" %36, i64 3, 1 + %len = extractvalue %"int[]" %37, 1 + %not = icmp eq i64 %len, 0 + %38 = zext i1 %not to i8 + store i8 %38, i8* %xy, align 1 + %39 = load i8, i8* %xy, align 1 + %40 = trunc i8 %39 to i1 + %not7 = xor i1 %40, true + br i1 %not7, label %if.then, label %if.exit if.then: ; preds = %entry - %36 = call i32 @"std::io.println"(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.9, i32 0, i32 0)) #3 + %41 = call i32 @"std::io.println"(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.9, i32 0, i32 0)) #3 br label %if.exit if.exit: ; preds = %if.then, %entry - %37 = bitcast %Bar* %b to i8* - call void @llvm.memset.p0i8.i64(i8* align 4 %37, i8 0, i64 8, i1 false) - %38 = bitcast %Baz* %z to i8* - call void @llvm.memset.p0i8.i64(i8* align 8 %38, i8 0, i64 8, i1 false) - store [0 x i32] zeroinitializer, [0 x i32]* %literal10, align 4 - %39 = bitcast [0 x i32]* %literal10 to i32* - %40 = insertvalue %"int[]" undef, i32* %39, 0 - %41 = insertvalue %"int[]" %40, i64 0, 1 - store %"int[]" %41, %"int[]"* %sub, align 8 - store [0 x %Bar] zeroinitializer, [0 x %Bar]* %literal11, align 4 - %42 = bitcast [0 x %Bar]* %literal11 to %Bar* - %43 = insertvalue %"Bar[]" undef, %Bar* %42, 0 - %44 = insertvalue %"Bar[]" %43, i64 0, 1 - store %"Bar[]" %44, %"Bar[]"* %foo, align 8 - %45 = bitcast [3 x %Baz]* %baz to i8* - call void @llvm.memset.p0i8.i64(i8* align 16 %45, i8 0, i64 24, i1 false) + %42 = bitcast %Bar* %b to i8* + call void @llvm.memset.p0i8.i64(i8* align 4 %42, i8 0, i64 8, i1 false) + %43 = bitcast %Baz* %z to i8* + call void @llvm.memset.p0i8.i64(i8* align 8 %43, i8 0, i64 8, i1 false) + store [0 x i32] zeroinitializer, [0 x i32]* %literal8, align 4 + %44 = bitcast [0 x i32]* %literal8 to i32* + %45 = insertvalue %"int[]" undef, i32* %44, 0 + %46 = insertvalue %"int[]" %45, i64 0, 1 + store %"int[]" %46, %"int[]"* %sub, align 8 + store [0 x %Bar] zeroinitializer, [0 x %Bar]* %literal9, align 4 + %47 = bitcast [0 x %Bar]* %literal9 to %Bar* + %48 = insertvalue %"Bar[]" undef, %Bar* %47, 0 + %49 = insertvalue %"Bar[]" %48, i64 0, 1 + store %"Bar[]" %49, %"Bar[]"* %foo, align 8 + %50 = bitcast [3 x %Baz]* %baz to i8* + call void @llvm.memset.p0i8.i64(i8* align 16 %50, i8 0, i64 24, i1 false) ret i32 1 -} \ No newline at end of file +} diff --git a/test/test_suite/macros/userland_bitcast.c3t b/test/test_suite/macros/userland_bitcast.c3t index 90ebe42ed..2e380f2cb 100644 --- a/test/test_suite/macros/userland_bitcast.c3t +++ b/test/test_suite/macros/userland_bitcast.c3t @@ -115,12 +115,12 @@ for.cond: ; preds = %for.inc, %entry for.body: ; preds = %for.cond %6 = load i16*, i16** %to, align 8 %7 = load i64, i64* %i, align 8 - %ptridx = getelementptr inbounds i16, i16* %6, i64 %7 + %ptroffset = getelementptr inbounds i16, i16* %6, i64 %7 %8 = load i16*, i16** %b, align 8 %9 = load i64, i64* %i, align 8 - %ptridx3 = getelementptr inbounds i16, i16* %8, i64 %9 - %10 = load i16, i16* %ptridx3, align 2 - store i16 %10, i16* %ptridx, align 2 + %ptroffset3 = getelementptr inbounds i16, i16* %8, i64 %9 + %10 = load i16, i16* %ptroffset3, align 2 + store i16 %10, i16* %ptroffset, align 2 br label %for.inc for.inc: ; preds = %for.body @@ -168,12 +168,12 @@ for.cond: ; preds = %for.inc, %entry for.body: ; preds = %for.cond %3 = load i8*, i8** %to, align 8 %4 = load i64, i64* %i, align 8 - %ptridx = getelementptr inbounds i8, i8* %3, i64 %4 + %ptroffset = getelementptr inbounds i8, i8* %3, i64 %4 %5 = load i8*, i8** %b, align 8 %6 = load i64, i64* %i, align 8 - %ptridx3 = getelementptr inbounds i8, i8* %5, i64 %6 - %7 = load i8, i8* %ptridx3, align 1 - store i8 %7, i8* %ptridx, align 1 + %ptroffset3 = getelementptr inbounds i8, i8* %5, i64 %6 + %7 = load i8, i8* %ptroffset3, align 1 + store i8 %7, i8* %ptroffset, align 1 br label %for.inc for.inc: ; preds = %for.body @@ -246,12 +246,12 @@ for.cond: ; preds = %for.inc, %entry for.body: ; preds = %for.cond %2 = load i32*, i32** %to, align 8 %3 = load i64, i64* %i1, align 8 - %ptridx = getelementptr inbounds i32, i32* %2, i64 %3 + %ptroffset = getelementptr inbounds i32, i32* %2, i64 %3 %4 = load i32*, i32** %b, align 8 %5 = load i64, i64* %i1, align 8 - %ptridx2 = getelementptr inbounds i32, i32* %4, i64 %5 - %6 = load i32, i32* %ptridx2, align 4 - store i32 %6, i32* %ptridx, align 4 + %ptroffset2 = getelementptr inbounds i32, i32* %4, i64 %5 + %6 = load i32, i32* %ptroffset2, align 4 + store i32 %6, i32* %ptroffset, align 4 br label %for.inc for.inc: ; preds = %for.body @@ -284,12 +284,12 @@ for.cond10: ; preds = %for.inc15, %expr_bl for.body12: ; preds = %for.cond10 %12 = load i32*, i32** %to7, align 8 %13 = load i64, i64* %i9, align 8 - %ptridx13 = getelementptr inbounds i32, i32* %12, i64 %13 + %ptroffset13 = getelementptr inbounds i32, i32* %12, i64 %13 %14 = load i32*, i32** %b6, align 8 %15 = load i64, i64* %i9, align 8 - %ptridx14 = getelementptr inbounds i32, i32* %14, i64 %15 - %16 = load i32, i32* %ptridx14, align 4 - store i32 %16, i32* %ptridx13, align 4 + %ptroffset14 = getelementptr inbounds i32, i32* %14, i64 %15 + %16 = load i32, i32* %ptroffset14, align 4 + store i32 %16, i32* %ptroffset13, align 4 br label %for.inc15 for.inc15: ; preds = %for.body12 @@ -329,12 +329,12 @@ for.cond27: ; preds = %for.inc32, %expr_bl for.body29: ; preds = %for.cond27 %25 = load i64*, i64** %to25, align 8 %26 = load i64, i64* %i26, align 8 - %ptridx30 = getelementptr inbounds i64, i64* %25, i64 %26 + %ptroffset30 = getelementptr inbounds i64, i64* %25, i64 %26 %27 = load i64*, i64** %b23, align 8 %28 = load i64, i64* %i26, align 8 - %ptridx31 = getelementptr inbounds i64, i64* %27, i64 %28 - %29 = load i64, i64* %ptridx31, align 8 - store i64 %29, i64* %ptridx30, align 8 + %ptroffset31 = getelementptr inbounds i64, i64* %27, i64 %28 + %29 = load i64, i64* %ptroffset31, align 8 + store i64 %29, i64* %ptroffset30, align 8 br label %for.inc32 for.inc32: ; preds = %for.body29 @@ -368,12 +368,12 @@ for.cond44: ; preds = %for.inc49, %expr_bl for.body46: ; preds = %for.cond44 %35 = load i64*, i64** %to41, align 8 %36 = load i64, i64* %i43, align 8 - %ptridx47 = getelementptr inbounds i64, i64* %35, i64 %36 + %ptroffset47 = getelementptr inbounds i64, i64* %35, i64 %36 %37 = load i64*, i64** %b39, align 8 %38 = load i64, i64* %i43, align 8 - %ptridx48 = getelementptr inbounds i64, i64* %37, i64 %38 - %39 = load i64, i64* %ptridx48, align 8 - store i64 %39, i64* %ptridx47, align 8 + %ptroffset48 = getelementptr inbounds i64, i64* %37, i64 %38 + %39 = load i64, i64* %ptroffset48, align 8 + store i64 %39, i64* %ptroffset47, align 8 br label %for.inc49 for.inc49: ; preds = %for.body46 @@ -395,4 +395,4 @@ expr_block.exit52: ; preds = %for.exit51 %45 = load double, double* %d2, align 8 call void (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.1, i32 0, i32 0), double %43, i64 %44, double %45) ret void -} +} \ No newline at end of file diff --git a/test/test_suite/pointers/pointer_index.c3t b/test/test_suite/pointers/pointer_index.c3t index 2011c5424..6997e9e49 100644 --- a/test/test_suite/pointers/pointer_index.c3t +++ b/test/test_suite/pointers/pointer_index.c3t @@ -24,19 +24,71 @@ func void test3(long* x) // #expect: pointer_index.ll +define void @pointer_index.test1(i32* %0) #0 { +entry: + %x = alloca i32*, align 8 + %a = alloca i32, align 4 + %b = alloca i32, align 4 + %c = alloca i32, align 4 + %d = alloca i32, align 4 + store i32* %0, i32** %x, align 8 + %1 = load i32*, i32** %x, align 8 + %ptroffset = getelementptr inbounds i32, i32* %1, i64 0 + %2 = load i32, i32* %ptroffset, align 4 + store i32 %2, i32* %a, align 4 + %3 = load i32*, i32** %x, align 8 + %4 = load i32, i32* %3, align 8 + store i32 %4, i32* %b, align 4 + %5 = load i32*, i32** %x, align 8 + %ptroffset1 = getelementptr inbounds i32, i32* %5, i64 1 + %6 = load i32, i32* %ptroffset1, align 4 + store i32 %6, i32* %c, align 4 + %7 = load i32*, i32** %x, align 8 + %ptroffset2 = getelementptr inbounds i32, i32* %7, i64 -1 + %8 = load i32, i32* %ptroffset2, align 4 + store i32 %8, i32* %d, align 4 + ret void +} + +; Function Attrs: nounwind +define void @pointer_index.test2(i8* %0) #0 { +entry: + %x = alloca i8*, align 8 + %a = alloca i8, align 1 + %b = alloca i8, align 1 + %c = alloca i8, align 1 + store i8* %0, i8** %x, align 8 + %1 = load i8*, i8** %x, align 8 + %ptroffset = getelementptr inbounds i8, i8* %1, i64 0 + %2 = load i8, i8* %ptroffset, align 1 + store i8 %2, i8* %a, align 1 + %3 = load i8*, i8** %x, align 8 + %4 = load i8, i8* %3, align 8 + store i8 %4, i8* %b, align 1 + %5 = load i8*, i8** %x, align 8 + %ptroffset1 = getelementptr inbounds i8, i8* %5, i64 1 + %6 = load i8, i8* %ptroffset1, align 1 + store i8 %6, i8* %c, align 1 + ret void +} + +define void @pointer_index.test3(i64* %0) #0 { +entry: %x = alloca i64*, align 8 %a = alloca i64, align 8 %b = alloca i64, align 8 %c = alloca i64, align 8 store i64* %0, i64** %x, align 8 %1 = load i64*, i64** %x, align 8 - %ptridx = getelementptr inbounds i64, i64* %1, i64 0 - %2 = load i64, i64* %ptridx, align 8 + %ptroffset = getelementptr inbounds i64, i64* %1, i64 0 + %2 = load i64, i64* %ptroffset, align 8 store i64 %2, i64* %a, align 8 %3 = load i64*, i64** %x, align 8 %4 = load i64, i64* %3, align 8 store i64 %4, i64* %b, align 8 %5 = load i64*, i64** %x, align 8 - %ptridx1 = getelementptr inbounds i64, i64* %5, i64 1 - %6 = load i64, i64* %ptridx1, align 8 - store i64 %6, i64* %c, align 8 \ No newline at end of file + %ptroffset1 = getelementptr inbounds i64, i64* %5, i64 1 + %6 = load i64, i64* %ptroffset1, align 8 + store i64 %6, i64* %c, align 8 + ret void +} diff --git a/test/test_suite/slices/slice_assign.c3t b/test/test_suite/slices/slice_assign.c3t new file mode 100644 index 000000000..beb49e923 --- /dev/null +++ b/test/test_suite/slices/slice_assign.c3t @@ -0,0 +1,78 @@ +module test; + +extern fn void printf(char*, ...); + +fn void main() +{ + int[8] x; + x[0..1] = 3; + x[1..2] = 5; + x[5..7] = 52; + foreach (i : x) + { + printf("%d\n", i); + } + x[0..7] = 123; +} + +/* #expect: test.ll + +@.str = private constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: nounwind +declare void @printf(i8*, ...) #0 + +; Function Attrs: nounwind +define void @main() #0 { +entry: + %x = alloca [8 x i32], align 16 + %idx = alloca i64, align 8 + %i = alloca i32, align 4 + %0 = bitcast [8 x i32]* %x to i8* + call void @llvm.memset.p0i8.i64(i8* align 16 %0, i8 0, i64 32, i1 false) + %1 = getelementptr inbounds [8 x i32], [8 x i32]* %x, i64 0, i64 0 + store i32 3, i32* %1, align 4 + %2 = getelementptr inbounds [8 x i32], [8 x i32]* %x, i64 0, i64 1 + store i32 3, i32* %2, align 4 + %3 = getelementptr inbounds [8 x i32], [8 x i32]* %x, i64 0, i64 1 + store i32 5, i32* %3, align 4 + %4 = getelementptr inbounds [8 x i32], [8 x i32]* %x, i64 0, i64 2 + store i32 5, i32* %4, align 4 + %5 = getelementptr inbounds [8 x i32], [8 x i32]* %x, i64 0, i64 5 + store i32 52, i32* %5, align 4 + %6 = getelementptr inbounds [8 x i32], [8 x i32]* %x, i64 0, i64 6 + store i32 52, i32* %6, align 4 + %7 = getelementptr inbounds [8 x i32], [8 x i32]* %x, i64 0, i64 7 + store i32 52, i32* %7, align 4 + store i64 0, i64* %idx, align 8 + br label %foreach.cond +foreach.cond: ; preds = %foreach.inc, %entry + %8 = load i64, i64* %idx, align 8 + %lt = icmp ult i64 %8, 8 + br i1 %lt, label %foreach.body, label %foreach.exit +foreach.body: ; preds = %foreach.cond + %ptroffset = getelementptr inbounds i32, [8 x i32]* %x, i64 %8 + %9 = load i32, i32* %ptroffset, align 4 + store i32 %9, i32* %i, align 4 + %10 = load i32, i32* %i, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %10) + br label %foreach.inc +foreach.inc: ; preds = %foreach.body + %11 = load i64, i64* %idx, align 8 + %12 = add i64 %11, 1 + store i64 %12, i64* %idx, align 8 + br label %foreach.cond +foreach.exit: ; preds = %foreach.cond + br label %cond +cond: ; preds = %assign, %foreach.exit + %13 = phi i64 [ 0, %foreach.exit ], [ %add, %assign ] + %le = icmp sle i64 %13, 7 + br i1 %le, label %assign, label %exit +assign: ; preds = %cond + %14 = getelementptr inbounds [8 x i32], [8 x i32]* %x, i64 0, i64 %13 + store i32 123, i32* %14, align 4 + %add = add i64 %13, 1 + br label %cond +exit: ; preds = %cond + ret void +} \ No newline at end of file diff --git a/test/test_suite/statements/foreach_break.c3t b/test/test_suite/statements/foreach_break.c3t index e15810df3..e9b47c63e 100644 --- a/test/test_suite/statements/foreach_break.c3t +++ b/test/test_suite/statements/foreach_break.c3t @@ -17,35 +17,44 @@ func void test() store i32 0, i32* %g, align 4 store i64 0, i64* %idx, align 8 br label %foreach.cond -foreach.cond: + +foreach.cond: ; preds = %foreach.inc, %entry %1 = load i64, i64* %idx, align 8 %lt = icmp ult i64 %1, 3 br i1 %lt, label %foreach.body, label %foreach.exit -foreach.body: - %2 = getelementptr inbounds i32, [3 x i32]* %x, i64 %1 - %3 = load i32, i32* %2, align 4 - store i32 %3, i32* %z, align 4 - %4 = load i32, i32* %z, align 4 - %gt = icmp sgt i32 %4, 0 +foreach.body: ; preds = %foreach.cond + %ptroffset = getelementptr inbounds i32, [3 x i32]* %x, i64 %1 + %2 = load i32, i32* %ptroffset, align 4 + store i32 %2, i32* %z, align 4 + %3 = load i32, i32* %z, align 4 + %gt = icmp sgt i32 %3, 0 br i1 %gt, label %if.then, label %if.exit -if.then: + +if.then: ; preds = %foreach.body br label %foreach.exit -if.exit: - %5 = load i32, i32* %z, align 4 - %eq = icmp eq i32 %5, 1 + +if.exit: ; preds = %foreach.body + %4 = load i32, i32* %z, align 4 + %eq = icmp eq i32 %4, 1 br i1 %eq, label %if.then1, label %if.exit2 -if.then1: + +if.then1: ; preds = %if.exit br label %foreach.inc -if.exit2: - %6 = load i32, i32* %g, align 4 - %7 = load i32, i32* %z, align 4 - %add = add i32 %6, %7 + +if.exit2: ; preds = %if.exit + %5 = load i32, i32* %g, align 4 + %6 = load i32, i32* %z, align 4 + %add = add i32 %5, %6 store i32 %add, i32* %g, align 4 br label %foreach.inc -foreach.inc: - %8 = load i64, i64* %idx, align 8 - %9 = add i64 %8, 1 - store i64 %9, i64* %idx, align 8 + +foreach.inc: ; preds = %if.exit2, %if.then1 + %7 = load i64, i64* %idx, align 8 + %8 = add i64 %7, 1 + store i64 %8, i64* %idx, align 8 br label %foreach.cond -foreach.exit: + +foreach.exit: ; preds = %if.then, %foreach.cond + ret void +} \ No newline at end of file diff --git a/test/test_suite/statements/foreach_common.c3t b/test/test_suite/statements/foreach_common.c3t index 93b6cb5ae..17e80aad1 100644 --- a/test/test_suite/statements/foreach_common.c3t +++ b/test/test_suite/statements/foreach_common.c3t @@ -40,171 +40,172 @@ entry: %a = alloca float, align 4 %idx1 = alloca i64, align 8 %a2 = alloca float*, align 8 - %idx9 = alloca i64, align 8 - %a10 = alloca i8*, align 8 + %idx10 = alloca i64, align 8 + %a11 = alloca i8*, align 8 %i = alloca i64, align 8 - %a18 = alloca float, align 4 - %i25 = alloca i8, align 1 - %idx26 = alloca i64, align 8 - %a27 = alloca double, align 8 - %idx34 = alloca i64, align 8 - %a35 = alloca double, align 8 + %a20 = alloca float, align 4 + %i28 = alloca i8, align 1 + %idx29 = alloca i64, align 8 + %a30 = alloca double, align 8 + %idx38 = alloca i64, align 8 + %a39 = alloca double, align 8 %0 = bitcast [3 x float]* %foo to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([3 x float]* @.__const to i8*), i32 12, i1 false) store i64 0, i64* %idx, align 8 br label %foreach.cond -foreach.cond: +foreach.cond: ; preds = %foreach.inc, %entry %1 = load i64, i64* %idx, align 8 %lt = icmp ult i64 %1, 3 br i1 %lt, label %foreach.body, label %foreach.exit -foreach.body: - %2 = getelementptr inbounds float, [3 x float]* %foo, i64 %1 - %3 = load float, float* %2, align 4 - store float %3, float* %a, align 4 - %4 = load float, float* %a, align 4 - %fpfpext = fpext float %4 to double +foreach.body: ; preds = %foreach.cond + %ptroffset = getelementptr inbounds float, [3 x float]* %foo, i64 %1 + %2 = load float, float* %ptroffset, align 4 + store float %2, float* %a, align 4 + %3 = load float, float* %a, align 4 + %fpfpext = fpext float %3 to double call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i32 0, i32 0), double %fpfpext) br label %foreach.inc -foreach.inc: - %5 = load i64, i64* %idx, align 8 - %6 = add i64 %5, 1 - store i64 %6, i64* %idx, align 8 +foreach.inc: ; preds = %foreach.body + %4 = load i64, i64* %idx, align 8 + %5 = add i64 %4, 1 + store i64 %5, i64* %idx, align 8 br label %foreach.cond -foreach.exit: +foreach.exit: ; preds = %foreach.cond store i64 0, i64* %idx1, align 8 br label %foreach.cond3 -foreach.cond3: - %7 = load i64, i64* %idx1, align 8 - %lt4 = icmp ult i64 %7, 3 - br i1 %lt4, label %foreach.body5, label %foreach.exit8 +foreach.cond3: ; preds = %foreach.inc8, %foreach.exit + %6 = load i64, i64* %idx1, align 8 + %lt4 = icmp ult i64 %6, 3 + br i1 %lt4, label %foreach.body5, label %foreach.exit9 -foreach.body5: - %8 = getelementptr inbounds float, [3 x float]* %foo, i64 %7 - store float* %8, float** %a2, align 8 +foreach.body5: ; preds = %foreach.cond3 + %ptroffset6 = getelementptr inbounds float, [3 x float]* %foo, i64 %6 + store float* %ptroffset6, float** %a2, align 8 + %7 = load float*, float** %a2, align 8 + %8 = load float, float* %7, align 8 + %fmul = fmul float %8, 2.000000e+00 + store float %fmul, float* %7, align 8 %9 = load float*, float** %a2, align 8 %10 = load float, float* %9, align 8 - %fmul = fmul float %10, 2.000000e+00 - store float %fmul, float* %9, align 8 - %11 = load float*, float** %a2, align 8 - %12 = load float, float* %11, align 8 - %fpfpext6 = fpext float %12 to double - call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.1, i32 0, i32 0), double %fpfpext6) - br label %foreach.inc7 + %fpfpext7 = fpext float %10 to double + call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.1, i32 0, i32 0), double %fpfpext7) + br label %foreach.inc8 -foreach.inc7: - %13 = load i64, i64* %idx1, align 8 - %14 = add i64 %13, 1 - store i64 %14, i64* %idx1, align 8 +foreach.inc8: ; preds = %foreach.body5 + %11 = load i64, i64* %idx1, align 8 + %12 = add i64 %11, 1 + store i64 %12, i64* %idx1, align 8 br label %foreach.cond3 -foreach.exit8: - store i64 0, i64* %idx9, align 8 - br label %foreach.cond11 +foreach.exit9: ; preds = %foreach.cond3 + store i64 0, i64* %idx10, align 8 + br label %foreach.cond12 -foreach.cond11: - %15 = load i64, i64* %idx9, align 8 - %lt12 = icmp ult i64 %15, 3 - br i1 %lt12, label %foreach.body13, label %foreach.exit17 +foreach.cond12: ; preds = %foreach.inc18, %foreach.exit9 + %13 = load i64, i64* %idx10, align 8 + %lt13 = icmp ult i64 %13, 3 + br i1 %lt13, label %foreach.body14, label %foreach.exit19 -foreach.body13: - %16 = getelementptr inbounds float, [3 x float]* %foo, i64 %15 - %ptrptr = bitcast float* %16 to i8* - store i8* %ptrptr, i8** %a10, align 8 - %17 = load i8*, i8** %a10, align 8 - %ptrptr14 = bitcast i8* %17 to float* - %18 = load float, float* %ptrptr14, align 8 - %fpfpext15 = fpext float %18 to double - call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.2, i32 0, i32 0), double %fpfpext15) - br label %foreach.inc16 +foreach.body14: ; preds = %foreach.cond12 + %ptroffset15 = getelementptr inbounds float, [3 x float]* %foo, i64 %13 + %ptrptr = bitcast float* %ptroffset15 to i8* + store i8* %ptrptr, i8** %a11, align 8 + %14 = load i8*, i8** %a11, align 8 + %ptrptr16 = bitcast i8* %14 to float* + %15 = load float, float* %ptrptr16, align 8 + %fpfpext17 = fpext float %15 to double + call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.2, i32 0, i32 0), double %fpfpext17) + br label %foreach.inc18 -foreach.inc16: - %19 = load i64, i64* %idx9, align 8 - %20 = add i64 %19, 1 - store i64 %20, i64* %idx9, align 8 - br label %foreach.cond11 +foreach.inc18: ; preds = %foreach.body14 + %16 = load i64, i64* %idx10, align 8 + %17 = add i64 %16, 1 + store i64 %17, i64* %idx10, align 8 + br label %foreach.cond12 -foreach.exit17: +foreach.exit19: ; preds = %foreach.cond12 store i64 0, i64* %i, align 8 - br label %foreach.cond19 + br label %foreach.cond21 -foreach.cond19: - %21 = load i64, i64* %i, align 8 - %lt20 = icmp ult i64 %21, 3 - br i1 %lt20, label %foreach.body21, label %foreach.exit24 +foreach.cond21: ; preds = %foreach.inc26, %foreach.exit19 + %18 = load i64, i64* %i, align 8 + %lt22 = icmp ult i64 %18, 3 + br i1 %lt22, label %foreach.body23, label %foreach.exit27 -foreach.body21: - %22 = getelementptr inbounds float, [3 x float]* %foo, i64 %21 - %23 = load float, float* %22, align 4 - store float %23, float* %a18, align 4 - %24 = load i64, i64* %i, align 8 - %25 = load float, float* %a18, align 4 - %fpfpext22 = fpext float %25 to double - call void (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.3, i32 0, i32 0), i64 %24, double %fpfpext22) - br label %foreach.inc23 +foreach.body23: ; preds = %foreach.cond21 + %ptroffset24 = getelementptr inbounds float, [3 x float]* %foo, i64 %18 + %19 = load float, float* %ptroffset24, align 4 + store float %19, float* %a20, align 4 + %20 = load i64, i64* %i, align 8 + %21 = load float, float* %a20, align 4 + %fpfpext25 = fpext float %21 to double + call void (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.3, i32 0, i32 0), i64 %20, double %fpfpext25) + br label %foreach.inc26 -foreach.inc23: - %26 = load i64, i64* %i, align 8 - %27 = add i64 %26, 1 - store i64 %27, i64* %i, align 8 - br label %foreach.cond19 +foreach.inc26: ; preds = %foreach.body23 + %22 = load i64, i64* %i, align 8 + %23 = add i64 %22, 1 + store i64 %23, i64* %i, align 8 + br label %foreach.cond21 -foreach.exit24: - store i8 0, i8* %i25, align 1 - store i64 0, i64* %idx26, align 8 - br label %foreach.cond28 +foreach.exit27: ; preds = %foreach.cond21 + store i8 0, i8* %i28, align 1 + store i64 0, i64* %idx29, align 8 + br label %foreach.cond31 -foreach.cond28: - %28 = load i64, i64* %idx26, align 8 - %lt29 = icmp ult i64 %28, 3 - br i1 %lt29, label %foreach.body30, label %foreach.exit33 +foreach.cond31: ; preds = %foreach.inc36, %foreach.exit27 + %24 = load i64, i64* %idx29, align 8 + %lt32 = icmp ult i64 %24, 3 + br i1 %lt32, label %foreach.body33, label %foreach.exit37 -foreach.body30: - %29 = trunc i64 %28 to i8 - store i8 %29, i8* %i25, align 1 - %30 = getelementptr inbounds float, [3 x float]* %foo, i64 %28 - %31 = load float, float* %30, align 4 - %fpfpext31 = fpext float %31 to double - store double %fpfpext31, double* %a27, align 8 - %32 = load i8, i8* %i25, align 1 - %uisiext = zext i8 %32 to i32 - %33 = load double, double* %a27, align 8 - call void (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.4, i32 0, i32 0), i32 %uisiext, double %33) - br label %foreach.inc32 +foreach.body33: ; preds = %foreach.cond31 + %25 = trunc i64 %24 to i8 + store i8 %25, i8* %i28, align 1 + %ptroffset34 = getelementptr inbounds float, [3 x float]* %foo, i64 %24 + %26 = load float, float* %ptroffset34, align 4 + %fpfpext35 = fpext float %26 to double + store double %fpfpext35, double* %a30, align 8 + %27 = load i8, i8* %i28, align 1 + %uisiext = zext i8 %27 to i32 + %28 = load double, double* %a30, align 8 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.4, i32 0, i32 0), i32 %uisiext, double %28) + br label %foreach.inc36 -foreach.inc32: - %34 = load i64, i64* %idx26, align 8 +foreach.inc36: ; preds = %foreach.body33 + %29 = load i64, i64* %idx29, align 8 + %30 = add i64 %29, 1 + store i64 %30, i64* %idx29, align 8 + br label %foreach.cond31 + +foreach.exit37: ; preds = %foreach.cond31 + store i64 0, i64* %idx38, align 8 + br label %foreach.cond40 + +foreach.cond40: ; preds = %foreach.inc45, %foreach.exit37 + %31 = load i64, i64* %idx38, align 8 + %lt41 = icmp ult i64 %31, 3 + br i1 %lt41, label %foreach.body42, label %foreach.exit46 + +foreach.body42: ; preds = %foreach.cond40 + %ptroffset43 = getelementptr inbounds float, [3 x float]* %foo, i64 %31 + %32 = load float, float* %ptroffset43, align 4 + %fpfpext44 = fpext float %32 to double + store double %fpfpext44, double* %a39, align 8 + %33 = load double, double* %a39, align 8 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.5, i32 0, i32 0), double %33) + br label %foreach.inc45 + +foreach.inc45: ; preds = %foreach.body42 + %34 = load i64, i64* %idx38, align 8 %35 = add i64 %34, 1 - store i64 %35, i64* %idx26, align 8 - br label %foreach.cond28 + store i64 %35, i64* %idx38, align 8 + br label %foreach.cond40 -foreach.exit33: - store i64 0, i64* %idx34, align 8 - br label %foreach.cond36 - -foreach.cond36: - %36 = load i64, i64* %idx34, align 8 - %lt37 = icmp ult i64 %36, 3 - br i1 %lt37, label %foreach.body38, label %foreach.exit41 - -foreach.body38: - %37 = getelementptr inbounds float, [3 x float]* %foo, i64 %36 - %38 = load float, float* %37, align 4 - %fpfpext39 = fpext float %38 to double - store double %fpfpext39, double* %a35, align 8 - %39 = load double, double* %a35, align 8 - call void (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.5, i32 0, i32 0), double %39) - br label %foreach.inc40 - -foreach.inc40: - %40 = load i64, i64* %idx34, align 8 - %41 = add i64 %40, 1 - store i64 %41, i64* %idx34, align 8 - br label %foreach.cond36 - -foreach.exit41: +foreach.exit46: ; preds = %foreach.cond40 ret void +} \ No newline at end of file diff --git a/test/test_suite/statements/foreach_custom.c3t b/test/test_suite/statements/foreach_custom.c3t index adabc049d..0013c3644 100644 --- a/test/test_suite/statements/foreach_custom.c3t +++ b/test/test_suite/statements/foreach_custom.c3t @@ -58,7 +58,8 @@ entry: ret { i64, %Foo* } %6 } -define zeroext i8 @foo.FooIterator__next(%FooIterator* %0, i32* %1) +; Function Attrs: nounwind +define zeroext i8 @foo.FooIterator__next(%FooIterator* %0, i32* %1) #0 { entry: %it = alloca %FooIterator*, align 8 %value = alloca i32*, align 8 @@ -71,34 +72,35 @@ entry: %6 = getelementptr inbounds %FooIterator, %FooIterator* %5, i32 0, i32 1 %7 = load %Foo*, %Foo** %6, align 8 %8 = getelementptr inbounds %Foo, %Foo* %7, i32 0, i32 0 - %len = getelementptr inbounds %"int[]", %"int[]"* %8, i32 0, i32 1 - %9 = load i64, i64* %len, align 8 - %eq = icmp eq i64 %4, %9 + %9 = getelementptr inbounds %"int[]", %"int[]"* %8, i32 0, i32 1 + %10 = load i64, i64* %9, align 8 + %eq = icmp eq i64 %4, %10 br i1 %eq, label %if.then, label %if.exit -if.then: +if.then: ; preds = %entry ret i8 0 -if.exit: - %10 = load i32*, i32** %value, align 8 - %11 = load %FooIterator*, %FooIterator** %it, align 8 - %12 = getelementptr inbounds %FooIterator, %FooIterator* %11, i32 0, i32 1 - %13 = load %Foo*, %Foo** %12, align 8 - %14 = getelementptr inbounds %Foo, %Foo* %13, i32 0, i32 0 - %subarrayptr = getelementptr inbounds %"int[]", %"int[]"* %14, i32 0, i32 0 - %saptr = load i32*, i32** %subarrayptr, align 8 - %15 = load %FooIterator*, %FooIterator** %it, align 8 - %16 = getelementptr inbounds %FooIterator, %FooIterator* %15, i32 0, i32 0 - %17 = load i64, i64* %16, align 8 - %add = add i64 %17, 1 - store i64 %add, i64* %16, align 8 - %sarridx = getelementptr inbounds i32, i32* %saptr, i64 %17 - %18 = load i32, i32* %sarridx, align 4 - store i32 %18, i32* %10, align 8 +if.exit: ; preds = %entry + %11 = load i32*, i32** %value, align 8 + %12 = load %FooIterator*, %FooIterator** %it, align 8 + %13 = getelementptr inbounds %FooIterator, %FooIterator* %12, i32 0, i32 1 + %14 = load %Foo*, %Foo** %13, align 8 + %15 = getelementptr inbounds %Foo, %Foo* %14, i32 0, i32 0 + %16 = getelementptr inbounds %"int[]", %"int[]"* %15, i32 0, i32 0 + %17 = load i32*, i32** %16, align 8 + %18 = load %FooIterator*, %FooIterator** %it, align 8 + %19 = getelementptr inbounds %FooIterator, %FooIterator* %18, i32 0, i32 0 + %20 = load i64, i64* %19, align 8 + %add = add i64 %20, 1 + store i64 %add, i64* %19, align 8 + %ptroffset = getelementptr inbounds i32, i32* %17, i64 %20 + %21 = load i32, i32* %ptroffset, align 4 + store i32 %21, i32* %11, align 8 ret i8 1 } -define void @main() +; Function Attrs: nounwind +define void @main() #0 { entry: %i = alloca [3 x i32], align 4 %x = alloca %Foo, align 8 @@ -121,19 +123,19 @@ entry: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %7, i8* align 8 %8, i32 16, i1 false) br label %for.cond -for.cond: +for.cond: ; preds = %entry %9 = call i8 @foo.FooIterator__next(%FooIterator* %.iterator, i32* %f) %10 = trunc i8 %9 to i1 br i1 %10, label %for.body, label %for.exit -for.body: +for.body: ; preds = %for.cond %11 = load i32, i32* %f, align 4 %12 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %11) br label %while.begin -while.begin: +while.begin: ; preds = %for.body br label %for.exit -for.exit: +for.exit: ; preds = %while.begin, %for.cond ret void -} +} \ No newline at end of file diff --git a/test/test_suite/statements/foreach_custom_macro.c3t b/test/test_suite/statements/foreach_custom_macro.c3t index 0f41cc19c..198112872 100644 --- a/test/test_suite/statements/foreach_custom_macro.c3t +++ b/test/test_suite/statements/foreach_custom_macro.c3t @@ -38,7 +38,8 @@ extern func int printf(char *fmt, ...); // #expect: foo.ll -define void @main() +define void @main() #0 { +entry: %i = alloca [3 x i32], align 4 %x = alloca %Foo, align 8 %f = alloca i32, align 4 @@ -84,9 +85,9 @@ for.cond: ; preds = %expr_block.exit %16 = getelementptr inbounds %FooIterator, %FooIterator* %15, i32 0, i32 1 %17 = load %Foo*, %Foo** %16, align 8 %18 = getelementptr inbounds %Foo, %Foo* %17, i32 0, i32 0 - %len = getelementptr inbounds %"int[]", %"int[]"* %18, i32 0, i32 1 - %19 = load i64, i64* %len, align 8 - %eq = icmp eq i64 %14, %19 + %19 = getelementptr inbounds %"int[]", %"int[]"* %18, i32 0, i32 1 + %20 = load i64, i64* %19, align 8 + %eq = icmp eq i64 %14, %20 br i1 %eq, label %if.then, label %if.exit if.then: ; preds = %for.cond @@ -94,32 +95,32 @@ if.then: ; preds = %for.cond br label %expr_block.exit3 if.exit: ; preds = %for.cond - %20 = load i32*, i32** %value, align 8 - %21 = load %FooIterator*, %FooIterator** %it, align 8 - %22 = getelementptr inbounds %FooIterator, %FooIterator* %21, i32 0, i32 1 - %23 = load %Foo*, %Foo** %22, align 8 - %24 = getelementptr inbounds %Foo, %Foo* %23, i32 0, i32 0 - %subarrayptr = getelementptr inbounds %"int[]", %"int[]"* %24, i32 0, i32 0 - %saptr = load i32*, i32** %subarrayptr, align 8 - %25 = load %FooIterator*, %FooIterator** %it, align 8 - %26 = getelementptr inbounds %FooIterator, %FooIterator* %25, i32 0, i32 0 - %27 = load i64, i64* %26, align 8 - %add = add i64 %27, 1 - store i64 %add, i64* %26, align 8 - %sarridx = getelementptr inbounds i32, i32* %saptr, i64 %27 - %28 = load i32, i32* %sarridx, align 4 - store i32 %28, i32* %20, align 8 + %21 = load i32*, i32** %value, align 8 + %22 = load %FooIterator*, %FooIterator** %it, align 8 + %23 = getelementptr inbounds %FooIterator, %FooIterator* %22, i32 0, i32 1 + %24 = load %Foo*, %Foo** %23, align 8 + %25 = getelementptr inbounds %Foo, %Foo* %24, i32 0, i32 0 + %26 = getelementptr inbounds %"int[]", %"int[]"* %25, i32 0, i32 0 + %27 = load i32*, i32** %26, align 8 + %28 = load %FooIterator*, %FooIterator** %it, align 8 + %29 = getelementptr inbounds %FooIterator, %FooIterator* %28, i32 0, i32 0 + %30 = load i64, i64* %29, align 8 + %add = add i64 %30, 1 + store i64 %add, i64* %29, align 8 + %ptroffset = getelementptr inbounds i32, i32* %27, i64 %30 + %31 = load i32, i32* %ptroffset, align 4 + store i32 %31, i32* %21, align 8 store i8 1, i8* %blockret2, align 1 br label %expr_block.exit3 expr_block.exit3: ; preds = %if.exit, %if.then - %29 = load i8, i8* %blockret2, align 1 - %30 = trunc i8 %29 to i1 - br i1 %30, label %for.body, label %for.exit + %32 = load i8, i8* %blockret2, align 1 + %33 = trunc i8 %32 to i1 + br i1 %33, label %for.body, label %for.exit for.body: ; preds = %expr_block.exit3 - %31 = load i32, i32* %f, align 4 - %32 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %31) + %34 = load i32, i32* %f, align 4 + %35 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %34) br label %while.begin while.begin: ; preds = %for.body @@ -127,4 +128,4 @@ while.begin: ; preds = %for.body for.exit: ; preds = %while.begin, %expr_block.exit3 ret void -} +} \ No newline at end of file diff --git a/test/test_suite/statements/if_while_do_error.c3 b/test/test_suite/statements/if_while_do_error.c3 index ee5f9437c..66859d951 100644 --- a/test/test_suite/statements/if_while_do_error.c3 +++ b/test/test_suite/statements/if_while_do_error.c3 @@ -3,7 +3,7 @@ module test; func void test1() { bool! x = 0; - if (x) // #error: 'bool!' cannot be converted to 'bool' + if (x) // #error: 'bool!' to 'bool' { x = 100; } @@ -12,7 +12,7 @@ func void test1() func void test2() { bool! x = 0; - while (x) // #error: 'bool!' cannot be converted to 'bool' + while (x) // #error: 'bool!' to 'bool' { x = false; } @@ -30,5 +30,5 @@ func void test3() { x = !x; } - while (x); // #error: 'bool!' cannot be converted to 'bool' + while (x); // #error: A failable 'bool!' cannot be implicitly converted to a regular boolean value } \ No newline at end of file diff --git a/test/test_suite/statements/switch_errors.c3 b/test/test_suite/statements/switch_errors.c3 index 79ab20fc2..e55e23a1b 100644 --- a/test/test_suite/statements/switch_errors.c3 +++ b/test/test_suite/statements/switch_errors.c3 @@ -28,9 +28,9 @@ func void test_check_nums() Foo f = A; switch (f) { - case 2: + case (Foo)(2): break; - case 0: + case (Foo)(0): break; } } @@ -66,7 +66,7 @@ func void test_duplicate_case2(Foo i) { case A: break; - case 2: + case (Foo)(2): break; case A: // #error: same case value appears break; @@ -79,7 +79,7 @@ func void test_duplicate_case3(Foo i) { case A: break; - case 0: // #error: same case value appears + case (Foo)(0): // #error: same case value appears break; } } diff --git a/test/test_suite/struct/struct_as_value.c3t b/test/test_suite/struct/struct_as_value.c3t index c2b1acf55..e7649f315 100644 --- a/test/test_suite/struct/struct_as_value.c3t +++ b/test/test_suite/struct/struct_as_value.c3t @@ -46,7 +46,7 @@ func Event test(int x) cond.phi: ; preds = %cond.rhs, %cond.lhs %val = phi %Event [ %4, %cond.lhs ], [ %5, %cond.rhs ] store %Event %val, %Event* %taddr, align 4 - %dive = getelementptr inbounds %Event, %Event* %taddr, i32 0, i32 0 - %6 = load i32, i32* %dive, align 4 - ret i32 %6 + %6 = getelementptr inbounds %Event, %Event* %taddr, i32 0, i32 0 + %7 = load i32, i32* %6, align 4 + ret i32 %7 } \ No newline at end of file diff --git a/test/test_suite/struct/struct_as_value_aarch64.c3t b/test/test_suite/struct/struct_as_value_aarch64.c3t index 39211b0e7..bfa7757a6 100644 --- a/test/test_suite/struct/struct_as_value_aarch64.c3t +++ b/test/test_suite/struct/struct_as_value_aarch64.c3t @@ -28,18 +28,19 @@ func Event test(int x) %intbool = icmp ne i32 %3, 0 br i1 %intbool, label %cond.lhs, label %cond.rhs -cond.lhs: +cond.lhs: ; preds = %entry %4 = load %Event, %Event* %foo, align 4 br label %cond.phi -cond.rhs: +cond.rhs: ; preds = %entry %5 = load %Event, %Event* %bar, align 4 br label %cond.phi -cond.phi: +cond.phi: ; preds = %cond.rhs, %cond.lhs %val = phi %Event [ %4, %cond.lhs ], [ %5, %cond.rhs ] store %Event %val, %Event* %taddr, align 4 - %dive = getelementptr inbounds %Event, %Event* %taddr, i32 0, i32 0 - %6 = load i32, i32* %dive, align 4 - %7 = zext i32 %6 to i64 - ret i64 %7 \ No newline at end of file + %6 = getelementptr inbounds %Event, %Event* %taddr, i32 0, i32 0 + %7 = load i32, i32* %6, align 4 + %8 = zext i32 %7 to i64 + ret i64 %8 +} diff --git a/test/test_suite/subarrays/slice_comparison.c3t b/test/test_suite/subarrays/slice_comparison.c3t index f151c3259..74390947a 100644 --- a/test/test_suite/subarrays/slice_comparison.c3t +++ b/test/test_suite/subarrays/slice_comparison.c3t @@ -38,11 +38,11 @@ entry: %y = alloca %"char[]", align 8 %z = alloca %"char[]", align 8 %cmp.idx = alloca i64, align 8 - %cmp.idx4 = alloca i64, align 8 + %cmp.idx5 = alloca i64, align 8 %switch = alloca %"char[]", align 8 - %cmp.idx17 = alloca i64, align 8 - %cmp.idx28 = alloca i64, align 8 - %cmp.idx41 = alloca i64, align 8 + %cmp.idx18 = alloca i64, align 8 + %cmp.idx29 = alloca i64, align 8 + %cmp.idx42 = alloca i64, align 8 store %"char[]" { i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i32 0, i32 0), i64 4 }, %"char[]"* %y, align 8 store %"char[]" { i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i32 0, i32 0), i64 4 }, %"char[]"* %z, align 8 %0 = load %"char[]", %"char[]"* %y, align 8 @@ -61,14 +61,14 @@ subarray_loop_start: ; preds = %subarray_loop_compa br i1 %lt, label %subarray_loop_comparison, label %subarray_cmp_exit subarray_loop_comparison: ; preds = %subarray_loop_start - %lhs.ptr = getelementptr inbounds i8, i8* %2, i64 %3 - %rhs.ptr = getelementptr inbounds i8, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.2, i32 0, i32 0), i64 %3 - %4 = load i8, i8* %lhs.ptr, align 1 - %5 = load i8, i8* %rhs.ptr, align 1 - %eq1 = icmp eq i8 %4, %5 + %ptroffset = getelementptr inbounds i8, i8* %2, i64 %3 + %ptroffset1 = getelementptr inbounds i8, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.2, i32 0, i32 0), i64 %3 + %4 = load i8, i8* %ptroffset, align 1 + %5 = load i8, i8* %ptroffset1, align 1 + %eq2 = icmp eq i8 %4, %5 %6 = add i64 %3, 1 store i64 %6, i64* %cmp.idx, align 8 - br i1 %eq1, label %subarray_loop_start, label %subarray_cmp_exit + br i1 %eq2, label %subarray_loop_start, label %subarray_cmp_exit subarray_cmp_exit: ; preds = %subarray_loop_comparison, %subarray_loop_start, %entry %subarray_cmp_phi = phi i1 [ true, %subarray_loop_start ], [ false, %entry ], [ false, %subarray_loop_comparison ] @@ -85,149 +85,149 @@ if.exit: ; preds = %if.then, %subarray_ %10 = extractvalue %"char[]" %8, 1 %11 = extractvalue %"char[]" %7, 0 %12 = extractvalue %"char[]" %8, 0 - %eq2 = icmp eq i64 %9, %10 - br i1 %eq2, label %subarray_cmp_values3, label %subarray_cmp_exit11 + %eq3 = icmp eq i64 %9, %10 + br i1 %eq3, label %subarray_cmp_values4, label %subarray_cmp_exit12 -subarray_cmp_values3: ; preds = %if.exit - store i64 0, i64* %cmp.idx4, align 8 - br label %subarray_loop_start5 +subarray_cmp_values4: ; preds = %if.exit + store i64 0, i64* %cmp.idx5, align 8 + br label %subarray_loop_start6 -subarray_loop_start5: ; preds = %subarray_loop_comparison7, %subarray_cmp_values3 - %13 = load i64, i64* %cmp.idx4, align 8 - %lt6 = icmp ult i64 %13, %9 - br i1 %lt6, label %subarray_loop_comparison7, label %subarray_cmp_exit11 +subarray_loop_start6: ; preds = %subarray_loop_comparison8, %subarray_cmp_values4 + %13 = load i64, i64* %cmp.idx5, align 8 + %lt7 = icmp ult i64 %13, %9 + br i1 %lt7, label %subarray_loop_comparison8, label %subarray_cmp_exit12 -subarray_loop_comparison7: ; preds = %subarray_loop_start5 - %lhs.ptr8 = getelementptr inbounds i8, i8* %11, i64 %13 - %rhs.ptr9 = getelementptr inbounds i8, i8* %12, i64 %13 - %14 = load i8, i8* %lhs.ptr8, align 1 - %15 = load i8, i8* %rhs.ptr9, align 1 - %eq10 = icmp eq i8 %14, %15 +subarray_loop_comparison8: ; preds = %subarray_loop_start6 + %ptroffset9 = getelementptr inbounds i8, i8* %11, i64 %13 + %ptroffset10 = getelementptr inbounds i8, i8* %12, i64 %13 + %14 = load i8, i8* %ptroffset9, align 1 + %15 = load i8, i8* %ptroffset10, align 1 + %eq11 = icmp eq i8 %14, %15 %16 = add i64 %13, 1 - store i64 %16, i64* %cmp.idx4, align 8 - br i1 %eq10, label %subarray_loop_start5, label %subarray_cmp_exit11 + store i64 %16, i64* %cmp.idx5, align 8 + br i1 %eq11, label %subarray_loop_start6, label %subarray_cmp_exit12 -subarray_cmp_exit11: ; preds = %subarray_loop_comparison7, %subarray_loop_start5, %if.exit - %subarray_cmp_phi12 = phi i1 [ true, %subarray_loop_start5 ], [ false, %if.exit ], [ false, %subarray_loop_comparison7 ] - br i1 %subarray_cmp_phi12, label %if.then13, label %if.exit14 +subarray_cmp_exit12: ; preds = %subarray_loop_comparison8, %subarray_loop_start6, %if.exit + %subarray_cmp_phi13 = phi i1 [ true, %subarray_loop_start6 ], [ false, %if.exit ], [ false, %subarray_loop_comparison8 ] + br i1 %subarray_cmp_phi13, label %if.then14, label %if.exit15 -if.then13: ; preds = %subarray_cmp_exit11 +if.then14: ; preds = %subarray_cmp_exit12 call void (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.4, i32 0, i32 0)) - br label %if.exit14 + br label %if.exit15 -if.exit14: ; preds = %if.then13, %subarray_cmp_exit11 +if.exit15: ; preds = %if.then14, %subarray_cmp_exit12 %17 = bitcast %"char[]"* %switch to i8* %18 = bitcast %"char[]"* %y to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %17, i8* align 8 %18, i32 16, i1 false) br label %switch.entry -switch.entry: ; preds = %if.exit14 +switch.entry: ; preds = %if.exit15 %19 = load %"char[]", %"char[]"* %switch, align 8 %20 = extractvalue %"char[]" %19, 1 %21 = extractvalue %"char[]" %19, 0 - %eq15 = icmp eq i64 4, %20 - br i1 %eq15, label %subarray_cmp_values16, label %subarray_cmp_exit24 + %eq16 = icmp eq i64 4, %20 + br i1 %eq16, label %subarray_cmp_values17, label %subarray_cmp_exit25 -subarray_cmp_values16: ; preds = %switch.entry - store i64 0, i64* %cmp.idx17, align 8 - br label %subarray_loop_start18 +subarray_cmp_values17: ; preds = %switch.entry + store i64 0, i64* %cmp.idx18, align 8 + br label %subarray_loop_start19 -subarray_loop_start18: ; preds = %subarray_loop_comparison20, %subarray_cmp_values16 - %22 = load i64, i64* %cmp.idx17, align 8 - %lt19 = icmp ult i64 %22, 4 - br i1 %lt19, label %subarray_loop_comparison20, label %subarray_cmp_exit24 +subarray_loop_start19: ; preds = %subarray_loop_comparison21, %subarray_cmp_values17 + %22 = load i64, i64* %cmp.idx18, align 8 + %lt20 = icmp ult i64 %22, 4 + br i1 %lt20, label %subarray_loop_comparison21, label %subarray_cmp_exit25 -subarray_loop_comparison20: ; preds = %subarray_loop_start18 - %lhs.ptr21 = getelementptr inbounds i8, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.5, i32 0, i32 0), i64 %22 - %rhs.ptr22 = getelementptr inbounds i8, i8* %21, i64 %22 - %23 = load i8, i8* %lhs.ptr21, align 1 - %24 = load i8, i8* %rhs.ptr22, align 1 - %eq23 = icmp eq i8 %23, %24 +subarray_loop_comparison21: ; preds = %subarray_loop_start19 + %ptroffset22 = getelementptr inbounds i8, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.5, i32 0, i32 0), i64 %22 + %ptroffset23 = getelementptr inbounds i8, i8* %21, i64 %22 + %23 = load i8, i8* %ptroffset22, align 1 + %24 = load i8, i8* %ptroffset23, align 1 + %eq24 = icmp eq i8 %23, %24 %25 = add i64 %22, 1 - store i64 %25, i64* %cmp.idx17, align 8 - br i1 %eq23, label %subarray_loop_start18, label %subarray_cmp_exit24 + store i64 %25, i64* %cmp.idx18, align 8 + br i1 %eq24, label %subarray_loop_start19, label %subarray_cmp_exit25 -subarray_cmp_exit24: ; preds = %subarray_loop_comparison20, %subarray_loop_start18, %switch.entry - %subarray_cmp_phi25 = phi i1 [ true, %subarray_loop_start18 ], [ false, %switch.entry ], [ false, %subarray_loop_comparison20 ] - br i1 %subarray_cmp_phi25, label %switch.case, label %next_if +subarray_cmp_exit25: ; preds = %subarray_loop_comparison21, %subarray_loop_start19, %switch.entry + %subarray_cmp_phi26 = phi i1 [ true, %subarray_loop_start19 ], [ false, %switch.entry ], [ false, %subarray_loop_comparison21 ] + br i1 %subarray_cmp_phi26, label %switch.case, label %next_if -switch.case: ; preds = %subarray_cmp_exit24 +switch.case: ; preds = %subarray_cmp_exit25 call void (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.6, i32 0, i32 0)) br label %switch.exit -next_if: ; preds = %subarray_cmp_exit24 +next_if: ; preds = %subarray_cmp_exit25 %26 = extractvalue %"char[]" %19, 1 %27 = extractvalue %"char[]" %19, 0 - %eq26 = icmp eq i64 5, %26 - br i1 %eq26, label %subarray_cmp_values27, label %subarray_cmp_exit35 + %eq27 = icmp eq i64 5, %26 + br i1 %eq27, label %subarray_cmp_values28, label %subarray_cmp_exit36 -subarray_cmp_values27: ; preds = %next_if - store i64 0, i64* %cmp.idx28, align 8 - br label %subarray_loop_start29 +subarray_cmp_values28: ; preds = %next_if + store i64 0, i64* %cmp.idx29, align 8 + br label %subarray_loop_start30 -subarray_loop_start29: ; preds = %subarray_loop_comparison31, %subarray_cmp_values27 - %28 = load i64, i64* %cmp.idx28, align 8 - %lt30 = icmp ult i64 %28, 5 - br i1 %lt30, label %subarray_loop_comparison31, label %subarray_cmp_exit35 +subarray_loop_start30: ; preds = %subarray_loop_comparison32, %subarray_cmp_values28 + %28 = load i64, i64* %cmp.idx29, align 8 + %lt31 = icmp ult i64 %28, 5 + br i1 %lt31, label %subarray_loop_comparison32, label %subarray_cmp_exit36 -subarray_loop_comparison31: ; preds = %subarray_loop_start29 - %lhs.ptr32 = getelementptr inbounds i8, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.7, i32 0, i32 0), i64 %28 - %rhs.ptr33 = getelementptr inbounds i8, i8* %27, i64 %28 - %29 = load i8, i8* %lhs.ptr32, align 1 - %30 = load i8, i8* %rhs.ptr33, align 1 - %eq34 = icmp eq i8 %29, %30 +subarray_loop_comparison32: ; preds = %subarray_loop_start30 + %ptroffset33 = getelementptr inbounds i8, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.7, i32 0, i32 0), i64 %28 + %ptroffset34 = getelementptr inbounds i8, i8* %27, i64 %28 + %29 = load i8, i8* %ptroffset33, align 1 + %30 = load i8, i8* %ptroffset34, align 1 + %eq35 = icmp eq i8 %29, %30 %31 = add i64 %28, 1 - store i64 %31, i64* %cmp.idx28, align 8 - br i1 %eq34, label %subarray_loop_start29, label %subarray_cmp_exit35 + store i64 %31, i64* %cmp.idx29, align 8 + br i1 %eq35, label %subarray_loop_start30, label %subarray_cmp_exit36 -subarray_cmp_exit35: ; preds = %subarray_loop_comparison31, %subarray_loop_start29, %next_if - %subarray_cmp_phi36 = phi i1 [ true, %subarray_loop_start29 ], [ false, %next_if ], [ false, %subarray_loop_comparison31 ] - br i1 %subarray_cmp_phi36, label %switch.case37, label %next_if38 +subarray_cmp_exit36: ; preds = %subarray_loop_comparison32, %subarray_loop_start30, %next_if + %subarray_cmp_phi37 = phi i1 [ true, %subarray_loop_start30 ], [ false, %next_if ], [ false, %subarray_loop_comparison32 ] + br i1 %subarray_cmp_phi37, label %switch.case38, label %next_if39 -switch.case37: ; preds = %subarray_cmp_exit35 +switch.case38: ; preds = %subarray_cmp_exit36 call void (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.8, i32 0, i32 0)) br label %switch.exit -next_if38: ; preds = %subarray_cmp_exit35 +next_if39: ; preds = %subarray_cmp_exit36 %32 = extractvalue %"char[]" %19, 1 %33 = extractvalue %"char[]" %19, 0 - %eq39 = icmp eq i64 4, %32 - br i1 %eq39, label %subarray_cmp_values40, label %subarray_cmp_exit48 + %eq40 = icmp eq i64 4, %32 + br i1 %eq40, label %subarray_cmp_values41, label %subarray_cmp_exit49 -subarray_cmp_values40: ; preds = %next_if38 - store i64 0, i64* %cmp.idx41, align 8 - br label %subarray_loop_start42 +subarray_cmp_values41: ; preds = %next_if39 + store i64 0, i64* %cmp.idx42, align 8 + br label %subarray_loop_start43 -subarray_loop_start42: ; preds = %subarray_loop_comparison44, %subarray_cmp_values40 - %34 = load i64, i64* %cmp.idx41, align 8 - %lt43 = icmp ult i64 %34, 4 - br i1 %lt43, label %subarray_loop_comparison44, label %subarray_cmp_exit48 +subarray_loop_start43: ; preds = %subarray_loop_comparison45, %subarray_cmp_values41 + %34 = load i64, i64* %cmp.idx42, align 8 + %lt44 = icmp ult i64 %34, 4 + br i1 %lt44, label %subarray_loop_comparison45, label %subarray_cmp_exit49 -subarray_loop_comparison44: ; preds = %subarray_loop_start42 - %lhs.ptr45 = getelementptr inbounds i8, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.9, i32 0, i32 0), i64 %34 - %rhs.ptr46 = getelementptr inbounds i8, i8* %33, i64 %34 - %35 = load i8, i8* %lhs.ptr45, align 1 - %36 = load i8, i8* %rhs.ptr46, align 1 - %eq47 = icmp eq i8 %35, %36 +subarray_loop_comparison45: ; preds = %subarray_loop_start43 + %ptroffset46 = getelementptr inbounds i8, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.9, i32 0, i32 0), i64 %34 + %ptroffset47 = getelementptr inbounds i8, i8* %33, i64 %34 + %35 = load i8, i8* %ptroffset46, align 1 + %36 = load i8, i8* %ptroffset47, align 1 + %eq48 = icmp eq i8 %35, %36 %37 = add i64 %34, 1 - store i64 %37, i64* %cmp.idx41, align 8 - br i1 %eq47, label %subarray_loop_start42, label %subarray_cmp_exit48 + store i64 %37, i64* %cmp.idx42, align 8 + br i1 %eq48, label %subarray_loop_start43, label %subarray_cmp_exit49 -subarray_cmp_exit48: ; preds = %subarray_loop_comparison44, %subarray_loop_start42, %next_if38 - %subarray_cmp_phi49 = phi i1 [ true, %subarray_loop_start42 ], [ false, %next_if38 ], [ false, %subarray_loop_comparison44 ] - br i1 %subarray_cmp_phi49, label %switch.case50, label %next_if51 +subarray_cmp_exit49: ; preds = %subarray_loop_comparison45, %subarray_loop_start43, %next_if39 + %subarray_cmp_phi50 = phi i1 [ true, %subarray_loop_start43 ], [ false, %next_if39 ], [ false, %subarray_loop_comparison45 ] + br i1 %subarray_cmp_phi50, label %switch.case51, label %next_if52 -switch.case50: ; preds = %subarray_cmp_exit48 +switch.case51: ; preds = %subarray_cmp_exit49 call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.10, i32 0, i32 0)) br label %switch.exit -next_if51: ; preds = %subarray_cmp_exit48 +next_if52: ; preds = %subarray_cmp_exit49 br label %switch.default -switch.default: ; preds = %next_if51 +switch.default: ; preds = %next_if52 call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.11, i32 0, i32 0)) br label %switch.exit -switch.exit: ; preds = %switch.default, %switch.case50, %switch.case37, %switch.case +switch.exit: ; preds = %switch.default, %switch.case51, %switch.case38, %switch.case ret void -} +} \ No newline at end of file diff --git a/test/test_suite/subarrays/slice_offset.c3t b/test/test_suite/subarrays/slice_offset.c3t index 6dbe6c59a..21c45f302 100644 --- a/test/test_suite/subarrays/slice_offset.c3t +++ b/test/test_suite/subarrays/slice_offset.c3t @@ -10,8 +10,7 @@ func void test() %y = alloca %"int[]", align 8 %0 = bitcast [3 x i32]* %x to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([3 x i32]* @.__const to i8*), i32 12, i1 false) - %1 = bitcast [3 x i32]* %x to i32* - %offset = getelementptr inbounds i32, i32* %1, i64 1 - %2 = insertvalue %"int[]" undef, i32* %offset, 0 + %1 = getelementptr inbounds [3 x i32], [3 x i32]* %x, i64 0, i64 1 + %2 = insertvalue %"int[]" undef, i32* %1, 0 %3 = insertvalue %"int[]" %2, i64 2, 1 store %"int[]" %3, %"int[]"* %y, align 8 diff --git a/test/test_suite/subarrays/slice_offset_neg_end.c3t b/test/test_suite/subarrays/slice_offset_neg_end.c3t index 039aff46d..fe1fc7a2e 100644 --- a/test/test_suite/subarrays/slice_offset_neg_end.c3t +++ b/test/test_suite/subarrays/slice_offset_neg_end.c3t @@ -11,9 +11,8 @@ func void test() %y = alloca %"int[]", align 8 %0 = bitcast [3 x i32]* %x to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([3 x i32]* @.__const to i8*), i32 12, i1 false) - %1 = bitcast [3 x i32]* %x to i32* - %offset = getelementptr inbounds i32, i32* %1, i64 1 - %2 = insertvalue %"int[]" undef, i32* %offset, 0 + %1 = getelementptr inbounds [3 x i32], [3 x i32]* %x, i64 0, i64 1 + %2 = insertvalue %"int[]" undef, i32* %1, 0 %3 = insertvalue %"int[]" %2, i64 2, 1 store %"int[]" %3, %"int[]"* %y, align 8 diff --git a/test/test_suite/subarrays/slice_offset_neg_start.c3t b/test/test_suite/subarrays/slice_offset_neg_start.c3t index 33f1fd884..10e60898f 100644 --- a/test/test_suite/subarrays/slice_offset_neg_start.c3t +++ b/test/test_suite/subarrays/slice_offset_neg_start.c3t @@ -10,8 +10,7 @@ func void test() %y = alloca %"int[]", align 8 %0 = bitcast [3 x i32]* %x to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([3 x i32]* @.__const to i8*), i32 12, i1 false) - %1 = bitcast [3 x i32]* %x to i32* - %offset = getelementptr inbounds i32, i32* %1, i64 1 - %2 = insertvalue %"int[]" undef, i32* %offset, 0 + %1 = getelementptr inbounds [3 x i32], [3 x i32]* %x, i64 0, i64 1 + %2 = insertvalue %"int[]" undef, i32* %1, 0 %3 = insertvalue %"int[]" %2, i64 1, 1 store %"int[]" %3, %"int[]"* %y, align 8 diff --git a/test/test_suite/subarrays/slice_start.c3t b/test/test_suite/subarrays/slice_start.c3t index e81043920..23e35724e 100644 --- a/test/test_suite/subarrays/slice_start.c3t +++ b/test/test_suite/subarrays/slice_start.c3t @@ -10,8 +10,7 @@ func void test() %y = alloca %"int[]", align 8 %0 = bitcast [3 x i32]* %x to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([3 x i32]* @.__const to i8*), i32 12, i1 false) - %1 = bitcast [3 x i32]* %x to i32* - %offset = getelementptr inbounds i32, i32* %1, i64 0 - %2 = insertvalue %"int[]" undef, i32* %offset, 0 + %1 = getelementptr inbounds [3 x i32], [3 x i32]* %x, i64 0, i64 0 + %2 = insertvalue %"int[]" undef, i32* %1, 0 %3 = insertvalue %"int[]" %2, i64 3, 1 store %"int[]" %3, %"int[]"* %y, align 8 diff --git a/test/test_suite/switch/failable_switch.c3 b/test/test_suite/switch/failable_switch.c3 new file mode 100644 index 000000000..587e4e0cf --- /dev/null +++ b/test/test_suite/switch/failable_switch.c3 @@ -0,0 +1,14 @@ +errtype MyError +{ + FOO +} + +fn void test() +{ + int x = 0; + switch (x) + { + case MyError.FOO!: // #error: You cannot have a failable here + x = x + 1; + } +} \ No newline at end of file diff --git a/test/test_suite/types/enum_inference.c3 b/test/test_suite/types/enum_inference.c3 index 479ee9b89..37141955e 100644 --- a/test/test_suite/types/enum_inference.c3 +++ b/test/test_suite/types/enum_inference.c3 @@ -34,7 +34,7 @@ func void enumInferenceTest() return; case B: return; - case 111: + case (Inf2)(111): x1 += 1; return; default: diff --git a/wrapper/src/wrapper.cpp b/wrapper/src/wrapper.cpp index f7cbcaebf..4c8ac2314 100644 --- a/wrapper/src/wrapper.cpp +++ b/wrapper/src/wrapper.cpp @@ -2,6 +2,35 @@ #include #include +// For hacking the C API +#include "llvm-c/Core.h" +#include "llvm/IR/Attributes.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/IR/GlobalAlias.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InlineAsm.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Threading.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include + namespace lld { namespace coff { bool link(llvm::ArrayRef args, bool canExitEarly, @@ -79,8 +108,27 @@ static bool llvm_link(ObjFormat format, const char **args, int arg_count, const return false; } + extern "C" { + LLVMValueRef LLVMConstGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal, + LLVMValueRef *ConstantIndices, unsigned NumIndices) { + llvm::ArrayRef IdxList(llvm::unwrap(ConstantIndices, NumIndices), + NumIndices); + llvm::Constant *Val = llvm::unwrap(ConstantVal); + return wrap(llvm::ConstantExpr::getGetElementPtr(llvm::unwrap(Ty), Val, IdxList)); + } + + LLVMValueRef LLVMConstInBoundsGEP2(LLVMTypeRef Ty, + LLVMValueRef ConstantVal, + LLVMValueRef *ConstantIndices, + unsigned NumIndices) { + llvm::ArrayRef IdxList(llvm::unwrap(ConstantIndices, NumIndices), + NumIndices); + llvm::Constant *Val = llvm::unwrap(ConstantVal); + return wrap(llvm::ConstantExpr::getInBoundsGetElementPtr(llvm::unwrap(Ty), Val, IdxList)); + } + bool llvm_link_elf(const char **args, int arg_count, const char** error_string) { return llvm_link(ELF, args, arg_count, error_string);