Merge remote-tracking branch 'origin/master' into llvm12

This commit is contained in:
Andrew Kelley
2021-04-02 12:09:38 -07:00
52 changed files with 17153 additions and 11734 deletions

View File

@@ -484,7 +484,23 @@ pub const Instruction = union(enum) {
}
};
fn loadStoreRegister(rt: Register, rn: Register, offset: LoadStoreOffset, load: bool) Instruction {
/// Which kind of load/store to perform
const LoadStoreVariant = enum {
/// 32-bit or 64-bit
normal,
/// 16-bit
half,
/// 8-bit
byte,
};
fn loadStoreRegister(
rt: Register,
rn: Register,
offset: LoadStoreOffset,
variant: LoadStoreVariant,
load: bool,
) Instruction {
const off = offset.toU12();
const op1: u2 = blk: {
switch (offset) {
@@ -497,35 +513,27 @@ pub const Instruction = union(enum) {
break :blk 0b00;
};
const opc: u2 = if (load) 0b01 else 0b00;
switch (rt.size()) {
32 => {
return Instruction{
.LoadStoreRegister = .{
.rt = rt.id(),
.rn = rn.id(),
.offset = offset.toU12(),
.opc = opc,
.op1 = op1,
.v = 0,
.size = 0b10,
},
};
return Instruction{
.LoadStoreRegister = .{
.rt = rt.id(),
.rn = rn.id(),
.offset = off,
.opc = opc,
.op1 = op1,
.v = 0,
.size = blk: {
switch (variant) {
.normal => switch (rt.size()) {
32 => break :blk 0b10,
64 => break :blk 0b11,
else => unreachable, // unexpected register size
},
.half => break :blk 0b01,
.byte => break :blk 0b00,
}
},
},
64 => {
return Instruction{
.LoadStoreRegister = .{
.rt = rt.id(),
.rn = rn.id(),
.offset = offset.toU12(),
.opc = opc,
.op1 = op1,
.v = 0,
.size = 0b11,
},
};
},
else => unreachable, // unexpected register size
}
};
}
fn loadStorePairOfRegisters(
@@ -748,7 +756,7 @@ pub const Instruction = union(enum) {
pub fn ldr(rt: Register, args: LdrArgs) Instruction {
switch (args) {
.register => |info| return loadStoreRegister(rt, info.rn, info.offset, true),
.register => |info| return loadStoreRegister(rt, info.rn, info.offset, .normal, true),
.literal => |literal| return loadLiteral(rt, literal),
}
}
@@ -758,7 +766,15 @@ pub const Instruction = union(enum) {
};
pub fn str(rt: Register, rn: Register, args: StrArgs) Instruction {
return loadStoreRegister(rt, rn, args.offset, false);
return loadStoreRegister(rt, rn, args.offset, .normal, false);
}
pub fn strh(rt: Register, rn: Register, args: StrArgs) Instruction {
return loadStoreRegister(rt, rn, args.offset, .half, false);
}
pub fn strb(rt: Register, rn: Register, args: StrArgs) Instruction {
return loadStoreRegister(rt, rn, args.offset, .byte, false);
}
// Load or store pair of registers
@@ -996,6 +1012,14 @@ test "serialize instructions" {
.inst = Instruction.str(.x2, .x1, .{ .offset = Instruction.LoadStoreOffset.reg(.x3) }),
.expected = 0b11_111_0_00_00_1_00011_011_0_10_00001_00010,
},
.{ // strh w0, [x1]
.inst = Instruction.strh(.w0, .x1, .{}),
.expected = 0b01_111_0_01_00_000000000000_00001_00000,
},
.{ // strb w8, [x9]
.inst = Instruction.strb(.w8, .x9, .{}),
.expected = 0b00_111_0_01_00_000000000000_01001_01000,
},
.{ // adr x2, #0x8
.inst = Instruction.adr(.x2, 0x8),
.expected = 0b0_00_10000_0000000000000000010_00010,

View File

@@ -14,6 +14,7 @@ const TypedValue = @import("../TypedValue.zig");
const C = link.File.C;
const Decl = Module.Decl;
const trace = @import("../tracy.zig").trace;
const LazySrcLoc = Module.LazySrcLoc;
const Mutability = enum { Const, Mut };
@@ -145,11 +146,10 @@ pub const DeclGen = struct {
error_msg: ?*Module.ErrorMsg,
typedefs: TypedefMap,
fn fail(dg: *DeclGen, src: usize, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
dg.error_msg = try Module.ErrorMsg.create(dg.module.gpa, .{
.file_scope = dg.decl.getFileScope(),
.byte_offset = src,
}, format, args);
fn fail(dg: *DeclGen, src: LazySrcLoc, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
@setCold(true);
const src_loc = src.toSrcLocWithDecl(dg.decl);
dg.error_msg = try Module.ErrorMsg.create(dg.module.gpa, src_loc, format, args);
return error.AnalysisFail;
}
@@ -160,7 +160,7 @@ pub const DeclGen = struct {
val: Value,
) error{ OutOfMemory, AnalysisFail }!void {
if (val.isUndef()) {
return dg.fail(dg.decl.src(), "TODO: C backend: properly handle undefined in all cases (with debug safety?)", .{});
return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: properly handle undefined in all cases (with debug safety?)", .{});
}
switch (t.zigTypeTag()) {
.Int => {
@@ -193,7 +193,7 @@ pub const DeclGen = struct {
try writer.print("{s}", .{decl.name});
},
else => |e| return dg.fail(
dg.decl.src(),
.{ .node_offset = 0 },
"TODO: C backend: implement Pointer value {s}",
.{@tagName(e)},
),
@@ -276,7 +276,7 @@ pub const DeclGen = struct {
try writer.writeAll(", .error = 0 }");
}
},
else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement value {s}", .{
else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement value {s}", .{
@tagName(e),
}),
}
@@ -350,7 +350,7 @@ pub const DeclGen = struct {
break;
}
} else {
return dg.fail(dg.decl.src(), "TODO: C backend: implement integer types larger than 128 bits", .{});
return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement integer types larger than 128 bits", .{});
}
},
else => unreachable,
@@ -358,7 +358,7 @@ pub const DeclGen = struct {
},
.Pointer => {
if (t.isSlice()) {
return dg.fail(dg.decl.src(), "TODO: C backend: implement slices", .{});
return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement slices", .{});
} else {
try dg.renderType(w, t.elemType());
try w.writeAll(" *");
@@ -431,7 +431,7 @@ pub const DeclGen = struct {
dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
},
.Null, .Undefined => unreachable, // must be const or comptime
else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement type {s}", .{
else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type {s}", .{
@tagName(e),
}),
}
@@ -569,13 +569,15 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
.optional_payload_ptr => try genOptionalPayload(o, inst.castTag(.optional_payload_ptr).?),
.is_err => try genIsErr(o, inst.castTag(.is_err).?),
.is_err_ptr => try genIsErr(o, inst.castTag(.is_err_ptr).?),
.error_to_int => try genErrorToInt(o, inst.castTag(.error_to_int).?),
.int_to_error => try genIntToError(o, inst.castTag(.int_to_error).?),
.unwrap_errunion_payload => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload).?),
.unwrap_errunion_err => try genUnwrapErrUnionErr(o, inst.castTag(.unwrap_errunion_err).?),
.unwrap_errunion_payload_ptr => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload_ptr).?),
.unwrap_errunion_err_ptr => try genUnwrapErrUnionErr(o, inst.castTag(.unwrap_errunion_err_ptr).?),
.wrap_errunion_payload => try genWrapErrUnionPay(o, inst.castTag(.wrap_errunion_payload).?),
.wrap_errunion_err => try genWrapErrUnionErr(o, inst.castTag(.wrap_errunion_err).?),
else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}),
else => |e| return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for {}", .{e}),
};
switch (result_value) {
.none => {},
@@ -756,11 +758,11 @@ fn genCall(o: *Object, inst: *Inst.Call) !CValue {
try writer.writeAll(");\n");
return result_local;
} else {
return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement function pointers", .{});
return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement function pointers", .{});
}
}
fn genDbgStmt(o: *Object, inst: *Inst.NoOp) !CValue {
fn genDbgStmt(o: *Object, inst: *Inst.DbgStmt) !CValue {
// TODO emit #line directive here with line number and filename
return CValue.none;
}
@@ -913,13 +915,13 @@ fn genAsm(o: *Object, as: *Inst.Assembly) !CValue {
try o.writeCValue(writer, arg_c_value);
try writer.writeAll(";\n");
} else {
return o.dg.fail(o.dg.decl.src(), "TODO non-explicit inline asm regs", .{});
return o.dg.fail(.{ .node_offset = 0 }, "TODO non-explicit inline asm regs", .{});
}
}
const volatile_string: []const u8 = if (as.is_volatile) "volatile " else "";
try writer.print("__asm {s}(\"{s}\"", .{ volatile_string, as.asm_source });
if (as.output) |_| {
return o.dg.fail(o.dg.decl.src(), "TODO inline asm output", .{});
return o.dg.fail(.{ .node_offset = 0 }, "TODO inline asm output", .{});
}
if (as.inputs.len > 0) {
if (as.output == null) {
@@ -945,7 +947,7 @@ fn genAsm(o: *Object, as: *Inst.Assembly) !CValue {
if (as.base.isUnused())
return CValue.none;
return o.dg.fail(o.dg.decl.src(), "TODO: C backend: inline asm expression result used", .{});
return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: inline asm expression result used", .{});
}
fn genIsNull(o: *Object, inst: *Inst.UnOp) !CValue {
@@ -1072,6 +1074,14 @@ fn genIsErr(o: *Object, inst: *Inst.UnOp) !CValue {
return local;
}
fn genIntToError(o: *Object, inst: *Inst.UnOp) !CValue {
return o.resolveInst(inst.operand);
}
fn genErrorToInt(o: *Object, inst: *Inst.UnOp) !CValue {
return o.resolveInst(inst.operand);
}
fn IndentWriter(comptime UnderlyingWriter: type) type {
return struct {
const Self = @This();

File diff suppressed because it is too large Load Diff

View File

@@ -14,6 +14,7 @@ const Type = @import("../type.zig").Type;
const Value = @import("../value.zig").Value;
const Compilation = @import("../Compilation.zig");
const AnyMCValue = @import("../codegen.zig").AnyMCValue;
const LazySrcLoc = Module.LazySrcLoc;
/// Wasm Value, created when generating an instruction
const WValue = union(enum) {
@@ -70,11 +71,9 @@ pub const Context = struct {
}
/// Sets `err_msg` on `Context` and returns `error.CodegemFail` which is caught in link/Wasm.zig
fn fail(self: *Context, src: usize, comptime fmt: []const u8, args: anytype) InnerError {
self.err_msg = try Module.ErrorMsg.create(self.gpa, .{
.file_scope = self.decl.getFileScope(),
.byte_offset = src,
}, fmt, args);
fn fail(self: *Context, src: LazySrcLoc, comptime fmt: []const u8, args: anytype) InnerError {
const src_loc = src.toSrcLocWithDecl(self.decl);
self.err_msg = try Module.ErrorMsg.create(self.gpa, src_loc, fmt, args);
return error.CodegenFail;
}
@@ -91,7 +90,7 @@ pub const Context = struct {
}
/// Using a given `Type`, returns the corresponding wasm value type
fn genValtype(self: *Context, src: usize, ty: Type) InnerError!u8 {
fn genValtype(self: *Context, src: LazySrcLoc, ty: Type) InnerError!u8 {
return switch (ty.tag()) {
.f32 => wasm.valtype(.f32),
.f64 => wasm.valtype(.f64),
@@ -104,7 +103,7 @@ pub const Context = struct {
/// Using a given `Type`, returns the corresponding wasm value type
/// Differently from `genValtype` this also allows `void` to create a block
/// with no return type
fn genBlockType(self: *Context, src: usize, ty: Type) InnerError!u8 {
fn genBlockType(self: *Context, src: LazySrcLoc, ty: Type) InnerError!u8 {
return switch (ty.tag()) {
.void, .noreturn => wasm.block_empty,
else => self.genValtype(src, ty),
@@ -139,7 +138,7 @@ pub const Context = struct {
ty.fnParamTypes(params);
for (params) |param_type| {
// Can we maybe get the source index of each param?
const val_type = try self.genValtype(self.decl.src(), param_type);
const val_type = try self.genValtype(.{ .node_offset = 0 }, param_type);
try writer.writeByte(val_type);
}
}
@@ -151,7 +150,7 @@ pub const Context = struct {
else => |ret_type| {
try leb.writeULEB128(writer, @as(u32, 1));
// Can we maybe get the source index of the return type?
const val_type = try self.genValtype(self.decl.src(), return_type);
const val_type = try self.genValtype(.{ .node_offset = 0 }, return_type);
try writer.writeByte(val_type);
},
}
@@ -168,7 +167,7 @@ pub const Context = struct {
const mod_fn = blk: {
if (tv.val.castTag(.function)) |func| break :blk func.data;
if (tv.val.castTag(.extern_fn)) |ext_fn| return; // don't need codegen for extern functions
return self.fail(self.decl.src(), "TODO: Wasm codegen for decl type '{s}'", .{tv.ty.tag()});
return self.fail(.{ .node_offset = 0 }, "TODO: Wasm codegen for decl type '{s}'", .{tv.ty.tag()});
};
// Reserve space to write the size after generating the code as well as space for locals count