Constant div

This commit is contained in:
David Gonzalez Martin 2025-02-21 12:48:44 -06:00
parent 7bd79cb741
commit 1c8fd82e1f
4 changed files with 89 additions and 55 deletions

View File

@ -552,6 +552,14 @@ pub const Builder = opaque {
return api.LLVMBuildMul(builder, left, right, ""); return api.LLVMBuildMul(builder, left, right, "");
} }
pub fn create_sdiv(builder: *Builder, left: *Value, right: *Value) *Value {
return api.LLVMBuildSDiv(builder, left, right, "");
}
pub fn create_udiv(builder: *Builder, left: *Value, right: *Value) *Value {
return api.LLVMBuildUDiv(builder, left, right, "");
}
pub fn create_ret_void(builder: *Builder) void { pub fn create_ret_void(builder: *Builder) void {
builder.create_ret(null); builder.create_ret(null);
} }
@ -807,11 +815,6 @@ const LldArgvBuilder = struct {
} }
}; };
pub const FunctionBuilder = struct {
function: *Function,
current_basic_block: *BasicBlock,
};
pub fn default_initialize() *Thread { pub fn default_initialize() *Thread {
assert(lib.GlobalState.initialized); assert(lib.GlobalState.initialized);
if (!initialized) { if (!initialized) {

View File

@ -59,6 +59,29 @@ const CallingConvention = enum {
c, c,
}; };
pub const FunctionBuilder = struct {
function: *llvm.Function,
current_basic_block: *llvm.BasicBlock,
return_type: Type,
};
const Type = packed struct(u64) {
llvm: u48,
signedness: bool,
reserved: u15 = 0,
pub fn new(llvm_type: *llvm.Type, signedness: bool) Type {
return .{
.llvm = @intCast(@intFromPtr(llvm_type)),
.signedness = signedness,
};
}
pub fn get(t: Type) *llvm.Type {
return @ptrFromInt(t.llvm);
}
};
const Converter = struct { const Converter = struct {
content: []const u8, content: []const u8,
offset: usize, offset: usize,
@ -75,7 +98,7 @@ const Converter = struct {
} }
} }
pub fn parse_type(noalias converter: *Converter, noalias thread: *llvm.Thread) *llvm.Type { pub fn parse_type(noalias converter: *Converter, noalias thread: *llvm.Thread) Type {
const identifier = converter.parse_identifier(); const identifier = converter.parse_identifier();
var integer_type = identifier.len > 1 and identifier[0] == 's' or identifier[0] == 'u'; var integer_type = identifier.len > 1 and identifier[0] == 's' or identifier[0] == 'u';
if (integer_type) { if (integer_type) {
@ -85,6 +108,11 @@ const Converter = struct {
} }
if (integer_type) { if (integer_type) {
const signedness = switch (identifier[0]) {
's' => true,
'u' => false,
else => unreachable,
};
const bit_count = lib.parse.integer_decimal(identifier[1..]); const bit_count = lib.parse.integer_decimal(identifier[1..]);
const llvm_int_type = switch (bit_count) { const llvm_int_type = switch (bit_count) {
// TODO: consider u1? // TODO: consider u1?
@ -96,7 +124,7 @@ const Converter = struct {
else => converter.report_error(), else => converter.report_error(),
}; };
const llvm_type = llvm_int_type.to_type(); const llvm_type = llvm_int_type.to_type();
return llvm_type; return Type.new(llvm_type, signedness);
} else { } else {
os.abort(); os.abort();
} }
@ -159,33 +187,19 @@ const Converter = struct {
return value; return value;
} }
fn parse_integer(noalias converter: *Converter, expected_type: *llvm.Type, signed: bool) *llvm.Value { fn parse_integer(noalias converter: *Converter, expected_type: Type, sign: bool) *llvm.Value {
const start = converter.offset; const start = converter.offset;
const integer_start_ch = converter.content[start]; const integer_start_ch = converter.content[start];
assert(!is_space(integer_start_ch)); assert(!is_space(integer_start_ch));
assert(is_decimal_ch(integer_start_ch)); assert(is_decimal_ch(integer_start_ch));
const integer_type = expected_type.to_integer();
const sign_extend = signed; const value: u64 = switch (integer_start_ch) {
'0' => blk: {
converter.offset += 1;
const value: u64 = switch (signed) { const next_ch = converter.content[converter.offset];
true => switch (integer_start_ch) { break :blk switch (sign) {
'0' => blk: { false => switch (next_ch) {
converter.offset += 1;
switch (converter.content[converter.offset]) {
'x', 'o', 'b', '0'...'9' => converter.report_error(),
else => break :blk 0,
}
},
'1'...'9' => @bitCast(-@as(i64, @intCast(converter.parse_decimal()))),
else => unreachable,
},
false => switch (integer_start_ch) {
'0' => blk: {
converter.offset += 1;
switch (converter.content[converter.offset]) {
'x' => { 'x' => {
// TODO: parse hexadecimal // TODO: parse hexadecimal
converter.report_error(); converter.report_error();
@ -202,15 +216,24 @@ const Converter = struct {
converter.report_error(); converter.report_error();
}, },
// Zero literal // Zero literal
else => break :blk 0, else => 0,
} },
}, true => switch (next_ch) {
'1'...'9' => converter.parse_decimal(), 'x', 'o', 'b', '0' => converter.report_error(),
else => unreachable, '1'...'9' => @bitCast(-@as(i64, @intCast(converter.parse_decimal()))),
else => unreachable,
},
};
}, },
'1'...'9' => switch (sign) {
true => @bitCast(-@as(i64, @intCast(converter.parse_decimal()))),
false => converter.parse_decimal(),
},
else => unreachable,
}; };
const integer_value = integer_type.get_constant(value, @intFromBool(sign_extend)); const integer_type = expected_type.get().to_integer();
const integer_value = integer_type.get_constant(value, @intFromBool(expected_type.signedness));
return integer_value.to_value(); return integer_value.to_value();
} }
@ -220,7 +243,7 @@ const Converter = struct {
} }
} }
fn parse_block(noalias converter: *Converter, noalias thread: *llvm.Thread, noalias function_builder: *llvm.FunctionBuilder) void { fn parse_block(noalias converter: *Converter, noalias thread: *llvm.Thread, noalias function_builder: *FunctionBuilder) void {
converter.skip_space(); converter.skip_space();
converter.expect_character(left_brace); converter.expect_character(left_brace);
@ -243,7 +266,7 @@ const Converter = struct {
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.function.get_type().get_return_type()); const return_value = converter.parse_value(thread, function_builder.return_type);
thread.builder.create_ret(return_value); thread.builder.create_ret(return_value);
}, },
else => unreachable, else => unreachable,
@ -271,9 +294,11 @@ const Converter = struct {
add, add,
sub, sub,
mul, mul,
udiv,
sdiv,
}; };
fn parse_value(noalias converter: *Converter, noalias thread: *llvm.Thread, expected_type: *llvm.Type) *llvm.Value { fn parse_value(noalias converter: *Converter, noalias thread: *llvm.Thread, expected_type: Type) *llvm.Value {
converter.skip_space(); converter.skip_space();
var value_state = ExpressionState.none; var value_state = ExpressionState.none;
@ -295,6 +320,8 @@ const Converter = struct {
.sub => thread.builder.create_sub(left, right), .sub => thread.builder.create_sub(left, right),
.add => thread.builder.create_add(left, right), .add => thread.builder.create_add(left, right),
.mul => thread.builder.create_mul(left, right), .mul => thread.builder.create_mul(left, right),
.sdiv => thread.builder.create_sdiv(left, right),
.udiv => thread.builder.create_udiv(left, right),
}; };
const ch = converter.content[converter.offset]; const ch = converter.content[converter.offset];
@ -312,6 +339,13 @@ const Converter = struct {
converter.offset += 1; converter.offset += 1;
break :blk .mul; break :blk .mul;
}, },
'/' => blk: {
converter.offset += 1;
switch (expected_type.signedness) {
true => break :blk .sdiv,
false => break :blk .udiv,
}
},
else => os.abort(), else => os.abort(),
}; };
@ -326,12 +360,11 @@ const Converter = struct {
negative, negative,
}; };
fn parse_single_value(noalias converter: *Converter, expected_type: *llvm.Type) *llvm.Value { fn parse_single_value(noalias converter: *Converter, expected_type: Type) *llvm.Value {
converter.skip_space(); converter.skip_space();
const prefix_offset = converter.offset; const prefix_offset = converter.offset;
const prefix_ch = converter.content[prefix_offset]; const prefix_ch = converter.content[prefix_offset];
var is_signed = false;
const prefix: Prefix = switch (prefix_ch) { const prefix: Prefix = switch (prefix_ch) {
'a'...'z', 'A'...'Z', '_', '0'...'9' => .none, 'a'...'z', 'A'...'Z', '_', '0'...'9' => .none,
'-' => blk: { '-' => blk: {
@ -339,33 +372,20 @@ const Converter = struct {
// TODO: should we skip space here? // TODO: should we skip space here?
converter.skip_space(); converter.skip_space();
is_signed = true;
break :blk .negative; break :blk .negative;
}, },
else => os.abort(), else => os.abort(),
}; };
_ = prefix;
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', '_' => os.abort(),
'0'...'9' => converter.parse_integer(expected_type, is_signed), '0'...'9' => converter.parse_integer(expected_type, prefix == .negative),
else => os.abort(), else => os.abort(),
}; };
return value; return value;
// if (is_identifier_start_ch(value_start_ch)) {
// converter.report_error();
// } else if (is_decimal_ch(value_start_ch)) {
// const value = converter.parse_integer(expected_type);
// return value;
// } else if ({
// switch (value_start_ch) {
//
// }
// converter.report_error();
// }
} }
}; };
@ -607,7 +627,7 @@ pub noinline fn convert(options: ConvertOptions) void {
converter.skip_space(); converter.skip_space();
const return_type = converter.parse_type(thread); const return_type = converter.parse_type(thread);
const function_type = llvm.Type.Function.get(return_type, &.{}, false); const function_type = llvm.Type.Function.get(return_type.get(), &.{}, false);
const function = module.create_function(.{ const function = module.create_function(.{
.name = global_name, .name = global_name,
@ -621,9 +641,10 @@ pub noinline fn convert(options: ConvertOptions) void {
const entry_block = thread.context.create_basic_block("entry", function); const entry_block = thread.context.create_basic_block("entry", function);
thread.builder.position_at_end(entry_block); thread.builder.position_at_end(entry_block);
var function_builder = llvm.FunctionBuilder{ var function_builder = FunctionBuilder{
.function = function, .function = function,
.current_basic_block = entry_block, .current_basic_block = entry_block,
.return_type = return_type,
}; };
converter.parse_block(thread, &function_builder); converter.parse_block(thread, &function_builder);
@ -703,3 +724,7 @@ test "constant sub" {
test "constant mul" { test "constant mul" {
try invoke("constant_mul"); try invoke("constant_mul");
} }
test "constant div" {
try invoke("constant_div");
}

View File

@ -22,6 +22,8 @@ pub extern fn LLVMBuildRet(builder: *llvm.Builder, value: ?*llvm.Value) void;
pub extern fn LLVMBuildAdd(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value; pub extern fn LLVMBuildAdd(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildSub(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value; pub extern fn LLVMBuildSub(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildMul(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value; pub extern fn LLVMBuildMul(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildSDiv(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildUDiv(builder: *llvm.Builder, left: *llvm.Value, right: *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;

4
tests/constant_div.bbb Normal file
View File

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