aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen.zig')
-rw-r--r--src/codegen.zig97
1 files changed, 93 insertions, 4 deletions
diff --git a/src/codegen.zig b/src/codegen.zig
index a2de3e2d01..2c2524257c 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -85,16 +85,104 @@ pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*co
}
}
+/// Every code generation backend has a different MIR representation. However, we want to pass
+/// MIR from codegen to the linker *regardless* of which backend is in use. So, we use this: a
+/// union of all MIR types. The active tag is known from the backend in use; see `AnyMir.tag`.
+pub const AnyMir = union {
+ aarch64: @import("arch/aarch64/Mir.zig"),
+ arm: @import("arch/arm/Mir.zig"),
+ powerpc: noreturn, //@import("arch/powerpc/Mir.zig"),
+ riscv64: @import("arch/riscv64/Mir.zig"),
+ sparc64: @import("arch/sparc64/Mir.zig"),
+ x86_64: @import("arch/x86_64/Mir.zig"),
+ wasm: @import("arch/wasm/Mir.zig"),
+ c: @import("codegen/c.zig").Mir,
+
+ pub inline fn tag(comptime backend: std.builtin.CompilerBackend) []const u8 {
+ return switch (backend) {
+ .stage2_aarch64 => "aarch64",
+ .stage2_arm => "arm",
+ .stage2_powerpc => "powerpc",
+ .stage2_riscv64 => "riscv64",
+ .stage2_sparc64 => "sparc64",
+ .stage2_x86_64 => "x86_64",
+ .stage2_wasm => "wasm",
+ .stage2_c => "c",
+ else => unreachable,
+ };
+ }
+
+ pub fn deinit(mir: *AnyMir, zcu: *const Zcu) void {
+ const gpa = zcu.gpa;
+ const backend = target_util.zigBackend(zcu.root_mod.resolved_target.result, zcu.comp.config.use_llvm);
+ switch (backend) {
+ else => unreachable,
+ inline .stage2_aarch64,
+ .stage2_arm,
+ .stage2_powerpc,
+ .stage2_riscv64,
+ .stage2_sparc64,
+ .stage2_x86_64,
+ .stage2_c,
+ => |backend_ct| @field(mir, tag(backend_ct)).deinit(gpa),
+ }
+ }
+};
+
+/// Runs code generation for a function. This process converts the `Air` emitted by `Sema`,
+/// alongside annotated `Liveness` data, to machine code in the form of MIR (see `AnyMir`).
+///
+/// This is supposed to be a "pure" process, but some backends are currently buggy; see
+/// `Zcu.Feature.separate_thread` for details.
pub fn generateFunction(
lf: *link.File,
pt: Zcu.PerThread,
src_loc: Zcu.LazySrcLoc,
func_index: InternPool.Index,
- air: Air,
- liveness: Air.Liveness,
+ air: *const Air,
+ liveness: *const Air.Liveness,
+) CodeGenError!AnyMir {
+ const zcu = pt.zcu;
+ const func = zcu.funcInfo(func_index);
+ const target = zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result;
+ switch (target_util.zigBackend(target, false)) {
+ else => unreachable,
+ inline .stage2_aarch64,
+ .stage2_arm,
+ .stage2_powerpc,
+ .stage2_riscv64,
+ .stage2_sparc64,
+ .stage2_x86_64,
+ .stage2_c,
+ => |backend| {
+ dev.check(devFeatureForBackend(backend));
+ const CodeGen = importBackend(backend);
+ const mir = try CodeGen.generate(lf, pt, src_loc, func_index, air, liveness);
+ return @unionInit(AnyMir, AnyMir.tag(backend), mir);
+ },
+ }
+}
+
+/// Converts the MIR returned by `generateFunction` to finalized machine code to be placed in
+/// the output binary. This is called from linker implementations, and may query linker state.
+///
+/// This function is not called for the C backend, as `link.C` directly understands its MIR.
+///
+/// The `air` parameter is not supposed to exist, but some backends are currently buggy; see
+/// `Zcu.Feature.separate_thread` for details.
+pub fn emitFunction(
+ lf: *link.File,
+ pt: Zcu.PerThread,
+ src_loc: Zcu.LazySrcLoc,
+ func_index: InternPool.Index,
+ any_mir: *const AnyMir,
code: *std.ArrayListUnmanaged(u8),
debug_output: link.File.DebugInfoOutput,
-) CodeGenError!void {
+ /// TODO: this parameter needs to be removed. We should not still hold AIR this late
+ /// in the pipeline. Any information needed to call emit must be stored in MIR.
+ /// This is `undefined` if the backend supports the `separate_thread` feature.
+ air: *const Air,
+) Allocator.Error!void {
const zcu = pt.zcu;
const func = zcu.funcInfo(func_index);
const target = zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result;
@@ -108,7 +196,8 @@ pub fn generateFunction(
.stage2_x86_64,
=> |backend| {
dev.check(devFeatureForBackend(backend));
- return importBackend(backend).generate(lf, pt, src_loc, func_index, air, liveness, code, debug_output);
+ const mir = &@field(any_mir, AnyMir.tag(backend));
+ return mir.emit(lf, pt, src_loc, func_index, code, debug_output, air);
},
}
}