aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2016-01-07 03:23:38 -0700
committerAndrew Kelley <superjoe30@gmail.com>2016-01-07 03:23:38 -0700
commita3c97081ca37a6f78732c9a5f2244cef5a11cb07 (patch)
treeaec69a113eacaa084039364b65ef803d695e0dd5 /src/codegen.cpp
parent9b9fd5ad23e37d1e2b37b05b168abcfd53f4629d (diff)
downloadzig-a3c97081ca37a6f78732c9a5f2244cef5a11cb07.tar.gz
zig-a3c97081ca37a6f78732c9a5f2244cef5a11cb07.zip
add ?? maybe unwrapping binary operator
add null literal fix number literal / maybe interactions
Diffstat (limited to 'src/codegen.cpp')
-rw-r--r--src/codegen.cpp90
1 files changed, 86 insertions, 4 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 3f4262364e..0f4499c48d 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -613,6 +613,7 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
case BinOpTypeAssign:
case BinOpTypeAssignBoolAnd:
case BinOpTypeAssignBoolOr:
+ case BinOpTypeUnwrapMaybe:
zig_unreachable();
}
zig_unreachable();
@@ -814,6 +815,70 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
return gen_assign_raw(g, node, node->data.bin_op_expr.bin_op, target_ref, value, op1_type, op2_type);
}
+static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef maybe_struct_ref) {
+ add_debug_source_node(g, node);
+ LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 0, "");
+ // TODO if it's a struct we might not want to load the pointer
+ return LLVMBuildLoad(g->builder, maybe_field_ptr, "");
+}
+
+static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) {
+ assert(node->type == NodeTypeBinOpExpr);
+ assert(node->data.bin_op_expr.bin_op == BinOpTypeUnwrapMaybe);
+
+ AstNode *op1_node = node->data.bin_op_expr.op1;
+ AstNode *op2_node = node->data.bin_op_expr.op2;
+
+ LLVMValueRef maybe_struct_ref = gen_expr(g, op1_node);
+
+ add_debug_source_node(g, node);
+ LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 1, "");
+ LLVMValueRef cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");
+
+ LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNonNull");
+ LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNull");
+ LLVMBasicBlockRef end_block;
+
+ bool non_null_reachable = get_expr_type(op1_node)->id != TypeTableEntryIdUnreachable;
+ bool null_reachable = get_expr_type(op2_node)->id != TypeTableEntryIdUnreachable;
+ bool end_reachable = non_null_reachable || null_reachable;
+ if (end_reachable) {
+ end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeEnd");
+ }
+
+ LLVMBuildCondBr(g->builder, cond_value, non_null_block, null_block);
+
+ LLVMPositionBuilderAtEnd(g->builder, non_null_block);
+ LLVMValueRef non_null_result = gen_unwrap_maybe(g, op1_node, maybe_struct_ref);
+ if (non_null_reachable) {
+ add_debug_source_node(g, node);
+ LLVMBuildBr(g->builder, end_block);
+ }
+
+ LLVMPositionBuilderAtEnd(g->builder, null_block);
+ LLVMValueRef null_result = gen_expr(g, op2_node);
+ if (null_reachable) {
+ add_debug_source_node(g, node);
+ LLVMBuildBr(g->builder, end_block);
+ }
+
+ if (end_reachable) {
+ LLVMPositionBuilderAtEnd(g->builder, end_block);
+ if (null_reachable) {
+ add_debug_source_node(g, node);
+ LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(non_null_result), "");
+ LLVMValueRef incoming_values[2] = {non_null_result, null_result};
+ LLVMBasicBlockRef incoming_blocks[2] = {non_null_block, null_block};
+ LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
+ return phi;
+ } else {
+ return non_null_result;
+ }
+ }
+
+ return nullptr;
+}
+
static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
switch (node->data.bin_op_expr.bin_op) {
case BinOpTypeInvalid:
@@ -843,6 +908,8 @@ static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
case BinOpTypeCmpLessOrEq:
case BinOpTypeCmpGreaterOrEq:
return gen_cmp_expr(g, node);
+ case BinOpTypeUnwrapMaybe:
+ return gen_unwrap_maybe_expr(g, node);
case BinOpTypeBinOr:
case BinOpTypeBinXor:
case BinOpTypeBinAnd:
@@ -1124,6 +1191,22 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");
}
+static LLVMValueRef gen_null_literal(CodeGen *g, AstNode *node) {
+ assert(node->type == NodeTypeNullLiteral);
+
+ TypeTableEntry *type_entry = get_expr_type(node);
+ assert(type_entry->id == TypeTableEntryIdMaybe);
+
+ LLVMValueRef tmp_struct_ptr = node->codegen_node->data.struct_val_expr_node.ptr;
+
+ add_debug_source_node(g, node);
+ LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, "");
+ LLVMValueRef null_value = LLVMConstNull(LLVMInt1Type());
+ LLVMBuildStore(g->builder, null_value, field_ptr);
+
+ return tmp_struct_ptr;
+}
+
static LLVMValueRef gen_struct_val_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeStructValueExpr);
@@ -1242,10 +1325,7 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
LLVMValueRef value;
if (unwrap_maybe) {
assert(var_decl->expr);
- add_debug_source_node(g, source_node);
- LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, *init_value, 0, "");
- // TODO if it's a struct we might not want to load the pointer
- value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");
+ value = gen_unwrap_maybe(g, source_node, *init_value);
} else {
value = *init_value;
}
@@ -1375,6 +1455,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
return LLVMConstAllOnes(LLVMInt1Type());
else
return LLVMConstNull(LLVMInt1Type());
+ case NodeTypeNullLiteral:
+ return gen_null_literal(g, node);
case NodeTypeIfBoolExpr:
return gen_if_bool_expr(g, node);
case NodeTypeIfVarExpr: