aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-11-23 22:49:13 -0500
committerGitHub <noreply@github.com>2022-11-23 22:49:13 -0500
commit02e1facc72fa9cb8e4793ecf114fdd61ea8df6bd (patch)
treedb7205a04318c4dd3fbc6a07ac47c7dec7917890 /src/codegen
parentdcb16731cf58cf2ec5a5f57f3d7a66dde8f055a0 (diff)
parent8fe3d67c795d639b1670d2312aff7150ba4ad8ba (diff)
downloadzig-02e1facc72fa9cb8e4793ecf114fdd61ea8df6bd.tar.gz
zig-02e1facc72fa9cb8e4793ecf114fdd61ea8df6bd.zip
Merge pull request #13632 from ziglang/cbe
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/c.zig206
-rw-r--r--src/codegen/llvm.zig51
2 files changed, 189 insertions, 68 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index a06f8e76dd..9b3ed334c0 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -18,6 +18,12 @@ const Air = @import("../Air.zig");
const Liveness = @import("../Liveness.zig");
const CType = @import("../type.zig").CType;
+const target_util = @import("../target.zig");
+const libcFloatPrefix = target_util.libcFloatPrefix;
+const libcFloatSuffix = target_util.libcFloatSuffix;
+const compilerRtFloatAbbrev = target_util.compilerRtFloatAbbrev;
+const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev;
+
const Mutability = enum { Const, ConstArgument, Mut };
const BigIntLimb = std.math.big.Limb;
const BigInt = std.math.big.int;
@@ -733,7 +739,7 @@ pub const DeclGen = struct {
try dg.fmtIntLiteral(ty.errorUnionSet(), val),
});
},
- .Array => {
+ .Array, .Vector => {
if (location != .Initializer) {
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
@@ -770,10 +776,10 @@ pub const DeclGen = struct {
.BoundFn,
.Opaque,
=> unreachable,
+
.Fn,
.Frame,
.AnyFrame,
- .Vector,
=> |tag| return dg.fail("TODO: C backend: implement value of type {s}", .{
@tagName(tag),
}),
@@ -922,7 +928,7 @@ pub const DeclGen = struct {
=> try dg.renderParentPtr(writer, val, ty),
else => unreachable,
},
- .Array => {
+ .Array, .Vector => {
if (location == .FunctionArgument) {
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
@@ -1200,7 +1206,6 @@ pub const DeclGen = struct {
.Frame,
.AnyFrame,
- .Vector,
=> |tag| return dg.fail("TODO: C backend: implement value of type {s}", .{
@tagName(tag),
}),
@@ -1746,7 +1751,7 @@ pub const DeclGen = struct {
if (t.isVolatilePtr()) try w.writeAll(" volatile");
return w.writeAll(" *");
},
- .Array => {
+ .Array, .Vector => {
var array_pl = Type.Payload.Array{ .base = .{ .tag = .array }, .data = .{
.len = t.arrayLenIncludingSentinel(),
.elem_type = t.childType(),
@@ -1859,7 +1864,6 @@ pub const DeclGen = struct {
.Frame,
.AnyFrame,
- .Vector,
=> |tag| return dg.fail("TODO: C backend: implement value of type {s}", .{
@tagName(tag),
}),
@@ -3180,25 +3184,43 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
const rhs = try f.resolveInst(bin_op.rhs);
const inst_ty = f.air.typeOfIndex(inst);
- const scalar_ty = f.air.typeOf(bin_op.lhs).scalarType();
+ const vector_ty = f.air.typeOf(bin_op.lhs);
+ const scalar_ty = vector_ty.scalarType();
const w = f.object.writer();
const local = try f.allocLocal(inst_ty, .Mut);
try w.writeAll(";\n");
- try f.writeCValueMember(w, local, .{ .field = 1 });
- try w.writeAll(" = zig_");
- try w.writeAll(operation);
- try w.writeAll("o_");
- try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty);
- try w.writeAll("(&");
- try f.writeCValueMember(w, local, .{ .field = 0 });
- try w.writeAll(", ");
+ switch (vector_ty.zigTypeTag()) {
+ .Vector => {
+ try w.writeAll("zig_v");
+ try w.writeAll(operation);
+ try w.writeAll("o_");
+ try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty);
+ try w.writeAll("(");
+ try f.writeCValueMember(w, local, .{ .field = 1 });
+ try w.writeAll(", ");
+ try f.writeCValueMember(w, local, .{ .field = 0 });
+ try w.print(", {d}, ", .{vector_ty.vectorLen()});
+ },
+ else => {
+ try f.writeCValueMember(w, local, .{ .field = 1 });
+ try w.writeAll(" = zig_");
+ try w.writeAll(operation);
+ try w.writeAll("o_");
+ try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty);
+ try w.writeAll("(&");
+ try f.writeCValueMember(w, local, .{ .field = 0 });
+ try w.writeAll(", ");
+ },
+ }
+
try f.writeCValue(w, lhs, .FunctionArgument);
try w.writeAll(", ");
try f.writeCValue(w, rhs, .FunctionArgument);
try f.object.dg.renderBuiltinInfo(w, scalar_ty, info);
try w.writeAll(");\n");
+
return local;
}
@@ -5206,16 +5228,153 @@ fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {
fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
if (f.liveness.isUnused(inst)) return CValue.none;
- const inst_ty = f.air.typeOfIndex(inst);
+ const target = f.object.dg.module.getTarget();
+ const scalar_ty = f.air.typeOfIndex(inst);
const reduce = f.air.instructions.items(.data)[inst].reduce;
const operand = try f.resolveInst(reduce.operand);
+ const operand_ty = f.air.typeOf(reduce.operand);
+ const vector_len = operand_ty.vectorLen();
const writer = f.object.writer();
- const local = try f.allocLocal(inst_ty, .Const);
+
+ const Op = union(enum) {
+ call_fn: []const u8,
+ infix: []const u8,
+ ternary: []const u8,
+ };
+ var fn_name_buf: [64]u8 = undefined;
+ const op: Op = switch (reduce.operation) {
+ .And => .{ .infix = " &= " },
+ .Or => .{ .infix = " |= " },
+ .Xor => .{ .infix = " ^= " },
+ .Min => switch (scalar_ty.zigTypeTag()) {
+ .Int => Op{ .ternary = " < " },
+ .Float => op: {
+ const float_bits = scalar_ty.floatBits(target);
+ break :op Op{
+ .call_fn = std.fmt.bufPrintZ(&fn_name_buf, "{s}fmin{s}", .{
+ libcFloatPrefix(float_bits), libcFloatSuffix(float_bits),
+ }) catch unreachable,
+ };
+ },
+ else => unreachable,
+ },
+ .Max => switch (scalar_ty.zigTypeTag()) {
+ .Int => Op{ .ternary = " > " },
+ .Float => op: {
+ const float_bits = scalar_ty.floatBits(target);
+ break :op Op{
+ .call_fn = std.fmt.bufPrintZ(&fn_name_buf, "{s}fmax{s}", .{
+ libcFloatPrefix(float_bits), libcFloatSuffix(float_bits),
+ }) catch unreachable,
+ };
+ },
+ else => unreachable,
+ },
+ .Add => switch (scalar_ty.zigTypeTag()) {
+ .Int => Op{ .infix = " += " },
+ .Float => op: {
+ const float_bits = scalar_ty.floatBits(target);
+ break :op Op{
+ .call_fn = std.fmt.bufPrintZ(&fn_name_buf, "__add{s}f3", .{
+ compilerRtFloatAbbrev(float_bits),
+ }) catch unreachable,
+ };
+ },
+ else => unreachable,
+ },
+ .Mul => switch (scalar_ty.zigTypeTag()) {
+ .Int => Op{ .infix = " *= " },
+ .Float => op: {
+ const float_bits = scalar_ty.floatBits(target);
+ break :op Op{
+ .call_fn = std.fmt.bufPrintZ(&fn_name_buf, "__mul{s}f3", .{
+ compilerRtFloatAbbrev(float_bits),
+ }) catch unreachable,
+ };
+ },
+ else => unreachable,
+ },
+ };
+
+ // Reduce a vector by repeatedly applying a function to produce an
+ // accumulated result.
+ //
+ // Equivalent to:
+ // reduce: {
+ // var i: usize = 0;
+ // var accum: T = init;
+ // while (i < vec.len) : (i += 1) {
+ // accum = func(accum, vec[i]);
+ // }
+ // break :reduce accum;
+ // }
+ const it = try f.allocLocal(Type.usize, .Mut);
+ try writer.writeAll(" = 0;\n");
+
+ const accum = try f.allocLocal(scalar_ty, .Mut);
try writer.writeAll(" = ");
- _ = operand;
- _ = local;
- return f.fail("TODO: C backend: implement airReduce", .{});
+ const init_val = switch (reduce.operation) {
+ .And, .Or, .Xor, .Add => "0",
+ .Min => switch (scalar_ty.zigTypeTag()) {
+ .Int => "TODO_intmax",
+ .Float => "TODO_nan",
+ else => unreachable,
+ },
+ .Max => switch (scalar_ty.zigTypeTag()) {
+ .Int => "TODO_intmin",
+ .Float => "TODO_nan",
+ else => unreachable,
+ },
+ .Mul => "1",
+ };
+ try writer.writeAll(init_val);
+ try writer.writeAll(";");
+ try f.object.indent_writer.insertNewline();
+ try writer.writeAll("for(;");
+ try f.writeCValue(writer, it, .Other);
+ try writer.print("<{d};++", .{vector_len});
+ try f.writeCValue(writer, it, .Other);
+ try writer.writeAll(") ");
+ try f.writeCValue(writer, accum, .Other);
+
+ switch (op) {
+ .call_fn => |fn_name| {
+ try writer.print(" = {s}(", .{fn_name});
+ try f.writeCValue(writer, accum, .FunctionArgument);
+ try writer.writeAll(", ");
+ try f.writeCValue(writer, operand, .Other);
+ try writer.writeAll("[");
+ try f.writeCValue(writer, it, .Other);
+ try writer.writeAll("])");
+ },
+ .infix => |ass| {
+ try writer.writeAll(ass);
+ try f.writeCValue(writer, operand, .Other);
+ try writer.writeAll("[");
+ try f.writeCValue(writer, it, .Other);
+ try writer.writeAll("]");
+ },
+ .ternary => |cmp| {
+ try writer.writeAll(" = ");
+ try f.writeCValue(writer, accum, .Other);
+ try writer.writeAll(cmp);
+ try f.writeCValue(writer, operand, .Other);
+ try writer.writeAll("[");
+ try f.writeCValue(writer, it, .Other);
+ try writer.writeAll("] ? ");
+ try f.writeCValue(writer, accum, .Other);
+ try writer.writeAll(" : ");
+ try f.writeCValue(writer, operand, .Other);
+ try writer.writeAll("[");
+ try f.writeCValue(writer, it, .Other);
+ try writer.writeAll("]");
+ },
+ }
+
+ try writer.writeAll(";\n");
+
+ return accum;
}
fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
@@ -5234,7 +5393,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
const local = try f.allocLocal(inst_ty, mutability);
try writer.writeAll(" = ");
switch (inst_ty.zigTypeTag()) {
- .Array => {
+ .Array, .Vector => {
const elem_ty = inst_ty.childType();
try writer.writeByte('{');
var empty = true;
@@ -5354,7 +5513,6 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
try writer.writeAll(";\n");
},
},
- .Vector => return f.fail("TODO: C backend: implement airAggregateInit for vectors", .{}),
else => unreachable,
}
@@ -5868,7 +6026,7 @@ fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) T
fn lowersToArray(ty: Type, target: std.Target) bool {
return switch (ty.zigTypeTag()) {
- .Array => return true,
+ .Array, .Vector => return true,
else => return ty.isAbiInt() and toCIntBits(@intCast(u32, ty.bitSize(target))) == null,
};
}
@@ -5877,7 +6035,7 @@ fn loweredArrayInfo(ty: Type, target: std.Target) ?Type.ArrayInfo {
if (!lowersToArray(ty, target)) return null;
switch (ty.zigTypeTag()) {
- .Array => return ty.arrayInfo(),
+ .Array, .Vector => return ty.arrayInfo(),
else => {
const abi_size = ty.abiSize(target);
const abi_align = ty.abiAlignment(target);
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index d34336701a..b3ea892566 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -16,7 +16,6 @@ const Package = @import("../Package.zig");
const TypedValue = @import("../TypedValue.zig");
const Air = @import("../Air.zig");
const Liveness = @import("../Liveness.zig");
-const target_util = @import("../target.zig");
const Value = @import("../value.zig").Value;
const Type = @import("../type.zig").Type;
const LazySrcLoc = Module.LazySrcLoc;
@@ -27,6 +26,12 @@ const aarch64_c_abi = @import("../arch/aarch64/abi.zig");
const arm_c_abi = @import("../arch/arm/abi.zig");
const riscv_c_abi = @import("../arch/riscv64/abi.zig");
+const target_util = @import("../target.zig");
+const libcFloatPrefix = target_util.libcFloatPrefix;
+const libcFloatSuffix = target_util.libcFloatSuffix;
+const compilerRtFloatAbbrev = target_util.compilerRtFloatAbbrev;
+const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev;
+
const Error = error{ OutOfMemory, CodegenFail };
pub fn targetTriple(allocator: Allocator, target: std.Target) ![:0]u8 {
@@ -7328,46 +7333,6 @@ pub const FuncGen = struct {
};
}
- fn libcFloatPrefix(float_bits: u16) []const u8 {
- return switch (float_bits) {
- 16, 80 => "__",
- 32, 64, 128 => "",
- else => unreachable,
- };
- }
-
- fn libcFloatSuffix(float_bits: u16) []const u8 {
- return switch (float_bits) {
- 16 => "h", // Non-standard
- 32 => "f",
- 64 => "",
- 80 => "x", // Non-standard
- 128 => "q", // Non-standard (mimics convention in GCC libquadmath)
- else => unreachable,
- };
- }
-
- fn compilerRtFloatAbbrev(float_bits: u16) []const u8 {
- return switch (float_bits) {
- 16 => "h",
- 32 => "s",
- 64 => "d",
- 80 => "x",
- 128 => "t",
- else => unreachable,
- };
- }
-
- fn compilerRtIntAbbrev(bits: u16) []const u8 {
- return switch (bits) {
- 16 => "h",
- 32 => "s",
- 64 => "d",
- 128 => "t",
- else => "o", // Non-standard
- };
- }
-
/// Creates a floating point comparison by lowering to the appropriate
/// hardware instruction or softfloat routine for the target
fn buildFloatCmp(
@@ -9034,12 +8999,10 @@ pub const FuncGen = struct {
const target = self.dg.module.getTarget();
const reduce = self.air.instructions.items(.data)[inst].reduce;
- var operand = try self.resolveInst(reduce.operand);
+ const operand = try self.resolveInst(reduce.operand);
const operand_ty = self.air.typeOf(reduce.operand);
const scalar_ty = self.air.typeOfIndex(inst);
- // TODO handle the fast math setting
-
switch (reduce.operation) {
.And => return self.builder.buildAndReduce(operand),
.Or => return self.builder.buildOrReduce(operand),