Merge pull request #72 from birth-software/fix-range-compute
Fix range compute
This commit is contained in:
commit
ebf63eee26
@ -717,6 +717,7 @@ pub const Instruction = union(enum) {
|
||||
|
||||
pub const BasicBlock = struct{
|
||||
instructions: ArrayList(Instruction.Index) = .{},
|
||||
useful_instructions: usize = 0,
|
||||
predecessor: BasicBlock.Index = .null,
|
||||
// TODO: not use a bool
|
||||
terminated: bool = false,
|
||||
@ -812,6 +813,7 @@ pub const V = struct{
|
||||
pub const Comptime = union(enum){
|
||||
unresolved: Node.Index,
|
||||
undefined,
|
||||
void,
|
||||
type: Type.Index,
|
||||
bool: bool,
|
||||
comptime_int: ComptimeInt,
|
||||
@ -1476,9 +1478,7 @@ pub const Builder = struct {
|
||||
try builder.branch(unit, context, instruction_index, true_block, false_block);
|
||||
|
||||
builder.current_basic_block = false_block;
|
||||
const unreachable_instruction = try unit.instructions.append(context.allocator, .@"unreachable");
|
||||
// TODO: terminate block properly
|
||||
try builder.appendInstruction(unit, context, unreachable_instruction);
|
||||
try builder.buildUnreachable(unit, context);
|
||||
|
||||
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 {
|
||||
const basic_block = unit.basic_blocks.get(builder.current_basic_block);
|
||||
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);
|
||||
} else {
|
||||
const instruction = unit.instructions.get(instruction_index);
|
||||
@ -1944,6 +1976,35 @@ pub const Builder = struct {
|
||||
|
||||
if (body_node.id == .block) {
|
||||
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;
|
||||
|
||||
@ -2125,9 +2186,9 @@ pub const Builder = struct {
|
||||
.unsigned => .zero_extend,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
unreachable;
|
||||
},
|
||||
.comptime_int => {
|
||||
return .materialize_int;
|
||||
@ -3720,6 +3781,17 @@ pub const Builder = struct {
|
||||
});
|
||||
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, .{
|
||||
.insert_value = .{
|
||||
.expression = V{
|
||||
@ -3729,16 +3801,47 @@ pub const Builder = struct {
|
||||
.type = expression_to_slice.type,
|
||||
},
|
||||
.index = 1,
|
||||
.new_value = .{
|
||||
.value = .{
|
||||
.@"comptime" = .{
|
||||
.constant_int = .{
|
||||
.value = array.count,
|
||||
.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,
|
||||
};
|
||||
},
|
||||
.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 = .{
|
||||
.@"comptime" = .{
|
||||
.constant_int = .{
|
||||
.value = range,
|
||||
},
|
||||
},
|
||||
},
|
||||
.type = .usize,
|
||||
};
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
// },
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, final_slice);
|
||||
@ -4772,24 +4875,18 @@ pub const Builder = struct {
|
||||
const phi = &unit.instructions.get(builder.return_phi).phi;
|
||||
try phi.values.append(context.allocator, return_value);
|
||||
try phi.basic_blocks.append(context.allocator, current_basic_block);
|
||||
|
||||
const ret = try unit.instructions.append(context.allocator, .{
|
||||
.ret = .{
|
||||
.value = .{
|
||||
.runtime = builder.return_phi,
|
||||
},
|
||||
.type = return_type,
|
||||
|
||||
try builder.buildRet(unit, context, .{
|
||||
.value = .{
|
||||
.runtime = builder.return_phi,
|
||||
},
|
||||
.type = return_type,
|
||||
});
|
||||
try builder.appendInstruction(unit, context, ret);
|
||||
|
||||
builder.current_basic_block = current_basic_block;
|
||||
try builder.jump(unit, context, builder.return_block);
|
||||
} else {
|
||||
const ret = try unit.instructions.append(context.allocator, .{
|
||||
.ret = return_value,
|
||||
});
|
||||
try builder.appendInstruction(unit, context, ret);
|
||||
try builder.buildRet(unit, context, return_value);
|
||||
}
|
||||
},
|
||||
.call => {
|
||||
@ -4827,8 +4924,7 @@ pub const Builder = struct {
|
||||
}
|
||||
},
|
||||
.@"unreachable" => {
|
||||
const instruction = try unit.instructions.append(context.allocator, .@"unreachable");
|
||||
try builder.appendInstruction(unit, context, instruction);
|
||||
try builder.buildUnreachable(unit, context);
|
||||
},
|
||||
.@"while" => {
|
||||
assert(statement_node.left != .null);
|
||||
@ -5586,6 +5682,20 @@ pub const Builder = struct {
|
||||
|
||||
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 {
|
||||
|
@ -3179,7 +3179,10 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
}
|
||||
},
|
||||
.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 ret = llvm.builder.createRet(value) orelse return LLVM.Value.Instruction.Error.ret;
|
||||
_ = ret; // autofix
|
||||
@ -3463,17 +3466,10 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
}
|
||||
|
||||
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;
|
||||
const function_str = llvm.function.toString(&message_len);
|
||||
const function_dump = function_str[0..message_len];
|
||||
std.debug.panic("Function block with no termination:\n{s}\n", .{function_dump});
|
||||
}
|
||||
var message_len: usize = 0;
|
||||
const function_str = llvm.function.toString(&message_len);
|
||||
const function_dump = function_str[0..message_len];
|
||||
std.debug.panic("Function block with no termination:\n{s}\n", .{function_dump});
|
||||
}
|
||||
|
||||
const verify_function = true;
|
||||
|
@ -8,7 +8,7 @@ comptime {
|
||||
}
|
||||
}
|
||||
|
||||
const _start:: export = fn naked() noreturn {
|
||||
const _start :: export = fn naked() noreturn {
|
||||
#asm({
|
||||
xor ebp, ebp;
|
||||
mov rdi, rsp;
|
||||
@ -21,7 +21,7 @@ var argument_count: usize = 0;
|
||||
var argument_values: [&]const [&:0]const u8 = undefined;
|
||||
var environment_values: [&:null]const ?[&:null]const u8 = undefined;
|
||||
|
||||
const start:: export = fn (argc_argv_address: usize) noreturn {
|
||||
const start :: export = fn (argc_argv_address: usize) noreturn {
|
||||
var argument_address_iterator = argc_argv_address;
|
||||
const argument_count_ptr: &usize = #cast(argument_address_iterator);
|
||||
argument_count = argument_count_ptr.@;
|
||||
@ -33,6 +33,6 @@ const start:: export = fn (argc_argv_address: usize) noreturn {
|
||||
std.os.exit(exit_code = result);
|
||||
}
|
||||
|
||||
const main:: export = fn (argc: s32, argv: [&:null]?[&:null]u8, env: [&:null]?[&:null]u8) s32 {
|
||||
const main :: export = fn (argc: s32, argv: [&:null]?[&:null]u8, env: [&:null]?[&:null]u8) s32 {
|
||||
return #import("main").main();
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ const format_usize = fn(n: usize, buffer: &[65]u8) []u8 {
|
||||
const print_usize = fn(n: usize) void {
|
||||
var buffer: [65]u8 = undefined;
|
||||
const bytes = format_usize(n, buffer = buffer.&);
|
||||
#assert(bytes.len < buffer.len);
|
||||
const file_descriptor = os.StdFileDescriptor.get(descriptor = .stdout);
|
||||
const file_writer = FileWriter{
|
||||
.descriptor = file_descriptor,
|
||||
|
11
test/standalone/slice_len/main.nat
Normal file
11
test/standalone/slice_len/main.nat
Normal 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..];
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user