allow constants to have number literal values
also codegen takes advantage of constant expr eval
This commit is contained in:
parent
32e2196257
commit
b09a0cd072
|
@ -90,6 +90,7 @@ struct Expr {
|
|||
Cast implicit_cast; // happens first
|
||||
Cast implicit_maybe_cast; // happens second
|
||||
|
||||
LLVMValueRef const_llvm_val;
|
||||
ConstExprValue const_val;
|
||||
};
|
||||
|
||||
|
@ -955,6 +956,7 @@ struct CodeGen {
|
|||
// there will not be a corresponding fn_defs entry.
|
||||
ZigList<FnTableEntry *> fn_protos;
|
||||
ZigList<VariableTableEntry *> global_vars;
|
||||
ZigList<Expr *> global_const_list;
|
||||
|
||||
OutType out_type;
|
||||
FnTableEntry *cur_fn;
|
||||
|
|
|
@ -1667,7 +1667,13 @@ static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node,
|
|||
static TypeTableEntry *resolve_expr_const_val_as_other_expr(CodeGen *g, AstNode *node, AstNode *other) {
|
||||
Expr *expr = get_resolved_expr(node);
|
||||
Expr *other_expr = get_resolved_expr(other);
|
||||
expr->const_val = other_expr->const_val;
|
||||
ConstExprValue *other_const_val;
|
||||
if (other_expr->implicit_maybe_cast.after_type) {
|
||||
other_const_val = &other_expr->implicit_maybe_cast.const_val;
|
||||
} else {
|
||||
other_const_val = &other_expr->const_val;
|
||||
}
|
||||
expr->const_val = *other_const_val;
|
||||
return other_expr->type_entry;
|
||||
}
|
||||
|
||||
|
@ -1766,8 +1772,14 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,
|
|||
AstNode *decl_node = var->decl_node;
|
||||
if (decl_node->type == NodeTypeVariableDeclaration) {
|
||||
AstNode *expr_node = decl_node->data.variable_declaration.expr;
|
||||
ConstExprValue *const_val = &get_resolved_expr(expr_node)->const_val;
|
||||
if (const_val->ok) {
|
||||
Expr *other_expr = get_resolved_expr(expr_node);
|
||||
ConstExprValue *other_const_val;
|
||||
if (other_expr->implicit_maybe_cast.after_type) {
|
||||
other_const_val = &other_expr->implicit_maybe_cast.const_val;
|
||||
} else {
|
||||
other_const_val = &other_expr->const_val;
|
||||
}
|
||||
if (other_const_val->ok) {
|
||||
return resolve_expr_const_val_as_other_expr(g, node, expr_node);
|
||||
}
|
||||
}
|
||||
|
@ -2206,6 +2218,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
|
|||
bool expr_is_maybe)
|
||||
{
|
||||
bool is_const = variable_declaration->is_const;
|
||||
bool is_export = (variable_declaration->visib_mod == VisibModExport);
|
||||
|
||||
TypeTableEntry *explicit_type = nullptr;
|
||||
if (variable_declaration->type != nullptr) {
|
||||
|
@ -2233,7 +2246,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
|
|||
add_node_error(g, source_node,
|
||||
buf_sprintf("variable initialization is unreachable"));
|
||||
implicit_type = g->builtin_types.entry_invalid;
|
||||
} else if (!is_const &&
|
||||
} else if ((!is_const || is_export) &&
|
||||
(implicit_type->id == TypeTableEntryIdNumLitFloat ||
|
||||
implicit_type->id == TypeTableEntryIdNumLitInt))
|
||||
{
|
||||
|
@ -3273,6 +3286,33 @@ static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import,
|
|||
return g->builtin_types.entry_unreachable;
|
||||
}
|
||||
|
||||
static bool type_has_codegen_value(TypeTableEntryId id) {
|
||||
switch (id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdVoid:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
return false;
|
||||
|
||||
// TODO make num lits return false when we make implicit casts insert ast nodes
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
case TypeTableEntryIdNumLitInt:
|
||||
|
||||
case TypeTableEntryIdBool:
|
||||
case TypeTableEntryIdInt:
|
||||
case TypeTableEntryIdFloat:
|
||||
case TypeTableEntryIdPointer:
|
||||
case TypeTableEntryIdArray:
|
||||
case TypeTableEntryIdStruct:
|
||||
case TypeTableEntryIdMaybe:
|
||||
case TypeTableEntryIdError:
|
||||
case TypeTableEntryIdEnum:
|
||||
case TypeTableEntryIdFn:
|
||||
return true;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
TypeTableEntry *expected_type, AstNode *node)
|
||||
{
|
||||
|
@ -3457,14 +3497,22 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
|
|||
resolve_type_compatibility(g, context, node, expected_type, return_type);
|
||||
|
||||
Expr *expr = get_resolved_expr(node);
|
||||
expr->type_entry = return_type;
|
||||
if (!expr->resolved_type) {
|
||||
expr->resolved_type = return_type;
|
||||
}
|
||||
expr->type_entry = expr->resolved_type;
|
||||
expr->block_context = context;
|
||||
|
||||
if (expr->const_val.ok && type_has_codegen_value(expr->resolved_type->id)) {
|
||||
g->global_const_list.append(expr);
|
||||
}
|
||||
|
||||
|
||||
if (expr->type_entry->id == TypeTableEntryIdUnreachable) {
|
||||
return expr->type_entry;
|
||||
}
|
||||
|
||||
/*
|
||||
/* TODO delete this code when we make implicit casts insert ast nodes
|
||||
Cast *cast_node = &expr->implicit_cast;
|
||||
if (cast_node->after_type) {
|
||||
eval_const_expr_implicit_cast(g, import, context, node, cast_node, node);
|
||||
|
|
159
src/codegen.cpp
159
src/codegen.cpp
|
@ -134,38 +134,6 @@ static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_no
|
|||
}
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *expr_node) {
|
||||
Expr *expr = get_resolved_expr(expr_node);
|
||||
TypeTableEntry *type_entry = expr->resolved_type;
|
||||
if (!type_entry) {
|
||||
type_entry = expr->type_entry;
|
||||
}
|
||||
assert(type_entry);
|
||||
|
||||
ConstExprValue *const_val = &expr->const_val;
|
||||
|
||||
assert(const_val->ok);
|
||||
|
||||
if (type_entry->id == TypeTableEntryIdInt) {
|
||||
assert(const_val->data.x_bignum.kind == BigNumKindInt);
|
||||
return LLVMConstInt(type_entry->type_ref,
|
||||
bignum_to_twos_complement(&const_val->data.x_bignum),
|
||||
type_entry->data.integral.is_signed);
|
||||
} else if (type_entry->id == TypeTableEntryIdFloat) {
|
||||
if (const_val->data.x_bignum.kind == BigNumKindFloat) {
|
||||
return LLVMConstReal(type_entry->type_ref, const_val->data.x_bignum.data.x_float);
|
||||
} else {
|
||||
int64_t x = const_val->data.x_bignum.data.x_uint;
|
||||
if (const_val->data.x_bignum.is_negative) {
|
||||
x = -x;
|
||||
}
|
||||
return LLVMConstReal(type_entry->type_ref, x);
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
|
||||
assert(node->type == NodeTypeFnCallExpr);
|
||||
AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
|
||||
|
@ -277,7 +245,8 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
|
|||
case BuiltinFnIdMinValue:
|
||||
case BuiltinFnIdMaxValue:
|
||||
case BuiltinFnIdMemberCount:
|
||||
return gen_number_literal(g, node);
|
||||
// caught by constant expression eval codegen
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
@ -1884,6 +1853,16 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
|
|||
}
|
||||
|
||||
static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {
|
||||
AstNode *init_expr = node->data.variable_declaration.expr;
|
||||
if (node->data.variable_declaration.is_const && init_expr) {
|
||||
TypeTableEntry *init_expr_type = get_expr_type(init_expr);
|
||||
if (init_expr_type->id == TypeTableEntryIdNumLitFloat ||
|
||||
init_expr_type->id == TypeTableEntryIdNumLitInt)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
LLVMValueRef init_val;
|
||||
return gen_var_decl_raw(g, node, &node->data.variable_declaration,
|
||||
get_resolved_expr(node)->block_context, false, &init_val);
|
||||
|
@ -1992,6 +1971,11 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
|
|||
}
|
||||
|
||||
static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
|
||||
Expr *expr = get_resolved_expr(node);
|
||||
if (expr->const_val.ok) {
|
||||
assert(expr->const_llvm_val);
|
||||
return expr->const_llvm_val;
|
||||
}
|
||||
switch (node->type) {
|
||||
case NodeTypeBinOpExpr:
|
||||
return gen_bin_op_expr(g, node);
|
||||
|
@ -2009,11 +1993,6 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
|
|||
return gen_slice_expr(g, node);
|
||||
case NodeTypeFieldAccessExpr:
|
||||
return gen_field_access_expr(g, node, false);
|
||||
case NodeTypeBoolLiteral:
|
||||
if (node->data.bool_literal.value)
|
||||
return LLVMConstAllOnes(LLVMInt1Type());
|
||||
else
|
||||
return LLVMConstNull(LLVMInt1Type());
|
||||
case NodeTypeNullLiteral:
|
||||
return gen_null_literal(g, node);
|
||||
case NodeTypeIfBoolExpr:
|
||||
|
@ -2026,8 +2005,6 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
|
|||
return gen_for_expr(g, node);
|
||||
case NodeTypeAsmExpr:
|
||||
return gen_asm_expr(g, node);
|
||||
case NodeTypeNumberLiteral:
|
||||
return gen_number_literal(g, node);
|
||||
case NodeTypeErrorLiteral:
|
||||
return gen_error_literal(g, node);
|
||||
case NodeTypeStringLiteral:
|
||||
|
@ -2070,6 +2047,10 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
|
|||
return gen_container_init_expr(g, node);
|
||||
case NodeTypeSwitchExpr:
|
||||
return gen_switch_expr(g, node);
|
||||
case NodeTypeNumberLiteral:
|
||||
case NodeTypeBoolLiteral:
|
||||
// caught by constant expression eval codegen
|
||||
zig_unreachable();
|
||||
case NodeTypeRoot:
|
||||
case NodeTypeRootExportDecl:
|
||||
case NodeTypeFnProto:
|
||||
|
@ -2129,16 +2110,114 @@ static void build_label_blocks(CodeGen *g, AstNode *block_node) {
|
|||
label_node->data.label.label_entry->basic_block = LLVMAppendBasicBlock(
|
||||
g->cur_fn->fn_value, buf_ptr(name));
|
||||
}
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val) {
|
||||
assert(const_val->ok);
|
||||
|
||||
if (type_entry->id == TypeTableEntryIdInt) {
|
||||
return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false);
|
||||
} else if (type_entry->id == TypeTableEntryIdFloat) {
|
||||
if (const_val->data.x_bignum.kind == BigNumKindFloat) {
|
||||
return LLVMConstReal(type_entry->type_ref, const_val->data.x_bignum.data.x_float);
|
||||
} else {
|
||||
int64_t x = const_val->data.x_bignum.data.x_uint;
|
||||
if (const_val->data.x_bignum.is_negative) {
|
||||
x = -x;
|
||||
}
|
||||
return LLVMConstReal(type_entry->type_ref, x);
|
||||
}
|
||||
} else if (type_entry->id == TypeTableEntryIdBool) {
|
||||
if (const_val->data.x_bool) {
|
||||
return LLVMConstAllOnes(LLVMInt1Type());
|
||||
} else {
|
||||
return LLVMConstNull(LLVMInt1Type());
|
||||
}
|
||||
} else if (type_entry->id == TypeTableEntryIdMaybe) {
|
||||
TypeTableEntry *child_type = type_entry->data.maybe.child_type;
|
||||
LLVMValueRef child_val;
|
||||
LLVMValueRef maybe_val;
|
||||
if (const_val->data.x_maybe) {
|
||||
child_val = gen_const_val(g, child_type, const_val->data.x_maybe);
|
||||
maybe_val = LLVMConstAllOnes(LLVMInt1Type());
|
||||
} else {
|
||||
child_val = LLVMConstNull(child_type->type_ref);
|
||||
maybe_val = LLVMConstNull(LLVMInt1Type());
|
||||
}
|
||||
LLVMValueRef fields[] = {
|
||||
child_val,
|
||||
maybe_val,
|
||||
};
|
||||
return LLVMConstStruct(fields, 2, false);
|
||||
} else if (type_entry->id == TypeTableEntryIdStruct) {
|
||||
zig_panic("TODO");
|
||||
} else if (type_entry->id == TypeTableEntryIdArray) {
|
||||
zig_panic("TODO");
|
||||
} else if (type_entry->id == TypeTableEntryIdEnum) {
|
||||
LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref;
|
||||
LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, const_val->data.x_enum.tag, false);
|
||||
if (type_entry->data.enumeration.gen_field_count == 0) {
|
||||
return tag_value;
|
||||
} else {
|
||||
zig_panic("TODO");
|
||||
/*
|
||||
LLVMValueRef fields[] = {
|
||||
tag_value,
|
||||
union_value,
|
||||
};
|
||||
return LLVMConstStruct(fields, 2, false);
|
||||
*/
|
||||
}
|
||||
} else if (type_entry->id == TypeTableEntryIdFn) {
|
||||
return const_val->data.x_fn->fn_value;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_const_globals(CodeGen *g) {
|
||||
for (int i = 0; i < g->global_const_list.length; i += 1) {
|
||||
Expr *expr = g->global_const_list.at(i);
|
||||
ConstExprValue *const_val = &expr->const_val;
|
||||
assert(const_val->ok);
|
||||
TypeTableEntry *type_entry = expr->resolved_type;
|
||||
|
||||
// TODO delete this if when we make implicit casts insert ast nodes
|
||||
if (type_entry->id == TypeTableEntryIdNumLitFloat ||
|
||||
type_entry->id == TypeTableEntryIdNumLitInt)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (handle_is_ptr(type_entry)) {
|
||||
LLVMValueRef global_value = LLVMAddGlobal(g->module, type_entry->type_ref, "");
|
||||
LLVMSetLinkage(global_value, LLVMPrivateLinkage);
|
||||
LLVMValueRef init_val = gen_const_val(g, type_entry, const_val);
|
||||
LLVMSetInitializer(global_value, init_val);
|
||||
LLVMSetGlobalConstant(global_value, true);
|
||||
LLVMSetUnnamedAddr(global_value, true);
|
||||
expr->const_llvm_val = global_value;
|
||||
} else {
|
||||
expr->const_llvm_val = gen_const_val(g, type_entry, const_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void do_code_gen(CodeGen *g) {
|
||||
assert(!g->errors.length);
|
||||
|
||||
gen_const_globals(g);
|
||||
|
||||
// Generate module level variables
|
||||
for (int i = 0; i < g->global_vars.length; i += 1) {
|
||||
VariableTableEntry *var = g->global_vars.at(i);
|
||||
|
||||
if (var->type->id == TypeTableEntryIdNumLitFloat ||
|
||||
var->type->id == TypeTableEntryIdNumLitInt)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO if the global is exported, set external linkage
|
||||
LLVMValueRef global_value = LLVMAddGlobal(g->module, var->type->type_ref, "");
|
||||
LLVMSetLinkage(global_value, LLVMPrivateLinkage);
|
||||
|
|
|
@ -866,7 +866,7 @@ pub fn main(args: [][]u8) i32 => {
|
|||
}
|
||||
)SOURCE", "20\n");
|
||||
|
||||
add_simple_case("#min_value() and #max_value()", R"SOURCE(
|
||||
add_simple_case("@min_value() and @max_value()", R"SOURCE(
|
||||
import "std.zig";
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
print_str("max u8: ");
|
||||
|
|
Loading…
Reference in New Issue
Block a user