mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Fixed bool->bool casts. Fixed ternary with boolean "legs". Removed some superfluous code.
This commit is contained in:
committed by
Christoffer Lerno
parent
8731634f4d
commit
6e386538dc
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
110
test/test_suite/expressions/ternary_bool.c3t
Normal file
110
test/test_suite/expressions/ternary_bool.c3t
Normal file
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user