aboutsummaryrefslogtreecommitdiff
path: root/src-self-hosted/ir.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-04-24 15:37:21 -0400
committerGitHub <noreply@github.com>2020-04-24 15:37:21 -0400
commit7634e67ba503fdbdf75daff48a13f9d35e331cd4 (patch)
tree17266638acfc3403956633c8c28a7a4ab871275c /src-self-hosted/ir.zig
parentc829f2f7b7c5bdd13d3c39ae2960ed108393a210 (diff)
parent9ebf25d1458988b6aa75d4608062f18f802c6a38 (diff)
downloadzig-7634e67ba503fdbdf75daff48a13f9d35e331cd4.tar.gz
zig-7634e67ba503fdbdf75daff48a13f9d35e331cd4.zip
Merge pull request #5158 from ziglang/zir-to-elf
beginnings of (non-LLVM) self-hosted machine code generation and linking
Diffstat (limited to 'src-self-hosted/ir.zig')
-rw-r--r--src-self-hosted/ir.zig80
1 files changed, 61 insertions, 19 deletions
diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig
index e33d468a26..9a609b63ae 100644
--- a/src-self-hosted/ir.zig
+++ b/src-self-hosted/ir.zig
@@ -24,6 +24,7 @@ pub const Inst = struct {
constant,
assembly,
ptrtoint,
+ bitcast,
};
pub fn cast(base: *Inst, comptime T: type) ?*T {
@@ -45,6 +46,7 @@ pub const Inst = struct {
.assembly,
.ptrtoint,
+ .bitcast,
=> null,
};
}
@@ -84,6 +86,15 @@ pub const Inst = struct {
ptr: *Inst,
},
};
+
+ pub const BitCast = struct {
+ pub const base_tag = Tag.bitcast;
+
+ base: Inst,
+ args: struct {
+ operand: *Inst,
+ },
+ };
};
pub const TypedValue = struct {
@@ -96,6 +107,7 @@ pub const Module = struct {
errors: []ErrorMsg,
arena: std.heap.ArenaAllocator,
fns: []Fn,
+ target: Target,
pub const Export = struct {
name: []const u8,
@@ -122,9 +134,7 @@ pub const ErrorMsg = struct {
msg: []const u8,
};
-pub fn analyze(allocator: *Allocator, old_module: text.Module) !Module {
- const native_info = try std.zig.system.NativeTargetInfo.detect(allocator, .{});
-
+pub fn analyze(allocator: *Allocator, old_module: text.Module, target: Target) !Module {
var ctx = Analyze{
.allocator = allocator,
.arena = std.heap.ArenaAllocator.init(allocator),
@@ -133,7 +143,7 @@ pub fn analyze(allocator: *Allocator, old_module: text.Module) !Module {
.decl_table = std.AutoHashMap(*text.Inst, Analyze.NewDecl).init(allocator),
.exports = std.ArrayList(Module.Export).init(allocator),
.fns = std.ArrayList(Module.Fn).init(allocator),
- .target = native_info.target,
+ .target = target,
};
defer ctx.errors.deinit();
defer ctx.decl_table.deinit();
@@ -152,6 +162,7 @@ pub fn analyze(allocator: *Allocator, old_module: text.Module) !Module {
.errors = ctx.errors.toOwnedSlice(),
.fns = ctx.fns.toOwnedSlice(),
.arena = ctx.arena,
+ .target = target,
};
}
@@ -234,7 +245,7 @@ const Analyze = struct {
fn resolveConstString(self: *Analyze, func: ?*Fn, old_inst: *text.Inst) ![]u8 {
const new_inst = try self.resolveInst(func, old_inst);
const wanted_type = Type.initTag(.const_slice_u8);
- const coerced_inst = try self.coerce(wanted_type, new_inst);
+ const coerced_inst = try self.coerce(func, wanted_type, new_inst);
const val = try self.resolveConstValue(coerced_inst);
return val.toAllocatedBytes(&self.arena.allocator);
}
@@ -242,7 +253,7 @@ const Analyze = struct {
fn resolveType(self: *Analyze, func: ?*Fn, old_inst: *text.Inst) !Type {
const new_inst = try self.resolveInst(func, old_inst);
const wanted_type = Type.initTag(.@"type");
- const coerced_inst = try self.coerce(wanted_type, new_inst);
+ const coerced_inst = try self.coerce(func, wanted_type, new_inst);
const val = try self.resolveConstValue(coerced_inst);
return val.toType();
}
@@ -409,6 +420,7 @@ const Analyze = struct {
.primitive => return self.analyzeInstPrimitive(func, old_inst.cast(text.Inst.Primitive).?),
.fntype => return self.analyzeInstFnType(func, old_inst.cast(text.Inst.FnType).?),
.intcast => return self.analyzeInstIntCast(func, old_inst.cast(text.Inst.IntCast).?),
+ .bitcast => return self.analyzeInstBitCast(func, old_inst.cast(text.Inst.BitCast).?),
}
}
@@ -472,7 +484,7 @@ const Analyze = struct {
fn analyzeInstAs(self: *Analyze, func: ?*Fn, as: *text.Inst.As) InnerError!*Inst {
const dest_type = try self.resolveType(func, as.positionals.dest_type);
const new_inst = try self.resolveInst(func, as.positionals.value);
- return self.coerce(dest_type, new_inst);
+ return self.coerce(func, dest_type, new_inst);
}
fn analyzeInstPtrToInt(self: *Analyze, func: ?*Fn, ptrtoint: *text.Inst.PtrToInt) InnerError!*Inst {
@@ -545,12 +557,18 @@ const Analyze = struct {
}
if (dest_is_comptime_int or new_inst.value() != null) {
- return self.coerce(dest_type, new_inst);
+ return self.coerce(func, dest_type, new_inst);
}
return self.fail(intcast.base.src, "TODO implement analyze widen or shorten int", .{});
}
+ fn analyzeInstBitCast(self: *Analyze, func: ?*Fn, inst: *text.Inst.BitCast) InnerError!*Inst {
+ const dest_type = try self.resolveType(func, inst.positionals.dest_type);
+ const operand = try self.resolveInst(func, inst.positionals.operand);
+ return self.bitcast(func, dest_type, operand);
+ }
+
fn analyzeInstDeref(self: *Analyze, func: ?*Fn, deref: *text.Inst.Deref) InnerError!*Inst {
const ptr = try self.resolveInst(func, deref.positionals.ptr);
const elem_ty = switch (ptr.ty.zigTypeTag()) {
@@ -583,7 +601,8 @@ const Analyze = struct {
elem.* = try self.resolveConstString(func, assembly.kw_args.clobbers[i]);
}
for (args) |*elem, i| {
- elem.* = try self.resolveInst(func, assembly.kw_args.args[i]);
+ const arg = try self.resolveInst(func, assembly.kw_args.args[i]);
+ elem.* = try self.coerce(func, Type.initTag(.usize), arg);
}
const f = try self.requireFunctionBody(func, assembly.base.src);
@@ -602,10 +621,14 @@ const Analyze = struct {
return self.addNewInstArgs(f, unreach.base.src, Type.initTag(.noreturn), Inst.Unreach, {});
}
- fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {
+ fn coerce(self: *Analyze, func: ?*Fn, dest_type: Type, inst: *Inst) !*Inst {
+ // If the types are the same, we can return the operand.
+ if (dest_type.eql(inst.ty))
+ return inst;
+
const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty);
if (in_memory_result == .ok) {
- return self.bitcast(dest_type, inst);
+ return self.bitcast(func, dest_type, inst);
}
// *[N]T to []T
@@ -634,12 +657,14 @@ const Analyze = struct {
return self.fail(inst.src, "TODO implement type coercion", .{});
}
- fn bitcast(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {
+ fn bitcast(self: *Analyze, func: ?*Fn, dest_type: Type, inst: *Inst) !*Inst {
if (inst.value()) |val| {
// Keep the comptime Value representation; take the new type.
return self.constInst(inst.src, .{ .ty = dest_type, .val = val });
}
- return self.fail(inst.src, "TODO implement runtime bitcast", .{});
+ // TODO validate the type size and other compile errors
+ const f = try self.requireFunctionBody(func, inst.src);
+ return self.addNewInstArgs(f, inst.src, dest_type, Inst.BitCast, Inst.Args(Inst.BitCast){ .operand = inst });
}
fn coerceArrayPtrToSlice(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {
@@ -699,7 +724,9 @@ pub fn main() anyerror!void {
std.process.exit(1);
}
- var analyzed_module = try analyze(allocator, zir_module);
+ const native_info = try std.zig.system.NativeTargetInfo.detect(allocator, .{});
+
+ var analyzed_module = try analyze(allocator, zir_module, native_info.target);
defer analyzed_module.deinit(allocator);
if (analyzed_module.errors.len != 0) {
@@ -711,12 +738,27 @@ pub fn main() anyerror!void {
std.process.exit(1);
}
- var new_zir_module = try text.emit_zir(allocator, analyzed_module);
- defer new_zir_module.deinit(allocator);
+ const output_zir = true;
+ if (output_zir) {
+ var new_zir_module = try text.emit_zir(allocator, analyzed_module);
+ defer new_zir_module.deinit(allocator);
- var bos = std.io.bufferedOutStream(std.io.getStdOut().outStream());
- try new_zir_module.writeToStream(allocator, bos.outStream());
- try bos.flush();
+ var bos = std.io.bufferedOutStream(std.io.getStdOut().outStream());
+ try new_zir_module.writeToStream(allocator, bos.outStream());
+ try bos.flush();
+ }
+
+ const link = @import("link.zig");
+ var result = try link.updateExecutableFilePath(allocator, analyzed_module, std.fs.cwd(), "a.out");
+ defer result.deinit(allocator);
+ if (result.errors.len != 0) {
+ for (result.errors) |err_msg| {
+ const loc = findLineColumn(source, err_msg.byte_offset);
+ std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });
+ }
+ if (debug_error_trace) return error.ParseFailure;
+ std.process.exit(1);
+ }
}
fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usize, column: usize } {