Fix range compute

This commit is contained in:
David Gonzalez Martin 2024-02-12 12:53:05 -06:00
parent e664e10666
commit bd6c637f7c
5 changed files with 159 additions and 41 deletions

View File

@ -717,6 +717,7 @@ pub const Instruction = union(enum) {
pub const BasicBlock = struct{ pub const BasicBlock = struct{
instructions: ArrayList(Instruction.Index) = .{}, instructions: ArrayList(Instruction.Index) = .{},
useful_instructions: usize = 0,
predecessor: BasicBlock.Index = .null, predecessor: BasicBlock.Index = .null,
// TODO: not use a bool // TODO: not use a bool
terminated: bool = false, terminated: bool = false,
@ -812,6 +813,7 @@ pub const V = struct{
pub const Comptime = union(enum){ pub const Comptime = union(enum){
unresolved: Node.Index, unresolved: Node.Index,
undefined, undefined,
void,
type: Type.Index, type: Type.Index,
bool: bool, bool: bool,
comptime_int: ComptimeInt, comptime_int: ComptimeInt,
@ -1476,9 +1478,7 @@ pub const Builder = struct {
try builder.branch(unit, context, instruction_index, true_block, false_block); try builder.branch(unit, context, instruction_index, true_block, false_block);
builder.current_basic_block = false_block; builder.current_basic_block = false_block;
const unreachable_instruction = try unit.instructions.append(context.allocator, .@"unreachable"); try builder.buildUnreachable(unit, context);
// TODO: terminate block properly
try builder.appendInstruction(unit, context, unreachable_instruction);
builder.current_basic_block = true_block; builder.current_basic_block = true_block;
}, },
@ -1639,6 +1639,38 @@ pub const Builder = struct {
fn appendInstruction(builder: *Builder, unit: *Unit, context: *const Context, instruction_index: Instruction.Index) !void { fn appendInstruction(builder: *Builder, unit: *Unit, context: *const Context, instruction_index: Instruction.Index) !void {
const basic_block = unit.basic_blocks.get(builder.current_basic_block); const basic_block = unit.basic_blocks.get(builder.current_basic_block);
if (!basic_block.terminated) { if (!basic_block.terminated) {
basic_block.useful_instructions += @intFromBool(switch (unit.instructions.get(instruction_index).*) {
.argument_declaration,
.branch,
.call,
.cast,
.constant_int,
.extract_value,
.insert_value,
.get_element_pointer,
.global,
.inline_assembly,
.integer_compare,
.integer_binary_operation,
.jump,
.load,
.umin,
.smin,
.phi,
.ret,
.ret_void,
.stack_slot,
.store,
.syscall,
.@"unreachable",
=> true,
.block,
.pop_scope,
.push_scope,
.debug_checkpoint,
.debug_declare_local_variable,
=> false,
});
try basic_block.instructions.append(context.allocator, instruction_index); try basic_block.instructions.append(context.allocator, instruction_index);
} else { } else {
const instruction = unit.instructions.get(instruction_index); const instruction = unit.instructions.get(instruction_index);
@ -1944,6 +1976,35 @@ pub const Builder = struct {
if (body_node.id == .block) { if (body_node.id == .block) {
function.body = try builder.resolveBlock(unit, context, body_node_index); function.body = try builder.resolveBlock(unit, context, body_node_index);
if (builder.return_block == .null) {
const cbb = unit.basic_blocks.get(builder.current_basic_block);
const function_prototype = unit.function_prototypes.get(function_prototype_index);
const return_type = function_prototype.return_type;
if (!cbb.terminated) {
switch (function_prototype.attributes.naked) {
true => {
assert(return_type == .noreturn);
try builder.buildUnreachable(unit, context);
},
false => switch (return_type) {
.void => {
try builder.buildRet(unit, context, .{
.value = .{
.@"comptime" = .void,
},
.type = .void,
});
},
.noreturn => {
try builder.buildUnreachable(unit, context);
},
else => unreachable,
},
}
}
}
const function_definition_index = builder.current_function; const function_definition_index = builder.current_function;
@ -2125,9 +2186,9 @@ pub const Builder = struct {
.unsigned => .zero_extend, .unsigned => .zero_extend,
}; };
} }
} } else {
unreachable; unreachable;
}
}, },
.comptime_int => { .comptime_int => {
return .materialize_int; return .materialize_int;
@ -3720,6 +3781,17 @@ pub const Builder = struct {
}); });
try builder.appendInstruction(unit, context, slice_builder); try builder.appendInstruction(unit, context, slice_builder);
const array_len_value = V{
.value = .{
.@"comptime" = .{
.constant_int = .{
.value = array.count,
},
},
},
.type = .usize,
};
const final_slice = try unit.instructions.append(context.allocator, .{ const final_slice = try unit.instructions.append(context.allocator, .{
.insert_value = .{ .insert_value = .{
.expression = V{ .expression = V{
@ -3729,16 +3801,47 @@ pub const Builder = struct {
.type = expression_to_slice.type, .type = expression_to_slice.type,
}, },
.index = 1, .index = 1,
.new_value = .{ .new_value = switch (range_start.value) {
.runtime => b: {
const range_compute = try unit.instructions.append(context.allocator, .{
.integer_binary_operation = .{
.id = .sub,
.left = array_len_value,
.right = range_start,
.signedness = .unsigned,
},
});
try builder.appendInstruction(unit, context, range_compute);
break :b V{
.value = .{
.runtime = range_compute,
},
.type = .usize,
};
},
.@"comptime" => |ct| b: {
const range_start_value = switch (ct) {
.constant_int => |const_int| const_int.value,
else => |t| @panic(@tagName(t)),
};
const range = array.count - range_start_value;
break :b V{
.value = .{ .value = .{
.@"comptime" = .{ .@"comptime" = .{
.constant_int = .{ .constant_int = .{
.value = array.count, .value = range,
}, },
}, },
}, },
.type = .usize, .type = .usize,
};
}, },
else => |t| @panic(@tagName(t)),
},
// },
}, },
}); });
try builder.appendInstruction(unit, context, final_slice); try builder.appendInstruction(unit, context, final_slice);
@ -4773,23 +4876,17 @@ pub const Builder = struct {
try phi.values.append(context.allocator, return_value); try phi.values.append(context.allocator, return_value);
try phi.basic_blocks.append(context.allocator, current_basic_block); try phi.basic_blocks.append(context.allocator, current_basic_block);
const ret = try unit.instructions.append(context.allocator, .{ try builder.buildRet(unit, context, .{
.ret = .{
.value = .{ .value = .{
.runtime = builder.return_phi, .runtime = builder.return_phi,
}, },
.type = return_type, .type = return_type,
},
}); });
try builder.appendInstruction(unit, context, ret);
builder.current_basic_block = current_basic_block; builder.current_basic_block = current_basic_block;
try builder.jump(unit, context, builder.return_block); try builder.jump(unit, context, builder.return_block);
} else { } else {
const ret = try unit.instructions.append(context.allocator, .{ try builder.buildRet(unit, context, return_value);
.ret = return_value,
});
try builder.appendInstruction(unit, context, ret);
} }
}, },
.call => { .call => {
@ -4827,8 +4924,7 @@ pub const Builder = struct {
} }
}, },
.@"unreachable" => { .@"unreachable" => {
const instruction = try unit.instructions.append(context.allocator, .@"unreachable"); try builder.buildUnreachable(unit, context);
try builder.appendInstruction(unit, context, instruction);
}, },
.@"while" => { .@"while" => {
assert(statement_node.left != .null); assert(statement_node.left != .null);
@ -5586,6 +5682,20 @@ pub const Builder = struct {
return result; return result;
} }
fn buildUnreachable(builder: *Builder, unit: *Unit, context: *const Context) !void {
const instruction = try unit.instructions.append(context.allocator, .@"unreachable");
try builder.appendInstruction(unit, context, instruction);
unit.basic_blocks.get(builder.current_basic_block).terminated = true;
}
fn buildRet(builder: *Builder, unit: *Unit, context: *const Context, value: V) !void {
const ret = try unit.instructions.append(context.allocator, .{
.ret = value,
});
try builder.appendInstruction(unit, context, ret);
unit.basic_blocks.get(builder.current_basic_block).terminated = true;
}
}; };
pub const Enum = struct { pub const Enum = struct {

View File

@ -3179,7 +3179,10 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
} }
}, },
.ret => |return_value| { .ret => |return_value| {
const value = try llvm.emitRightValue(unit, context, return_value); const value = switch (return_value.type) {
.void => null,
else => try llvm.emitRightValue(unit, context, return_value),
};
// const value = llvm.llvm_value_map.get(return_value).?; // const value = llvm.llvm_value_map.get(return_value).?;
const ret = llvm.builder.createRet(value) orelse return LLVM.Value.Instruction.Error.ret; const ret = llvm.builder.createRet(value) orelse return LLVM.Value.Instruction.Error.ret;
_ = ret; // autofix _ = ret; // autofix
@ -3463,18 +3466,11 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
} }
if (!builder.isCurrentBlockTerminated()) { if (!builder.isCurrentBlockTerminated()) {
const return_type = function_prototype.return_type;
if (return_type == Compilation.Type.Index.noreturn) {
_ = builder.createUnreachable() orelse return LLVM.Value.Instruction.Error.@"unreachable";
} else if (return_type == Compilation.Type.Index.void) {
_ = builder.createRet(null) orelse unreachable;
} else {
var message_len: usize = 0; var message_len: usize = 0;
const function_str = llvm.function.toString(&message_len); const function_str = llvm.function.toString(&message_len);
const function_dump = function_str[0..message_len]; const function_dump = function_str[0..message_len];
std.debug.panic("Function block with no termination:\n{s}\n", .{function_dump}); std.debug.panic("Function block with no termination:\n{s}\n", .{function_dump});
} }
}
const verify_function = true; const verify_function = true;
if (verify_function) { if (verify_function) {

View File

@ -42,6 +42,7 @@ const format_usize = fn(n: usize, buffer: &[65]u8) []u8 {
const print_usize = fn(n: usize) void { const print_usize = fn(n: usize) void {
var buffer: [65]u8 = undefined; var buffer: [65]u8 = undefined;
const bytes = format_usize(n, buffer = buffer.&); const bytes = format_usize(n, buffer = buffer.&);
#assert(bytes.len < buffer.len);
const file_descriptor = os.StdFileDescriptor.get(descriptor = .stdout); const file_descriptor = os.StdFileDescriptor.get(descriptor = .stdout);
const file_writer = FileWriter{ const file_writer = FileWriter{
.descriptor = file_descriptor, .descriptor = file_descriptor,

View File

@ -0,0 +1,11 @@
const main = fn() s32 {
var buffer: [65]u8 = undefined;
const slice = foo(5, buffer.&);
#assert(slice.len + 5 == buffer.len);
const result: u32 = #cast(slice.len + 5 - buffer.len);
return #cast(result);
}
const foo = fn(n: usize, buffer: &[65]u8) []u8 {
return buffer[n..];
}