]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
Merge branch 'master' into threading graphitemaster/threading
authorDale Weiler <killfieldengine@gmail.com>
Fri, 18 Oct 2013 01:30:17 +0000 (21:30 -0400)
committerDale Weiler <killfieldengine@gmail.com>
Fri, 18 Oct 2013 01:30:17 +0000 (21:30 -0400)
Conflicts:
gmqcc.h
include.mk
parser.c

Makefile
gmqcc.h
include.mk
main.c
opts.c
opts.def
parser.c
thread.c [new file with mode: 0644]

index 12151070539d078e9b932d61b0ae232834d078f1..31d0d68d3d05451cb8455da9caa035868c9803a2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -158,6 +158,7 @@ ir.o: gmqcc.h opts.def ir.h
 ftepp.o: gmqcc.h opts.def lexer.h
 utf8.o: gmqcc.h opts.def
 correct.o: gmqcc.h opts.def
+thread.o: gmqcc.h opts.def
 fold.o: ast.h ir.h gmqcc.h opts.def parser.h lexer.h
 intrin.o: parser.h gmqcc.h opts.def lexer.h ast.h ir.h
 exec.o: gmqcc.h opts.def
diff --git a/gmqcc.h b/gmqcc.h
index 49b5a824437e2dc3ce2ee7f22849f8148cf75a36..50abefee7d6ee2fe496d4364827cd5486995bc82 100644 (file)
--- a/gmqcc.h
+++ b/gmqcc.h
@@ -402,6 +402,10 @@ void         *util_htgeth(hash_table_t *ht, const char *key, size_t hash);
 int           util_snprintf(char *str, size_t, const char *fmt, ...);
 
 
+/* thread.c */
+uint32_t util_atomic_xadd32(volatile uint32_t *x, uint32_t v);
+
+
 /* fs.c */
 #define FS_FILE_SEEK_SET  0
 #define FS_FILE_SEEK_CUR  1
index 2bc2a839a339161f796b9721ccddb5dec6b1d11b..dae57d36632d72299867d590db4869de281daf42 100644 (file)
@@ -11,13 +11,13 @@ CC      ?= clang
 
 # linker flags and optional additional libraries if required
 LDFLAGS +=
-LIBS    += -lm
+LIBS    += -lm -lpthread
 
 #common objects
 COMMON   = ansi.o util.o stat.o fs.o opts.o conout.o
 
 #objects
-OBJ_C = $(COMMON) main.o lexer.o parser.o code.o ast.o ir.o ftepp.o utf8.o correct.o fold.o intrin.o
+OBJ_C = $(COMMON) main.o lexer.o parser.o code.o ast.o ir.o ftepp.o utf8.o correct.o fold.o intrin.o thread.o
 OBJ_P = $(COMMON) pak.o
 OBJ_T = $(COMMON) test.o
 OBJ_X = $(COMMON) exec.o
diff --git a/main.c b/main.c
index 78293d6d7615a3682a6153ff6b221381e5dc44cf..1b63ef9437a83548c1ad9edcaec91c96c2df03ca 100644 (file)
--- a/main.c
+++ b/main.c
@@ -216,6 +216,11 @@ static bool options_parse(int argc, char **argv) {
                 OPTS_OPTION_U16 (OPTION_FORCED_CRC) = strtol(argarg, NULL, 0);
                 continue;
             }
