authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-21 15:23:24-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-21 15:23:24-07:00
logb09a0cd0727055217742cb178822521733078c27
treeac851b52831016a2f8bd5fb5ca6be6279e1bac76
parent32e2196257b2650e41b683d16bf00ba77ccfbb13

allow constants to have number literal values

also codegen takes advantage of constant expr eval

4 files changed, 176 insertions(+), 47 deletions(-)

src/all_types.hpp+2
...@@ -90,6 +90,7 @@ struct Expr {...@@ -90,6 +90,7 @@ struct Expr {
90 Cast implicit_cast; // happens first90 Cast implicit_cast; // happens first
91 Cast implicit_maybe_cast; // happens second91 Cast implicit_maybe_cast; // happens second
9292
93 LLVMValueRef const_llvm_val;
93 ConstExprValue const_val;94 ConstExprValue const_val;
94};95};
9596
...@@ -955,6 +956,7 @@ struct CodeGen {...@@ -955,6 +956,7 @@ struct CodeGen {
955 // there will not be a corresponding fn_defs entry.956 // there will not be a corresponding fn_defs entry.
956 ZigList<FnTableEntry *> fn_protos;957 ZigList<FnTableEntry *> fn_protos;
957 ZigList<VariableTableEntry *> global_vars;958 ZigList<VariableTableEntry *> global_vars;
959 ZigList<Expr *> global_const_list;
958960
959 OutType out_type;961 OutType out_type;
960 FnTableEntry *cur_fn;962 FnTableEntry *cur_fn;
src/analyze.cpp+54-6
...@@ -1667,7 +1667,13 @@ static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node,...@@ -1667,7 +1667,13 @@ static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node,
1667static TypeTableEntry *resolve_expr_const_val_as_other_expr(CodeGen *g, AstNode *node, AstNode *other) {1667static TypeTableEntry *resolve_expr_const_val_as_other_expr(CodeGen *g, AstNode *node, AstNode *other) {
1668 Expr *expr = get_resolved_expr(node);1668 Expr *expr = get_resolved_expr(node);
1669 Expr *other_expr = get_resolved_expr(other);1669 Expr *other_expr = get_resolved_expr(other);
1670 expr->const_val = other_expr->const_val;1670 ConstExprValue *other_const_val;
1671 if (other_expr->implicit_maybe_cast.after_type) {
1672 other_const_val = &other_expr->implicit_maybe_cast.const_val;
1673 } else {
1674 other_const_val = &other_expr->const_val;
1675 }
1676 expr->const_val = *other_const_val;
1671 return other_expr->type_entry;1677 return other_expr->type_entry;
1672}1678}
16731679
...@@ -1766,8 +1772,14 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,...@@ -1766,8 +1772,14 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,
1766 AstNode *decl_node = var->decl_node;1772 AstNode *decl_node = var->decl_node;
1767 if (decl_node->type == NodeTypeVariableDeclaration) {1773 if (decl_node->type == NodeTypeVariableDeclaration) {
1768 AstNode *expr_node = decl_node->data.variable_declaration.expr;1774 AstNode *expr_node = decl_node->data.variable_declaration.expr;
1769 ConstExprValue *const_val = &get_resolved_expr(expr_node)->const_val;1775 Expr *other_expr = get_resolved_expr(expr_node);
1770 if (const_val->ok) {1776 ConstExprValue *other_const_val;
1777 if (other_expr->implicit_maybe_cast.after_type) {
1778 other_const_val = &other_expr->implicit_maybe_cast.const_val;
1779 } else {
1780 other_const_val = &other_expr->const_val;
1781 }
1782 if (other_const_val->ok) {
1771 return resolve_expr_const_val_as_other_expr(g, node, expr_node);1783 return resolve_expr_const_val_as_other_expr(g, node, expr_node);
1772 }1784 }
1773 }1785 }
...@@ -2206,6 +2218,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa...@@ -2206,6 +2218,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
2206 bool expr_is_maybe)2218 bool expr_is_maybe)
2207{2219{
2208 bool is_const = variable_declaration->is_const;2220 bool is_const = variable_declaration->is_const;
2221 bool is_export = (variable_declaration->visib_mod == VisibModExport);
22092222
2210 TypeTableEntry *explicit_type = nullptr;2223 TypeTableEntry *explicit_type = nullptr;
2211 if (variable_declaration->type != nullptr) {2224 if (variable_declaration->type != nullptr) {
...@@ -2233,7 +2246,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa...@@ -2233,7 +2246,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
2233 add_node_error(g, source_node,2246 add_node_error(g, source_node,
2234 buf_sprintf("variable initialization is unreachable"));2247 buf_sprintf("variable initialization is unreachable"));
2235 implicit_type = g->builtin_types.entry_invalid;2248 implicit_type = g->builtin_types.entry_invalid;
2236 } else if (!is_const &&2249 } else if ((!is_const || is_export) &&
2237 (implicit_type->id == TypeTableEntryIdNumLitFloat ||2250 (implicit_type->id == TypeTableEntryIdNumLitFloat ||
2238 implicit_type->id == TypeTableEntryIdNumLitInt))2251 implicit_type->id == TypeTableEntryIdNumLitInt))
2239 {2252 {
...@@ -3273,6 +3286,33 @@ static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import,...@@ -3273,6 +3286,33 @@ static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import,
3273 return g->builtin_types.entry_unreachable;3286 return g->builtin_types.entry_unreachable;
3274}3287}
32753288
3289static bool type_has_codegen_value(TypeTableEntryId id) {
3290 switch (id) {
3291 case TypeTableEntryIdInvalid:
3292 case TypeTableEntryIdMetaType:
3293 case TypeTableEntryIdVoid:
3294 case TypeTableEntryIdUnreachable:
3295 return false;
3296
3297 // TODO make num lits return false when we make implicit casts insert ast nodes
3298 case TypeTableEntryIdNumLitFloat:
3299 case TypeTableEntryIdNumLitInt:
3300
3301 case TypeTableEntryIdBool:
3302 case TypeTableEntryIdInt:
3303 case TypeTableEntryIdFloat:
3304 case TypeTableEntryIdPointer:
3305 case TypeTableEntryIdArray:
3306 case TypeTableEntryIdStruct:
3307 case TypeTableEntryIdMaybe:
3308 case TypeTableEntryIdError:
3309 case TypeTableEntryIdEnum:
3310 case TypeTableEntryIdFn:
3311 return true;
3312 }
3313 zig_unreachable();
3314}
3315
3276static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,3316static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
3277 TypeTableEntry *expected_type, AstNode *node)3317 TypeTableEntry *expected_type, AstNode *node)
3278{3318{
...@@ -3457,14 +3497,22 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -3457,14 +3497,22 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
3457 resolve_type_compatibility(g, context, node, expected_type, return_type);3497 resolve_type_compatibility(g, context, node, expected_type, return_type);
34583498
3459 Expr *expr = get_resolved_expr(node);3499 Expr *expr = get_resolved_expr(node);
3460 expr->type_entry = return_type;3500 if (!expr->resolved_type) {
3501 expr->resolved_type = return_type;
3502 }
3503 expr->type_entry = expr->resolved_type;
3461 expr->block_context = context;3504 expr->block_context = context;
34623505
3506 if (expr->const_val.ok && type_has_codegen_value(expr->resolved_type->id)) {
3507 g->global_const_list.append(expr);
3508 }
3509
3510
3463 if (expr->type_entry->id == TypeTableEntryIdUnreachable) {3511 if (expr->type_entry->id == TypeTableEntryIdUnreachable) {
3464 return expr->type_entry;3512 return expr->type_entry;
3465 }3513 }
34663514
3467 /*3515 /* TODO delete this code when we make implicit casts insert ast nodes
3468 Cast *cast_node = &expr->implicit_cast;3516 Cast *cast_node = &expr->implicit_cast;
3469 if (cast_node->after_type) {3517 if (cast_node->after_type) {
3470 eval_const_expr_implicit_cast(g, import, context, node, cast_node, node);3518 eval_const_expr_implicit_cast(g, import, context, node, cast_node, node);
src/codegen.cpp+119-40
...@@ -134,38 +134,6 @@ static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_no...@@ -134,38 +134,6 @@ static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_no
134 }134 }
135}135}
136136
137static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *expr_node) {
138 Expr *expr = get_resolved_expr(expr_node);
139 TypeTableEntry *type_entry = expr->resolved_type;
140 if (!type_entry) {
141 type_entry = expr->type_entry;
142 }
143 assert(type_entry);
144
145 ConstExprValue *const_val = &expr->const_val;
146
147 assert(const_val->ok);
148
149 if (type_entry->id == TypeTableEntryIdInt) {
150 assert(const_val->data.x_bignum.kind == BigNumKindInt);
151 return LLVMConstInt(type_entry->type_ref,
152 bignum_to_twos_complement(&const_val->data.x_bignum),
153 type_entry->data.integral.is_signed);
154 } else if (type_entry->id == TypeTableEntryIdFloat) {
155 if (const_val->data.x_bignum.kind == BigNumKindFloat) {
156 return LLVMConstReal(type_entry->type_ref, const_val->data.x_bignum.data.x_float);
157 } else {
158 int64_t x = const_val->data.x_bignum.data.x_uint;
159 if (const_val->data.x_bignum.is_negative) {
160 x = -x;
161 }
162 return LLVMConstReal(type_entry->type_ref, x);
163 }
164 } else {
165 zig_unreachable();
166 }
167}
168
169static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {137static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
170 assert(node->type == NodeTypeFnCallExpr);138 assert(node->type == NodeTypeFnCallExpr);
171 AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;139 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) {...@@ -277,7 +245,8 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
277 case BuiltinFnIdMinValue:245 case BuiltinFnIdMinValue:
278 case BuiltinFnIdMaxValue:246 case BuiltinFnIdMaxValue:
279 case BuiltinFnIdMemberCount:247 case BuiltinFnIdMemberCount:
280 return gen_number_literal(g, node);248 // caught by constant expression eval codegen
249 zig_unreachable();
281 }250 }
282 zig_unreachable();251 zig_unreachable();
283}252}
...@@ -1884,6 +1853,16 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa...@@ -1884,6 +1853,16 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
1884}1853}
18851854
1886static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {1855static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {
1856 AstNode *init_expr = node->data.variable_declaration.expr;
1857 if (node->data.variable_declaration.is_const && init_expr) {
1858 TypeTableEntry *init_expr_type = get_expr_type(init_expr);
1859 if (init_expr_type->id == TypeTableEntryIdNumLitFloat ||
1860 init_expr_type->id == TypeTableEntryIdNumLitInt)
1861 {
1862 return nullptr;
1863 }
1864 }
1865
1887 LLVMValueRef init_val;1866 LLVMValueRef init_val;
1888 return gen_var_decl_raw(g, node, &node->data.variable_declaration,1867 return gen_var_decl_raw(g, node, &node->data.variable_declaration,
1889 get_resolved_expr(node)->block_context, false, &init_val);1868 get_resolved_expr(node)->block_context, false, &init_val);
...@@ -1992,6 +1971,11 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {...@@ -1992,6 +1971,11 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
1992}1971}
19931972
1994static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {1973static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
1974 Expr *expr = get_resolved_expr(node);
1975 if (expr->const_val.ok) {
1976 assert(expr->const_llvm_val);
1977 return expr->const_llvm_val;
1978 }
1995 switch (node->type) {1979 switch (node->type) {
1996 case NodeTypeBinOpExpr:1980 case NodeTypeBinOpExpr:
1997 return gen_bin_op_expr(g, node);1981 return gen_bin_op_expr(g, node);
...@@ -2009,11 +1993,6 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {...@@ -2009,11 +1993,6 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
2009 return gen_slice_expr(g, node);1993 return gen_slice_expr(g, node);
2010 case NodeTypeFieldAccessExpr:1994 case NodeTypeFieldAccessExpr:
2011 return gen_field_access_expr(g, node, false);1995 return gen_field_access_expr(g, node, false);
2012 case NodeTypeBoolLiteral:
2013 if (node->data.bool_literal.value)
2014 return LLVMConstAllOnes(LLVMInt1Type());
2015 else
2016 return LLVMConstNull(LLVMInt1Type());
2017 case NodeTypeNullLiteral:1996 case NodeTypeNullLiteral:
2018 return gen_null_literal(g, node);1997 return gen_null_literal(g, node);
2019 case NodeTypeIfBoolExpr:1998 case NodeTypeIfBoolExpr:
...@@ -2026,8 +2005,6 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {...@@ -2026,8 +2005,6 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
2026 return gen_for_expr(g, node);2005 return gen_for_expr(g, node);
2027 case NodeTypeAsmExpr:2006 case NodeTypeAsmExpr:
2028 return gen_asm_expr(g, node);2007 return gen_asm_expr(g, node);
2029 case NodeTypeNumberLiteral:
2030 return gen_number_literal(g, node);
2031 case NodeTypeErrorLiteral:2008 case NodeTypeErrorLiteral:
2032 return gen_error_literal(g, node);2009 return gen_error_literal(g, node);
2033 case NodeTypeStringLiteral:2010 case NodeTypeStringLiteral:
...@@ -2070,6 +2047,10 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {...@@ -2070,6 +2047,10 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
2070 return gen_container_init_expr(g, node);2047 return gen_container_init_expr(g, node);
2071 case NodeTypeSwitchExpr:2048 case NodeTypeSwitchExpr:
2072 return gen_switch_expr(g, node);2049 return gen_switch_expr(g, node);
2050 case NodeTypeNumberLiteral:
2051 case NodeTypeBoolLiteral:
2052 // caught by constant expression eval codegen
2053 zig_unreachable();
2073 case NodeTypeRoot:2054 case NodeTypeRoot:
2074 case NodeTypeRootExportDecl:2055 case NodeTypeRootExportDecl:
2075 case NodeTypeFnProto:2056 case NodeTypeFnProto:
...@@ -2129,16 +2110,114 @@ static void build_label_blocks(CodeGen *g, AstNode *block_node) {...@@ -2129,16 +2110,114 @@ static void build_label_blocks(CodeGen *g, AstNode *block_node) {
2129 label_node->data.label.label_entry->basic_block = LLVMAppendBasicBlock(2110 label_node->data.label.label_entry->basic_block = LLVMAppendBasicBlock(
2130 g->cur_fn->fn_value, buf_ptr(name));2111 g->cur_fn->fn_value, buf_ptr(name));
2131 }2112 }
2113}
21322114
2115static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val) {
2116 assert(const_val->ok);
2117
2118 if (type_entry->id == TypeTableEntryIdInt) {
2119 return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false);
2120 } else if (type_entry->id == TypeTableEntryIdFloat) {
2121 if (const_val->data.x_bignum.kind == BigNumKindFloat) {
2122 return LLVMConstReal(type_entry->type_ref, const_val->data.x_bignum.data.x_float);
2123 } else {
2124 int64_t x = const_val->data.x_bignum.data.x_uint;
2125 if (const_val->data.x_bignum.is_negative) {
2126 x = -x;
2127 }
2128 return LLVMConstReal(type_entry->type_ref, x);
2129 }
2130 } else if (type_entry->id == TypeTableEntryIdBool) {
2131 if (const_val->data.x_bool) {
2132 return LLVMConstAllOnes(LLVMInt1Type());
2133 } else {
2134 return LLVMConstNull(LLVMInt1Type());
2135 }
2136 } else if (type_entry->id == TypeTableEntryIdMaybe) {
2137 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
2138 LLVMValueRef child_val;
2139 LLVMValueRef maybe_val;
2140 if (const_val->data.x_maybe) {
2141 child_val = gen_const_val(g, child_type, const_val->data.x_maybe);
2142 maybe_val = LLVMConstAllOnes(LLVMInt1Type());
2143 } else {
2144 child_val = LLVMConstNull(child_type->type_ref);
2145 maybe_val = LLVMConstNull(LLVMInt1Type());
2146 }
2147 LLVMValueRef fields[] = {
2148 child_val,
2149 maybe_val,
2150 };
2151 return LLVMConstStruct(fields, 2, false);
2152 } else if (type_entry->id == TypeTableEntryIdStruct) {
2153 zig_panic("TODO");
2154 } else if (type_entry->id == TypeTableEntryIdArray) {
2155 zig_panic("TODO");
2156 } else if (type_entry->id == TypeTableEntryIdEnum) {
2157 LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref;
2158 LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, const_val->data.x_enum.tag, false);
2159 if (type_entry->data.enumeration.gen_field_count == 0) {
2160 return tag_value;
2161 } else {
2162 zig_panic("TODO");
2163 /*
2164 LLVMValueRef fields[] = {
2165 tag_value,
2166 union_value,
2167 };
2168 return LLVMConstStruct(fields, 2, false);
2169 */
2170 }
2171 } else if (type_entry->id == TypeTableEntryIdFn) {
2172 return const_val->data.x_fn->fn_value;
2173 } else {
2174 zig_unreachable();
2175 }
2176}
2177
2178static void gen_const_globals(CodeGen *g) {
2179 for (int i = 0; i < g->global_const_list.length; i += 1) {
2180 Expr *expr = g->global_const_list.at(i);
2181 ConstExprValue *const_val = &expr->const_val;
2182 assert(const_val->ok);
2183 TypeTableEntry *type_entry = expr->resolved_type;
2184
2185 // TODO delete this if when we make implicit casts insert ast nodes
2186 if (type_entry->id == TypeTableEntryIdNumLitFloat ||
2187 type_entry->id == TypeTableEntryIdNumLitInt)
2188 {
2189 continue;
2190 }
2191
2192 if (handle_is_ptr(type_entry)) {
2193 LLVMValueRef global_value = LLVMAddGlobal(g->module, type_entry->type_ref, "");
2194 LLVMSetLinkage(global_value, LLVMPrivateLinkage);
2195 LLVMValueRef init_val = gen_const_val(g, type_entry, const_val);
2196 LLVMSetInitializer(global_value, init_val);
2197 LLVMSetGlobalConstant(global_value, true);
2198 LLVMSetUnnamedAddr(global_value, true);
2199 expr->const_llvm_val = global_value;
2200 } else {
2201 expr->const_llvm_val = gen_const_val(g, type_entry, const_val);
2202 }
2203 }
2133}2204}
21342205
2135static void do_code_gen(CodeGen *g) {2206static void do_code_gen(CodeGen *g) {
2136 assert(!g->errors.length);2207 assert(!g->errors.length);
21372208
2209 gen_const_globals(g);
2210
2138 // Generate module level variables2211 // Generate module level variables
2139 for (int i = 0; i < g->global_vars.length; i += 1) {2212 for (int i = 0; i < g->global_vars.length; i += 1) {
2140 VariableTableEntry *var = g->global_vars.at(i);2213 VariableTableEntry *var = g->global_vars.at(i);
21412214
2215 if (var->type->id == TypeTableEntryIdNumLitFloat ||
2216 var->type->id == TypeTableEntryIdNumLitInt)
2217 {
2218 continue;
2219 }
2220
2142 // TODO if the global is exported, set external linkage2221 // TODO if the global is exported, set external linkage
2143 LLVMValueRef global_value = LLVMAddGlobal(g->module, var->type->type_ref, "");2222 LLVMValueRef global_value = LLVMAddGlobal(g->module, var->type->type_ref, "");
2144 LLVMSetLinkage(global_value, LLVMPrivateLinkage);2223 LLVMSetLinkage(global_value, LLVMPrivateLinkage);
test/run_tests.cpp+1-1
...@@ -866,7 +866,7 @@ pub fn main(args: [][]u8) i32 => {...@@ -866,7 +866,7 @@ pub fn main(args: [][]u8) i32 => {
866}866}
867 )SOURCE", "20\n");867 )SOURCE", "20\n");
868868
869 add_simple_case("#min_value() and #max_value()", R"SOURCE(869 add_simple_case("@min_value() and @max_value()", R"SOURCE(
870import "std.zig";870import "std.zig";
871pub fn main(args: [][]u8) i32 => {871pub fn main(args: [][]u8) i32 => {
872 print_str("max u8: ");872 print_str("max u8: ");