Commit c2e5d50027

Andrew Kelley <superjoe30@gmail.com>
2015-11-24 21:00:38
write object file and fix void return type
1 parent e112818
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 <stdio.h>
 
-#include <llvm-c/Core.h>
-#include <llvm-c/Analysis.h>
-
 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<ErrorMsg> *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);
+    }
+}
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<ErrorMsg> *codegen_error_messages(CodeGen *g);
 
 #endif
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
 
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;
 }
 
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 <stdarg.h>
@@ -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;
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
 
src/tokenizer.cpp
@@ -170,6 +170,7 @@ ZigList<Token> *tokenize(Buf *buf, Buf *cur_dir_path) {
                     case WHITESPACE:
                         break;
                     case ALPHA:
+                    case '_':
                         t.state = TokenizeStateSymbol;
                         begin_token(&t, TokenIdSymbol);
                         break;
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 <llvm/InitializePasses.h>
+#include <llvm/PassRegistry.h>
+#include <llvm/MC/SubtargetFeature.h>
+
+
+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<bool> host_features;
+    //if (sys::getHostCPUFeatures(host_features)) {
+    //    for (auto &F : host_features)
+    //        features.AddFeature(F.first(), F.second);
+    //}
+
+    //return strdup(features.getString().c_str());
+}
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 <llvm-c/Core.h>
+#include <llvm-c/Analysis.h>
+#include <llvm-c/Target.h>
+#include <llvm-c/Initialization.h>
+#include <llvm-c/TargetMachine.h>
+
+void LLVMZigInitializeLoopStrengthReducePass(LLVMPassRegistryRef R);
+void LLVMZigInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R);
+void LLVMZigInitializeUnreachableBlockElimPass(LLVMPassRegistryRef R);
+
+char *LLVMZigGetHostCPUName(void);
+char *LLVMZigGetNativeFeatures(void);
+
+#endif
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);
 }
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")