authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-28 14:04:22-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-28 14:04:22-07:00
loga09b5055585a869bf5af522d19836e3f2c25fc5b
treef0be1c21f41b917b190e85fa14938cd5fe157d39
parent2fc4b3629a0fdcca04b5c107a70f0e159bca3e49

null pointer optimization for ?&T

this is necessary for the parseh change where all pointers from .h files are maybe pointers.

5 files changed, 152 insertions(+), 98 deletions(-)

README.md+5
...@@ -112,3 +112,8 @@ To fix this, you have 2 options:...@@ -112,3 +112,8 @@ To fix this, you have 2 options:
112112
113 * Compile Zig with the same compiler that LLVM was compiled with.113 * Compile Zig with the same compiler that LLVM was compiled with.
114 * Add `-DZIG_LLVM_OLD_CXX_ABI=yes` to the cmake configure line.114 * Add `-DZIG_LLVM_OLD_CXX_ABI=yes` to the cmake configure line.
115
116## Community
117
118Zig is in its infancy. However one place you can gather to chat is the `#zig`
119IRC channel on Freenode.
src/analyze.cpp+43-31
...@@ -199,43 +199,54 @@ static TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {...@@ -199,43 +199,54 @@ static TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
199 return entry;199 return entry;
200 } else {200 } else {
201 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMaybe);201 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMaybe);
202 // create a struct with a boolean whether this is the null value
203 assert(child_type->type_ref);202 assert(child_type->type_ref);
204 LLVMTypeRef elem_types[] = {203 assert(child_type->di_type);
205 child_type->type_ref,204
206 LLVMInt1Type(),
207 };
208 entry->type_ref = LLVMStructType(elem_types, 2, false);
209 buf_resize(&entry->name, 0);205 buf_resize(&entry->name, 0);
210 buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));206 buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));
211 entry->size_in_bits = child_type->size_in_bits + 8;
212 entry->align_in_bits = child_type->align_in_bits;
213 assert(child_type->di_type);
214207
208 if (child_type->id == TypeTableEntryIdPointer) {
209 // this is an optimization but also is necessary for calling C
210 // functions where all pointers are maybe pointers
211 entry->size_in_bits = child_type->size_in_bits;
212 entry->align_in_bits = child_type->align_in_bits;
213 entry->type_ref = child_type->type_ref;
214 entry->di_type = child_type->di_type;
215 } else {
216 // create a struct with a boolean whether this is the null value
217 LLVMTypeRef elem_types[] = {
218 child_type->type_ref,
219 LLVMInt1Type(),
220 };
221 entry->type_ref = LLVMStructType(elem_types, 2, false);
222 entry->size_in_bits = child_type->size_in_bits + 8;
223 entry->align_in_bits = child_type->align_in_bits;
215224
216 LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit);
217 LLVMZigDIFile *di_file = nullptr;
218 unsigned line = 0;
219 entry->di_type = LLVMZigCreateReplaceableCompositeType(g->dbuilder,
220 LLVMZigTag_DW_structure_type(), buf_ptr(&entry->name),
221 compile_unit_scope, di_file, line);
222225
223 LLVMZigDIType *di_element_types[] = {226 LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit);
224 LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),227 LLVMZigDIFile *di_file = nullptr;
225 "val", di_file, line, child_type->size_in_bits, child_type->align_in_bits, 0, 0,228 unsigned line = 0;
226 child_type->di_type),229 entry->di_type = LLVMZigCreateReplaceableCompositeType(g->dbuilder,
227 LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),230 LLVMZigTag_DW_structure_type(), buf_ptr(&entry->name),
228 "maybe", di_file, line, 8, 8, child_type->size_in_bits, 0,231 compile_unit_scope, di_file, line);
229 child_type->di_type),
230 };
231 LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
232 compile_unit_scope,
233 buf_ptr(&entry->name),
234 di_file, line, entry->size_in_bits, entry->align_in_bits, 0,
235 nullptr, di_element_types, 2, 0, nullptr, "");
236232
237 LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);233 LLVMZigDIType *di_element_types[] = {
238 entry->di_type = replacement_di_type;234 LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
235 "val", di_file, line, child_type->size_in_bits, child_type->align_in_bits, 0, 0,
236 child_type->di_type),
237 LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
238 "maybe", di_file, line, 8, 8, child_type->size_in_bits, 0,
239 child_type->di_type),
240 };
241 LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
242 compile_unit_scope,
243 buf_ptr(&entry->name),
244 di_file, line, entry->size_in_bits, entry->align_in_bits, 0,
245 nullptr, di_element_types, 2, 0, nullptr, "");
246
247 LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
248 entry->di_type = replacement_di_type;
249 }
239250
240 entry->data.maybe.child_type = child_type;251 entry->data.maybe.child_type = child_type;
241252
...@@ -5078,12 +5089,13 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {...@@ -5078,12 +5089,13 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
5078 return false;5089 return false;
5079 case TypeTableEntryIdArray:5090 case TypeTableEntryIdArray:
5080 case TypeTableEntryIdStruct:5091 case TypeTableEntryIdStruct:
5081 case TypeTableEntryIdMaybe:
5082 return true;5092 return true;
5083 case TypeTableEntryIdErrorUnion:5093 case TypeTableEntryIdErrorUnion:
5084 return type_entry->data.error.child_type->size_in_bits > 0;5094 return type_entry->data.error.child_type->size_in_bits > 0;
5085 case TypeTableEntryIdEnum:5095 case TypeTableEntryIdEnum:
5086 return type_entry->data.enumeration.gen_field_count != 0;5096 return type_entry->data.enumeration.gen_field_count != 0;
5097 case TypeTableEntryIdMaybe:
5098 return type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer;
5087 }5099 }
5088 zig_unreachable();5100 zig_unreachable();
5089}5101}
src/codegen.cpp+92-61
...@@ -74,7 +74,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);...@@ -74,7 +74,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);
74static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, TypeTableEntry **out_type_entry);74static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, TypeTableEntry **out_type_entry);
75static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue);75static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue);
76static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl,76static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl,
77 bool unwrap_maybe, LLVMValueRef *init_val);77 bool unwrap_maybe, LLVMValueRef *init_val, TypeTableEntry **init_val_type);
78static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op,78static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op,
79 LLVMValueRef target_ref, LLVMValueRef value,79 LLVMValueRef target_ref, LLVMValueRef value,
80 TypeTableEntry *op1_type, TypeTableEntry *op2_type);80 TypeTableEntry *op1_type, TypeTableEntry *op2_type);
...@@ -389,14 +389,20 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {...@@ -389,14 +389,20 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
389 assert(wanted_type->id == TypeTableEntryIdMaybe);389 assert(wanted_type->id == TypeTableEntryIdMaybe);
390 assert(actual_type);390 assert(actual_type);
391391
392 add_debug_source_node(g, node);392 TypeTableEntry *child_type = wanted_type->data.maybe.child_type;
393 LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 0, "");
394 gen_assign_raw(g, node, BinOpTypeAssign,
395 val_ptr, expr_val, wanted_type->data.maybe.child_type, actual_type);
396393
397 add_debug_source_node(g, node);394 if (child_type->id == TypeTableEntryIdPointer) {
398 LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 1, "");395 return expr_val;
399 LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);396 } else {
397 add_debug_source_node(g, node);
398 LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 0, "");
399 gen_assign_raw(g, node, BinOpTypeAssign,
400 val_ptr, expr_val, child_type, actual_type);
401
402 add_debug_source_node(g, node);
403 LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 1, "");
404 LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);
405 }
400406
401 return cast_expr->tmp_ptr;407 return cast_expr->tmp_ptr;
402 }408 }
...@@ -1245,10 +1251,20 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {...@@ -1245,10 +1251,20 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
1245}1251}
12461252
1247static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef maybe_struct_ref) {1253static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef maybe_struct_ref) {
1248 add_debug_source_node(g, node);1254 TypeTableEntry *type_entry = get_expr_type(node);
1249 LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 0, "");1255 assert(type_entry->id == TypeTableEntryIdMaybe);
1250 // TODO if it's a struct we might not want to load the pointer1256 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
1251 return LLVMBuildLoad(g->builder, maybe_field_ptr, "");1257 if (child_type->id == TypeTableEntryIdPointer) {
1258 return maybe_struct_ref;
1259 } else {
1260 add_debug_source_node(g, node);
1261 LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 0, "");
1262 if (handle_is_ptr(child_type)) {
1263 return maybe_field_ptr;
1264 } else {
1265 return LLVMBuildLoad(g->builder, maybe_field_ptr, "");
1266 }
1267 }
1252}1268}
12531269
1254static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) {1270static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) {
...@@ -1260,29 +1276,32 @@ static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) {...@@ -1260,29 +1276,32 @@ static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) {
12601276
1261 LLVMValueRef maybe_struct_ref = gen_expr(g, op1_node);1277 LLVMValueRef maybe_struct_ref = gen_expr(g, op1_node);
12621278
1263 add_debug_source_node(g, node);1279 TypeTableEntry *maybe_type = get_expr_type(op1_node);
1264 LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 1, "");1280 assert(maybe_type->id == TypeTableEntryIdMaybe);
1265 LLVMValueRef cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");1281 TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
1282
1283 LLVMValueRef cond_value;
1284 if (child_type->id == TypeTableEntryIdPointer) {
1285 cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, maybe_struct_ref,
1286 LLVMConstNull(child_type->type_ref), "");
1287 } else {
1288 add_debug_source_node(g, node);
1289 LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 1, "");
1290 cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");
1291 }
12661292
1267 LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNonNull");1293 LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNonNull");
1268 LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNull");1294 LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNull");
1269 LLVMBasicBlockRef end_block;1295 LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeEnd");
12701296
1271 bool non_null_reachable = get_expr_type(op1_node)->id != TypeTableEntryIdUnreachable;
1272 bool null_reachable = get_expr_type(op2_node)->id != TypeTableEntryIdUnreachable;1297 bool null_reachable = get_expr_type(op2_node)->id != TypeTableEntryIdUnreachable;
1273 bool end_reachable = non_null_reachable || null_reachable;
1274 if (end_reachable) {
1275 end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeEnd");
1276 }
12771298
1278 LLVMBuildCondBr(g->builder, cond_value, non_null_block, null_block);1299 LLVMBuildCondBr(g->builder, cond_value, non_null_block, null_block);
12791300
1280 LLVMPositionBuilderAtEnd(g->builder, non_null_block);1301 LLVMPositionBuilderAtEnd(g->builder, non_null_block);
1281 LLVMValueRef non_null_result = gen_unwrap_maybe(g, op1_node, maybe_struct_ref);1302 LLVMValueRef non_null_result = gen_unwrap_maybe(g, op1_node, maybe_struct_ref);
1282 if (non_null_reachable) {1303 add_debug_source_node(g, node);
1283 add_debug_source_node(g, node);1304 LLVMBuildBr(g->builder, end_block);
1284 LLVMBuildBr(g->builder, end_block);
1285 }
1286 LLVMBasicBlockRef post_non_null_result_block = LLVMGetInsertBlock(g->builder);1305 LLVMBasicBlockRef post_non_null_result_block = LLVMGetInsertBlock(g->builder);
12871306
1288 LLVMPositionBuilderAtEnd(g->builder, null_block);1307 LLVMPositionBuilderAtEnd(g->builder, null_block);
...@@ -1293,18 +1312,16 @@ static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) {...@@ -1293,18 +1312,16 @@ static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) {
1293 }1312 }
1294 LLVMBasicBlockRef post_null_result_block = LLVMGetInsertBlock(g->builder);1313 LLVMBasicBlockRef post_null_result_block = LLVMGetInsertBlock(g->builder);
12951314
1296 if (end_reachable) {1315 LLVMPositionBuilderAtEnd(g->builder, end_block);
1297 LLVMPositionBuilderAtEnd(g->builder, end_block);1316 if (null_reachable) {
1298 if (null_reachable) {1317 add_debug_source_node(g, node);
1299 add_debug_source_node(g, node);1318 LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(non_null_result), "");
1300 LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(non_null_result), "");1319 LLVMValueRef incoming_values[2] = {non_null_result, null_result};
1301 LLVMValueRef incoming_values[2] = {non_null_result, null_result};1320 LLVMBasicBlockRef incoming_blocks[2] = {post_non_null_result_block, post_null_result_block};
1302 LLVMBasicBlockRef incoming_blocks[2] = {post_non_null_result_block, post_null_result_block};1321 LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
1303 LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);1322 return phi;
1304 return phi;1323 } else {
1305 } else {1324 return non_null_result;
1306 return non_null_result;
1307 }
1308 }1325 }
13091326
1310 return nullptr;1327 return nullptr;
...@@ -1607,12 +1624,20 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {...@@ -1607,12 +1624,20 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {
1607 assert(node->data.if_var_expr.var_decl.expr);1624 assert(node->data.if_var_expr.var_decl.expr);
16081625
1609 LLVMValueRef init_val;1626 LLVMValueRef init_val;
1610 gen_var_decl_raw(g, node, &node->data.if_var_expr.var_decl, true, &init_val);1627 TypeTableEntry *expr_type;
1628 gen_var_decl_raw(g, node, &node->data.if_var_expr.var_decl, true, &init_val, &expr_type);
16111629
1612 // test if value is the maybe state1630 // test if value is the maybe state
1613 add_debug_source_node(g, node);1631 assert(expr_type->id == TypeTableEntryIdMaybe);
1614 LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, init_val, 1, "");1632 TypeTableEntry *child_type = expr_type->data.maybe.child_type;
1615 LLVMValueRef cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");1633 LLVMValueRef cond_value;
1634 if (child_type->id == TypeTableEntryIdPointer) {
1635 cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, init_val, LLVMConstNull(child_type->type_ref), "");
1636 } else {
1637 add_debug_source_node(g, node);
1638 LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, init_val, 1, "");
1639 cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");
1640 }
16161641
1617 LLVMValueRef return_value = gen_if_bool_expr_raw(g, node, cond_value,1642 LLVMValueRef return_value = gen_if_bool_expr_raw(g, node, cond_value,
1618 node->data.if_var_expr.then_block,1643 node->data.if_var_expr.then_block,
...@@ -1978,7 +2003,7 @@ static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) {...@@ -1978,7 +2003,7 @@ static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) {
1978}2003}
19792004
1980static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl,2005static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl,
1981 bool unwrap_maybe, LLVMValueRef *init_value)2006 bool unwrap_maybe, LLVMValueRef *init_value, TypeTableEntry **expr_type)
1982{2007{
1983 VariableTableEntry *variable = var_decl->variable;2008 VariableTableEntry *variable = var_decl->variable;
19842009
...@@ -1987,6 +2012,7 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa...@@ -1987,6 +2012,7 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
19872012
1988 if (var_decl->expr) {2013 if (var_decl->expr) {
1989 *init_value = gen_expr(g, var_decl->expr);2014 *init_value = gen_expr(g, var_decl->expr);
2015 *expr_type = get_expr_type(var_decl->expr);
1990 }2016 }
1991 if (variable->type->size_in_bits == 0) {2017 if (variable->type->size_in_bits == 0) {
1992 return nullptr;2018 return nullptr;
...@@ -2005,7 +2031,7 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa...@@ -2005,7 +2031,7 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
2005 if (unwrap_maybe) {2031 if (unwrap_maybe) {
2006 assert(var_decl->expr);2032 assert(var_decl->expr);
2007 assert(expr_type->id == TypeTableEntryIdMaybe);2033 assert(expr_type->id == TypeTableEntryIdMaybe);
2008 value = gen_unwrap_maybe(g, source_node, *init_value);2034 value = gen_unwrap_maybe(g, var_decl->expr, *init_value);
2009 expr_type = expr_type->data.maybe.child_type;2035 expr_type = expr_type->data.maybe.child_type;
2010 } else {2036 } else {
2011 value = *init_value;2037 value = *init_value;
...@@ -2089,7 +2115,8 @@ static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {...@@ -2089,7 +2115,8 @@ static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {
2089 }2115 }
20902116
2091 LLVMValueRef init_val;2117 LLVMValueRef init_val;
2092 return gen_var_decl_raw(g, node, &node->data.variable_declaration, false, &init_val);2118 TypeTableEntry *init_val_type;
2119 return gen_var_decl_raw(g, node, &node->data.variable_declaration, false, &init_val, &init_val_type);
2093}2120}
20942121
2095static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {2122static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
...@@ -2100,11 +2127,7 @@ static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {...@@ -2100,11 +2127,7 @@ static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
2100 return nullptr;2127 return nullptr;
2101 } else if (variable->is_ptr) {2128 } else if (variable->is_ptr) {
2102 assert(variable->value_ref);2129 assert(variable->value_ref);
2103 if (variable->type->id == TypeTableEntryIdArray) {2130 if (handle_is_ptr(variable->type)) {
2104 return variable->value_ref;
2105 } else if (variable->type->id == TypeTableEntryIdStruct ||
2106 variable->type->id == TypeTableEntryIdMaybe)
2107 {
2108 return variable->value_ref;2131 return variable->value_ref;
2109 } else {2132 } else {
2110 add_debug_source_node(g, node);2133 add_debug_source_node(g, node);
...@@ -2330,20 +2353,28 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE...@@ -2330,20 +2353,28 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
2330 case TypeTableEntryIdMaybe:2353 case TypeTableEntryIdMaybe:
2331 {2354 {
2332 TypeTableEntry *child_type = type_entry->data.maybe.child_type;2355 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
2333 LLVMValueRef child_val;2356 if (child_type->id == TypeTableEntryIdPointer) {
2334 LLVMValueRef maybe_val;2357 if (const_val->data.x_maybe) {
2335 if (const_val->data.x_maybe) {2358 return gen_const_val(g, child_type, const_val->data.x_maybe);
2336 child_val = gen_const_val(g, child_type, const_val->data.x_maybe);2359 } else {
2337 maybe_val = LLVMConstAllOnes(LLVMInt1Type());2360 return LLVMConstNull(child_type->type_ref);
2361 }
2338 } else {2362 } else {
2339 child_val = LLVMConstNull(child_type->type_ref);2363 LLVMValueRef child_val;
2340 maybe_val = LLVMConstNull(LLVMInt1Type());2364 LLVMValueRef maybe_val;
2365 if (const_val->data.x_maybe) {
2366 child_val = gen_const_val(g, child_type, const_val->data.x_maybe);
2367 maybe_val = LLVMConstAllOnes(LLVMInt1Type());
2368 } else {
2369 child_val = LLVMConstNull(child_type->type_ref);
2370 maybe_val = LLVMConstNull(LLVMInt1Type());
2371 }
2372 LLVMValueRef fields[] = {
2373 child_val,
2374 maybe_val,
2375 };
2376 return LLVMConstStruct(fields, 2, false);
2341 }2377 }
2342 LLVMValueRef fields[] = {
2343 child_val,
2344 maybe_val,
2345 };
2346 return LLVMConstStruct(fields, 2, false);
2347 }2378 }
2348 case TypeTableEntryIdStruct:2379 case TypeTableEntryIdStruct:
2349 {2380 {
src/parseh.cpp+11-5
...@@ -97,6 +97,14 @@ static AstNode *create_var_decl_node(Context *c, const char *var_name, AstNode *...@@ -97,6 +97,14 @@ static AstNode *create_var_decl_node(Context *c, const char *var_name, AstNode *
97 return node;97 return node;
98}98}
9999
100static AstNode *create_prefix_node(Context *c, PrefixOp op, AstNode *child_node) {
101 AstNode *node = create_node(c, NodeTypePrefixOpExpr);
102 node->data.prefix_op_expr.prefix_op = op;
103 node->data.prefix_op_expr.primary_expr = child_node;
104 normalize_parent_ptrs(node);
105 return node;
106}
107
100static const char *decl_name(const Decl *decl) {108static const char *decl_name(const Decl *decl) {
101 const NamedDecl *named_decl = static_cast<const NamedDecl *>(decl);109 const NamedDecl *named_decl = static_cast<const NamedDecl *>(decl);
102 return (const char *)named_decl->getName().bytes_begin();110 return (const char *)named_decl->getName().bytes_begin();
...@@ -132,11 +140,9 @@ static AstNode *pointer_to_type(Context *c, AstNode *type_node, bool is_const) {...@@ -132,11 +140,9 @@ static AstNode *pointer_to_type(Context *c, AstNode *type_node, bool is_const) {
132 if (!type_node) {140 if (!type_node) {
133 return nullptr;141 return nullptr;
134 }142 }
135 AstNode *node = create_node(c, NodeTypePrefixOpExpr);143 PrefixOp op = is_const ? PrefixOpConstAddressOf : PrefixOpAddressOf;
136 node->data.prefix_op_expr.prefix_op = is_const ? PrefixOpConstAddressOf : PrefixOpAddressOf;144 AstNode *child_node = create_prefix_node(c, op, convert_to_c_void(c, type_node));
137 node->data.prefix_op_expr.primary_expr = convert_to_c_void(c, type_node);145 return create_prefix_node(c, PrefixOpMaybe, child_node);
138 normalize_parent_ptrs(node);
139 return node;
140}146}
141147
142static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl) {148static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl) {
test/run_tests.cpp+1-1
...@@ -1827,7 +1827,7 @@ pub const Foo = enum_Foo;)OUTPUT");...@@ -1827,7 +1827,7 @@ pub const Foo = enum_Foo;)OUTPUT");
1827 add_parseh_case("restrict -> noalias", R"SOURCE(1827 add_parseh_case("restrict -> noalias", R"SOURCE(
1828void foo(void *restrict bar, void *restrict);1828void foo(void *restrict bar, void *restrict);
1829 )SOURCE", R"OUTPUT(pub const c_void = u8;1829 )SOURCE", R"OUTPUT(pub const c_void = u8;
1830pub extern fn foo(noalias bar: &c_void, noalias arg1: &c_void);)OUTPUT");1830pub extern fn foo(noalias bar: ?&c_void, noalias arg1: ?&c_void);)OUTPUT");
1831}1831}
18321832
1833static void print_compiler_invocation(TestCase *test_case) {1833static void print_compiler_invocation(TestCase *test_case) {