Merge pull request #22 from birth-software/c-transpiler

Add C transpiler
This commit is contained in:
David 2023-11-20 08:58:45 -06:00 committed by GitHub
commit 3ae6193706
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 484 additions and 32 deletions

View File

@ -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
View File

@ -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

View File

@ -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) {

View File

@ -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,
}; };
} }
} }

View 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)),
}
}

View File

@ -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,

View File

@ -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)),

View File

@ -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;

View File

@ -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,

View File

@ -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;