From c2e5d50027779468c66608f445f3ab0f77d34c15 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 24 Nov 2015 13:00:38 -0700 Subject: [PATCH] write object file and fix void return type --- CMakeLists.txt | 5 +---- src/codegen.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++++--- src/codegen.hpp | 9 ++++++++ src/hash_map.hpp | 7 ++++++ src/main.cpp | 4 ++++ src/parser.cpp | 20 ++++++++++++++---- src/parser.hpp | 7 ++++++ src/tokenizer.cpp | 1 + src/zig_llvm.cpp | 45 +++++++++++++++++++++++++++++++++++++++ src/zig_llvm.hpp | 24 +++++++++++++++++++++ test/hello.zig | 7 +++--- 11 files changed, 169 insertions(+), 14 deletions(-) create mode 100644 src/zig_llvm.cpp create mode 100644 src/zig_llvm.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index cdeacca7f..5310a16d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ set(ZIG_SOURCES "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" "${CMAKE_SOURCE_DIR}/src/util.cpp" "${CMAKE_SOURCE_DIR}/src/codegen.cpp" + "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" ) set(CONFIGURE_OUT_FILE "${CMAKE_BINARY_DIR}/config.h") @@ -38,10 +39,6 @@ configure_file ( ${CONFIGURE_OUT_FILE} ) -# GTFO, -lstdc++ !! -set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "") -set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "") - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wno-unused-variable -Wno-unused-but-set-variable") set(EXE_CFLAGS "-std=c++11 -Werror -Wall -Werror=strict-prototypes -Werror=old-style-definition -Werror=missing-prototypes") diff --git a/src/codegen.cpp b/src/codegen.cpp index f1aaf8439..0577e98c5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1,11 +1,16 @@ +/* + * Copyright (c) 2015 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + #include "codegen.hpp" #include "hash_map.hpp" +#include "zig_llvm.hpp" #include -#include -#include - struct FnTableEntry { LLVMValueRef fn_value; AstNode *proto_node; @@ -49,6 +54,7 @@ static void add_node_error(CodeGen *g, AstNode *node, Buf *msg) { static LLVMTypeRef to_llvm_type(AstNode *type_node) { assert(type_node->type == NodeTypeType); assert(type_node->codegen_node); + assert(type_node->codegen_node->data.type_ref); return type_node->codegen_node->data.type_ref; } @@ -134,9 +140,12 @@ static void analyze_node(CodeGen *g, AstNode *node) { node->codegen_node->data.type_ref = LLVMInt8Type(); } else if (buf_eql_str(name, "i32")) { node->codegen_node->data.type_ref = LLVMInt32Type(); + } else if (buf_eql_str(name, "void")) { + node->codegen_node->data.type_ref = LLVMVoidType(); } else { add_node_error(g, node, buf_sprintf("invalid type name: '%s'", buf_ptr(name))); + node->codegen_node->data.type_ref = LLVMInt8Type(); } break; } @@ -339,3 +348,42 @@ void code_gen(CodeGen *g) { ZigList *codegen_error_messages(CodeGen *g) { return &g->errors; } + + +void code_gen_link(CodeGen *g, bool is_static, const char *out_file) { + LLVMInitializeAllTargets(); + LLVMInitializeAllTargetMCs(); + LLVMInitializeAllAsmPrinters(); + LLVMInitializeAllAsmParsers(); + LLVMInitializeNativeTarget(); + + + LLVMPassRegistryRef registry = LLVMGetGlobalPassRegistry(); + LLVMInitializeCore(registry); + LLVMInitializeCodeGen(registry); + LLVMZigInitializeLoopStrengthReducePass(registry); + LLVMZigInitializeLowerIntrinsicsPass(registry); + LLVMZigInitializeUnreachableBlockElimPass(registry); + + char *native_triple = LLVMGetDefaultTargetTriple(); + + LLVMTargetRef target_ref; + char *err_msg = nullptr; + if (LLVMGetTargetFromTriple(native_triple, &target_ref, &err_msg)) { + zig_panic("unable to get target from triple: %s", err_msg); + } + + char *native_cpu = LLVMZigGetHostCPUName(); + char *native_features = LLVMZigGetNativeFeatures(); + + LLVMCodeGenOptLevel opt_level = LLVMCodeGenLevelNone; + + LLVMRelocMode reloc_mode = is_static ? LLVMRelocStatic : LLVMRelocPIC; + + LLVMTargetMachineRef target_machine = LLVMCreateTargetMachine(target_ref, native_triple, + native_cpu, native_features, opt_level, reloc_mode, LLVMCodeModelDefault); + + if (LLVMTargetMachineEmitToFile(target_machine, g->mod, strdup(out_file), LLVMObjectFile, &err_msg)) { + zig_panic("unable to write object file: %s", err_msg); + } +} diff --git a/src/codegen.hpp b/src/codegen.hpp index 1cffdf585..814c49fcb 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2015 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + #ifndef ZIG_CODEGEN_HPP #define ZIG_CODEGEN_HPP @@ -20,6 +27,8 @@ void semantic_analyze(CodeGen *g); void code_gen(CodeGen *g); +void code_gen_link(CodeGen *g, bool is_static, const char *out_file); + ZigList *codegen_error_messages(CodeGen *g); #endif diff --git a/src/hash_map.hpp b/src/hash_map.hpp index 1e3f921e9..0892349ad 100644 --- a/src/hash_map.hpp +++ b/src/hash_map.hpp @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2015 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + #ifndef ZIG_HASH_MAP_HPP #define ZIG_HASH_MAP_HPP diff --git a/src/main.cpp b/src/main.cpp index cf94ce4a6..6ef75d209 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -112,6 +112,10 @@ static int build(const char *arg0, const char *in_file, const char *out_file, Zi fprintf(stderr, "------------------\n"); code_gen(codegen); + fprintf(stderr, "\nLink:\n"); + fprintf(stderr, "------------------\n"); + code_gen_link(codegen, false, out_file); + return 0; } diff --git a/src/parser.cpp b/src/parser.cpp index cd90e8e97..72052e414 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2015 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + #include "parser.hpp" #include @@ -168,6 +175,13 @@ static AstNode *ast_create_node_with_node(NodeType type, AstNode *other_node) { return node; } +static AstNode *ast_create_void_type_node(ParseContext *pc, Token *token) { + AstNode *node = ast_create_node(NodeTypeType, token); + node->data.type.type = AstNodeTypeTypePrimitive; + buf_init_from_str(&node->data.type.primitive_name, "void"); + return node; +} + static void ast_buf_from_token(ParseContext *pc, Token *token, Buf *buf) { buf_init_from_mem(buf, buf_ptr(pc->buf) + token->start_pos, token->end_pos - token->start_pos); } @@ -468,13 +482,11 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int token_index, int *new_t ast_parse_param_decl_list(pc, token_index, &token_index, &node->data.fn_proto.params); Token *arrow = &pc->tokens->at(token_index); - token_index += 1; if (arrow->id == TokenIdArrow) { + token_index += 1; node->data.fn_proto.return_type = ast_parse_type(pc, token_index, &token_index); - } else if (arrow->id == TokenIdLBrace) { - node->data.fn_proto.return_type = nullptr; } else { - ast_invalid_token_error(pc, arrow); + node->data.fn_proto.return_type = ast_create_void_type_node(pc, arrow); } *new_token_index = token_index; diff --git a/src/parser.hpp b/src/parser.hpp index e084aba13..501749eea 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2015 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + #ifndef ZIG_PARSER_HPP #define ZIG_PARSER_HPP diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 129b10766..fafc5b1f3 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -170,6 +170,7 @@ ZigList *tokenize(Buf *buf, Buf *cur_dir_path) { case WHITESPACE: break; case ALPHA: + case '_': t.state = TokenizeStateSymbol; begin_token(&t, TokenIdSymbol); break; diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp new file mode 100644 index 000000000..2f064a297 --- /dev/null +++ b/src/zig_llvm.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + +#include "zig_llvm.hpp" + +#include +#include +#include + + +using namespace llvm; + +void LLVMZigInitializeLoopStrengthReducePass(LLVMPassRegistryRef R) { + initializeLoopStrengthReducePass(*unwrap(R)); +} + +void LLVMZigInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R) { + initializeLowerIntrinsicsPass(*unwrap(R)); +} + +void LLVMZigInitializeUnreachableBlockElimPass(LLVMPassRegistryRef R) { + initializeUnreachableBlockElimPass(*unwrap(R)); +} + +char *LLVMZigGetHostCPUName(void) { + std::string str = sys::getHostCPUName(); + return strdup(str.c_str()); +} + +char *LLVMZigGetNativeFeatures(void) { + return strdup(""); + //SubtargetFeatures features; + + //StringMap host_features; + //if (sys::getHostCPUFeatures(host_features)) { + // for (auto &F : host_features) + // features.AddFeature(F.first(), F.second); + //} + + //return strdup(features.getString().c_str()); +} diff --git a/src/zig_llvm.hpp b/src/zig_llvm.hpp new file mode 100644 index 000000000..1a7a6ef73 --- /dev/null +++ b/src/zig_llvm.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2015 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + +#ifndef ZIG_ZIG_LLVM_HPP +#define ZIG_ZIG_LLVM_HPP + +#include +#include +#include +#include +#include + +void LLVMZigInitializeLoopStrengthReducePass(LLVMPassRegistryRef R); +void LLVMZigInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R); +void LLVMZigInitializeUnreachableBlockElimPass(LLVMPassRegistryRef R); + +char *LLVMZigGetHostCPUName(void); +char *LLVMZigGetNativeFeatures(void); + +#endif diff --git a/test/hello.zig b/test/hello.zig index fefafb591..1d96b2376 100644 --- a/test/hello.zig +++ b/test/hello.zig @@ -1,8 +1,9 @@ extern { fn puts(s: *mut u8) -> i32; + fn exit(code: i32); } -fn main(argc: i32, argv: *mut *mut u8) -> i32 { - puts("Hello, world!\n"); - return 0; +fn _start() { + puts("Hello, world!"); + exit(0); }