diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a22a9291e..da6aae6ae 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -52,10 +52,10 @@ jobs: cd test python3.exe src/tester.py ..\build\${{ matrix.build_type }}\c3c.exe test_suite/ - - name: Compile run stdlib tests + - name: Compile run unit tests run: | cd test - ..\build\${{ matrix.build_type }}\c3c.exe compile-test stdlib\conv_tests.c3 -g1 --safe + ..\build\${{ matrix.build_type }}\c3c.exe compile-test unit -g1 --safe - name: upload artifacts uses: actions/upload-artifact@v3 @@ -210,10 +210,10 @@ jobs: ../build/c3c compile-run examples/fannkuch-redux.c3 ../build/c3c compile-run examples/contextfree/boolerr.c3 - - name: Compile run stdlib tests + - name: Compile run unit tests run: | cd test - ../build/c3c compile-test stdlib/conv_tests.c3 -g1 --safe + ../build/c3c compile-test unit -g1 --safe - name: Build testproject run: | @@ -281,10 +281,10 @@ jobs: ../build/c3c compile-run examples/fannkuch-redux.c3 ../build/c3c compile-run examples/contextfree/boolerr.c3 - - name: Compile run stdlib tests + - name: Compile run unit tests run: | cd test - ../build/c3c compile-test stdlib/conv_tests.c3 -g1 --safe + ../build/c3c compile-test unit -g1 --safe - name: Build testproject run: | diff --git a/src/build/build_options.c b/src/build/build_options.c index c3e3399d1..0cdafbbc1 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -801,7 +801,7 @@ BuildOptions parse_arguments(int argc, const char *argv[]) .optimization_setting_override = OPT_SETTING_NOT_SET, .debug_info_override = DEBUG_INFO_NOT_SET, .safe_mode = -1, - .build_threads = 16, + .build_threads = 1, .command = COMMAND_MISSING, .reloc_model = RELOC_DEFAULT, .backend = BACKEND_LLVM, diff --git a/src/build/build_options.h b/src/build/build_options.h index c58d4b59c..9505164b9 100644 --- a/src/build/build_options.h +++ b/src/build/build_options.h @@ -353,6 +353,7 @@ typedef struct bool benchmarking; bool testing; bool read_stdin; + int build_threads; OptimizationLevel optimization_level; SizeOptimizationLevel size_optimization_level; bool single_module; diff --git a/src/build/builder.c b/src/build/builder.c index 46b096126..92d7f16f5 100644 --- a/src/build/builder.c +++ b/src/build/builder.c @@ -220,6 +220,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions * if (options->no_stdlib) target->no_stdlib = true; if (options->no_libc) target->no_libc = true; target->emit_llvm = options->emit_llvm; + target->build_threads = options->build_threads; target->emit_asm = options->emit_asm; target->force_linker = options->force_linker; target->panicfn = options->panicfn; diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index d3b77dd1b..57a70fb20 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -391,19 +391,16 @@ void compiler_compile(void) filename[len - 1] = 'o'; obj_files[output_file_count + i] = filename; } - } - - TaskQueueRef queue = taskqueue_create(16); - - + Task **tasks = NULL; for (unsigned i = 0; i < output_file_count; i++) { compile_data[i] = (CompileData) { .context = gen_contexts[i] }; compile_data[i].task = (Task) { task, &compile_data[i] }; - taskqueue_add(queue, &compile_data[i].task); + vec_add(tasks, &compile_data[i].task); } + TaskQueueRef queue = taskqueue_create(active_target.build_threads, tasks); taskqueue_wait_for_completion(queue); taskqueue_destroy(queue); @@ -414,8 +411,6 @@ void compiler_compile(void) assert(obj_files[i] || !output_exe); } - - output_file_count += cfiles; free(compile_data); compiler_codegen_time = bench_mark(); @@ -472,6 +467,7 @@ static const char **target_expand_source_names(const char** dirs, const char **s VECEACH(dirs, i) { const char *name = dirs[i]; + DEBUG_LOG("Searching for sources in %s", name); size_t name_len = strlen(name); if (name_len < 1) goto INVALID_NAME; if (name[name_len - 1] == '*') @@ -483,9 +479,11 @@ static const char **target_expand_source_names(const char** dirs, const char **s continue; } if (name[name_len - 2] != '*') goto INVALID_NAME; + DEBUG_LOG("Searching for wildcard sources in %s", name); if (name_len == 2 || name[name_len - 3] == '/') { char *path = str_copy(name, name_len - 2); + DEBUG_LOG("Reduced path %s", path); file_add_wildcard_files(&files, path, true, suffix_list, suffix_count); continue; } @@ -496,6 +494,11 @@ static const char **target_expand_source_names(const char** dirs, const char **s vec_add(files, name); continue; INVALID_NAME: + if (file_is_dir(name)) + { + file_add_wildcard_files(&files, name, true, suffix_list, suffix_count); + continue; + } if (!error_on_mismatch) continue; error_exit("File names must end with %s or they cannot be compiled: '%s' is invalid.", suffix_list[0], name); } diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 70032454a..15fc2ba75 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -3,6 +3,7 @@ // a copy of which can be found in the LICENSE file. #include "llvm_codegen_internal.h" +#include "compiler_tests/benchmark.h" #include #include @@ -56,6 +57,7 @@ static void diagnostics_handler(LLVMDiagnosticInfoRef ref, void *context) static void gencontext_init(GenContext *context, Module *module, LLVMContextRef shared_context) { + assert(LLVMIsMultithreaded()); memset(context, 0, sizeof(GenContext)); if (shared_context) { @@ -66,7 +68,11 @@ static void gencontext_init(GenContext *context, Module *module, LLVMContextRef { context->context = LLVMContextCreate(); } - LLVMContextSetDiagnosticHandler(context->context, &diagnostics_handler, context); + if (debug_log) + { + LLVMContextSetDiagnosticHandler(context->context, &diagnostics_handler, context); + } + if (!active_target.emit_llvm && !active_target.test_output) LLVMContextSetDiscardValueNames(context->context, true); context->code_module = module; } @@ -1069,8 +1075,8 @@ INLINE GenContext *llvm_gen_tests(Module** modules, unsigned module_count, LLVMC LLVMValueRef array_of_names = LLVMConstArray(chars_type, names, test_count); LLVMValueRef array_of_decls = LLVMConstArray(LLVMPointerType(opt_test, 0), decls, test_count); LLVMTypeRef arr_type = LLVMTypeOf(array_of_names); - name_ref = llvm_add_global_raw(c, ".test_names", arr_type, llvm_alloc_size(c, arr_type)); - decl_ref = llvm_add_global_raw(c, ".test_decls", LLVMTypeOf(array_of_decls), llvm_alloc_size(c, arr_type)); + name_ref = llvm_add_global_raw(c, ".test_names", arr_type, 0); + decl_ref = llvm_add_global_raw(c, ".test_decls", LLVMTypeOf(array_of_decls), 0); llvm_set_internal_linkage(name_ref); llvm_set_internal_linkage(decl_ref); LLVMSetGlobalConstant(name_ref, 1); diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index ee347a111..62d682d5b 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -21,15 +21,16 @@ static inline void llvm_emit_const_initialize_reference(GenContext *c, BEValue * static inline void llvm_emit_elvis_expr(GenContext *c, BEValue *value, Expr *expr); static inline void llvm_emit_expr_block(GenContext *context, BEValue *be_value, Expr *expr); static inline void llvm_emit_failable(GenContext *c, BEValue *be_value, Expr *expr); -static inline void llvm_emit_inc_dec_change(GenContext *c, bool use_mod, BEValue *addr, BEValue *after, BEValue *before, Expr *expr, int diff); +static inline void llvm_emit_inc_dec_change(GenContext *c, BEValue *addr, BEValue *after, BEValue *before, Expr *expr, + int diff); static inline void llvm_emit_initialize_reference(GenContext *c, BEValue *ref, Expr *expr); static inline void llvm_emit_initialize_reference_bitstruct(GenContext *c, BEValue *ref, Decl *bitstruct, Expr** elements); static inline void llvm_emit_initialize_reference_list(GenContext *c, BEValue *ref, Expr *expr); static inline void llvm_emit_initialize_reference_vector(GenContext *c, BEValue *ref, Type *real_type, Expr **elements); static inline void llvm_emit_initializer_list_expr(GenContext *c, BEValue *value, Expr *expr); static inline void llvm_emit_macro_block(GenContext *context, BEValue *be_value, Expr *expr); -static inline void llvm_emit_post_inc_dec(GenContext *c, BEValue *value, Expr *expr, int diff, bool use_mod); -static inline void llvm_emit_pre_inc_dec(GenContext *c, BEValue *value, Expr *expr, int diff, bool use_mod); +static inline void llvm_emit_post_inc_dec(GenContext *c, BEValue *value, Expr *expr, int diff); +static inline void llvm_emit_pre_inc_dec(GenContext *c, BEValue *value, Expr *expr, int diff); static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type *type, AstId current, BlockExit **block_exit); static inline void llvm_emit_subscript_addr_with_base(GenContext *c, BEValue *result, BEValue *parent, BEValue *index, SourceSpan loc); static inline void llvm_emit_try_unwrap(GenContext *c, BEValue *value, Expr *expr); @@ -2115,46 +2116,34 @@ static inline void llvm_emit_initialize_reference(GenContext *c, BEValue *ref, E } } -static inline void llvm_emit_inc_dec_change(GenContext *c, bool use_mod, BEValue *addr, BEValue *after, BEValue *before, Expr *expr, int diff) +static inline LLVMValueRef llvm_emit_inc_dec_value(GenContext *c, SourceSpan span, BEValue *original, int diff) { - EMIT_LOC(c, expr); - Type *type = type_reduced_from_expr(expr); - - // Copy the address and make it a value. - BEValue value = *addr; - llvm_value_rvalue(c, &value); - - // Store the original value if we want it - if (before) *before = value; - - LLVMValueRef after_value; + assert(!llvm_value_is_addr(original)); + Type *type = original->type; switch (type->type_kind) { case TYPE_POINTER: { // Use byte here, we don't need a big offset. LLVMValueRef add = LLVMConstInt(diff < 0 ? llvm_get_type(c, type_ichar) : llvm_get_type(c, type_char), (unsigned long long)diff, diff < 0); - after_value = llvm_emit_pointer_gep_raw(c, llvm_get_pointee_type(c, type), value.value, add); - break; + return llvm_emit_pointer_gep_raw(c, llvm_get_pointee_type(c, type), original->value, add); } case ALL_FLOATS: { // We allow inc/dec on floats, which is same as f += 1.0 or f -= 1.0 LLVMTypeRef llvm_type = llvm_get_type(c, type); LLVMValueRef add = LLVMConstReal(llvm_type, (double)diff); - after_value = LLVMBuildFAdd(c->builder, value.value, add, "fincdec"); - break; + return LLVMBuildFAdd(c->builder, original->value, add, "fincdec"); } case ALL_INTS: { // Instead of negative numbers do dec/inc with a positive number. LLVMTypeRef llvm_type = llvm_get_type(c, type); LLVMValueRef diff_value = LLVMConstInt(llvm_type, 1, false); - after_value = diff > 0 - ? llvm_emit_add_int(c, type, value.value, diff_value, expr->span) - : llvm_emit_sub_int(c, type, value.value, diff_value, expr->span); - break; + return diff > 0 + ? llvm_emit_add_int(c, type, original->value, diff_value, span) + : llvm_emit_sub_int(c, type, original->value, diff_value, span); } case TYPE_VECTOR: { @@ -2177,38 +2166,108 @@ static inline void llvm_emit_inc_dec_change(GenContext *c, bool use_mod, BEValue } if (is_integer) { - after_value = diff > 0 - ? llvm_emit_add_int(c, type, value.value, val, expr->span) - : llvm_emit_sub_int(c, type, value.value, val, expr->span); + return diff > 0 + ? llvm_emit_add_int(c, type, original->value, val, span) + : llvm_emit_sub_int(c, type, original->value, val, span); } else { - after_value = LLVMBuildFAdd(c->builder, value.value, val, "fincdec"); + return LLVMBuildFAdd(c->builder, original->value, val, "fincdec"); } - break; } default: UNREACHABLE } +} +static inline void llvm_emit_inc_dec_change(GenContext *c, BEValue *addr, BEValue *after, BEValue *before, Expr *expr, + int diff) +{ + EMIT_LOC(c, expr); + Type *type = type_reduced_from_expr(expr); + + // Copy the address and make it a value. + BEValue value = *addr; + llvm_value_rvalue(c, &value); + + // Store the original value if we want it + if (before) *before = value; + + LLVMValueRef after_value = llvm_emit_inc_dec_value(c, expr->span, &value, diff); // Store the result aligned. llvm_store_raw(c, addr, after_value); if (after) llvm_value_set(after, after_value, addr->type); } -/** - * This method implements the common ++x and --x operators, as well as the --%x and ++%x - * that have wrapping behaviour. See llvm_emit_post_inc_dec for more discussion. - */ -static inline void llvm_emit_pre_inc_dec(GenContext *c, BEValue *value, Expr *expr, int diff, bool use_mod) +static inline bool expr_is_vector_subscript(Expr *expr) { + if (expr->expr_kind != EXPR_SUBSCRIPT) return false; + Type *type = type_lowering(exprptr(expr->subscript_expr.expr)->type); + return type->type_kind == TYPE_VECTOR; +} + +/** + * This method implements the common ++x and --x operators on vector elements + */ +static inline void llvm_emit_pre_post_inc_dec_vector(GenContext *c, BEValue *value, Expr *expr, int diff, bool pre) +{ + // First grab the address + BEValue addr; + llvm_emit_exprid(c, &addr, expr->subscript_expr.expr); + *value = addr; + llvm_value_addr(c, &addr); + + // But we also want the value (of the full vector) + llvm_value_rvalue(c, value); + LLVMValueRef vector_value = value->value; + Type *vec = value->type; + assert(vec->type_kind == TYPE_VECTOR); + Type *element = vec->array.base; + LLVMValueRef vector = value->value; + + // Now let's get the subscript and store it in value + llvm_emit_exprid(c, value, expr->subscript_expr.range.start); + llvm_value_rvalue(c, value); + LLVMValueRef index = value->value; + if (expr->subscript_expr.range.start_from_end) + { + index = LLVMBuildNUWSub(c->builder, llvm_const_int(c, value->type, vec->array.len), index, ""); + } + + // We're now done, we can extract the current value: + BEValue current_res; + llvm_value_set(¤t_res, LLVMBuildExtractElement(c->builder, vector, index, ""), element); + + // Calculate the new value. + LLVMValueRef new_value = llvm_emit_inc_dec_value(c, expr->span, ¤t_res, diff); + + // We update the vector value. + vector = LLVMBuildInsertElement(c->builder, vector, new_value, index, ""); + + // And store it. + llvm_store_raw(c, &addr, vector); + + // And set the return value. + llvm_value_set(value, pre ? current_res.value : new_value, element); +} + +/** + * This method implements the common ++x and --x operators + */ +static inline void llvm_emit_pre_inc_dec(GenContext *c, BEValue *value, Expr *expr, int diff) +{ + if (expr_is_vector_subscript(expr)) + { + llvm_emit_pre_post_inc_dec_vector(c, value, expr, diff, true); + return; + } // Pull out the address, also allowing temporaries. BEValue addr; llvm_emit_expr(c, &addr, expr); llvm_value_addr(c, &addr); // Set the value to the new value. - llvm_emit_inc_dec_change(c, use_mod, &addr, value, NULL, expr, diff); + llvm_emit_inc_dec_change(c, &addr, value, NULL, expr, diff); } static inline void llvm_emit_deref(GenContext *c, BEValue *value, Expr *inner, Type *type) @@ -2229,11 +2288,15 @@ static inline void llvm_emit_deref(GenContext *c, BEValue *value, Expr *inner, T /** * Emit the common x++ and x-- operations. - * Normally overflow/underflow is considered UB, which is why C3 provides x%++ and x%-- for wrapping. - * We could also provide methods for the same but where it would cap on overflow. */ -static inline void llvm_emit_post_inc_dec(GenContext *c, BEValue *value, Expr *expr, int diff, bool use_mod) +static inline void llvm_emit_post_inc_dec(GenContext *c, BEValue *value, Expr *expr, int diff) { + if (expr_is_vector_subscript(expr)) + { + llvm_emit_pre_post_inc_dec_vector(c, value, expr, diff, false); + return; + } + // Retrieve the address, creating a temp in case this is // a temporary value (this gives us a lot of flexibility for temporaries) BEValue addr; @@ -2241,7 +2304,7 @@ static inline void llvm_emit_post_inc_dec(GenContext *c, BEValue *value, Expr *e llvm_value_addr(c, &addr); // Perform the actual dec/inc to generate the new value. - llvm_emit_inc_dec_change(c, use_mod, &addr, NULL, value, expr, diff); + llvm_emit_inc_dec_change(c, &addr, NULL, value, expr, diff); } @@ -2350,10 +2413,10 @@ static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr) llvm_emit_deref(c, value, inner, type_lowering(expr->type)); return; case UNARYOP_INC: - llvm_emit_pre_inc_dec(c, value, inner, 1, false); + llvm_emit_pre_inc_dec(c, value, inner, 1); return; case UNARYOP_DEC: - llvm_emit_pre_inc_dec(c, value, inner, -1, false); + llvm_emit_pre_inc_dec(c, value, inner, -1); return; } UNREACHABLE @@ -3638,8 +3701,7 @@ static void llvm_emit_post_unary_expr(GenContext *context, BEValue *be_value, Ex llvm_emit_post_inc_dec(context, be_value, expr->unary_expr.expr, - expr->unary_expr.operator == UNARYOP_INC ? 1 : -1, - false); + expr->unary_expr.operator == UNARYOP_INC ? 1 : -1); } void llvm_emit_typeid(GenContext *c, BEValue *be_value, Type *type) diff --git a/src/compiler/types.c b/src/compiler/types.c index 33d70f485..6304c7de7 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -1882,9 +1882,14 @@ Type *type_find_max_type(Type *type, Type *other) other = other->function.prototype->raw_type; type = other->function.prototype->raw_type; return other == type ? type : NULL; + case TYPE_UNTYPED_LIST: + if (other->type_kind == TYPE_ARRAY) return other; + if (other->type_kind == TYPE_VECTOR) return other; + if (other->type_kind == TYPE_STRUCT) return other; + if (other->type_kind == TYPE_SUBARRAY) return other; + return NULL; case TYPE_UNION: case TYPE_STRUCT: - case TYPE_UNTYPED_LIST: TODO case TYPE_TYPEID: case TYPE_MEMBER: diff --git a/src/compiler_tests/benchmark.c b/src/compiler_tests/benchmark.c index b95373d82..f359facf2 100644 --- a/src/compiler_tests/benchmark.c +++ b/src/compiler_tests/benchmark.c @@ -14,3 +14,13 @@ double bench_mark(void) { return (clock() - begin) / (double)CLOCKS_PER_SEC; } + +uint64_t benchstart(void) +{ + return clock(); +} + +double benchmark(uint64_t start) +{ + return (clock() - start) / (double)CLOCKS_PER_SEC; +} diff --git a/src/compiler_tests/benchmark.h b/src/compiler_tests/benchmark.h index 1c7e9a9ae..f00348783 100644 --- a/src/compiler_tests/benchmark.h +++ b/src/compiler_tests/benchmark.h @@ -5,5 +5,9 @@ // a copy of which can be found in the LICENSE file. +#include + void bench_begin(void); double bench_mark(void); +uint64_t benchstart(void); +double benchmark(uint64_t start); diff --git a/src/utils/file_utils.c b/src/utils/file_utils.c index 4bb5cc686..1dc7ec612 100644 --- a/src/utils/file_utils.c +++ b/src/utils/file_utils.c @@ -446,7 +446,7 @@ void file_add_wildcard_files(const char ***files, const char *path, bool recursi { size_t namelen = strlen(ent->d_name); if (namelen == 0 || ent->d_name[0] == '.') continue; - + DEBUG_LOG("Searching file %s", ent->d_name); if (namelen < 3 || !file_has_suffix_in_list(ent->d_name, namelen, suffix_list, suffix_count)) { char *format = path_ends_with_slash ? "%s%s" : "%s/%s"; @@ -461,11 +461,13 @@ void file_add_wildcard_files(const char ***files, const char *path, bool recursi is_directory = S_ISDIR(st.st_mode); if (is_directory && ent->d_name[0] != '.' && recursive) { + DEBUG_LOG("Enter sub dir %s", ent->d_name); file_add_wildcard_files(files, new_path, recursive, suffix_list, suffix_count); } continue; } char *format = path_ends_with_slash ? "%s%s" : "%s/%s"; + DEBUG_LOG("Added file"); vec_add(*files, str_printf(format, path, ent->d_name)); } closedir(dir); diff --git a/src/utils/lib.h b/src/utils/lib.h index a7504a32b..737f72b80 100644 --- a/src/utils/lib.h +++ b/src/utils/lib.h @@ -93,8 +93,7 @@ char *calloc_string(size_t len); void free_arena(void); void print_arena_status(void); void run_arena_allocator_tests(void); -TaskQueueRef taskqueue_create(int threads); -void taskqueue_add(TaskQueueRef queue, Task *task); +TaskQueueRef taskqueue_create(int threads, Task **task_list); void taskqueue_destroy(TaskQueueRef queue); void taskqueue_wait_for_completion(TaskQueueRef queue); diff --git a/src/utils/taskqueue.c b/src/utils/taskqueue.c index 2563d0a1c..cc12fffbb 100644 --- a/src/utils/taskqueue.c +++ b/src/utils/taskqueue.c @@ -1,4 +1,5 @@ #include "lib.h" +#include "compiler_tests/benchmark.h" // Our task queue is only made for scheduling compilation tasks so there is // a single thread that adds the tasks. @@ -17,62 +18,58 @@ typedef struct TaskQueue_ volatile int active_threads; } TaskQueue; -static void *taskqueue_thread(void *queue) +static void *taskqueue_thread(void *data) { - TaskQueue *task_queue = queue; - bool was_active = false; + TaskQueue *task_queue = data; + bool is_active = false; while (1) { pthread_mutex_lock(&task_queue->lock); - if (was_active) + unsigned task_count = vec_size(task_queue->queue); + if (!task_count || task_queue->shutdown) goto SHUTDOWN; + if (!is_active) { - was_active = false; - if (--task_queue->active_threads == 0) pthread_cond_broadcast(&task_queue->notify); + task_queue->active_threads++; + is_active = true; } - // Wait for a task. - while (!vec_size(task_queue->queue) && !task_queue->shutdown) - { - pthread_cond_wait(&task_queue->notify, &task_queue->lock); - } - if (task_queue->shutdown) break; - - Task *task = (Task*)task_queue->queue[vec_size(task_queue->queue) - 1]; + Task *task = (Task*)task_queue->queue[task_count - 1]; vec_pop(task_queue->queue); - task_queue->active_threads++; - was_active = true; pthread_mutex_unlock(&task_queue->lock); task->task(task->arg); } +SHUTDOWN: + if (is_active && --task_queue->active_threads == 0) + { + pthread_cond_broadcast(&task_queue->notify); + } pthread_mutex_unlock(&task_queue->lock); pthread_exit(NULL); return NULL; } -TaskQueueRef taskqueue_create(int threads) +TaskQueueRef taskqueue_create(int threads, Task **task_list) { assert(threads > 0); TaskQueue *queue = CALLOCS(TaskQueue); queue->threads = MALLOC(sizeof(pthread_t) * (unsigned)threads); queue->thread_count = threads; + queue->queue = (volatile Task **)task_list; if (pthread_mutex_init(&queue->lock, NULL)) error_exit("Failed to set up mutex"); if (pthread_cond_init(&queue->notify, NULL)) error_exit("Failed to set up cond"); + pthread_attr_t custom_sched_attr; + pthread_attr_init(&custom_sched_attr); + pthread_attr_setscope(&custom_sched_attr, PTHREAD_SCOPE_SYSTEM); for (int i = 0; i < threads; i++) { - if (pthread_create(&(queue->threads[i]), NULL, taskqueue_thread, queue)) error_exit("Fail to set up thread pool"); + pthread_t *pthread = &queue->threads[i]; + + if (pthread_create(pthread, &custom_sched_attr, taskqueue_thread, queue)) error_exit("Fail to set up thread pool"); + struct sched_param prio = { sched_get_priority_max(SCHED_OTHER) }; + if (pthread_setschedparam(*pthread, SCHED_OTHER, &prio)) error_exit("Failed to set thread priority"); } return queue; } -void taskqueue_add(TaskQueueRef queue_ref, Task *task) -{ - TaskQueue *queue = queue_ref; - assert(queue); - if (pthread_mutex_lock(&queue->lock) != 0) error_exit("Failed to lock task queue."); - vec_add(queue->queue, task); - if (pthread_cond_signal(&queue->notify) != 0) error_exit("Failed to signal tasks."); - if (pthread_mutex_unlock(&queue->lock) != 0) error_exit("Failed to unlock task queue"); -} - void taskqueue_wait_for_completion(TaskQueueRef queue_ref) { TaskQueue *queue = queue_ref; @@ -83,7 +80,6 @@ void taskqueue_wait_for_completion(TaskQueueRef queue_ref) pthread_cond_wait(&queue->notify, &queue->lock); } if (pthread_mutex_unlock(&queue->lock) != 0) error_exit("Failed to unlock task queue"); - } void taskqueue_destroy(TaskQueueRef queue_ref) @@ -94,7 +90,6 @@ void taskqueue_destroy(TaskQueueRef queue_ref) assert(!queue->shutdown); vec_resize(queue->queue, 0); queue->shutdown = true; - if (pthread_cond_broadcast(&queue->notify)) error_exit("Failed to signal tasks."); if (pthread_mutex_unlock(&queue->lock) != 0) error_exit("Failed to unlock task queue."); for (int i = 0; i < queue->thread_count; i++) { @@ -111,16 +106,19 @@ void taskqueue_destroy(TaskQueueRef queue_ref) void taskqueue_add(TaskQueueRef queue_ref, Task *task) { - task->task(task->arg); } -TaskQueueRef taskqueue_create(int threads) +TaskQueueRef taskqueue_create(int threads, Task **tasks) { - return NULL; + return tasks; } void taskqueue_wait_for_completion(TaskQueueRef queue) { + Task **tasks = queue; + FOREACH_BEGIN(Task *task, tasks) + task->task(task->arg); + FOREACH_END(); } #endif \ No newline at end of file diff --git a/src/version.h b/src/version.h index 6c1dc3d3c..3a224ce1c 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.3.114" \ No newline at end of file +#define COMPILER_VERSION "0.3.115" \ No newline at end of file diff --git a/test/unit/regression/inc_dec.c3 b/test/unit/regression/inc_dec.c3 new file mode 100644 index 000000000..0e7d40a26 --- /dev/null +++ b/test/unit/regression/inc_dec.c3 @@ -0,0 +1,34 @@ +fn void! vector_inc_dec() @test +{ + int[<3>] x; + int[<3>] y; + int z = ++x[0]; + int zz = y[0]++; + x[1]++; + ++y[2]; + int[<3>] g = x--; + assert($$reduce_and(x == { 0, 0, -1 })); + assert($$reduce_and(y == { 1, 0, 1 })); + assert(z == 0 && zz == 1); + assert($$reduce_and(g == { 1, 1, 0 })); +} + +fn void! int_inc_dec() @test +{ + int x; + assert(x++ == 0); + assert(x == 1); + assert(++x == 2); + assert(x-- == 2); + assert(--x == 0); +} + +fn void! float_inc_dec() @test +{ + double x; + assert(x++ == 0); + assert(x == 1.0); + assert(++x == 2.0); + assert(x-- == 2.0); + assert(--x == 0); +} diff --git a/test/stdlib/conv_tests.c3 b/test/unit/stdlib/conv_tests.c3 similarity index 100% rename from test/stdlib/conv_tests.c3 rename to test/unit/stdlib/conv_tests.c3