Fixed bool->bool casts. Fixed ternary with boolean "legs". Removed some superfluous code.

This commit is contained in:
Christoffer Lerno
2021-08-28 13:09:46 +02:00
committed by Christoffer Lerno
parent 8731634f4d
commit 6e386538dc
7 changed files with 141 additions and 130 deletions

View File

@@ -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)

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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:

View 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
}