LLVMValueRef gen_expr(compile_t* c, ast_t* ast) { LLVMValueRef ret; bool has_scope = ast_has_scope(ast); if(has_scope) codegen_pushscope(c, ast); switch(ast_id(ast)) { case TK_SEQ: ret = gen_seq(c, ast); break; case TK_FVARREF: case TK_FLETREF: ret = gen_fieldload(c, ast); break; case TK_EMBEDREF: ret = gen_fieldptr(c, ast); break; case TK_PARAMREF: ret = gen_param(c, ast); break; case TK_VAR: case TK_LET: case TK_MATCH_CAPTURE: ret = gen_localdecl(c, ast); break; case TK_VARREF: case TK_LETREF: ret = gen_localload(c, ast); break; case TK_IF: ret = gen_if(c, ast); break; case TK_WHILE: ret = gen_while(c, ast); break; case TK_REPEAT: ret = gen_repeat(c, ast); break; case TK_TRY: case TK_TRY_NO_CHECK: ret = gen_try(c, ast); break; case TK_MATCH: ret = gen_match(c, ast); break; case TK_CALL: ret = gen_call(c, ast); break; case TK_CONSUME: ret = gen_expr(c, ast_childidx(ast, 1)); break; case TK_RECOVER: ret = gen_expr(c, ast_childidx(ast, 1)); break; case TK_BREAK: ret = gen_break(c, ast); break; case TK_CONTINUE: ret = gen_continue(c, ast); break; case TK_RETURN: ret = gen_return(c, ast); break; case TK_ERROR: ret = gen_error(c, ast); break; case TK_IS: ret = gen_is(c, ast); break; case TK_ISNT: ret = gen_isnt(c, ast); break; case TK_ASSIGN: ret = gen_assign(c, ast); break; case TK_THIS: ret = gen_this(c, ast); break; case TK_TRUE: ret = LLVMConstInt(c->i1, 1, false); break; case TK_FALSE: ret = LLVMConstInt(c->i1, 0, false); break; case TK_INT: ret = gen_int(c, ast); break; case TK_FLOAT: ret = gen_float(c, ast); break; case TK_STRING: ret = gen_string(c, ast); break; case TK_TUPLE: ret = gen_tuple(c, ast); break; case TK_FFICALL: ret = gen_ffi(c, ast); break; case TK_ADDRESS: ret = gen_addressof(c, ast); break; case TK_DIGESTOF: ret = gen_digestof(c, ast); break; case TK_DONTCARE: ret = GEN_NOVALUE; break; case TK_COMPILE_INTRINSIC: ast_error(c->opt->check.errors, ast, "unimplemented compile intrinsic"); return NULL; case TK_COMPILE_ERROR: { ast_t* reason_seq = ast_child(ast); ast_t* reason = ast_child(reason_seq); ast_error(c->opt->check.errors, ast, "compile error: %s", ast_name(reason)); return NULL; } default: ast_error(c->opt->check.errors, ast, "not implemented (codegen unknown)"); return NULL; } if(has_scope) codegen_popscope(c); return ret; }
LLVMValueRef gen_expr(compile_t* c, ast_t* ast) { LLVMValueRef ret; bool has_scope = ast_has_scope(ast); bool has_source = codegen_hassource(c); if(has_scope) { codegen_pushscope(c); // Dwarf a new lexical scope, if necessary. if(has_source) dwarf_lexicalscope(&c->dwarf, ast); } switch(ast_id(ast)) { case TK_SEQ: ret = gen_seq(c, ast); break; case TK_FVARREF: case TK_FLETREF: ret = gen_fieldload(c, ast); break; case TK_PARAMREF: ret = gen_param(c, ast); break; case TK_VAR: case TK_LET: ret = gen_localdecl(c, ast); break; case TK_VARREF: case TK_LETREF: ret = gen_localload(c, ast); break; case TK_IF: ret = gen_if(c, ast); break; case TK_WHILE: ret = gen_while(c, ast); break; case TK_REPEAT: ret = gen_repeat(c, ast); break; case TK_TRY: case TK_TRY_NO_CHECK: ret = gen_try(c, ast); break; case TK_MATCH: ret = gen_match(c, ast); break; case TK_CALL: ret = gen_call(c, ast); break; case TK_CONSUME: ret = gen_expr(c, ast_childidx(ast, 1)); break; case TK_RECOVER: ret = gen_expr(c, ast_childidx(ast, 1)); break; case TK_BREAK: ret = gen_break(c, ast); break; case TK_CONTINUE: ret = gen_continue(c, ast); break; case TK_RETURN: ret = gen_return(c, ast); break; case TK_ERROR: ret = gen_error(c, ast); break; case TK_IS: ret = gen_is(c, ast); break; case TK_ISNT: ret = gen_isnt(c, ast); break; case TK_ASSIGN: ret = gen_assign(c, ast); break; case TK_THIS: ret = gen_this(c, ast); break; case TK_TRUE: ret = LLVMConstInt(c->i1, 1, false); break; case TK_FALSE: ret = LLVMConstInt(c->i1, 0, false); break; case TK_INT: ret = gen_int(c, ast); break; case TK_FLOAT: ret = gen_float(c, ast); break; case TK_STRING: ret = gen_string(c, ast); break; case TK_TUPLE: ret = gen_tuple(c, ast); break; case TK_FFICALL: ret = gen_ffi(c, ast); break; case TK_AMP: ret = gen_addressof(c, ast); break; case TK_IDENTITY: ret = gen_identity(c, ast); break; case TK_DONTCARE: ret = GEN_NOVALUE; break; case TK_COMPILER_INTRINSIC: ast_error(ast, "unimplemented compiler intrinsic"); LLVMBuildUnreachable(c->builder); ret = GEN_NOVALUE; break; default: ast_error(ast, "not implemented (codegen unknown)"); return NULL; } if(has_scope) { codegen_popscope(c); if(has_source) dwarf_finish(&c->dwarf); } return ret; }
LLVMValueRef gen_match(compile_t* c, ast_t* ast) { bool needed = is_result_needed(ast); ast_t* type = ast_type(ast); AST_GET_CHILDREN(ast, match_expr, cases, else_expr); // We will have no type if all case have control types. LLVMTypeRef phi_type = NULL; if(needed && !is_control_type(type)) { reach_type_t* t_phi = reach_type(c->reach, type); phi_type = t_phi->use_type; } ast_t* match_type = alias(ast_type(match_expr)); LLVMValueRef match_value = gen_expr(c, match_expr); LLVMBasicBlockRef pattern_block = codegen_block(c, "case_pattern"); LLVMBasicBlockRef else_block = codegen_block(c, "match_else"); LLVMBasicBlockRef post_block = NULL; LLVMBasicBlockRef next_block = NULL; // Jump to the first case. LLVMBuildBr(c->builder, pattern_block); LLVMValueRef phi = GEN_NOVALUE; if(!is_control_type(type)) { // Start the post block so that a case can modify the phi node. post_block = codegen_block(c, "match_post"); LLVMPositionBuilderAtEnd(c->builder, post_block); if(needed) phi = LLVMBuildPhi(c->builder, phi_type, ""); else phi = GEN_NOTNEEDED; } // Iterate over the cases. ast_t* the_case = ast_child(cases); while(the_case != NULL) { ast_t* next_case = ast_sibling(the_case); if(next_case != NULL) next_block = codegen_block(c, "case_pattern"); else next_block = else_block; AST_GET_CHILDREN(the_case, pattern, guard, body); LLVMPositionBuilderAtEnd(c->builder, pattern_block); codegen_pushscope(c, the_case); ast_t* pattern_type = ast_type(pattern); bool ok = true; if(is_matchtype(match_type, pattern_type, c->opt) != MATCHTYPE_ACCEPT) { // If there's no possible match, jump directly to the next block. LLVMBuildBr(c->builder, next_block); } else { // Check the pattern. ok = static_match(c, match_value, match_type, pattern, next_block); // Check the guard. ok = ok && guard_match(c, guard, next_block); // Case body. ok = ok && case_body(c, body, post_block, phi, phi_type); } codegen_popscope(c); if(!ok) { ast_free_unattached(match_type); return NULL; } the_case = next_case; pattern_block = next_block; } ast_free_unattached(match_type); // Else body. LLVMPositionBuilderAtEnd(c->builder, else_block); codegen_pushscope(c, else_expr); bool ok = case_body(c, else_expr, post_block, phi, phi_type); codegen_popscope(c); if(!ok) return NULL; if(post_block != NULL) LLVMPositionBuilderAtEnd(c->builder, post_block); return phi; }