Function with arguments
This commit is contained in:
parent
3d1cea128a
commit
4a91fa7e95
@ -106,6 +106,21 @@ const Mutability = enum(u1){
|
|||||||
@"var" = 1,
|
@"var" = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ArgumentSymbol = struct {
|
||||||
|
attributes: Attributes = .{},
|
||||||
|
argument_declaration: ArgumentDeclaration,
|
||||||
|
type: *Type,
|
||||||
|
value: Value,
|
||||||
|
instruction: Instruction,
|
||||||
|
alignment: u32,
|
||||||
|
|
||||||
|
const Attributes = struct{
|
||||||
|
};
|
||||||
|
const Attribute = enum{
|
||||||
|
const Mask = std.EnumSet(Attribute);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const LocalSymbol = struct {
|
const LocalSymbol = struct {
|
||||||
attributes: Attributes = .{},
|
attributes: Attributes = .{},
|
||||||
local_declaration: LocalDeclaration,
|
local_declaration: LocalDeclaration,
|
||||||
@ -498,6 +513,7 @@ const Parser = struct{
|
|||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
.argument => unreachable,
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
@ -580,7 +596,7 @@ const Parser = struct{
|
|||||||
.resolved = true,
|
.resolved = true,
|
||||||
.id = .instruction,
|
.id = .instruction,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.id = .load,
|
.id = .load,
|
||||||
},
|
},
|
||||||
.value = &local_symbol.instruction.value,
|
.value = &local_symbol.instruction.value,
|
||||||
@ -591,12 +607,41 @@ const Parser = struct{
|
|||||||
_ = analyzer.current_basic_block.instructions.append(&load.instruction);
|
_ = analyzer.current_basic_block.instructions.append(&load.instruction);
|
||||||
return &load.instruction.value;
|
return &load.instruction.value;
|
||||||
},
|
},
|
||||||
|
.argument => {
|
||||||
|
const argument_declaration = lookup_result.declaration.*.get_payload(.argument);
|
||||||
|
const argument_symbol = argument_declaration.to_symbol();
|
||||||
|
if (maybe_type) |ty| {
|
||||||
|
switch (typecheck(ty, argument_symbol.type)) {
|
||||||
|
.success => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const load = thread.loads.append(.{
|
||||||
|
.instruction = .{
|
||||||
|
.value = .{
|
||||||
|
.sema = .{
|
||||||
|
.thread = thread.get_index(),
|
||||||
|
.resolved = true,
|
||||||
|
.id = .instruction,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.id = .load,
|
||||||
|
},
|
||||||
|
.value = &argument_symbol.instruction.value,
|
||||||
|
.type = argument_symbol.type,
|
||||||
|
.alignment = argument_symbol.type.alignment,
|
||||||
|
.is_volatile = false,
|
||||||
|
});
|
||||||
|
_ = analyzer.current_basic_block.instructions.append(&load.instruction);
|
||||||
|
return &load.instruction.value;
|
||||||
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
else => exit(1),
|
else => exit(1),
|
||||||
}
|
}
|
||||||
} else exit(1);
|
} else {
|
||||||
|
exit_with_error("Unable to find declaration");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -638,6 +683,7 @@ const Parser = struct{
|
|||||||
var previous_value: *Value = undefined;
|
var previous_value: *Value = undefined;
|
||||||
var iterations: usize = 0;
|
var iterations: usize = 0;
|
||||||
var it_ty: ?*Type = ty;
|
var it_ty: ?*Type = ty;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (iterations == 1 and it_ty == null) {
|
if (iterations == 1 and it_ty == null) {
|
||||||
it_ty = previous_value.get_type();
|
it_ty = previous_value.get_type();
|
||||||
@ -968,9 +1014,11 @@ const Value = struct {
|
|||||||
lazy_expression,
|
lazy_expression,
|
||||||
instruction,
|
instruction,
|
||||||
function_declaration,
|
function_declaration,
|
||||||
|
argument,
|
||||||
};
|
};
|
||||||
|
|
||||||
const id_to_value_map = std.EnumArray(Id, type).init(.{
|
const id_to_value_map = std.EnumArray(Id, type).init(.{
|
||||||
|
.argument = ArgumentSymbol,
|
||||||
.basic_block = BasicBlock,
|
.basic_block = BasicBlock,
|
||||||
.constant_int = ConstantInt,
|
.constant_int = ConstantInt,
|
||||||
.function_declaration = Function.Declaration,
|
.function_declaration = Function.Declaration,
|
||||||
@ -1126,8 +1174,17 @@ const Range = struct{
|
|||||||
end: u32,
|
end: u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ArgumentDeclaration = struct {
|
||||||
|
declaration: Declaration,
|
||||||
|
|
||||||
|
fn to_symbol(argument_declaration: *ArgumentDeclaration) *ArgumentSymbol {
|
||||||
|
return @alignCast(@fieldParentPtr("argument_declaration", argument_declaration));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const LocalDeclaration = struct {
|
const LocalDeclaration = struct {
|
||||||
declaration: Declaration,
|
declaration: Declaration,
|
||||||
|
|
||||||
fn to_symbol(local_declaration: *LocalDeclaration) *LocalSymbol {
|
fn to_symbol(local_declaration: *LocalDeclaration) *LocalSymbol {
|
||||||
return @alignCast(@fieldParentPtr("local_declaration", local_declaration));
|
return @alignCast(@fieldParentPtr("local_declaration", local_declaration));
|
||||||
}
|
}
|
||||||
@ -1194,11 +1251,13 @@ const Declaration = struct {
|
|||||||
const Id = enum {
|
const Id = enum {
|
||||||
local,
|
local,
|
||||||
global,
|
global,
|
||||||
|
argument,
|
||||||
};
|
};
|
||||||
|
|
||||||
const id_to_declaration_map = std.EnumArray(Id, type).init(.{
|
const id_to_declaration_map = std.EnumArray(Id, type).init(.{
|
||||||
.global = GlobalDeclaration,
|
.global = GlobalDeclaration,
|
||||||
.local = LocalDeclaration,
|
.local = LocalDeclaration,
|
||||||
|
.argument = ArgumentDeclaration,
|
||||||
});
|
});
|
||||||
|
|
||||||
fn get_payload(declaration: *Declaration, comptime id: Id) *id_to_declaration_map.get(id) {
|
fn get_payload(declaration: *Declaration, comptime id: Id) *id_to_declaration_map.get(id) {
|
||||||
@ -1212,6 +1271,7 @@ const Function = struct{
|
|||||||
entry_block: *BasicBlock,
|
entry_block: *BasicBlock,
|
||||||
stack_slots: PinnedArray(*LocalSymbol) = .{},
|
stack_slots: PinnedArray(*LocalSymbol) = .{},
|
||||||
scope: Function.Scope,
|
scope: Function.Scope,
|
||||||
|
arguments: PinnedArray(*ArgumentSymbol) = .{},
|
||||||
|
|
||||||
const Attributes = struct{
|
const Attributes = struct{
|
||||||
calling_convention: CallingConvention = .custom,
|
calling_convention: CallingConvention = .custom,
|
||||||
@ -1228,7 +1288,7 @@ const Function = struct{
|
|||||||
value: Value,
|
value: Value,
|
||||||
global_symbol: GlobalSymbol,
|
global_symbol: GlobalSymbol,
|
||||||
return_type: *Type,
|
return_type: *Type,
|
||||||
argument_types: []const Type = &.{},
|
argument_types: []const *Type = &.{},
|
||||||
file: u32,
|
file: u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1254,6 +1314,7 @@ const Instruction = struct{
|
|||||||
id: Id,
|
id: Id,
|
||||||
|
|
||||||
const Id = enum{
|
const Id = enum{
|
||||||
|
argument_storage,
|
||||||
branch,
|
branch,
|
||||||
call,
|
call,
|
||||||
integer_binary_operation,
|
integer_binary_operation,
|
||||||
@ -1268,6 +1329,7 @@ const Instruction = struct{
|
|||||||
};
|
};
|
||||||
|
|
||||||
const id_to_instruction_map = std.EnumArray(Id, type).init(.{
|
const id_to_instruction_map = std.EnumArray(Id, type).init(.{
|
||||||
|
.argument_storage = ArgumentSymbol,
|
||||||
.branch = Branch,
|
.branch = Branch,
|
||||||
.call = Call,
|
.call = Call,
|
||||||
.integer_binary_operation = IntegerBinaryOperation,
|
.integer_binary_operation = IntegerBinaryOperation,
|
||||||
@ -1415,6 +1477,7 @@ const Thread = struct{
|
|||||||
imports: PinnedArray(Import) = .{},
|
imports: PinnedArray(Import) = .{},
|
||||||
local_blocks: PinnedArray(LocalBlock) = .{},
|
local_blocks: PinnedArray(LocalBlock) = .{},
|
||||||
local_symbols: PinnedArray(LocalSymbol) = .{},
|
local_symbols: PinnedArray(LocalSymbol) = .{},
|
||||||
|
argument_symbols: PinnedArray(ArgumentSymbol) = .{},
|
||||||
analyzed_file_count: u32 = 0,
|
analyzed_file_count: u32 = 0,
|
||||||
assigned_file_count: u32 = 0,
|
assigned_file_count: u32 = 0,
|
||||||
llvm: struct {
|
llvm: struct {
|
||||||
@ -2574,10 +2637,18 @@ fn worker_thread(thread_index: u32, cpu_count: *u32) void {
|
|||||||
var last_block = basic_block_node;
|
var last_block = basic_block_node;
|
||||||
|
|
||||||
if (emit_allocas) {
|
if (emit_allocas) {
|
||||||
|
for (nat_function.arguments.slice(), 0..) |argument, argument_index| {
|
||||||
|
const alloca_type = llvm_get_type(thread, argument.type);
|
||||||
|
argument.instruction.value.llvm = thread.llvm.builder.createAlloca(alloca_type, address_space, null, "", "".len, argument.alignment).toValue();
|
||||||
|
const llvm_argument = function.getArgument(@intCast(argument_index));
|
||||||
|
argument.value.llvm = llvm_argument.toValue();
|
||||||
|
}
|
||||||
|
|
||||||
for (nat_function.stack_slots.slice()) |local_slot| {
|
for (nat_function.stack_slots.slice()) |local_slot| {
|
||||||
const alloca_type = llvm_get_type(thread, local_slot.type);
|
const alloca_type = llvm_get_type(thread, local_slot.type);
|
||||||
local_slot.instruction.value.llvm = thread.llvm.builder.createAlloca(alloca_type, address_space, null, "", "".len, local_slot.alignment).toValue();
|
local_slot.instruction.value.llvm = thread.llvm.builder.createAlloca(alloca_type, address_space, null, "", "".len, local_slot.alignment).toValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
emit_allocas = false;
|
emit_allocas = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2828,6 +2899,12 @@ fn llvm_get_value(thread: *Thread, value: *Value) *LLVM.Value {
|
|||||||
const result = thread.llvm.context.getConstantInt(integer_type.bit_count, constant_int.n, @intFromEnum(integer_type.signedness) != 0);
|
const result = thread.llvm.context.getConstantInt(integer_type.bit_count, constant_int.n, @intFromEnum(integer_type.signedness) != 0);
|
||||||
break :b result.toValue();
|
break :b result.toValue();
|
||||||
},
|
},
|
||||||
|
.instruction => {
|
||||||
|
const instruction = value.get_payload(.instruction);
|
||||||
|
switch (instruction.id) {
|
||||||
|
else => |t| @panic(@tagName(t)),
|
||||||
|
}
|
||||||
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2895,8 +2972,8 @@ fn llvm_get_function(thread: *Thread, nat_function: *Function.Declaration, overr
|
|||||||
var argument_types = PinnedArray(*LLVM.Type){};
|
var argument_types = PinnedArray(*LLVM.Type){};
|
||||||
_ = &argument_types;
|
_ = &argument_types;
|
||||||
for (nat_function.argument_types) |argument_type| {
|
for (nat_function.argument_types) |argument_type| {
|
||||||
_ = argument_type; // autofix
|
const llvm_arg_type = llvm_get_type(thread, argument_type);
|
||||||
exit(1);
|
_ = argument_types.append(llvm_arg_type);
|
||||||
}
|
}
|
||||||
const is_var_args = false;
|
const is_var_args = false;
|
||||||
const function_type = LLVM.getFunctionType(return_type, argument_types.pointer, argument_types.length, is_var_args);
|
const function_type = LLVM.getFunctionType(return_type, argument_types.pointer, argument_types.length, is_var_args);
|
||||||
@ -3195,7 +3272,7 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
|
|||||||
.id = .local,
|
.id = .local,
|
||||||
.name = local_name,
|
.name = local_name,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.type = result.type,
|
.type = result.type,
|
||||||
.instruction = .{
|
.instruction = .{
|
||||||
.value = .{
|
.value = .{
|
||||||
@ -3562,6 +3639,8 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
|
|||||||
parser.skip_space(src);
|
parser.skip_space(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file.scope.scope.declarations.put_no_clobber(function.declaration.global_symbol.global_declaration.declaration.name, &function.declaration.global_symbol.global_declaration.declaration);
|
||||||
|
|
||||||
const split_modules = true;
|
const split_modules = true;
|
||||||
if (split_modules) {
|
if (split_modules) {
|
||||||
function.declaration.global_symbol.attributes.@"export" = true;
|
function.declaration.global_symbol.attributes.@"export" = true;
|
||||||
@ -3569,14 +3648,45 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
|
|||||||
|
|
||||||
parser.expect_character(src, '(');
|
parser.expect_character(src, '(');
|
||||||
|
|
||||||
|
const ArgumentData = struct{
|
||||||
|
type: *Type,
|
||||||
|
name: u32,
|
||||||
|
};
|
||||||
|
var arguments = PinnedArray(ArgumentData){};
|
||||||
|
var argument_types = PinnedArray(*Type){};
|
||||||
while (true) {
|
while (true) {
|
||||||
parser.skip_space(src);
|
parser.skip_space(src);
|
||||||
|
|
||||||
if (src[parser.i] == ')') break;
|
if (src[parser.i] == ')') break;
|
||||||
|
|
||||||
exit(1);
|
parser.skip_space(src);
|
||||||
|
|
||||||
|
const argument_name = parser.parse_identifier(thread, src);
|
||||||
|
|
||||||
|
parser.skip_space(src);
|
||||||
|
|
||||||
|
parser.expect_character(src, ':');
|
||||||
|
|
||||||
|
parser.skip_space(src);
|
||||||
|
|
||||||
|
const argument_type = parser.parse_type_expression(thread, src);
|
||||||
|
_ = arguments.append(.{
|
||||||
|
.type = argument_type,
|
||||||
|
.name = argument_name,
|
||||||
|
});
|
||||||
|
_ = argument_types.append(argument_type);
|
||||||
|
|
||||||
|
parser.skip_space(src);
|
||||||
|
|
||||||
|
switch (src[parser.i]) {
|
||||||
|
',' => parser.i += 1,
|
||||||
|
')' => {},
|
||||||
|
else => exit(1),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function.declaration.argument_types = argument_types.const_slice();
|
||||||
|
|
||||||
parser.expect_character(src, ')');
|
parser.expect_character(src, ')');
|
||||||
|
|
||||||
parser.skip_space(src);
|
parser.skip_space(src);
|
||||||
@ -3585,12 +3695,65 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
|
|||||||
|
|
||||||
parser.skip_space(src);
|
parser.skip_space(src);
|
||||||
|
|
||||||
file.scope.scope.declarations.put_no_clobber(function.declaration.global_symbol.global_declaration.declaration.name, &function.declaration.global_symbol.global_declaration.declaration);
|
|
||||||
|
|
||||||
analyzer.current_scope = &analyzer.current_function.scope.scope;
|
|
||||||
|
|
||||||
switch (src[parser.i]) {
|
switch (src[parser.i]) {
|
||||||
brace_open => {
|
brace_open => {
|
||||||
|
analyzer.current_scope = &analyzer.current_function.scope.scope;
|
||||||
|
|
||||||
|
for (arguments.const_slice()) |argument| {
|
||||||
|
if (analyzer.current_scope.declarations.get(argument.name) != null) {
|
||||||
|
exit_with_error("A declaration already exists with such name");
|
||||||
|
}
|
||||||
|
|
||||||
|
const argument_symbol = thread.argument_symbols.append(.{
|
||||||
|
.argument_declaration = .{
|
||||||
|
.declaration = .{
|
||||||
|
.id = .argument,
|
||||||
|
.name = argument.name,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.type = argument.type,
|
||||||
|
.alignment = argument.type.alignment,
|
||||||
|
.value = .{
|
||||||
|
.sema = .{
|
||||||
|
.id = .argument,
|
||||||
|
.resolved = true,
|
||||||
|
.thread = thread.get_index(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.instruction = .{
|
||||||
|
.value = .{
|
||||||
|
.sema = .{
|
||||||
|
.id = .instruction,
|
||||||
|
.thread = thread.get_index(),
|
||||||
|
.resolved = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.id = .argument_storage,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
_ = analyzer.current_function.arguments.append(argument_symbol);
|
||||||
|
|
||||||
|
analyzer.current_scope.declarations.put_no_clobber(argument.name, &argument_symbol.argument_declaration.declaration);
|
||||||
|
|
||||||
|
const store = thread.stores.append(.{
|
||||||
|
.instruction = .{
|
||||||
|
.id = .store,
|
||||||
|
.value = .{
|
||||||
|
.sema = .{
|
||||||
|
.id = .instruction,
|
||||||
|
.thread = thread.get_index(),
|
||||||
|
.resolved = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.destination = &argument_symbol.instruction.value,
|
||||||
|
.source = &argument_symbol.value,
|
||||||
|
.alignment = argument.type.alignment,
|
||||||
|
.is_volatile = false,
|
||||||
|
});
|
||||||
|
_ = analyzer.current_basic_block.instructions.append(&store.instruction);
|
||||||
|
}
|
||||||
|
|
||||||
analyze_local_block(thread, &analyzer, &parser, file);
|
analyze_local_block(thread, &analyzer, &parser, file);
|
||||||
|
|
||||||
const current_basic_block = analyzer.current_basic_block;
|
const current_basic_block = analyzer.current_basic_block;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
fn[extern] exit(exit_code: s32) noreturn;
|
fn align_forward(n: u64, alignment: u64) u64 {
|
||||||
fn my_exit(exit_code: s32) noreturn {
|
const mask = alignment - 1;
|
||||||
exit(exit_code);
|
return (value + mask) & ~mask;
|
||||||
}
|
}
|
||||||
|
3
retest/standalone/fn_args/main.nat
Normal file
3
retest/standalone/fn_args/main.nat
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fn [cc(.c)] main [export] (argc: s32) s32 {
|
||||||
|
return argc - argc;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user