Merge pull request #26 from birth-software/compile-in-different-optimization-modes

Compile in different optimization modes
This commit is contained in:
David 2024-07-24 13:56:41 +02:00 committed by GitHub
commit 667597d38e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 151 additions and 57 deletions

View File

@ -18,12 +18,12 @@ jobs:
- name: Build and test - name: Build and test
run: | run: |
./run_tests.sh 1 ./run_tests.sh 1
# macos_build_and_test: macos_build_and_test:
# runs-on: macos-latest runs-on: macos-latest
# timeout-minutes: 15 timeout-minutes: 15
# steps: steps:
# - name: Checkout - name: Checkout
# uses: actions/checkout@v4 uses: actions/checkout@v4
# - name: Build and test - name: Build and test
# run: | run: |
# ./run_tests.sh ./run_tests.sh 1

View File

@ -1,5 +1,6 @@
#include <stdint.h> #include <stdint.h>
#include <stdarg.h> #include <stdarg.h>
#include <stddef.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -159,7 +160,7 @@ fn u64 strlen (const char* c_string)
#define strlit(s) (String){ .pointer = (u8*)s, .length = sizeof(s) - 1, } #define strlit(s) (String){ .pointer = (u8*)s, .length = sizeof(s) - 1, }
#define ch_to_str(ch) (String){ .pointer = &ch, .length = 1 } #define ch_to_str(ch) (String){ .pointer = &ch, .length = 1 }
#define array_to_slice(arr) { .pointer = (arr), .length = array_length(arr) } #define array_to_slice(arr) { .pointer = (arr), .length = array_length(arr) }
#define pointer_to_bytes(p) Slice<u8>{ .pointer = (u8*)(p), .length = sizeof(*p) } #define pointer_to_bytes(p) (String) { .pointer = (u8*)(p), .length = sizeof(*p) }
#define struct_to_bytes(s) pointer_to_bytes(&(s)) #define struct_to_bytes(s) pointer_to_bytes(&(s))
#define case_to_name(prefix, e) case prefix ## e: return strlit(#e) #define case_to_name(prefix, e) case prefix ## e: return strlit(#e)
@ -2512,6 +2513,31 @@ fn u8 type_equal(Thread* thread, Type* a, Type* b)
return result; return result;
} }
fn Hash hash_type(Thread* thread, Type* type);
fn Hash node_get_hash_default(Thread* thread, Node* node)
{
return fnv_offset;
}
fn Hash node_get_hash_projection(Thread* thread, Node* node)
{
trap();
}
fn Hash node_get_hash_control_projection(Thread* thread, Node* node)
{
auto projection_index = node->control_projection.projection.index;
auto proj_index_bytes = struct_to_bytes(projection_index);
return hash_bytes(proj_index_bytes);
}
fn Hash node_get_hash_constant(Thread* thread, Node* node)
{
auto* type = thread_type_get(thread, node->type);
auto type_hash = hash_type(thread, type);
return type_hash;
}
typedef NodeIndex NodeIdealize(Thread* thread, NodeIndex node_index); typedef NodeIndex NodeIdealize(Thread* thread, NodeIndex node_index);
typedef TypeIndex NodeComputeType(Thread* thread, NodeIndex node_index); typedef TypeIndex NodeComputeType(Thread* thread, NodeIndex node_index);
@ -2573,11 +2599,6 @@ fn Hash type_get_hash_tuple(Thread* thread, Type* type)
return hash; return hash;
} }
fn Hash node_get_hash_constant(Thread* thread, Node* node)
{
trap();
}
fn u8 is_projection(Node* n) fn u8 is_projection(Node* n)
{ {
return (n->id == NODE_CONTROL_PROJECTION) | (n->id == NODE_PROJECTION); return (n->id == NODE_CONTROL_PROJECTION) | (n->id == NODE_PROJECTION);
@ -2921,22 +2942,27 @@ global const NodeVirtualTable node_functions[NODE_COUNT] = {
[NODE_START] = { [NODE_START] = {
.compute_type = &compute_type_start, .compute_type = &compute_type_start,
.idealize = &idealize_null, .idealize = &idealize_null,
.get_hash = &node_get_hash_default,
}, },
[NODE_STOP] = { [NODE_STOP] = {
.compute_type = &compute_type_bottom, .compute_type = &compute_type_bottom,
.idealize = &idealize_stop, .idealize = &idealize_stop,
.get_hash = &node_get_hash_default,
}, },
[NODE_CONTROL_PROJECTION] = { [NODE_CONTROL_PROJECTION] = {
.compute_type = &compute_type_projection, .compute_type = &compute_type_projection,
.idealize = &idealize_control_projection, .idealize = &idealize_control_projection,
.get_hash = &node_get_hash_control_projection,
}, },
[NODE_DEAD_CONTROL] = { [NODE_DEAD_CONTROL] = {
.compute_type = &compute_type_dead_control, .compute_type = &compute_type_dead_control,
.idealize = &idealize_null, .idealize = &idealize_null,
.get_hash = &node_get_hash_default,
}, },
[NODE_RETURN] = { [NODE_RETURN] = {
.compute_type = &compute_type_return, .compute_type = &compute_type_return,
.idealize = &idealize_return, .idealize = &idealize_return,
.get_hash = &node_get_hash_default,
}, },
[NODE_CONSTANT] = { [NODE_CONSTANT] = {
.compute_type = &compute_type_constant, .compute_type = &compute_type_constant,
@ -2954,7 +2980,7 @@ fn Hash hash_type(Thread* thread, Type* type)
hash = type_functions[type->id].get_hash(thread, type); hash = type_functions[type->id].get_hash(thread, type);
} }
assert(hash); assert(hash != 0);
type->hash = hash; type->hash = hash;
return hash; return hash;
@ -3032,20 +3058,33 @@ fn s32 intern_pool_find_node_slot(Thread* thread, u32 original_index, NodeIndex
return result; return result;
} }
fn Hash hash_node(Node* node) fn Hash hash_node(Thread* thread, Node* node)
{ {
auto hash = node->hash; auto hash = node->hash;
if (!hash) if (!hash)
{ {
hash = fnv_offset; hash = node_functions[node->id].get_hash(thread, node);
for (auto* it = (u8*)node; it < (u8*)(node + 1); it += 1)
hash = hash_byte(hash, node->id);
auto inputs = node_get_inputs(thread, node);
for (u32 i = 0; i < inputs.length; i += 1)
{ {
hash = hash_byte(hash, *it); auto input_index = inputs.pointer[i];
if (validi(input_index))
{
for (u8* it = (u8*)&input_index; it < (u8*)(&input_index + 1); it += 1)
{
hash = hash_byte(hash, *it);
}
}
} }
node->hash = hash; node->hash = hash;
} }
assert(hash);
return hash; return hash;
} }
@ -3053,7 +3092,7 @@ fn NodeGetOrPut intern_pool_get_or_put_node(Thread* thread, NodeIndex node_index
{ {
auto existing_capacity = thread->interned.nodes.capacity; auto existing_capacity = thread->interned.nodes.capacity;
auto* node = &thread->buffer.nodes.pointer[geti(node_index)]; auto* node = &thread->buffer.nodes.pointer[geti(node_index)];
auto hash = hash_node(node); auto hash = hash_node(thread, node);
auto original_index = hash & (existing_capacity - 1); auto original_index = hash & (existing_capacity - 1);
auto slot = intern_pool_find_node_slot(thread, original_index, node_index); auto slot = intern_pool_find_node_slot(thread, original_index, node_index);
@ -3092,23 +3131,47 @@ fn NodeIndex intern_pool_remove_node(Thread* thread, NodeIndex node_index)
{ {
auto existing_capacity = thread->interned.nodes.capacity; auto existing_capacity = thread->interned.nodes.capacity;
auto* node = thread_node_get(thread, node_index); auto* node = thread_node_get(thread, node_index);
auto hash = hash_node(node); auto hash = hash_node(thread, node);
auto original_index = hash & (existing_capacity - 1); auto original_index = hash & (existing_capacity - 1);
auto slot = intern_pool_find_node_slot(thread, original_index, node_index); auto slot = intern_pool_find_node_slot(thread, original_index, node_index);
if (slot != -1) if (slot != -1)
{ {
auto index = (u32)slot; auto slot_index = (u32)slot;
auto* slot_pointer = &thread->interned.nodes.pointer[index]; auto* slot_pointer = &thread->interned.nodes.pointer[slot_index];
auto old_node_index = *(NodeIndex*)slot_pointer; auto old_node_index = *(NodeIndex*)slot_pointer;
*slot_pointer = 0; *slot_pointer = 0;
auto index = slot_index;
while (1) while (1)
{ {
index = (index + 1) & (existing_capacity - 1); index = (index + 1) & (existing_capacity - 1);
if (thread->interned.nodes.pointer[index] == 0) auto existing = thread->interned.nodes.pointer[index];
if (existing == 0)
{ {
break; break;
} }
auto existing_node_index = *(NodeIndex*)&existing;
auto* existing_node = thread_node_get(thread, existing_node_index);
auto existing_node_hash = hash_node(thread, existing_node);
auto existing_index = existing_node_hash & (existing_capacity - 1);
if (slot_index <= existing_index)
{
if ((slot_index < existing_index) & (existing_index <= index))
{
continue;
}
}
else
{
if ((slot_index <= index) | (slot_index < existing_index))
{
continue;
}
}
trap(); trap();
} }
@ -4630,9 +4693,9 @@ fn String c_lower(Thread* thread)
fn void thread_init(Thread* thread) fn void thread_init(Thread* thread)
{ {
*thread = (Thread) { memset(thread, 0, sizeof(Thread));
.arena = arena_init_default(KB(64)), thread->arena = arena_init_default(KB(64));
};
Type top, bot, live_control, dead_control; Type top, bot, live_control, dead_control;
memset(&top, 0, sizeof(Type)); memset(&top, 0, sizeof(Type));
top.id = TYPE_TOP; top.id = TYPE_TOP;

View File

@ -2,13 +2,19 @@
function compile() function compile()
{ {
mkdir -p $build_dir
build_dir=$1 build_dir=$1
exe_name=$2 exe_name=$2
debug_info=$3 debug_info=$3
optimizations=$4 optimizations=$4
static=0 static=$5
mkdir -p $build_dir echo "BUILD_DIR: $build_dir"
echo "EXE_NAME: $exe_name"
echo "DEBUG_INFO: $debug_info"
echo "OPTIMIZATIONS: $optimizations"
echo "STATIC: $static"
compile_command="clang bootstrap/main.c -o $build_dir/$exe_name $debug_info $optimizations -std=gnu2x -Wall -Wextra -Wpedantic -Wno-nested-anon-types -Wno-keyword-macro -Wno-gnu-auto-type -Wno-auto-decl-extensions -pedantic -fno-exceptions -fno-stack-protector -ferror-limit=1 -MJ $build_dir/compile_commands.json" compile_command="clang bootstrap/main.c -o $build_dir/$exe_name $debug_info $optimizations -std=gnu2x -Wall -Wextra -Wpedantic -Wno-nested-anon-types -Wno-keyword-macro -Wno-gnu-auto-type -Wno-auto-decl-extensions -pedantic -fno-exceptions -fno-stack-protector -ferror-limit=1 -MJ $build_dir/compile_commands.json"

View File

@ -3,17 +3,26 @@
set -e set -e
path=$1 path=$1
echo $path if [ "$path" == "" ]
then
echo "error: a valid binary path must be provided to debug"
exit 1
fi
source ./compile.sh source ./compile.sh
build_dir="build" build_dir="build"
exe_name="nest" exe_name="nest"
exe_path=$build_dir/$exe_name exe_path=$build_dir/$exe_name
debug_flags="-g" debug_flags="-g"
optimization_flags="" optimization_flags="-O0"
bootstrap_args="$path" bootstrap_args="$path"
case "$OSTYPE" in
darwin*) static=0;;
linux*) static=1;;
*) echo "unknown: $OSTYPE" ;;
esac
compile $build_dir $exe_name $debug_flags $optimization_flags compile $build_dir $exe_name $debug_flags $optimization_flags $static
case "$OSTYPE" in case "$OSTYPE" in
darwin*) lldb -- $exe_path $bootstrap_args;; darwin*) lldb -- $exe_path $bootstrap_args;;

View File

@ -3,46 +3,62 @@
set -e set -e
source ./compile.sh source ./compile.sh
all=$1 all=$1
all=$1
build_dir="build" build_dir="build"
exe_name="nest" base_exe_name="nest"
exe_path=$build_dir/$exe_name
debug_flags="-g" debug_flags="-g"
no_optimization_flags="" no_optimization_flags=""
test_names="first" test_names="first"
if [ "$all" == "1" ] if [ "$all" == "1" ]
then then
optimization_modes=("" "-O1" "-O2 march=native", "-Os march=native" "-Oz march=native" "-O3 march=native") optimization_modes=("-O0" "-O1" "-O2" "-Os" "-Oz" "-O3")
case "$OSTYPE" in
darwin*) linking_modes=("0") ;;
linux*) linking_modes=("0" "1") ;;
*) echo "unknown: $OSTYPE"; exit 1 ;;
esac
else else
optimization_modes=("") optimization_modes=("-O0")
case "$OSTYPE" in
darwin*) linking_modes=("0") ;;
linux*) linking_modes=("1") ;;
*) echo "unknown: $OSTYPE"; exit 1 ;;
esac
fi fi
for optimization_mode in "${optimization_modes[@]}" for linking_mode in "${linking_modes[@]}"
do do
for optimization_mode in "${optimization_modes[@]}"
printf "\n===========================\n"
echo "TESTS ($optimization_mode)"
printf "===========================\n\n"
compile $build_dir $exe_name $debug_flags $optimization_mode;
printf "\n===========================\n"
echo "COMPILER BUILD OK"
printf "===========================\n\n"
for test_name in "${test_names[@]}"
do do
printf "\n===========================\n" printf "\n===========================\n"
echo "$test_name..." echo "TESTS (STATIC=$linking_mode, $optimization_mode)"
printf "===========================\n\n" printf "===========================\n\n"
build/nest "tests/$test_name.nat"
exe_name="${base_exe_name}_${optimization_mode}_$linking_mode"
compile $build_dir $exe_name $debug_flags $optimization_mode $linking_mode;
printf "\n===========================\n" printf "\n===========================\n"
echo "$test_name [COMPILATION] [OK]" echo "COMPILER BUILD OK"
printf "===========================\n\n"
nest/$test_name
printf "\n===========================\n"
echo "$test_name [RUN] [OK]"
printf "===========================\n\n" printf "===========================\n\n"
for test_name in "${test_names[@]}"
do
printf "\n===========================\n"
echo "$test_name..."
printf "===========================\n\n"
cmd="build/$exe_name tests/$test_name.nat"
echo "Run command: $cmd"
eval "$cmd"
printf "\n===========================\n"
echo "$test_name [COMPILATION] [OK]"
printf "===========================\n\n"
nest/$test_name
printf "\n===========================\n"
echo "$test_name [RUN] [OK]"
printf "===========================\n\n"
done
done done
done done