Minimal stack
This commit is contained in:
parent
de142080f3
commit
71f70a35fb
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@ -72,16 +72,8 @@ jobs:
|
|||||||
- uses: mlugg/setup-zig@v1
|
- uses: mlugg/setup-zig@v1
|
||||||
with:
|
with:
|
||||||
version: master
|
version: master
|
||||||
- name: Install dependencies
|
|
||||||
run: sudo apt-get update && sudo apt-get install -y llvm-dev liblld-dev
|
|
||||||
if: matrix.os == 'ubuntu-24.04'
|
|
||||||
- name: Build and test (Packaged LLVM)
|
- name: Build and test (Packaged LLVM)
|
||||||
run: |
|
run: |
|
||||||
zig build test --summary all -Doptimize=${{matrix.BIRTH_ZIG_BUILD_TYPE}} -Dsystem_llvm=false
|
zig build test --summary all -Doptimize=${{matrix.BIRTH_ZIG_BUILD_TYPE}} -Dsystem_llvm=false
|
||||||
zig build install -Doptimize=${{matrix.BIRTH_ZIG_BUILD_TYPE}} -Dsystem_llvm=false
|
zig build install -Doptimize=${{matrix.BIRTH_ZIG_BUILD_TYPE}} -Dsystem_llvm=false
|
||||||
ldd zig-out/bin/bloat-buster
|
ldd zig-out/bin/bloat-buster
|
||||||
- name: Build and test (System LLVM)
|
|
||||||
run: |
|
|
||||||
zig build test --summary all -Doptimize=${{matrix.BIRTH_ZIG_BUILD_TYPE}} -Dsystem_llvm=true
|
|
||||||
zig build install -Doptimize=${{matrix.BIRTH_ZIG_BUILD_TYPE}} -Dsystem_llvm=true
|
|
||||||
ldd zig-out/bin/bloat-buster
|
|
||||||
|
15
src/LLVM.zig
15
src/LLVM.zig
@ -540,6 +540,11 @@ pub const Builder = opaque {
|
|||||||
pub const position_at_end = api.LLVMPositionBuilderAtEnd;
|
pub const position_at_end = api.LLVMPositionBuilderAtEnd;
|
||||||
|
|
||||||
pub const create_ret = api.LLVMBuildRet;
|
pub const create_ret = api.LLVMBuildRet;
|
||||||
|
|
||||||
|
pub fn create_ret_void(builder: *Builder) void {
|
||||||
|
builder.create_ret(null);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_add(builder: *Builder, left: *Value, right: *Value) *Value {
|
pub fn create_add(builder: *Builder, left: *Value, right: *Value) *Value {
|
||||||
return api.LLVMBuildAdd(builder, left, right, "");
|
return api.LLVMBuildAdd(builder, left, right, "");
|
||||||
}
|
}
|
||||||
@ -592,8 +597,14 @@ pub const Builder = opaque {
|
|||||||
return api.LLVMBuildXor(builder, left, right, "");
|
return api.LLVMBuildXor(builder, left, right, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_ret_void(builder: *Builder) void {
|
pub fn create_alloca(builder: *Builder, ty: *Type, name: []const u8) *Value {
|
||||||
builder.create_ret(null);
|
return api.llvm_builder_create_alloca(builder, ty, 0, String.from_slice(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const create_store = api.LLVMBuildStore;
|
||||||
|
|
||||||
|
pub fn create_load(builder: *Builder, ty: *Type, pointer: *Value) *Value {
|
||||||
|
return api.LLVMBuildLoad2(builder, ty, pointer, "");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -63,10 +63,18 @@ const CallingConvention = enum {
|
|||||||
c,
|
c,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Local = struct {
|
||||||
|
name: []const u8,
|
||||||
|
alloca: *llvm.Value,
|
||||||
|
type: Type,
|
||||||
|
};
|
||||||
|
|
||||||
pub const FunctionBuilder = struct {
|
pub const FunctionBuilder = struct {
|
||||||
function: *llvm.Function,
|
function: *llvm.Function,
|
||||||
current_basic_block: *llvm.BasicBlock,
|
current_basic_block: *llvm.BasicBlock,
|
||||||
return_type: Type,
|
return_type: Type,
|
||||||
|
local_buffer: [64]Local = undefined,
|
||||||
|
local_count: u32 = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const Type = packed struct(u64) {
|
const Type = packed struct(u64) {
|
||||||
@ -252,6 +260,9 @@ const Converter = struct {
|
|||||||
|
|
||||||
converter.expect_character(left_brace);
|
converter.expect_character(left_brace);
|
||||||
|
|
||||||
|
const local_offset = function_builder.local_count;
|
||||||
|
defer function_builder.local_count = local_offset;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
@ -263,31 +274,66 @@ const Converter = struct {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const require_semicolon = true;
|
||||||
|
|
||||||
const statement_start_ch = converter.content[converter.offset];
|
const statement_start_ch = converter.content[converter.offset];
|
||||||
if (is_identifier_start_ch(statement_start_ch)) {
|
if (statement_start_ch == '>') {
|
||||||
|
converter.offset += 1;
|
||||||
|
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
const local_name = converter.parse_identifier();
|
||||||
|
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
if (converter.consume_character_if_match(':')) {
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
const local_type = converter.parse_type(thread);
|
||||||
|
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
converter.expect_character('=');
|
||||||
|
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
const value = converter.parse_value(thread, local_type, function_builder);
|
||||||
|
const alloca = thread.builder.create_alloca(local_type.get(), local_name);
|
||||||
|
_ = thread.builder.create_store(value, alloca);
|
||||||
|
|
||||||
|
const local = &function_builder.local_buffer[function_builder.local_count];
|
||||||
|
function_builder.local_count += 1;
|
||||||
|
local.* = .{
|
||||||
|
.name = local_name,
|
||||||
|
.alloca = alloca,
|
||||||
|
.type = local_type,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
converter.report_error();
|
||||||
|
}
|
||||||
|
} else if (is_identifier_start_ch(statement_start_ch)) {
|
||||||
const statement_start_identifier = converter.parse_identifier();
|
const statement_start_identifier = converter.parse_identifier();
|
||||||
|
|
||||||
if (string_to_enum(StatementStartKeyword, statement_start_identifier)) |statement_start_keyword| {
|
if (string_to_enum(StatementStartKeyword, statement_start_identifier)) |statement_start_keyword| {
|
||||||
switch (statement_start_keyword) {
|
switch (statement_start_keyword) {
|
||||||
.@"return" => {
|
.@"return" => {
|
||||||
const return_value = converter.parse_value(thread, function_builder.return_type);
|
const return_value = converter.parse_value(thread, function_builder.return_type, function_builder);
|
||||||
thread.builder.create_ret(return_value);
|
thread.builder.create_ret(return_value);
|
||||||
},
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
|
|
||||||
const require_semicolon = switch (statement_start_keyword) {
|
|
||||||
.@"return" => true,
|
|
||||||
else => converter.report_error(),
|
|
||||||
};
|
|
||||||
|
|
||||||
_ = converter.expect_or_consume(';', require_semicolon);
|
|
||||||
} else {
|
} else {
|
||||||
converter.report_error();
|
converter.report_error();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
converter.report_error();
|
converter.report_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
if (require_semicolon) {
|
||||||
|
converter.expect_character(';');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
converter.expect_character(right_brace);
|
converter.expect_character(right_brace);
|
||||||
@ -310,7 +356,7 @@ const Converter = struct {
|
|||||||
xor,
|
xor,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn parse_value(noalias converter: *Converter, noalias thread: *llvm.Thread, expected_type: Type) *llvm.Value {
|
fn parse_value(noalias converter: *Converter, noalias thread: *llvm.Thread, expected_type: Type, function_builder: *FunctionBuilder) *llvm.Value {
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
var value_state = ExpressionState.none;
|
var value_state = ExpressionState.none;
|
||||||
@ -319,7 +365,7 @@ const Converter = struct {
|
|||||||
const value = while (true) {
|
const value = while (true) {
|
||||||
const current_value = switch (converter.content[converter.offset] == left_parenthesis) {
|
const current_value = switch (converter.content[converter.offset] == left_parenthesis) {
|
||||||
true => os.abort(),
|
true => os.abort(),
|
||||||
false => converter.parse_single_value(expected_type),
|
false => converter.parse_single_value(thread, expected_type, function_builder),
|
||||||
};
|
};
|
||||||
|
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
@ -424,7 +470,7 @@ const Converter = struct {
|
|||||||
negative,
|
negative,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn parse_single_value(noalias converter: *Converter, expected_type: Type) *llvm.Value {
|
fn parse_single_value(noalias converter: *Converter, thread: *llvm.Thread, expected_type: Type, noalias function_builder: *FunctionBuilder) *llvm.Value {
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
const prefix_offset = converter.offset;
|
const prefix_offset = converter.offset;
|
||||||
@ -444,7 +490,16 @@ const Converter = struct {
|
|||||||
const value_offset = converter.offset;
|
const value_offset = converter.offset;
|
||||||
const value_start_ch = converter.content[value_offset];
|
const value_start_ch = converter.content[value_offset];
|
||||||
const value = switch (value_start_ch) {
|
const value = switch (value_start_ch) {
|
||||||
'a'...'z', 'A'...'Z', '_' => os.abort(),
|
'a'...'z', 'A'...'Z', '_' => b: {
|
||||||
|
const identifier = converter.parse_identifier();
|
||||||
|
for (function_builder.local_buffer[0..function_builder.local_count]) |*local| {
|
||||||
|
if (lib.string.equal(identifier, local.name)) {
|
||||||
|
break :b thread.builder.create_load(local.type.get(), local.alloca);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
os.abort();
|
||||||
|
}
|
||||||
|
},
|
||||||
'0'...'9' => converter.parse_integer(expected_type, prefix == .negative),
|
'0'...'9' => converter.parse_integer(expected_type, prefix == .negative),
|
||||||
else => os.abort(),
|
else => os.abort(),
|
||||||
};
|
};
|
||||||
|
@ -126,3 +126,7 @@ test "constant_or" {
|
|||||||
test "constant_xor" {
|
test "constant_xor" {
|
||||||
try invsrc(@src());
|
try invsrc(@src());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "minimal_stack" {
|
||||||
|
try invsrc(@src());
|
||||||
|
}
|
||||||
|
13
src/llvm.cpp
13
src/llvm.cpp
@ -65,12 +65,6 @@ EXPORT bool llvm_type_is_integer(const Type& type)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT Value* llvm_builder_create_add(IRBuilder<>& builder, Value* left, Value* right, bool nuw, bool nsw)
|
|
||||||
{
|
|
||||||
auto* result = builder.CreateAdd(left, right, "", nuw, nsw);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT Function* llvm_module_create_function(Module* module, FunctionType* function_type, GlobalValue::LinkageTypes linkage_type, unsigned address_space, BBLLVMString name)
|
EXPORT Function* llvm_module_create_function(Module* module, FunctionType* function_type, GlobalValue::LinkageTypes linkage_type, unsigned address_space, BBLLVMString name)
|
||||||
{
|
{
|
||||||
auto* function = Function::Create(function_type, linkage_type, address_space, name.string_ref(), module);
|
auto* function = Function::Create(function_type, linkage_type, address_space, name.string_ref(), module);
|
||||||
@ -97,6 +91,13 @@ EXPORT BasicBlock* llvm_context_create_basic_block(LLVMContext& context, BBLLVMS
|
|||||||
return basic_block;
|
return basic_block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXPORT AllocaInst* llvm_builder_create_alloca(IRBuilder<>& builder, Type* type, unsigned address_space, BBLLVMString name)
|
||||||
|
{
|
||||||
|
const DataLayout &data_layout = builder.GetInsertBlock()->getDataLayout();
|
||||||
|
Align alignment = data_layout.getABITypeAlign(type);
|
||||||
|
return builder.Insert(new AllocaInst(type, address_space, 0, alignment), name.string_ref());
|
||||||
|
}
|
||||||
|
|
||||||
fn BBLLVMString stream_to_string(raw_string_ostream& stream)
|
fn BBLLVMString stream_to_string(raw_string_ostream& stream)
|
||||||
{
|
{
|
||||||
// No need to call stream.flush(); because it's string-based
|
// No need to call stream.flush(); because it's string-based
|
||||||
|
@ -33,6 +33,10 @@ pub extern fn LLVMBuildAnd(builder: *llvm.Builder, left: *llvm.Value, right: *ll
|
|||||||
pub extern fn LLVMBuildOr(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
|
pub extern fn LLVMBuildOr(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
|
||||||
pub extern fn LLVMBuildXor(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
|
pub extern fn LLVMBuildXor(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
|
||||||
|
|
||||||
|
pub extern fn llvm_builder_create_alloca(builder: *llvm.Builder, ty: *llvm.Type, address_space: c_uint, name: llvm.String) *llvm.Value;
|
||||||
|
pub extern fn LLVMBuildStore(builder: *llvm.Builder, value: *llvm.Value, pointer: *llvm.Value) *llvm.Value;
|
||||||
|
pub extern fn LLVMBuildLoad2(builder: *llvm.Builder, ty: *llvm.Type, pointer: *llvm.Value, name: [*:0]const u8) *llvm.Value;
|
||||||
|
|
||||||
pub extern fn LLVMTypeOf(value: *llvm.Value) *llvm.Type;
|
pub extern fn LLVMTypeOf(value: *llvm.Value) *llvm.Type;
|
||||||
pub extern fn LLVMGlobalGetValueType(value: *llvm.GlobalValue) *llvm.Type;
|
pub extern fn LLVMGlobalGetValueType(value: *llvm.GlobalValue) *llvm.Type;
|
||||||
|
|
||||||
|
5
tests/minimal_stack.bbb
Normal file
5
tests/minimal_stack.bbb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[export] main = fn [cc(c)] () s32
|
||||||
|
{
|
||||||
|
>result: s32 = 0;
|
||||||
|
return result;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user