Merge pull request #22 from birth-software/c-transpiler
Add C transpiler
This commit is contained in:
commit
3ae6193706
@ -5,7 +5,7 @@ pub fn build(b: *std.Build) !void {
|
|||||||
all = b.option(bool, "all", "All") orelse false;
|
all = b.option(bool, "all", "All") orelse false;
|
||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
const optimization = b.standardOptimizeOption(.{});
|
const optimization = b.standardOptimizeOption(.{});
|
||||||
const use_llvm = b.option(bool, "use_llvm", "Use LLVM as the backend for generate the compiler binary") orelse true;
|
const use_llvm = b.option(bool, "use_llvm", "Use LLVM as the backend for generate the compiler binary") orelse false;
|
||||||
const exe = b.addExecutable(.{
|
const exe = b.addExecutable(.{
|
||||||
.name = "nativity",
|
.name = "nativity",
|
||||||
.root_source_file = .{ .path = "src/main.zig" },
|
.root_source_file = .{ .path = "src/main.zig" },
|
||||||
|
2
ci.sh
2
ci.sh
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
echo "Testing Nativity with Zig"
|
echo "Testing Nativity with Zig"
|
||||||
echo "Compiling Nativity with Zig"
|
echo "Compiling Nativity with Zig"
|
||||||
nativity_use_llvm=false
|
nativity_use_llvm=true
|
||||||
zig build -Duse_llvm=$nativity_use_llvm
|
zig build -Duse_llvm=$nativity_use_llvm
|
||||||
failed_test_count=0
|
failed_test_count=0
|
||||||
passed_test_count=0
|
passed_test_count=0
|
||||||
|
@ -7,8 +7,8 @@ const system = switch (current) {
|
|||||||
|
|
||||||
const write = fn (file_descriptor: FileDescriptor, bytes_ptr: [@]const u8, bytes_len: usize) ssize {
|
const write = fn (file_descriptor: FileDescriptor, bytes_ptr: [@]const u8, bytes_len: usize) ssize {
|
||||||
switch (current) {
|
switch (current) {
|
||||||
.linux => return #syscall(1, file_descriptor, bytes_ptr, bytes_len),
|
.linux => return #syscall(1, file_descriptor, #cast(bytes_ptr), bytes_len),
|
||||||
.macos => return macos.write(file_descriptor, bytes_ptr, bytes_len),
|
.macos => return macos.write(file_descriptor, #cast(bytes_ptr), bytes_len),
|
||||||
.windows => {
|
.windows => {
|
||||||
var written_bytes: u32 = 0;
|
var written_bytes: u32 = 0;
|
||||||
if (windows.WriteFile(file_descriptor, bytes_ptr, bytes_len, @written_bytes, false) != 0) {
|
if (windows.WriteFile(file_descriptor, bytes_ptr, bytes_len, @written_bytes, false) != 0) {
|
||||||
|
@ -21,6 +21,7 @@ const syntactic_analyzer = @import("frontend/syntactic_analyzer.zig");
|
|||||||
const Node = syntactic_analyzer.Node;
|
const Node = syntactic_analyzer.Node;
|
||||||
const semantic_analyzer = @import("frontend/semantic_analyzer.zig");
|
const semantic_analyzer = @import("frontend/semantic_analyzer.zig");
|
||||||
const intermediate_representation = @import("backend/intermediate_representation.zig");
|
const intermediate_representation = @import("backend/intermediate_representation.zig");
|
||||||
|
const c_transpiler = @import("backend/c_transpiler.zig");
|
||||||
const emit = @import("backend/emit.zig");
|
const emit = @import("backend/emit.zig");
|
||||||
|
|
||||||
test {
|
test {
|
||||||
@ -120,7 +121,7 @@ fn parseArguments(allocator: Allocator) !Compilation.Module.Descriptor {
|
|||||||
const arg = arguments[i];
|
const arg = arguments[i];
|
||||||
if (std.mem.eql(u8, arg, "true")) {
|
if (std.mem.eql(u8, arg, "true")) {
|
||||||
transpile_to_c = true;
|
transpile_to_c = true;
|
||||||
} else if (std.mem.equal(u8, arg, "false")) {
|
} else if (std.mem.eql(u8, arg, "false")) {
|
||||||
transpile_to_c = false;
|
transpile_to_c = false;
|
||||||
} else {
|
} else {
|
||||||
unreachable;
|
unreachable;
|
||||||
@ -301,6 +302,18 @@ pub const Type = union(enum) {
|
|||||||
.bit_count = 8,
|
.bit_count = 8,
|
||||||
.signedness = .unsigned,
|
.signedness = .unsigned,
|
||||||
});
|
});
|
||||||
|
pub const @"u16" = Type.Integer.getIndex(.{
|
||||||
|
.bit_count = 16,
|
||||||
|
.signedness = .unsigned,
|
||||||
|
});
|
||||||
|
pub const @"u32" = Type.Integer.getIndex(.{
|
||||||
|
.bit_count = 32,
|
||||||
|
.signedness = .unsigned,
|
||||||
|
});
|
||||||
|
pub const @"u64" = Type.Integer.getIndex(.{
|
||||||
|
.bit_count = 64,
|
||||||
|
.signedness = .unsigned,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Each time an enum is added here, a corresponding insertion in the initialization must be made
|
// Each time an enum is added here, a corresponding insertion in the initialization must be made
|
||||||
@ -308,6 +321,7 @@ pub const Intrinsic = enum {
|
|||||||
@"error",
|
@"error",
|
||||||
import,
|
import,
|
||||||
syscall,
|
syscall,
|
||||||
|
cast,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const FixedTypeKeyword = enum {
|
pub const FixedTypeKeyword = enum {
|
||||||
@ -479,8 +493,8 @@ const Unresolved = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const Assignment = struct {
|
pub const Assignment = struct {
|
||||||
store: Value.Index,
|
destination: Value.Index,
|
||||||
load: Value.Index,
|
source: Value.Index,
|
||||||
|
|
||||||
pub const List = BlockList(@This());
|
pub const List = BlockList(@This());
|
||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
@ -600,6 +614,7 @@ pub const Value = union(enum) {
|
|||||||
zero_extend: Cast.Index,
|
zero_extend: Cast.Index,
|
||||||
binary_operation: BinaryOperation.Index,
|
binary_operation: BinaryOperation.Index,
|
||||||
branch: Branch.Index,
|
branch: Branch.Index,
|
||||||
|
cast: Cast.Index,
|
||||||
|
|
||||||
pub const List = BlockList(@This());
|
pub const List = BlockList(@This());
|
||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
@ -740,6 +755,7 @@ pub const Module = struct {
|
|||||||
string_literal_types: data_structures.AutoArrayHashMap(u32, Type.Index) = .{},
|
string_literal_types: data_structures.AutoArrayHashMap(u32, Type.Index) = .{},
|
||||||
array_types: data_structures.AutoArrayHashMap(Array, Type.Index) = .{},
|
array_types: data_structures.AutoArrayHashMap(Array, Type.Index) = .{},
|
||||||
entry_point: Function.Index = Function.Index.invalid,
|
entry_point: Function.Index = Function.Index.invalid,
|
||||||
|
descriptor: Descriptor,
|
||||||
|
|
||||||
pub const Descriptor = struct {
|
pub const Descriptor = struct {
|
||||||
main_package_path: []const u8,
|
main_package_path: []const u8,
|
||||||
@ -972,6 +988,7 @@ pub fn compileModule(compilation: *Compilation, descriptor: Module.Descriptor) !
|
|||||||
};
|
};
|
||||||
break :blk result;
|
break :blk result;
|
||||||
},
|
},
|
||||||
|
.descriptor = descriptor,
|
||||||
};
|
};
|
||||||
|
|
||||||
const std_package_dir = "lib/std";
|
const std_package_dir = "lib/std";
|
||||||
@ -1074,10 +1091,15 @@ pub fn compileModule(compilation: *Compilation, descriptor: Module.Descriptor) !
|
|||||||
|
|
||||||
try semantic_analyzer.initialize(compilation, module, packages[0], value_allocation.ptr);
|
try semantic_analyzer.initialize(compilation, module, packages[0], value_allocation.ptr);
|
||||||
|
|
||||||
const ir = try intermediate_representation.initialize(compilation, module);
|
if (descriptor.transpile_to_c) {
|
||||||
|
try c_transpiler.initialize(compilation, module, descriptor);
|
||||||
switch (descriptor.target.cpu.arch) {
|
} else {
|
||||||
inline else => |arch| try emit.get(arch).initialize(compilation.base_allocator, ir, descriptor),
|
unreachable;
|
||||||
|
// const ir = try intermediate_representation.initialize(compilation, module);
|
||||||
|
//
|
||||||
|
// switch (descriptor.target.cpu.arch) {
|
||||||
|
// inline else => |arch| try emit.get(arch).initialize(compilation.base_allocator, ir, descriptor),
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1159,6 +1181,7 @@ const LoggerScope = enum {
|
|||||||
sema,
|
sema,
|
||||||
ir,
|
ir,
|
||||||
codegen,
|
codegen,
|
||||||
|
c,
|
||||||
};
|
};
|
||||||
|
|
||||||
const Logger = enum {
|
const Logger = enum {
|
||||||
@ -1177,6 +1200,7 @@ fn getLoggerScopeType(comptime logger_scope: LoggerScope) type {
|
|||||||
.sema => semantic_analyzer,
|
.sema => semantic_analyzer,
|
||||||
.ir => intermediate_representation,
|
.ir => intermediate_representation,
|
||||||
.codegen => emit,
|
.codegen => emit,
|
||||||
|
.c => c_transpiler,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
383
src/backend/c_transpiler.zig
Normal file
383
src/backend/c_transpiler.zig
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
|
||||||
|
const Compilation = @import("../Compilation.zig");
|
||||||
|
const Module = Compilation.Module;
|
||||||
|
const data_structures = @import("../data_structures.zig");
|
||||||
|
const ArrayList = data_structures.ArrayList;
|
||||||
|
const AutoArrayHashMap = data_structures.AutoArrayHashMap;
|
||||||
|
const StringArrayHashMap = data_structures.StringArrayHashMap;
|
||||||
|
|
||||||
|
pub const Logger = enum {
|
||||||
|
g,
|
||||||
|
|
||||||
|
pub var bitset = std.EnumSet(Logger).initMany(&.{
|
||||||
|
.g,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const TranslationUnit = struct {
|
||||||
|
string_literals: ArrayList(u8) = .{},
|
||||||
|
type_declarations: ArrayList(u8) = .{},
|
||||||
|
function_declarations: ArrayList(u8) = .{},
|
||||||
|
function_definitions: ArrayList(u8) = .{},
|
||||||
|
syscall_bitset: SyscallBitset = SyscallBitset.initEmpty(),
|
||||||
|
const SyscallBitset = std.StaticBitSet(6);
|
||||||
|
|
||||||
|
fn create(module: *Module, allocator: Allocator) !TranslationUnit {
|
||||||
|
var unit = TranslationUnit{};
|
||||||
|
try unit.type_declarations.appendSlice(allocator,
|
||||||
|
\\typedef unsigned char u8;
|
||||||
|
\\typedef unsigned short u16;
|
||||||
|
\\typedef unsigned int u32;
|
||||||
|
\\typedef unsigned long u64;
|
||||||
|
\\typedef u64 usize;
|
||||||
|
\\static_assert(sizeof(u8) == 1);
|
||||||
|
\\static_assert(sizeof(u16) == 2);
|
||||||
|
\\static_assert(sizeof(u32) == 4);
|
||||||
|
\\static_assert(sizeof(u64) == 8);
|
||||||
|
\\typedef signed char s8;
|
||||||
|
\\typedef signed short s16;
|
||||||
|
\\typedef signed int s32;
|
||||||
|
\\typedef signed long s64;
|
||||||
|
\\typedef s64 ssize;
|
||||||
|
\\static_assert(sizeof(s8) == 1);
|
||||||
|
\\static_assert(sizeof(s16) == 2);
|
||||||
|
\\static_assert(sizeof(s32) == 4);
|
||||||
|
\\static_assert(sizeof(s64) == 8);
|
||||||
|
\\
|
||||||
|
\\
|
||||||
|
);
|
||||||
|
|
||||||
|
{
|
||||||
|
var function_definitions = module.function_definitions.iterator();
|
||||||
|
while (function_definitions.nextIndex()) |function_definition_index| {
|
||||||
|
const function_definition = module.function_definitions.get(function_definition_index);
|
||||||
|
try unit.writeFunctionHeader(module, &unit.function_declarations, allocator, function_definition_index);
|
||||||
|
try unit.writeFunctionHeader(module, &unit.function_definitions, allocator, function_definition_index);
|
||||||
|
try unit.function_declarations.appendSlice(allocator, ";\n\n");
|
||||||
|
try unit.function_definitions.append(allocator, ' ');
|
||||||
|
try unit.writeBlock(module, &unit.function_definitions, allocator, function_definition.body, 1);
|
||||||
|
try unit.function_definitions.append(allocator, '\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeBlock(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, block_index: Compilation.Block.Index, indentation: usize) !void {
|
||||||
|
try list.appendSlice(allocator, "{\n");
|
||||||
|
const block = module.blocks.get(block_index);
|
||||||
|
for (block.statements.items) |statement_index| {
|
||||||
|
try list.appendNTimes(allocator, ' ', indentation * 4);
|
||||||
|
|
||||||
|
const statement = module.values.get(statement_index);
|
||||||
|
switch (statement.*) {
|
||||||
|
.declaration => |declaration_index| {
|
||||||
|
const declaration = module.declarations.get(declaration_index);
|
||||||
|
if (declaration.mutability == .@"const") {
|
||||||
|
try list.appendSlice(allocator, "const ");
|
||||||
|
}
|
||||||
|
try unit.writeType(module, list, allocator, declaration.type);
|
||||||
|
|
||||||
|
try list.append(allocator, ' ');
|
||||||
|
|
||||||
|
const declaration_name = module.getName(declaration.name).?;
|
||||||
|
try list.appendSlice(allocator, declaration_name);
|
||||||
|
|
||||||
|
try list.appendSlice(allocator, " = ");
|
||||||
|
|
||||||
|
try unit.writeValue(module, list, allocator, declaration.init_value, indentation);
|
||||||
|
try list.append(allocator, ';');
|
||||||
|
},
|
||||||
|
.assign => |assignment_index| {
|
||||||
|
const assignment = module.assignments.get(assignment_index);
|
||||||
|
try unit.writeValue(module, list, allocator, assignment.destination, indentation);
|
||||||
|
try list.appendSlice(allocator, " = ");
|
||||||
|
try unit.writeValue(module, list, allocator, assignment.source, indentation);
|
||||||
|
try list.append(allocator, ';');
|
||||||
|
},
|
||||||
|
.@"return" => |return_index| {
|
||||||
|
const return_expr = module.returns.get(return_index);
|
||||||
|
try list.appendSlice(allocator, "return ");
|
||||||
|
try unit.writeValue(module, list, allocator, return_expr.value, indentation);
|
||||||
|
try list.append(allocator, ';');
|
||||||
|
},
|
||||||
|
.syscall => |syscall_index| {
|
||||||
|
try unit.writeSyscall(module, list, allocator, syscall_index, indentation);
|
||||||
|
try list.append(allocator, ';');
|
||||||
|
},
|
||||||
|
.@"unreachable" => {
|
||||||
|
try writeUnreachable(list, allocator);
|
||||||
|
try list.append(allocator, ';');
|
||||||
|
},
|
||||||
|
.call => |call_index| {
|
||||||
|
try unit.writeCall(module, list, allocator, call_index, indentation);
|
||||||
|
try list.append(allocator, ';');
|
||||||
|
},
|
||||||
|
.branch => |branch_index| {
|
||||||
|
const branch = module.branches.get(branch_index);
|
||||||
|
try list.appendSlice(allocator, "if (");
|
||||||
|
try unit.writeValue(module, list, allocator, branch.condition, indentation);
|
||||||
|
try list.appendSlice(allocator, ") ");
|
||||||
|
try unit.writeValue(module, list, allocator, branch.true_expression, indentation);
|
||||||
|
if (!branch.false_expression.invalid) {
|
||||||
|
try list.appendSlice(allocator, " else ");
|
||||||
|
try unit.writeValue(module, list, allocator, branch.false_expression, indentation);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => |t| @panic(@tagName(t)),
|
||||||
|
}
|
||||||
|
|
||||||
|
try list.append(allocator, '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
try list.appendSlice(allocator, "}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeFunctionHeader(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, function_index: Compilation.Function.Index) !void {
|
||||||
|
const function_definition = module.function_definitions.get(function_index);
|
||||||
|
const function_prototype_type = module.types.get(function_definition.prototype);
|
||||||
|
const function_prototype = module.function_prototypes.get(function_prototype_type.function);
|
||||||
|
try unit.writeType(module, list, allocator, function_prototype.return_type);
|
||||||
|
try list.append(allocator, ' ');
|
||||||
|
const function_name_hash = module.function_name_map.get(function_index).?;
|
||||||
|
const function_name = module.getName(function_name_hash).?;
|
||||||
|
try list.appendSlice(allocator, function_name);
|
||||||
|
|
||||||
|
try list.append(allocator, '(');
|
||||||
|
if (function_prototype.arguments) |function_arguments| {
|
||||||
|
for (function_arguments) |argument_index| {
|
||||||
|
const arg_declaration = module.declarations.get(argument_index);
|
||||||
|
try unit.writeType(module, list, allocator, arg_declaration.type);
|
||||||
|
try list.append(allocator, ' ');
|
||||||
|
const arg_name = module.getName(arg_declaration.name).?;
|
||||||
|
try list.appendSlice(allocator, arg_name);
|
||||||
|
try list.append(allocator, ',');
|
||||||
|
}
|
||||||
|
_ = list.pop();
|
||||||
|
}
|
||||||
|
try list.appendSlice(allocator, ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeType(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, type_index: Compilation.Type.Index) !void {
|
||||||
|
const sema_type = module.types.get(type_index);
|
||||||
|
switch (sema_type.*) {
|
||||||
|
.void => try list.appendSlice(allocator, "void"),
|
||||||
|
.noreturn => try list.appendSlice(allocator, "[[noreturn]] void"),
|
||||||
|
.bool => try list.appendSlice(allocator, "bool"),
|
||||||
|
.integer => |integer| {
|
||||||
|
try list.append(allocator, switch (integer.signedness) {
|
||||||
|
.signed => 's',
|
||||||
|
.unsigned => 'u',
|
||||||
|
});
|
||||||
|
try list.writer(allocator).print("{}", .{integer.bit_count});
|
||||||
|
},
|
||||||
|
.pointer => |pointer| {
|
||||||
|
if (pointer.@"const") {
|
||||||
|
try list.appendSlice(allocator, "const ");
|
||||||
|
}
|
||||||
|
try unit.writeType(module, list, allocator, pointer.element_type);
|
||||||
|
try list.append(allocator, '*');
|
||||||
|
},
|
||||||
|
else => |t| @panic(@tagName(t)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeSyscall(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, syscall_index: Compilation.Syscall.Index, indentation: usize) !void {
|
||||||
|
const syscall = module.syscalls.get(syscall_index);
|
||||||
|
const arguments = syscall.getArguments();
|
||||||
|
if (!unit.syscall_bitset.isSet(arguments.len)) {
|
||||||
|
try unit.function_declarations.appendSlice(allocator, "static __inline u64 syscall");
|
||||||
|
try unit.function_declarations.writer(allocator).print("{}(", .{arguments.len});
|
||||||
|
try unit.function_declarations.appendSlice(allocator, "u64 n, ");
|
||||||
|
for (0..arguments.len) |arg_i| {
|
||||||
|
try unit.function_declarations.writer(allocator).print("u64 arg{}, ", .{arg_i});
|
||||||
|
}
|
||||||
|
_ = unit.function_declarations.pop();
|
||||||
|
_ = unit.function_declarations.pop();
|
||||||
|
try unit.function_declarations.appendSlice(allocator,
|
||||||
|
\\) {
|
||||||
|
\\ unsigned long ret;
|
||||||
|
\\ __asm__ __volatile__("syscall"
|
||||||
|
\\ : "=a"(ret)
|
||||||
|
\\ : "a"(n),
|
||||||
|
);
|
||||||
|
|
||||||
|
const argument_registers = [_]u8{ 'D', 'S', 'd' };
|
||||||
|
if (arguments.len <= 3) {
|
||||||
|
for (0..arguments.len, argument_registers[0..arguments.len]) |arg_i, arg_register| {
|
||||||
|
try unit.function_declarations.writer(allocator).print("\"{c}\"(arg{}), ", .{ arg_register, arg_i });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
_ = unit.function_declarations.pop();
|
||||||
|
_ = unit.function_declarations.pop();
|
||||||
|
try unit.function_declarations.appendSlice(allocator,
|
||||||
|
\\
|
||||||
|
\\ : "rcx", "r11", "memory"
|
||||||
|
\\ );
|
||||||
|
\\ return ret;
|
||||||
|
\\}
|
||||||
|
\\
|
||||||
|
\\
|
||||||
|
);
|
||||||
|
|
||||||
|
unit.syscall_bitset.set(arguments.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
try list.writer(allocator).print("syscall{}(", .{arguments.len});
|
||||||
|
|
||||||
|
try unit.writeValue(module, list, allocator, syscall.number, indentation);
|
||||||
|
try list.appendSlice(allocator, ", ");
|
||||||
|
|
||||||
|
for (arguments) |argument_index| {
|
||||||
|
try unit.writeValue(module, list, allocator, argument_index, indentation);
|
||||||
|
try list.appendSlice(allocator, ", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = list.pop();
|
||||||
|
_ = list.pop();
|
||||||
|
try list.append(allocator, ')');
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeUnreachable(list: *ArrayList(u8), allocator: Allocator) !void {
|
||||||
|
try list.appendSlice(allocator, "__builtin_unreachable()");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeCall(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, call_index: Compilation.Call.Index, indentation: usize) !void {
|
||||||
|
const call = module.calls.get(call_index);
|
||||||
|
const call_value = module.values.get(call.value);
|
||||||
|
const callable_name = switch (call_value.*) {
|
||||||
|
.function_definition => |function_definition_index| module.getName(module.function_name_map.get(function_definition_index).?).?,
|
||||||
|
else => |t| @panic(@tagName(t)),
|
||||||
|
};
|
||||||
|
try list.writer(allocator).print("{s}(", .{callable_name});
|
||||||
|
|
||||||
|
if (!call.arguments.invalid) {
|
||||||
|
const argument_list = module.argument_lists.get(call.arguments);
|
||||||
|
for (argument_list.array.items) |argument_index| {
|
||||||
|
try unit.writeValue(module, list, allocator, argument_index, indentation);
|
||||||
|
try list.appendSlice(allocator, ", ");
|
||||||
|
}
|
||||||
|
_ = list.pop();
|
||||||
|
_ = list.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
try list.append(allocator, ')');
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeValue(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, value_index: Compilation.Value.Index, indentation: usize) anyerror!void {
|
||||||
|
const value = module.values.get(value_index);
|
||||||
|
switch (value.*) {
|
||||||
|
.integer => |integer| {
|
||||||
|
try list.writer(allocator).print("{}", .{integer.value});
|
||||||
|
},
|
||||||
|
.declaration_reference => |declaration_reference| {
|
||||||
|
const declaration = module.declarations.get(declaration_reference.value);
|
||||||
|
const declaration_name = module.getName(declaration.name).?;
|
||||||
|
try list.appendSlice(allocator, declaration_name);
|
||||||
|
},
|
||||||
|
.binary_operation => |binary_operation_index| {
|
||||||
|
const binary_operation = module.binary_operations.get(binary_operation_index);
|
||||||
|
try unit.writeValue(module, list, allocator, binary_operation.left, indentation);
|
||||||
|
try list.append(allocator, ' ');
|
||||||
|
switch (binary_operation.id) {
|
||||||
|
.add => try list.append(allocator, '+'),
|
||||||
|
.sub => try list.append(allocator, '-'),
|
||||||
|
.logical_and => try list.append(allocator, '&'),
|
||||||
|
.logical_or => try list.append(allocator, '|'),
|
||||||
|
.logical_xor => try list.append(allocator, '^'),
|
||||||
|
.multiply => try list.append(allocator, '*'),
|
||||||
|
.divide => try list.append(allocator, '/'),
|
||||||
|
.shift_left => try list.appendSlice(allocator, "<<"),
|
||||||
|
.shift_right => try list.appendSlice(allocator, ">>"),
|
||||||
|
.compare_equal => try list.appendSlice(allocator, "=="),
|
||||||
|
}
|
||||||
|
try list.append(allocator, ' ');
|
||||||
|
try unit.writeValue(module, list, allocator, binary_operation.right, indentation);
|
||||||
|
},
|
||||||
|
.sign_extend => |cast_index| {
|
||||||
|
const sign_extend = module.casts.get(cast_index);
|
||||||
|
try unit.writeValue(module, list, allocator, sign_extend.value, indentation);
|
||||||
|
},
|
||||||
|
.cast => |cast_index| {
|
||||||
|
const cast = module.casts.get(cast_index);
|
||||||
|
try list.append(allocator, '(');
|
||||||
|
try unit.writeType(module, list, allocator, cast.type);
|
||||||
|
try list.append(allocator, ')');
|
||||||
|
try unit.writeValue(module, list, allocator, cast.value, indentation);
|
||||||
|
},
|
||||||
|
.string_literal => |string_literal_hash| {
|
||||||
|
try list.appendSlice(allocator, "(const u8*)");
|
||||||
|
const string_literal = module.string_literals.getValue(string_literal_hash).?;
|
||||||
|
try list.append(allocator, '"');
|
||||||
|
try list.appendSlice(allocator, string_literal);
|
||||||
|
try list.append(allocator, '"');
|
||||||
|
},
|
||||||
|
.@"unreachable" => try writeUnreachable(list, allocator),
|
||||||
|
.call => |call_index| try unit.writeCall(module, list, allocator, call_index, indentation),
|
||||||
|
.syscall => |syscall_index| try unit.writeSyscall(module, list, allocator, syscall_index, indentation),
|
||||||
|
.bool => |boolean| try list.appendSlice(allocator, if (boolean) "true" else "false"),
|
||||||
|
.block => |block_index| try unit.writeBlock(module, list, allocator, block_index, indentation + 1),
|
||||||
|
else => |t| @panic(@tagName(t)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// fn writeDeclarationReference(module: *Module, list: *ArrayList(u8), allocator: Allocator, declaration_reference: Compilation.Declaration.Reference) !void {
|
||||||
|
// _ = module;
|
||||||
|
// _ = list;
|
||||||
|
// _ = allocator;
|
||||||
|
// _ = declaration_reference;
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub fn initialize(compilation: *Compilation, module: *Module, descriptor: Compilation.Module.Descriptor) !void {
|
||||||
|
const allocator = compilation.base_allocator;
|
||||||
|
const unit = try TranslationUnit.create(module, allocator);
|
||||||
|
const c_source_file_path = try std.mem.concat(allocator, u8, &.{ descriptor.executable_path, ".c" });
|
||||||
|
const c_source_file = try std.fs.cwd().createFile(c_source_file_path, .{});
|
||||||
|
|
||||||
|
var offset: u64 = 0;
|
||||||
|
const slices = [_][]const u8{ unit.type_declarations.items, unit.function_declarations.items, unit.string_literals.items, unit.function_definitions.items };
|
||||||
|
for (slices) |slice| {
|
||||||
|
try c_source_file.pwriteAll(slice, offset);
|
||||||
|
offset += slice.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
c_source_file.close();
|
||||||
|
const c_source_file_realpath = try std.fs.cwd().realpathAlloc(allocator, c_source_file_path);
|
||||||
|
const c_flags = [_][]const u8{
|
||||||
|
"-std=c2x",
|
||||||
|
"-g",
|
||||||
|
};
|
||||||
|
|
||||||
|
var zig_command_line = ArrayList([]const u8){};
|
||||||
|
try zig_command_line.append(allocator, "zig");
|
||||||
|
try zig_command_line.append(allocator, "build-exe");
|
||||||
|
try zig_command_line.append(allocator, try std.mem.concat(allocator, u8, &.{ "-femit-bin=", descriptor.executable_path }));
|
||||||
|
try zig_command_line.append(allocator, "-cflags");
|
||||||
|
for (c_flags) |c_flag| {
|
||||||
|
try zig_command_line.append(allocator, c_flag);
|
||||||
|
}
|
||||||
|
try zig_command_line.append(allocator, "--");
|
||||||
|
try zig_command_line.append(allocator, c_source_file_realpath);
|
||||||
|
|
||||||
|
const run_result = try std.ChildProcess.run(.{
|
||||||
|
.allocator = allocator,
|
||||||
|
.argv = zig_command_line.items,
|
||||||
|
});
|
||||||
|
switch (run_result.term) {
|
||||||
|
.Exited => |exit_code| {
|
||||||
|
if (exit_code != 0) {
|
||||||
|
for (zig_command_line.items) |arg| {
|
||||||
|
std.debug.print("{s} ", .{arg});
|
||||||
|
}
|
||||||
|
std.debug.panic("\nZig command exited with code {}:\n{s}", .{ exit_code, run_result.stderr });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => |t| @panic(@tagName(t)),
|
||||||
|
}
|
||||||
|
}
|
@ -151,7 +151,7 @@ pub const Result = struct {
|
|||||||
target: std.Target,
|
target: std.Target,
|
||||||
|
|
||||||
pub fn create(section_manager: SectionManager, target: std.Target, entry_point_index: u32) !Result {
|
pub fn create(section_manager: SectionManager, target: std.Target, entry_point_index: u32) !Result {
|
||||||
var result = Result{
|
const result = Result{
|
||||||
.section_manager = section_manager,
|
.section_manager = section_manager,
|
||||||
.target = target,
|
.target = target,
|
||||||
.entry_point = entry_point_index,
|
.entry_point = entry_point_index,
|
||||||
|
@ -608,11 +608,11 @@ const Builder = struct {
|
|||||||
.assign => |sema_assignment_index| {
|
.assign => |sema_assignment_index| {
|
||||||
const sema_assignment = builder.ir.module.assignments.get(sema_assignment_index);
|
const sema_assignment = builder.ir.module.assignments.get(sema_assignment_index);
|
||||||
const current_function = builder.ir.function_definitions.get(builder.current_function_index);
|
const current_function = builder.ir.function_definitions.get(builder.current_function_index);
|
||||||
const sema_declaration = builder.ir.module.values.get(sema_assignment.store).declaration_reference.value;
|
const sema_declaration = builder.ir.module.values.get(sema_assignment.destination).declaration_reference.value;
|
||||||
const destination = current_function.stack_map.get(sema_declaration).?;
|
const destination = current_function.stack_map.get(sema_declaration).?;
|
||||||
_ = try builder.emitAssignment(.{
|
_ = try builder.emitAssignment(.{
|
||||||
.destination = destination,
|
.destination = destination,
|
||||||
.sema_source = sema_assignment.load,
|
.sema_source = sema_assignment.source,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
|
@ -1413,8 +1413,6 @@ const InstructionSelection = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var gp_i: u8 = 0;
|
var gp_i: u8 = 0;
|
||||||
var fp_i: u8 = 0;
|
|
||||||
_ = fp_i;
|
|
||||||
|
|
||||||
for (ir_arguments) |ir_argument_instruction_index| {
|
for (ir_arguments) |ir_argument_instruction_index| {
|
||||||
const ir_argument_instruction = mir.ir.instructions.get(ir_argument_instruction_index);
|
const ir_argument_instruction = mir.ir.instructions.get(ir_argument_instruction_index);
|
||||||
@ -4803,7 +4801,6 @@ pub const MIR = struct {
|
|||||||
register_allocator.used_in_instruction = RegisterBitset.initEmpty();
|
register_allocator.used_in_instruction = RegisterBitset.initEmpty();
|
||||||
|
|
||||||
var physical_register_use = false;
|
var physical_register_use = false;
|
||||||
var register_mask = false;
|
|
||||||
var virtual_register_definition = false;
|
var virtual_register_definition = false;
|
||||||
var register_definition = false;
|
var register_definition = false;
|
||||||
var early_clobber = false;
|
var early_clobber = false;
|
||||||
@ -4906,9 +4903,9 @@ pub const MIR = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (register_mask) {
|
// if (register_mask) {
|
||||||
unreachable;
|
// unreachable;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Physical register use
|
// Physical register use
|
||||||
if (physical_register_use) {
|
if (physical_register_use) {
|
||||||
@ -4935,8 +4932,6 @@ pub const MIR = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var undef_use = false;
|
|
||||||
_ = undef_use;
|
|
||||||
var rearranged_implicit_operands = true;
|
var rearranged_implicit_operands = true;
|
||||||
while (rearranged_implicit_operands) {
|
while (rearranged_implicit_operands) {
|
||||||
rearranged_implicit_operands = false;
|
rearranged_implicit_operands = false;
|
||||||
|
@ -387,8 +387,6 @@ const Analyzer = struct {
|
|||||||
const enum_field_name = analyzer.module.getName(e_field.name);
|
const enum_field_name = analyzer.module.getName(e_field.name);
|
||||||
_ = enum_field_name;
|
_ = enum_field_name;
|
||||||
|
|
||||||
var else_case_index: ?usize = null;
|
|
||||||
_ = else_case_index;
|
|
||||||
var existing_enums = ArrayList(u32){};
|
var existing_enums = ArrayList(u32){};
|
||||||
var switch_case_groups = try ArrayList(ArrayList(u32)).initCapacity(analyzer.allocator, switch_case_node_list.len);
|
var switch_case_groups = try ArrayList(ArrayList(u32)).initCapacity(analyzer.allocator, switch_case_node_list.len);
|
||||||
|
|
||||||
@ -551,8 +549,8 @@ const Analyzer = struct {
|
|||||||
unreachable;
|
unreachable;
|
||||||
} else {
|
} else {
|
||||||
const assignment = try analyzer.module.assignments.append(analyzer.allocator, .{
|
const assignment = try analyzer.module.assignments.append(analyzer.allocator, .{
|
||||||
.store = left.index,
|
.destination = left.index,
|
||||||
.load = right.index,
|
.source = right.index,
|
||||||
});
|
});
|
||||||
|
|
||||||
return Value{
|
return Value{
|
||||||
@ -898,6 +896,37 @@ const Analyzer = struct {
|
|||||||
}
|
}
|
||||||
unreachable;
|
unreachable;
|
||||||
},
|
},
|
||||||
|
.cast => {
|
||||||
|
assert(node.id == .compiler_intrinsic_one);
|
||||||
|
const value_to_cast = try analyzer.unresolvedAllocate(scope_index, ExpectType.none, node.left);
|
||||||
|
const value_type = value_to_cast.ptr.getType(analyzer.module);
|
||||||
|
assert(expect_type != .none);
|
||||||
|
const cast_result = try analyzer.canCast(expect_type, value_type);
|
||||||
|
if (cast_result == .success) {
|
||||||
|
const cast = try analyzer.module.casts.append(analyzer.allocator, .{
|
||||||
|
.value = value_to_cast.index,
|
||||||
|
.type = switch (expect_type) {
|
||||||
|
.none => unreachable,
|
||||||
|
.flexible_integer => |flexible_integer| if (flexible_integer.sign) |sign| switch (sign) {
|
||||||
|
else => unreachable,
|
||||||
|
} else switch (flexible_integer.byte_count) {
|
||||||
|
1 => Type.u8,
|
||||||
|
2 => Type.u16,
|
||||||
|
4 => Type.u32,
|
||||||
|
8 => Type.u64,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
break :blk .{
|
||||||
|
.cast = cast.index,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
std.debug.panic("Can't cast", .{});
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
unreachable;
|
unreachable;
|
||||||
},
|
},
|
||||||
@ -1140,11 +1169,17 @@ const Analyzer = struct {
|
|||||||
const string_literal_node = analyzer.getScopeNode(scope_index, node_index);
|
const string_literal_node = analyzer.getScopeNode(scope_index, node_index);
|
||||||
assert(string_literal_node.id == .string_literal);
|
assert(string_literal_node.id == .string_literal);
|
||||||
const original_string_literal = analyzer.tokenStringLiteral(scope_index, string_literal_node.token);
|
const original_string_literal = analyzer.tokenStringLiteral(scope_index, string_literal_node.token);
|
||||||
const string_literal = for (original_string_literal) |ch| {
|
const string_literal = blk: {
|
||||||
if (ch == '\\') {
|
if (!analyzer.module.descriptor.transpile_to_c) {
|
||||||
break try fixupStringLiteral(analyzer.allocator, original_string_literal);
|
for (original_string_literal) |ch| {
|
||||||
|
if (ch == '\\') {
|
||||||
|
break :blk try fixupStringLiteral(analyzer.allocator, original_string_literal);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else original_string_literal;
|
|
||||||
|
break :blk original_string_literal;
|
||||||
|
};
|
||||||
const string_key = try analyzer.module.addStringLiteral(analyzer.allocator, string_literal);
|
const string_key = try analyzer.module.addStringLiteral(analyzer.allocator, string_literal);
|
||||||
return string_key;
|
return string_key;
|
||||||
}
|
}
|
||||||
@ -1298,7 +1333,7 @@ const Analyzer = struct {
|
|||||||
var function_prototype = try analyzer.processSimpleFunctionPrototype(scope_index, function_prototype_node.left);
|
var function_prototype = try analyzer.processSimpleFunctionPrototype(scope_index, function_prototype_node.left);
|
||||||
const function_prototype_attribute_list_node = analyzer.getScopeNode(scope_index, function_prototype_node.right);
|
const function_prototype_attribute_list_node = analyzer.getScopeNode(scope_index, function_prototype_node.right);
|
||||||
const attribute_node_list = analyzer.getScopeNodeList(scope_index, function_prototype_attribute_list_node);
|
const attribute_node_list = analyzer.getScopeNodeList(scope_index, function_prototype_attribute_list_node);
|
||||||
var calling_convention: ?Compilation.CallingConvention = null;
|
const calling_convention: ?Compilation.CallingConvention = null;
|
||||||
|
|
||||||
for (attribute_node_list.items) |attribute_node_index| {
|
for (attribute_node_list.items) |attribute_node_index| {
|
||||||
const attribute_node = analyzer.getScopeNode(scope_index, attribute_node_index);
|
const attribute_node = analyzer.getScopeNode(scope_index, attribute_node_index);
|
||||||
@ -1569,6 +1604,21 @@ const Analyzer = struct {
|
|||||||
sign_extend,
|
sign_extend,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn canCast(analyzer: *Analyzer, expect_type: ExpectType, source: Type.Index) !TypeCheckResult {
|
||||||
|
return switch (expect_type) {
|
||||||
|
.none => unreachable,
|
||||||
|
.flexible_integer => |flexible_integer| blk: {
|
||||||
|
_ = flexible_integer;
|
||||||
|
const source_type = analyzer.module.types.get(source);
|
||||||
|
break :blk switch (source_type.*) {
|
||||||
|
.pointer => .success,
|
||||||
|
else => |t| @panic(@tagName(t)),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
else => |t| @panic(@tagName(t)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn typeCheck(analyzer: *Analyzer, expect_type: ExpectType, source: Type.Index) !TypeCheckResult {
|
fn typeCheck(analyzer: *Analyzer, expect_type: ExpectType, source: Type.Index) !TypeCheckResult {
|
||||||
return switch (expect_type) {
|
return switch (expect_type) {
|
||||||
.none => TypeCheckResult.success,
|
.none => TypeCheckResult.success,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
const main = fn() s32 {
|
const main = fn() s32 {
|
||||||
const x: u32 = 1;
|
var x: u32 = 1;
|
||||||
x = x << 5;
|
x = x << 5;
|
||||||
x = x >> 5;
|
x = x >> 5;
|
||||||
const b: u32 = 1;
|
const b: u32 = 1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user