Merge pull request #18 from birth-software/iterate-peephole
Implement peephole iteration skeleton
This commit is contained in:
commit
7c7edeed1c
213
bootstrap/main.c
213
bootstrap/main.c
@ -1558,7 +1558,7 @@ typedef struct Thread Thread;
|
|||||||
typedef enum TypeId : u32
|
typedef enum TypeId : u32
|
||||||
{
|
{
|
||||||
// Simple types
|
// Simple types
|
||||||
TYPE_BOT = 0,
|
TYPE_BOTTOM = 0,
|
||||||
TYPE_TOP,
|
TYPE_TOP,
|
||||||
TYPE_LIVE_CONTROL,
|
TYPE_LIVE_CONTROL,
|
||||||
TYPE_DEAD_CONTROL,
|
TYPE_DEAD_CONTROL,
|
||||||
@ -1780,6 +1780,59 @@ struct InternPool
|
|||||||
};
|
};
|
||||||
typedef struct InternPool InternPool;
|
typedef struct InternPool InternPool;
|
||||||
|
|
||||||
|
typedef u64 BitsetElement;
|
||||||
|
decl_vb(BitsetElement);
|
||||||
|
declare_slice(BitsetElement);
|
||||||
|
struct Bitset
|
||||||
|
{
|
||||||
|
VirtualBuffer(BitsetElement) arr;
|
||||||
|
u32 length;
|
||||||
|
};
|
||||||
|
typedef struct Bitset Bitset;
|
||||||
|
const u64 element_bitsize = sizeof(u64) * 8;
|
||||||
|
|
||||||
|
fn u8 bitset_get(Bitset* bitset, u64 index)
|
||||||
|
{
|
||||||
|
auto element_index = index / element_bitsize;
|
||||||
|
if (element_index < bitset->arr.length)
|
||||||
|
{
|
||||||
|
auto bit_index = index % element_bitsize;
|
||||||
|
auto result = (bitset->arr.pointer[element_index] & (1 << bit_index)) != 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void bitset_ensure_length(Bitset* bitset, u64 max)
|
||||||
|
{
|
||||||
|
auto length = (max / (sizeof(u64) * 8)) + (max % (sizeof(u64) * 8) != 0);
|
||||||
|
auto old_length = bitset->arr.length;
|
||||||
|
if (old_length < length)
|
||||||
|
{
|
||||||
|
auto new_element_count = length - old_length;
|
||||||
|
unused(vb_add(&bitset->arr, new_element_count));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void bitset_set_assert_unset(Bitset* bitset, u64 index)
|
||||||
|
{
|
||||||
|
bitset_ensure_length(bitset, index + 1);
|
||||||
|
auto element_index = index / element_bitsize;
|
||||||
|
auto bit_index = index % element_bitsize;
|
||||||
|
assert((bitset->arr.pointer[element_index] & (1 << bit_index)) == 0);
|
||||||
|
bitset->arr.pointer[element_index] |= 1 << bit_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WorkList
|
||||||
|
{
|
||||||
|
VirtualBuffer(NodeIndex) nodes;
|
||||||
|
Bitset visited;
|
||||||
|
Bitset bitset;
|
||||||
|
u32 mid_assert:1;
|
||||||
|
};
|
||||||
|
typedef struct WorkList WorkList;
|
||||||
|
|
||||||
struct Thread
|
struct Thread
|
||||||
{
|
{
|
||||||
Arena* arena;
|
Arena* arena;
|
||||||
@ -1815,6 +1868,7 @@ struct Thread
|
|||||||
u64 total;
|
u64 total;
|
||||||
u64 nop;
|
u64 nop;
|
||||||
} iteration;
|
} iteration;
|
||||||
|
WorkList worklist;
|
||||||
};
|
};
|
||||||
typedef struct Thread Thread;
|
typedef struct Thread Thread;
|
||||||
|
|
||||||
@ -2611,8 +2665,14 @@ fn NodeIndex idealize_stop(Thread* thread, NodeIndex node_index)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn TypeIndex compute_type_start(Thread* thread, NodeIndex node_index)
|
||||||
|
{
|
||||||
|
auto* node = thread_node_get(thread, node_index);
|
||||||
|
return node->start.arguments;
|
||||||
|
}
|
||||||
|
|
||||||
global const TypeVirtualTable type_functions[TYPE_COUNT] = {
|
global const TypeVirtualTable type_functions[TYPE_COUNT] = {
|
||||||
[TYPE_BOT] = { .get_hash = &type_get_hash_default },
|
[TYPE_BOTTOM] = { .get_hash = &type_get_hash_default },
|
||||||
[TYPE_TOP] = { .get_hash = &type_get_hash_default },
|
[TYPE_TOP] = { .get_hash = &type_get_hash_default },
|
||||||
[TYPE_LIVE_CONTROL] = { .get_hash = &type_get_hash_default },
|
[TYPE_LIVE_CONTROL] = { .get_hash = &type_get_hash_default },
|
||||||
[TYPE_DEAD_CONTROL] = { .get_hash = &type_get_hash_default },
|
[TYPE_DEAD_CONTROL] = { .get_hash = &type_get_hash_default },
|
||||||
@ -2621,6 +2681,10 @@ global const TypeVirtualTable type_functions[TYPE_COUNT] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
global const NodeVirtualTable node_functions[NODE_COUNT] = {
|
global const NodeVirtualTable node_functions[NODE_COUNT] = {
|
||||||
|
[NODE_START] = {
|
||||||
|
.compute_type = &compute_type_start,
|
||||||
|
.idealize = &idealize_null,
|
||||||
|
},
|
||||||
[NODE_STOP] = {
|
[NODE_STOP] = {
|
||||||
.compute_type = &compute_type_bottom,
|
.compute_type = &compute_type_bottom,
|
||||||
.idealize = &idealize_stop,
|
.idealize = &idealize_stop,
|
||||||
@ -2958,7 +3022,8 @@ fn TypeIndex type_meet(Thread* thread, TypeIndex a, TypeIndex b)
|
|||||||
}
|
}
|
||||||
else if (type_is_simple(a_type))
|
else if (type_is_simple(a_type))
|
||||||
{
|
{
|
||||||
trap();
|
left = a;
|
||||||
|
right = b;
|
||||||
}
|
}
|
||||||
else if (type_is_simple(b_type))
|
else if (type_is_simple(b_type))
|
||||||
{
|
{
|
||||||
@ -2985,25 +3050,49 @@ fn TypeIndex type_meet(Thread* thread, TypeIndex a, TypeIndex b)
|
|||||||
auto integer_top = thread->types.integer.top;
|
auto integer_top = thread->types.integer.top;
|
||||||
if (index_equal(left, integer_bot))
|
if (index_equal(left, integer_bot))
|
||||||
{
|
{
|
||||||
result = a;
|
result = left;
|
||||||
}
|
}
|
||||||
else if (index_equal(right, integer_bot))
|
else if (index_equal(right, integer_bot))
|
||||||
{
|
{
|
||||||
result = b;
|
result = right;
|
||||||
}
|
}
|
||||||
else if (index_equal(right, integer_top))
|
else if (index_equal(right, integer_top))
|
||||||
{
|
{
|
||||||
result = a;
|
result = left;
|
||||||
}
|
}
|
||||||
else if (index_equal(left, integer_top))
|
else if (index_equal(left, integer_top))
|
||||||
{
|
{
|
||||||
result = b;
|
result = right;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = integer_bot;
|
result = integer_bot;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
case TYPE_BOTTOM:
|
||||||
|
{
|
||||||
|
assert(type_is_simple(left_type));
|
||||||
|
if ((left_type->id == TYPE_BOTTOM) | (right_type->id == TYPE_TOP))
|
||||||
|
{
|
||||||
|
result = left;
|
||||||
|
}
|
||||||
|
else if ((left_type->id == TYPE_TOP) | (right_type->id == TYPE_BOTTOM))
|
||||||
|
{
|
||||||
|
result = right;
|
||||||
|
}
|
||||||
|
else if (!type_is_simple(right_type))
|
||||||
|
{
|
||||||
|
result = thread->types.bottom;
|
||||||
|
}
|
||||||
|
else if (left_type->id == TYPE_LIVE_CONTROL)
|
||||||
|
{
|
||||||
|
result = thread->types.live_control;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = thread->types.dead_control;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
trap();
|
trap();
|
||||||
}
|
}
|
||||||
@ -3618,6 +3707,98 @@ fn void analyze_file(Thread* thread, File* file)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef NodeIndex NodeCallback(Thread* thread, NodeIndex node_index);
|
||||||
|
|
||||||
|
fn NodeIndex node_walk_internal(Thread* thread, NodeIndex node_index, NodeCallback* callback)
|
||||||
|
{
|
||||||
|
if (bitset_get(&thread->worklist.visited, geti(node_index)))
|
||||||
|
{
|
||||||
|
return invalidi(Node);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bitset_set_assert_unset(&thread->worklist.visited, geti(node_index));
|
||||||
|
auto callback_result = callback(thread, node_index);
|
||||||
|
if (validi(callback_result))
|
||||||
|
{
|
||||||
|
return callback_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* node = thread_node_get(thread, node_index);
|
||||||
|
auto inputs = node_get_inputs(thread, node);
|
||||||
|
auto outputs = node_get_outputs(thread, node);
|
||||||
|
|
||||||
|
for (u64 i = 0; i < inputs.length; i += 1)
|
||||||
|
{
|
||||||
|
auto n = inputs.pointer[i];
|
||||||
|
if (validi(n))
|
||||||
|
{
|
||||||
|
auto n_result = node_walk_internal(thread, n, callback);
|
||||||
|
if (validi(n_result))
|
||||||
|
{
|
||||||
|
return n_result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u64 i = 0; i < outputs.length; i += 1)
|
||||||
|
{
|
||||||
|
auto n = outputs.pointer[i];
|
||||||
|
if (validi(n))
|
||||||
|
{
|
||||||
|
auto n_result = node_walk_internal(thread, n, callback);
|
||||||
|
if (validi(n_result))
|
||||||
|
{
|
||||||
|
return n_result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return invalidi(Node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn NodeIndex node_walk(Thread* thread, NodeIndex node_index, NodeCallback* callback)
|
||||||
|
{
|
||||||
|
assert(thread->worklist.visited.length == 0);
|
||||||
|
NodeIndex result = node_walk_internal(thread, node_index, callback);
|
||||||
|
thread->worklist.visited.length = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn NodeIndex progress_on_list_callback(Thread* thread, NodeIndex node_index)
|
||||||
|
{
|
||||||
|
if (bitset_get(&thread->worklist.bitset, geti(node_index)))
|
||||||
|
{
|
||||||
|
trap();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NodeIndex new_node = peephole_optimize(thread, node_index);
|
||||||
|
return new_node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u8 progress_on_list(Thread* thread, NodeIndex stop_node)
|
||||||
|
{
|
||||||
|
thread->worklist.mid_assert = 1;
|
||||||
|
|
||||||
|
NodeIndex changed = node_walk(thread, stop_node, &progress_on_list_callback);
|
||||||
|
|
||||||
|
thread->worklist.mid_assert = 0;
|
||||||
|
|
||||||
|
return !validi(changed);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void iterate_peepholes(Thread* thread, NodeIndex stop_node_index)
|
||||||
|
{
|
||||||
|
assert(progress_on_list(thread, stop_node_index));
|
||||||
|
if (thread->worklist.nodes.length > 0)
|
||||||
|
{
|
||||||
|
trap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn void thread_init(Thread* thread)
|
fn void thread_init(Thread* thread)
|
||||||
{
|
{
|
||||||
*thread = (Thread) {
|
*thread = (Thread) {
|
||||||
@ -3627,7 +3808,7 @@ fn void thread_init(Thread* thread)
|
|||||||
memset(&top, 0, sizeof(Type));
|
memset(&top, 0, sizeof(Type));
|
||||||
top.id = TYPE_TOP;
|
top.id = TYPE_TOP;
|
||||||
memset(&bot, 0, sizeof(Type));
|
memset(&bot, 0, sizeof(Type));
|
||||||
bot.id = TYPE_BOT;
|
bot.id = TYPE_BOTTOM;
|
||||||
memset(&live_control, 0, sizeof(Type));
|
memset(&live_control, 0, sizeof(Type));
|
||||||
live_control.id = TYPE_LIVE_CONTROL;
|
live_control.id = TYPE_LIVE_CONTROL;
|
||||||
memset(&dead_control, 0, sizeof(Type));
|
memset(&dead_control, 0, sizeof(Type));
|
||||||
@ -3864,7 +4045,8 @@ fn void thread_clear(Thread* thread)
|
|||||||
//
|
//
|
||||||
// system("clang main.o -o main.exe");
|
// system("clang main.o -o main.exe");
|
||||||
|
|
||||||
|
#define DO_UNIT_TESTS 1
|
||||||
|
#if DO_UNIT_TESTS
|
||||||
fn void unit_tests()
|
fn void unit_tests()
|
||||||
{
|
{
|
||||||
for (u64 power = 1, log2_i = 0; log2_i < 64; power <<= 1, log2_i += 1)
|
for (u64 power = 1, log2_i = 0; log2_i < 64; power <<= 1, log2_i += 1)
|
||||||
@ -3872,6 +4054,7 @@ fn void unit_tests()
|
|||||||
assert(log2_alignment(power) == log2_i);
|
assert(log2_alignment(power) == log2_i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if LINK_LIBC
|
#if LINK_LIBC
|
||||||
int main()
|
int main()
|
||||||
@ -3879,9 +4062,9 @@ int main()
|
|||||||
extern "C" void entry_point()
|
extern "C" void entry_point()
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
{
|
#if DO_UNIT_TESTS
|
||||||
unit_tests();
|
unit_tests();
|
||||||
}
|
#endif
|
||||||
Arena* global_arena = arena_init_default(KB(64));
|
Arena* global_arena = arena_init_default(KB(64));
|
||||||
Thread* thread = arena_allocate(global_arena, Thread, 1);
|
Thread* thread = arena_allocate(global_arena, Thread, 1);
|
||||||
thread_init(thread);
|
thread_init(thread);
|
||||||
@ -3893,6 +4076,14 @@ extern "C" void entry_point()
|
|||||||
.source = file_read(thread->arena, test_files[i]),
|
.source = file_read(thread->arena, test_files[i]),
|
||||||
};
|
};
|
||||||
analyze_file(thread, &file);
|
analyze_file(thread, &file);
|
||||||
|
|
||||||
|
for (u32 function_i = 0; function_i < thread->buffer.functions.length; function_i += 1)
|
||||||
|
{
|
||||||
|
Function* function = &thread->buffer.functions.pointer[function_i];
|
||||||
|
NodeIndex stop_node_index = function->stop;
|
||||||
|
iterate_peepholes(thread, stop_node_index);
|
||||||
|
}
|
||||||
|
|
||||||
thread_clear(thread);
|
thread_clear(thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user