diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 9229f9e6b..6d47b7905 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2015,6 +2015,7 @@ static inline bool type_is_integer_unsigned(Type *type); static inline bool type_is_integer_signed(Type *type); static inline bool type_is_integer_kind(Type *type); static inline bool type_is_numeric(Type *type); +static inline bool type_underlying_is_numeric(Type *type); static inline bool type_is_pointer(Type *type); static inline bool type_is_promotable_float(Type *type); static inline bool type_is_promotable_integer(Type *type); @@ -2259,10 +2260,14 @@ bool type_is_scalar(Type *type); static inline bool type_is_numeric(Type *type) { - type = type_flatten(type); return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_FXX; } +static inline bool type_underlying_is_numeric(Type *type) +{ + return type_is_numeric(type_flatten(type)); +} + static inline bool type_kind_is_derived(TypeKind kind) { switch (kind) diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 835f58fd6..832392ef8 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -621,6 +621,10 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_ value->value = LLVMBuildFCmp(c->builder, LLVMRealUNE, value->value, llvm_get_zero(c, from_type), "fpbool"); value->kind = BE_BOOLEAN; break; + case CAST_BOOLBOOL: + value->value = LLVMBuildTrunc(c->builder, value->value, c->bool_type, "boolbool"); + value->kind = BE_BOOLEAN; + break; case CAST_BOOLFP: llvm_value_rvalue(c, value); value->value = LLVMBuildUIToFP(c->builder, value->value, llvm_get_type(c, to_type), "boolfp"); @@ -690,7 +694,6 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_ value->value = LLVMBuildBitCast(c->builder, value->value, llvm_get_ptr_type(c, to_type), ""); value->type = to_type; return; - case CAST_BOOLBOOL: case CAST_SABOOL: TODO break; @@ -2511,6 +2514,7 @@ void gencontext_emit_elvis_expr(GenContext *c, BEValue *value, Expr *expr) { CastKind cast = cast_to_bool_kind(cond_type); llvm_emit_cast(c, cast, value, type_bool, cond_type); + assert(value->kind == BE_BOOLEAN); } llvm_emit_cond_br(c, value, phi_block, rhs_block); @@ -2560,7 +2564,7 @@ void gencontext_emit_ternary_expr(GenContext *c, BEValue *value, Expr *expr) llvm_emit_block(c, lhs_block); BEValue lhs; llvm_emit_expr(c, &lhs, expr->ternary_expr.then_expr); - llvm_value_rvalue(c, &lhs); + LLVMValueRef lhs_value = llvm_value_rvalue_store(c, &lhs); LLVMBasicBlockRef lhs_exit = llvm_get_current_block_if_in_use(c); if (lhs_exit) llvm_emit_br(c, phi_block); @@ -2568,7 +2572,7 @@ void gencontext_emit_ternary_expr(GenContext *c, BEValue *value, Expr *expr) llvm_emit_block(c, rhs_block); BEValue rhs; llvm_emit_expr(c, &rhs, expr->ternary_expr.else_expr); - llvm_value_rvalue(c, &rhs); + LLVMValueRef rhs_value = llvm_value_rvalue_store(c, &rhs); LLVMBasicBlockRef rhs_exit = llvm_get_current_block_if_in_use(c); if (rhs_exit) llvm_emit_br(c, phi_block); @@ -2577,14 +2581,16 @@ void gencontext_emit_ternary_expr(GenContext *c, BEValue *value, Expr *expr) llvm_emit_block(c, phi_block); if (!rhs_exit) { - *value = lhs; + llvm_value_set(value, lhs_value, lhs.type); + return; } if (!lhs_exit) { - *value = rhs; + llvm_value_set(value, rhs_value, rhs.type); + return; } LLVMValueRef phi = LLVMBuildPhi(c->builder, llvm_get_type(c, expr->type), "val"); - LLVMValueRef logic_values[2] = { lhs.value, rhs.value }; + LLVMValueRef logic_values[2] = { lhs_value, rhs_value }; LLVMBasicBlockRef blocks[2] = { lhs_exit, rhs_exit }; LLVMAddIncoming(phi, logic_values, blocks, 2); diff --git a/src/compiler/number.c b/src/compiler/number.c index bbdea097e..61d751f45 100644 --- a/src/compiler/number.c +++ b/src/compiler/number.c @@ -4,35 +4,6 @@ #include "compiler_internal.h" -#define CHECK_SI_KIND(_kind) assert(_kind >= TYPE_I8 && _kind <= TYPE_I64) -#define CHECK_IXX_KIND(_kind) assert(_kind == TYPE_IXX) -#define CHECK_UI_KIND(_kind) assert(_kind >= TYPE_U8 && _kind <= TYPE_U64) -#define CHECK_INT_KIND(_kind) assert(_kind >= TYPE_I8 && _kind <= TYPE_U64) -#define CHECK_CONVERSION(_kind) assert(i->kind != _kind && "Unnecessary conversion") -#define TYPE_MATCH assert(left->kind == right->kind && left != res && right != res) - -static uint64_t type_mask[TYPE_U64 + 1] = { - [TYPE_U8] = 0xFF, - [TYPE_I8] = 0xFF, - [TYPE_U16] = 0xFFFF, - [TYPE_I16] = 0xFFFF, - [TYPE_U32] = 0xFFFFFFFFU, - [TYPE_I32] = 0xFFFFFFFFU, - [TYPE_U64] = 0xFFFFFFFFFFFFFFFFLLU, - [TYPE_I64] = 0xFFFFFFFFFFFFFFFFLLU, -}; - -static int type_bits[TYPE_U64 + 1] = { - [TYPE_U8] = 8, - [TYPE_I8] = 8, - [TYPE_U16] = 16, - [TYPE_I16] = 16, - [TYPE_U32] = 32, - [TYPE_I32] = 32, - [TYPE_U64] = 64, - [TYPE_I64] = 64, -}; - void expr_const_fprint(FILE *__restrict file, ExprConst *expr) { diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index c9b771f90..a8aa90f1b 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -397,6 +397,7 @@ static bool sema_analyse_struct_union(Context *context, Decl *decl) static bool sema_analyse_bitstruct(Context *context, Decl *decl) { + int overlap = -1; VECEACH(decl->attributes, i) { Attr *attr = decl->attributes[i]; @@ -405,12 +406,11 @@ static bool sema_analyse_bitstruct(Context *context, Decl *decl) if (attribute == ATTRIBUTE_NONE) return decl_poison(decl); bool had = false; - int overlap = -1; #define SET_ATTR(_X) had = decl->func_decl._X; decl->func_decl._X = true; break switch (attribute) { case ATTRIBUTE_OVERLAP: - had = overlap != -1; + had = (overlap != -1); overlap = 1; break; case ATTRIBUTE_OPAQUE: @@ -1304,7 +1304,6 @@ bool sema_analyse_var_decl(Context *context, Decl *decl) if (!sema_analyse_attributes_for_var(context, decl)) return false; - // TODO unify with global decl analysis if (is_global) { diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 728a8f54b..42b9f8a43 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -891,8 +891,6 @@ static inline bool sema_expand_call_arguments(Context *context, Expr *call, Decl unsigned entries_needed = func_param_count > num_args ? func_param_count : num_args; Expr **actual_args = VECNEW(Expr*, entries_needed); for (unsigned i = 0; i < entries_needed; i++) vec_add(actual_args, NULL); - // TODO this should not be needed: - memset(actual_args, 0, entries_needed * sizeof(Expr*)); // 2. Loop through the parameters. bool uses_named_parameters = false; @@ -2035,84 +2033,6 @@ static bool sema_expr_analyse_typeinfo(Context *context, Expr *expr) return true; } -/* -static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr) -{ - Type *type = expr->access_expr.parent->type->decl->member_decl.type_info->type; - Type *canonical = type->canonical; - const char *sub_element = TOKSTR(expr->access_expr.sub_element); - if (sub_element == kw_sizeof) - { - expr_rewrite_to_int_const(expr, type_usize, type_size(canonical)); - return true; - } - if (sub_element == kw_offsetof) - { - TODO // calculate offset. - } - // Possibly alignof - if (!type_may_have_sub_elements(type)) - { - SEMA_ERROR(expr, "'%s' does not have a member '%s'.", type_to_error_string(type), sub_element); - return false; - } - Decl *decl = canonical->decl; - - switch (decl->decl_kind) - { - case DECL_ENUM: - if (TOKTYPE(expr->access_expr.sub_element) == TOKEN_CONST_IDENT) - { - if (!sema_expr_analyse_enum_constant(expr, sub_element, decl)) - { - SEMA_ERROR(expr, - "'%s' has no enumeration value '%s'.", - decl->name, - sub_element); - return false; - } - return true; - } - break; - case DECL_ERR: - case DECL_UNION: - case DECL_STRUCT: - break; - default: - UNREACHABLE - } - - VECEACH(decl->methods, i) - { - Decl *function = decl->methods[i]; - if (sub_element == function->name) - { - expr->access_expr.ref = function; - expr->type = function->type; - return true; - } - } - - if (decl_is_struct_type(decl)) - { - VECEACH(decl->strukt.members, i) - { - Decl *member = decl->strukt.members[i]; - if (sub_element == member->name) - { - expr->access_expr.ref = member; - expr->type = member->member_decl.reference_type; - return true; - } - } - } - SEMA_ERROR(expr, - "No function or member '%s.%s' found.", - type_to_error_string(type), - sub_element); - return false; -} -*/ static void add_members_to_context(Context *context, Decl *decl) @@ -3635,7 +3555,7 @@ static bool sema_expr_analyse_common_assign(Context *context, Expr *expr, Expr * } // 4. In any case, these ops are only defined on numbers. - if (!type_is_numeric(left->type)) + if (!type_underlying_is_numeric(left->type)) { SEMA_ERROR(left, "Expected a numeric type here."); return false; @@ -3747,7 +3667,7 @@ static bool sema_expr_analyse_add_sub_assign(Context *context, Expr *expr, Expr if (!cast_implicit(right, left->type)) return false; // 9. We expect a numeric type on both left and right - if (!type_is_numeric(left->type)) + if (!type_underlying_is_numeric(left->type)) { SEMA_ERROR(left, "Expected a numeric type here."); return false; @@ -3779,7 +3699,7 @@ static bool binary_arithmetic_promotion(Context *context, Expr *left, Expr *righ { Type *max = numeric_arithmetic_promotion(type_find_max_type(left_type, right_type)); - if (!max || !type_is_numeric(max)) + if (!max || !type_underlying_is_numeric(max)) { if (!error_message) { @@ -4862,7 +4782,7 @@ static inline bool sema_expr_analyse_incdec(Context *context, Expr *expr, Expr * Type *type = type_flatten(inner->type); - if (!type_is_numeric(type) && type->type_kind != TYPE_POINTER) + if (!type_underlying_is_numeric(type) && type->type_kind != TYPE_POINTER) { SEMA_ERROR(inner, "Expression must be a number or a pointer."); return false; @@ -4914,7 +4834,7 @@ static inline bool sema_expr_analyse_binary(Context *context, Type *to, Expr *ex return expr_poison(expr); } // Don't push down bool conversions for example. - if (to && !type_is_numeric(to)) to = NULL; + if (to && !type_underlying_is_numeric(to)) to = NULL; switch (expr->binary_expr.operator) { case BINARYOP_ASSIGN: @@ -5915,18 +5835,18 @@ static inline bool sema_expr_analyse_ct_alignof(Context *context, Type *to, Expr } return false; } - Decl *decl = type->decl; + Decl *member; SCOPE_START add_members_to_context(context, type->decl); - decl = sema_resolve_symbol_in_current_dynamic_scope(context, element.ident); + member = sema_resolve_symbol_in_current_dynamic_scope(context, element.ident); SCOPE_END; - if (!decl) + if (!member) { SEMA_ERROR(first, "There is no such member in %s.", type_quoted_error_string(expr->ct_call_expr.type)); return false; } - type = decl->type; - align = type_min_alignment(decl->offset, align); + type = member->type; + align = type_min_alignment(member->offset, align); } expr_rewrite_to_int_const(expr, type_compint, align); diff --git a/src/compiler/types.c b/src/compiler/types.c index ac4670080..db1b54c50 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -1574,7 +1574,7 @@ Type *type_find_max_type(Type *type, Type *other) case TYPE_BITSTRUCT: return NULL; case TYPE_IXX: - if (other->type_kind == TYPE_DISTINCT && type_is_numeric(other->decl->distinct_decl.base_type)) return other; + if (other->type_kind == TYPE_DISTINCT && type_underlying_is_numeric(other)) return other; FALLTHROUGH; case ALL_SIGNED_INTS: case ALL_UNSIGNED_INTS: diff --git a/test/test_suite/expressions/ternary_bool.c3t b/test/test_suite/expressions/ternary_bool.c3t new file mode 100644 index 000000000..01b176ebb --- /dev/null +++ b/test/test_suite/expressions/ternary_bool.c3t @@ -0,0 +1,110 @@ +// #target: x64-darwin + +extern func void printf(char *, ...); + +func void main() +{ + + bool b = true; + bool* c = &b; + if (*c ? *c : *c) printf("Woa!\n"); + if (b ? b : b) printf("Woa!\n"); + if (*c ?: *c) printf("Woa!\n"); + if (b ?: b) printf("Woa!\n"); +} + +// #expect: ternary_bool.ll + +define void @main() #0 { +entry: + %b = alloca i8, align 1 + %c = alloca i8*, align 8 + store i8 1, i8* %b, align 1 + store i8* %b, i8** %c, align 8 + %0 = load i8*, i8** %c, align 8 + %1 = load i8, i8* %0, align 8 + %2 = trunc i8 %1 to i1 + br i1 %2, label %cond.lhs, label %cond.rhs + +cond.lhs: ; preds = %entry + %3 = load i8*, i8** %c, align 8 + %4 = load i8, i8* %3, align 8 + br label %cond.phi + +cond.rhs: ; preds = %entry + %5 = load i8*, i8** %c, align 8 + %6 = load i8, i8* %5, align 8 + br label %cond.phi + +cond.phi: ; preds = %cond.rhs, %cond.lhs + %val = phi i8 [ %4, %cond.lhs ], [ %6, %cond.rhs ] + %7 = trunc i8 %val to i1 + br i1 %7, label %if.then, label %if.exit + +if.then: ; preds = %cond.phi + call void (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i32 0, i32 0)) + br label %if.exit + +if.exit: ; preds = %if.then, %cond.phi + %8 = load i8, i8* %b, align 1 + %9 = trunc i8 %8 to i1 + br i1 %9, label %cond.lhs1, label %cond.rhs2 + +cond.lhs1: ; preds = %if.exit + %10 = load i8, i8* %b, align 1 + br label %cond.phi3 + +cond.rhs2: ; preds = %if.exit + %11 = load i8, i8* %b, align 1 + br label %cond.phi3 + +cond.phi3: ; preds = %cond.rhs2, %cond.lhs1 + %val4 = phi i8 [ %10, %cond.lhs1 ], [ %11, %cond.rhs2 ] + %12 = trunc i8 %val4 to i1 + br i1 %12, label %if.then5, label %if.exit6 + +if.then5: ; preds = %cond.phi3 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0)) + br label %if.exit6 + +if.exit6: ; preds = %if.then5, %cond.phi3 + %13 = load i8*, i8** %c, align 8 + %14 = load i8, i8* %13, align 8 + %15 = trunc i8 %14 to i1 + br i1 %15, label %cond.phi8, label %cond.rhs7 + +cond.rhs7: ; preds = %if.exit6 + %16 = load i8*, i8** %c, align 8 + %17 = load i8, i8* %16, align 8 + %18 = trunc i8 %17 to i1 + br label %cond.phi8 + +cond.phi8: ; preds = %cond.rhs7, %if.exit6 + %val9 = phi i1 [ %15, %if.exit6 ], [ %18, %cond.rhs7 ] + br i1 %val9, label %if.then10, label %if.exit11 + +if.then10: ; preds = %cond.phi8 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.2, i32 0, i32 0)) + br label %if.exit11 + +if.exit11: ; preds = %if.then10, %cond.phi8 + %19 = load i8, i8* %b, align 1 + %20 = trunc i8 %19 to i1 + br i1 %20, label %cond.phi13, label %cond.rhs12 + +cond.rhs12: ; preds = %if.exit11 + %21 = load i8, i8* %b, align 1 + %22 = trunc i8 %21 to i1 + br label %cond.phi13 + +cond.phi13: ; preds = %cond.rhs12, %if.exit11 + %val14 = phi i1 [ %20, %if.exit11 ], [ %22, %cond.rhs12 ] + br i1 %val14, label %if.then15, label %if.exit16 + +if.then15: ; preds = %cond.phi13 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.3, i32 0, i32 0)) + br label %if.exit16 + +if.exit16: ; preds = %if.then15, %cond.phi13 + ret void +}