+            if (options_long_gcc("jobs", &argc, &argv, &argarg)) {
+
+                OPTS_OPTION_U32 (OPTION_J) = strtol(argarg, NULL, 0);
+                continue;
+            }
             if (options_long_gcc("redirout", &argc, &argv, &redirout)) {
                 con_change(redirout, redirerr);
                 continue;
@@ -468,6 +473,14 @@ static bool options_parse(int argc, char **argv) {
                     vec_push(items, item);
                     break;
 
+                case 'j':
+                    if (!options_witharg(&argc, &argv, &argarg)) {
+                        con_out("option -j requires a parameter\n");
+                        return false;
+                    }
+                    OPTS_OPTION_U32 (OPTION_J) = strtol(argarg, NULL, 0);
+                    break;
+
                 case '-':
                     if (!argv[0][2]) {
                         /* anything following -- is considered a non-option argument */
diff --git a/opts.c b/opts.c
index e50bd7441791925861f046a3420b1d90e6d0454a..94c936ebf88bdc632cbb1c56c95b656bc460b613 100644 (file)
--- a/opts.c
+++ b/opts.c
@@ -133,6 +133,7 @@ void opts_init(const char *output, int standard, size_t arraysize) {
     OPTS_OPTION_U32(OPTION_STANDARD)       = standard;
     OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE) = arraysize;
     OPTS_OPTION_U16(OPTION_MEMDUMPCOLS)    = 16;
+    OPTS_OPTION_U32(OPTION_J)              = 2;
 }
 
 static bool opts_setflag_all(const char *name, bool on, uint32_t *flags, const opts_flag_def_t *list, size_t listsize) {
index 57625ddb3ce23bde3bbfde21b48e364971cd3bf1..5827ca548214da93319f8480b4890ba3a770ff88 100644 (file)
--- a/opts.def
+++ b/opts.def
     GMQCC_DEFINE_FLAG(MAX_ARRAY_SIZE)
     GMQCC_DEFINE_FLAG(ADD_INFO)
     GMQCC_DEFINE_FLAG(CORRECTION)
+    GMQCC_DEFINE_FLAG(J)
     GMQCC_DEFINE_FLAG(STATISTICS)
     GMQCC_DEFINE_FLAG(PROGSRC)
 #endif
index 82ce53b0a47a84deeb0b422fc32c1558c8412681..e6b7f612d9c40791fe7b05b425ca72387c688a10 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -23,6 +23,7 @@
  */
 #include <string.h>
 #include <math.h>
+#include <pthread.h>
 
 #include "parser.h"
 
@@ -6141,6 +6142,86 @@ void parser_cleanup(parser_t *parser)
     mem_d(parser);
 }
 
+static void function_finalize_worker_do(ast_function **list, size_t count, volatile uint32_t *counter, bool *failure)
+{
+    do {
+        uint32_t idx = util_atomic_xadd32(counter, 1);
+        if (idx >= count) {
+            *counter = count;
+            return;
+        }
+        if (!ir_function_finalize(list[idx]->ir_func)) {
+            con_out("failed to finalize function %s\n", list[idx]->name);
+            *failure = true;
+            return;
+        }
+    } while (true);
+}
+
+typedef struct {
+    ast_function     **list;
+    size_t             count;
+    volatile uint32_t *counter;
+    bool              *failure;
+} function_finalize_worker_data;
+static void* function_finalize_worker(void *_d) {
+    function_finalize_worker_data *d = (function_finalize_worker_data*)_d;
+    function_finalize_worker_do(d->list, d->count, d->counter, d->failure);
+    return NULL;
+}
+
+static bool function_finalize_all_threaded(ast_function **list, size_t count)
+{
+    volatile uint32_t counter = 0;
+    function_finalize_worker_data wd;
+
+    size_t poolsize = OPTS_OPTION_U32(OPTION_J);
+    bool   failure = false;
+    size_t i, j;
+
+    pthread_t *threads;
+
+    if (!list || !count)
+        return true;
+
+    wd.list    = list;
+    wd.count   = count;
+    wd.counter = &counter;
+    wd.failure = &failure;
+
+    threads = (pthread_t*)mem_a(poolsize*sizeof(pthread_t));
+
+    for (i = 0; i < poolsize; ++i) {
+        if (pthread_create(threads+i, NULL, &function_finalize_worker, &wd) != 0)
+            break;
+    }
+    if (i < poolsize) {
+        con_out("failed to spawn worker threads\n");
+        for (j = 0; j <= i; ++j)
+            pthread_join(threads[j], NULL);
+        return false;
+    }
+    for (i = 0; i < poolsize; ++i)
+        pthread_join(threads[i], NULL);
+    return !failure;
+}
+
+bool function_finalize_all(ast_function **list, size_t count);
+bool function_finalize_all(ast_function **list, size_t count)
+{
+    size_t i;
+    if (OPTS_OPTION_U32(OPTION_J) > 1)
+        return function_finalize_all_threaded(list, count);
+
+    for (i = 0; i < count; ++i) {
+        if (!ir_function_finalize(list[i]->ir_func)) {
+            con_out("failed to finalize function %s\n", list[i]->name);
+            return false;
+        }
+    }
+    return true;
+}
+
 bool parser_finish(parser_t *parser, const char *output)
 {
     size_t i;
@@ -6281,6 +6362,8 @@ bool parser_finish(parser_t *parser, const char *output)
 
     if (OPTS_OPTION_BOOL(OPTION_DUMP))
         ir_builder_dump(ir, con_out);
+
+#if 0
     for (i = 0; i < vec_size(parser->functions); ++i) {
         if (!ir_function_finalize(parser->functions[i]->ir_func)) {
             con_out("failed to finalize function %s\n", parser->functions[i]->name);
@@ -6288,6 +6371,14 @@ bool parser_finish(parser_t *parser, const char *output)
             return false;
         }
     }
+
+#else
+    if (!function_finalize_all(parser->functions, vec_size(parser->functions))) {
+        ir_builder_delete(ir);
+        return false;
+    }
+#endif
+
     parser_remove_ast(parser);
 
     if (compile_Werrors) {
diff --git a/thread.c b/thread.c
new file mode 100644 (file)
index 0000000..8ea036f
--- /dev/null
+++ b/thread.c
@@ -0,0 +1,12 @@
+#include "gmqcc.h"
+
+GMQCC_INLINE uint32_t util_atomic_xadd32(volatile uint32_t *x, uint32_t v)
+{
+    asm volatile (
+        "lock xaddl %1, %0"
+        : "+m"(*x), "=r"(v)
+        : "1"(v)
+        : "cc"
+    );
+    return v;
+}