Minimal stack

This commit is contained in:
David Gonzalez Martin 2025-02-21 14:42:26 -06:00
parent de142080f3
commit 71f70a35fb
7 changed files with 101 additions and 29 deletions

View File

@ -72,16 +72,8 @@ jobs:
- uses: mlugg/setup-zig@v1
with:
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)
run: |
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
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

View File

@ -540,6 +540,11 @@ pub const Builder = opaque {
pub const position_at_end = api.LLVMPositionBuilderAtEnd;
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 {
return api.LLVMBuildAdd(builder, left, right, "");
}
@ -592,8 +597,14 @@ pub const Builder = opaque {
return api.LLVMBuildXor(builder, left, right, "");
}
pub fn create_ret_void(builder: *Builder) void {
builder.create_ret(null);
pub fn create_alloca(builder: *Builder, ty: *Type, name: []const u8) *Value {
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, "");
}
};

View File

@ -63,10 +63,18 @@ const CallingConvention = enum {
c,
};
const Local = struct {
name: []const u8,
alloca: *llvm.Value,
type: Type,
};
pub const FunctionBuilder = struct {
function: *llvm.Function,
current_basic_block: *llvm.BasicBlock,
return_type: Type,
local_buffer: [64]Local = undefined,
local_count: u32 = 0,
};
const Type = packed struct(u64) {
@ -252,6 +260,9 @@ const Converter = struct {
converter.expect_character(left_brace);
const local_offset = function_builder.local_count;
defer function_builder.local_count = local_offset;
while (true) {
converter.skip_space();
@ -263,31 +274,66 @@ const Converter = struct {
break;
}
const require_semicolon = true;
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();
if (string_to_enum(StatementStartKeyword, statement_start_identifier)) |statement_start_keyword| {
switch (statement_start_keyword) {
.@"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);
},
else => unreachable,
}
const require_semicolon = switch (statement_start_keyword) {
.@"return" => true,
else => converter.report_error(),
};
_ = converter.expect_or_consume(';', require_semicolon);
} else {
converter.report_error();
}
} else {
converter.report_error();
}
converter.skip_space();
if (require_semicolon) {
converter.expect_character(';');
}
}
converter.expect_character(right_brace);
@ -310,7 +356,7 @@ const Converter = struct {
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();
var value_state = ExpressionState.none;
@ -319,7 +365,7 @@ const Converter = struct {
const value = while (true) {
const current_value = switch (converter.content[converter.offset] == left_parenthesis) {
true => os.abort(),
false => converter.parse_single_value(expected_type),
false => converter.parse_single_value(thread, expected_type, function_builder),
};
converter.skip_space();
@ -424,7 +470,7 @@ const Converter = struct {
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();
const prefix_offset = converter.offset;
@ -444,7 +490,16 @@ const Converter = struct {
const value_offset = converter.offset;
const value_start_ch = converter.content[value_offset];
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),
else => os.abort(),
};

View File

@ -126,3 +126,7 @@ test "constant_or" {
test "constant_xor" {
try invsrc(@src());
}
test "minimal_stack" {
try invsrc(@src());
}

View File

@ -65,12 +65,6 @@ EXPORT bool llvm_type_is_integer(const Type& type)
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)
{
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;
}
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)
{
// No need to call stream.flush(); because it's string-based

View File

@ -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 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 LLVMGlobalGetValueType(value: *llvm.GlobalValue) *llvm.Type;

5
tests/minimal_stack.bbb Normal file
View File

@ -0,0 +1,5 @@
[export] main = fn [cc(c)] () s32
{
>result: s32 = 0;
return result;
}