aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2023-03-05 14:48:06 -0500
committerGitHub <noreply@github.com>2023-03-05 14:48:06 -0500
commit7b01af2bfd4cf9232fb0157c26d7c59642452fab (patch)
tree733810a59ad5a4177198d60b9058e2951567a94a /src
parenta63134a4a56e8683aeee292b641b4e943cbfb999 (diff)
parent1efd36cd5c9a1128ae702b081d60ee32f21bc258 (diff)
downloadzig-7b01af2bfd4cf9232fb0157c26d7c59642452fab.tar.gz
zig-7b01af2bfd4cf9232fb0157c26d7c59642452fab.zip
Merge pull request #14745 from jacobly0/bigint
CBE: add support for integers larger than 128 bits (and apparently vectors too)
Diffstat (limited to 'src')
-rw-r--r--src/Sema.zig40
-rw-r--r--src/codegen/c.zig1406
-rw-r--r--src/codegen/c/type.zig481
-rw-r--r--src/link/C.zig22
-rw-r--r--src/value.zig2
5 files changed, 1378 insertions, 573 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index 8940527bc0..8c6e3cf05c 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -574,11 +574,13 @@ pub const Block = struct {
});
}
- fn addCmpVector(block: *Block, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref, cmp_op: std.math.CompareOperator, vector_ty: Air.Inst.Ref) !Air.Inst.Ref {
+ fn addCmpVector(block: *Block, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref, cmp_op: std.math.CompareOperator) !Air.Inst.Ref {
return block.addInst(.{
.tag = if (block.float_mode == .Optimized) .cmp_vector_optimized else .cmp_vector,
.data = .{ .ty_pl = .{
- .ty = vector_ty,
+ .ty = try block.sema.addType(
+ try Type.vector(block.sema.arena, block.sema.typeOf(lhs).vectorLen(), Type.bool),
+ ),
.payload = try block.sema.addExtra(Air.VectorCmp{
.lhs = lhs,
.rhs = rhs,
@@ -9412,7 +9414,7 @@ fn intCast(
const ok = if (is_vector) ok: {
const zeros = try Value.Tag.repeated.create(sema.arena, Value.zero);
const zero_inst = try sema.addConstant(sema.typeOf(operand), zeros);
- const is_in_range = try block.addCmpVector(operand, zero_inst, .eq, try sema.addType(operand_ty));
+ const is_in_range = try block.addCmpVector(operand, zero_inst, .eq);
const all_in_range = try block.addInst(.{
.tag = .reduce,
.data = .{ .reduce = .{ .operand = is_in_range, .operation = .And } },
@@ -9466,7 +9468,7 @@ fn intCast(
const dest_range = try sema.addConstant(unsigned_operand_ty, dest_range_val);
const ok = if (is_vector) ok: {
- const is_in_range = try block.addCmpVector(diff_unsigned, dest_range, .lte, try sema.addType(operand_ty));
+ const is_in_range = try block.addCmpVector(diff_unsigned, dest_range, .lte);
const all_in_range = try block.addInst(.{
.tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
.data = .{ .reduce = .{
@@ -9483,7 +9485,7 @@ fn intCast(
try sema.addSafetyCheck(block, ok, .cast_truncated_data);
} else {
const ok = if (is_vector) ok: {
- const is_in_range = try block.addCmpVector(diff, dest_max, .lte, try sema.addType(operand_ty));
+ const is_in_range = try block.addCmpVector(diff, dest_max, .lte);
const all_in_range = try block.addInst(.{
.tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
.data = .{ .reduce = .{
@@ -9504,7 +9506,7 @@ fn intCast(
const ok = if (is_vector) ok: {
const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
const zero_inst = try sema.addConstant(operand_ty, zero_val);
- const is_in_range = try block.addCmpVector(operand, zero_inst, .gte, try sema.addType(operand_ty));
+ const is_in_range = try block.addCmpVector(operand, zero_inst, .gte);
const all_in_range = try block.addInst(.{
.tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
.data = .{ .reduce = .{
@@ -12016,7 +12018,7 @@ fn zirShl(
const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: {
const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val));
- const lt = try block.addCmpVector(rhs, bit_count_inst, .lt, try sema.addType(rhs_ty));
+ const lt = try block.addCmpVector(rhs, bit_count_inst, .lt);
break :ok try block.addInst(.{
.tag = .reduce,
.data = .{ .reduce = .{
@@ -12172,7 +12174,7 @@ fn zirShr(
const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: {
const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val));
- const lt = try block.addCmpVector(rhs, bit_count_inst, .lt, try sema.addType(rhs_ty));
+ const lt = try block.addCmpVector(rhs, bit_count_inst, .lt);
break :ok try block.addInst(.{
.tag = .reduce,
.data = .{ .reduce = .{
@@ -12191,7 +12193,7 @@ fn zirShr(
const back = try block.addBinOp(.shl, result, rhs);
const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: {
- const eql = try block.addCmpVector(lhs, back, .eq, try sema.addType(rhs_ty));
+ const eql = try block.addCmpVector(lhs, back, .eq);
break :ok try block.addInst(.{
.tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
.data = .{ .reduce = .{
@@ -13192,7 +13194,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const floored = try block.addUnOp(.floor, result);
if (resolved_type.zigTypeTag() == .Vector) {
- const eql = try block.addCmpVector(result, floored, .eq, try sema.addType(resolved_type));
+ const eql = try block.addCmpVector(result, floored, .eq);
break :ok try block.addInst(.{
.tag = switch (block.float_mode) {
.Strict => .reduce,
@@ -13216,7 +13218,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
if (resolved_type.zigTypeTag() == .Vector) {
const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
const zero = try sema.addConstant(resolved_type, zero_val);
- const eql = try block.addCmpVector(remainder, zero, .eq, try sema.addType(resolved_type));
+ const eql = try block.addCmpVector(remainder, zero, .eq);
break :ok try block.addInst(.{
.tag = .reduce,
.data = .{ .reduce = .{
@@ -13514,14 +13516,13 @@ fn addDivIntOverflowSafety(
var ok: Air.Inst.Ref = .none;
if (resolved_type.zigTypeTag() == .Vector) {
- const vector_ty_ref = try sema.addType(resolved_type);
if (maybe_lhs_val == null) {
const min_int_ref = try sema.addConstant(resolved_type, min_int);
- ok = try block.addCmpVector(casted_lhs, min_int_ref, .neq, vector_ty_ref);
+ ok = try block.addCmpVector(casted_lhs, min_int_ref, .neq);
}
if (maybe_rhs_val == null) {
const neg_one_ref = try sema.addConstant(resolved_type, neg_one);
- const rhs_ok = try block.addCmpVector(casted_rhs, neg_one_ref, .neq, vector_ty_ref);
+ const rhs_ok = try block.addCmpVector(casted_rhs, neg_one_ref, .neq);
if (ok == .none) {
ok = rhs_ok;
} else {
@@ -13573,7 +13574,7 @@ fn addDivByZeroSafety(
const ok = if (resolved_type.zigTypeTag() == .Vector) ok: {
const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
const zero = try sema.addConstant(resolved_type, zero_val);
- const ok = try block.addCmpVector(casted_rhs, zero, .neq, try sema.addType(resolved_type));
+ const ok = try block.addCmpVector(casted_rhs, zero, .neq);
break :ok try block.addInst(.{
.tag = if (is_int) .reduce else .reduce_optimized,
.data = .{ .reduce = .{
@@ -15202,9 +15203,7 @@ fn cmpSelf(
};
try sema.requireRuntimeBlock(block, src, runtime_src);
if (resolved_type.zigTypeTag() == .Vector) {
- const result_ty = try Type.vector(sema.arena, resolved_type.vectorLen(), Type.bool);
- const result_ty_ref = try sema.addType(result_ty);
- return block.addCmpVector(casted_lhs, casted_rhs, op, result_ty_ref);
+ return block.addCmpVector(casted_lhs, casted_rhs, op);
}
const tag = Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized);
return block.addBinOp(tag, casted_lhs, casted_rhs);
@@ -23035,7 +23034,7 @@ fn panicSentinelMismatch(
const ok = if (sentinel_ty.zigTypeTag() == .Vector) ok: {
const eql =
- try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq, try sema.addType(sentinel_ty));
+ try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq);
break :ok try parent_block.addInst(.{
.tag = .reduce,
.data = .{ .reduce = .{
@@ -29368,8 +29367,7 @@ fn cmpVector(
};
try sema.requireRuntimeBlock(block, src, runtime_src);
- const result_ty_inst = try sema.addType(result_ty);
- return block.addCmpVector(lhs, rhs, op, result_ty_inst);
+ return block.addCmpVector(lhs, rhs, op);
}
fn wrapOptional(
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index c0585c3a4a..3d059adc15 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -17,12 +17,6 @@ const LazySrcLoc = Module.LazySrcLoc;
const Air = @import("../Air.zig");
const Liveness = @import("../Liveness.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 BigIntLimb = std.math.big.Limb;
const BigInt = std.math.big.int;
@@ -112,11 +106,7 @@ const ValueRenderLocation = enum {
}
};
-const BuiltinInfo = enum {
- None,
- Range,
- Bits,
-};
+const BuiltinInfo = enum { none, bits };
const reserved_idents = std.ComptimeStringMap(void, .{
// C language
@@ -440,16 +430,24 @@ pub const Function = struct {
return f.object.dg.typeToCType(ty, kind);
}
+ fn byteSize(f: *Function, cty: CType) u64 {
+ return f.object.dg.byteSize(cty);
+ }
+
fn renderType(f: *Function, w: anytype, t: Type) !void {
return f.object.dg.renderType(w, t);
}
- fn renderIntCast(f: *Function, w: anytype, dest_ty: Type, src: CValue, src_ty: Type, location: ValueRenderLocation) !void {
- return f.object.dg.renderIntCast(w, dest_ty, .{ .c_value = .{ .f = f, .value = src } }, src_ty, location);
+ fn renderCType(f: *Function, w: anytype, t: CType.Index) !void {
+ return f.object.dg.renderCType(w, t);
+ }
+
+ fn renderIntCast(f: *Function, w: anytype, dest_ty: Type, src: CValue, v: Vectorizer, src_ty: Type, location: ValueRenderLocation) !void {
+ return f.object.dg.renderIntCast(w, dest_ty, .{ .c_value = .{ .f = f, .value = src, .v = v } }, src_ty, location);
}
fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) {
- return f.object.dg.fmtIntLiteral(ty, val);
+ return f.object.dg.fmtIntLiteral(ty, val, .Other);
}
fn getLazyFnName(f: *Function, key: LazyFnKey, data: LazyFnValue.Data) ![]const u8 {
@@ -574,9 +572,9 @@ pub const DeclGen = struct {
const len_val = Value.initPayload(&len_pl.base);
if (location == .StaticInitializer) {
- return writer.print(", {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val)});
+ return writer.print(", {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val, .Other)});
} else {
- return writer.print(", .len = {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val)});
+ return writer.print(", .len = {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val, .Other)});
}
}
@@ -606,7 +604,7 @@ pub const DeclGen = struct {
try writer.writeByte(')');
}
switch (ptr_val.tag()) {
- .int_u64, .one => try writer.print("{x}", .{try dg.fmtIntLiteral(Type.usize, ptr_val)}),
+ .int_u64, .one => try writer.print("{x}", .{try dg.fmtIntLiteral(Type.usize, ptr_val, .Other)}),
.decl_ref_mut, .decl_ref, .variable => {
const decl_index = switch (ptr_val.tag()) {
.decl_ref => ptr_val.castTag(.decl_ref).?.data,
@@ -670,7 +668,9 @@ pub const DeclGen = struct {
container_ptr_ty,
location,
);
- try writer.print(" + {})", .{try dg.fmtIntLiteral(Type.usize, byte_offset_val)});
+ try writer.print(" + {})", .{
+ try dg.fmtIntLiteral(Type.usize, byte_offset_val, .Other),
+ });
},
.end => {
try writer.writeAll("((");
@@ -680,7 +680,9 @@ pub const DeclGen = struct {
container_ptr_ty,
location,
);
- try writer.print(") + {})", .{try dg.fmtIntLiteral(Type.usize, Value.one)});
+ try writer.print(") + {})", .{
+ try dg.fmtIntLiteral(Type.usize, Value.one, .Other),
+ });
},
}
},
@@ -746,7 +748,7 @@ pub const DeclGen = struct {
return writer.writeAll("false");
}
},
- .Int, .Enum, .ErrorSet => return writer.print("{x}", .{try dg.fmtIntLiteralLoc(ty, val, location)}),
+ .Int, .Enum, .ErrorSet => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, val, location)}),
.Float => {
const bits = ty.floatBits(target);
var int_pl = Type.Payload.Bits{ .base = .{ .tag = .int_signed }, .data = bits };
@@ -780,11 +782,11 @@ pub const DeclGen = struct {
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
const ptr_ty = ty.slicePtrFieldType(&buf);
try dg.renderType(writer, ptr_ty);
- return writer.print("){x}, {0x}}}", .{try dg.fmtIntLiteral(Type.usize, val)});
+ return writer.print("){x}, {0x}}}", .{try dg.fmtIntLiteral(Type.usize, val, .Other)});
} else {
try writer.writeAll("((");
try dg.renderType(writer, ty);
- return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val)});
+ return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val, .Other)});
},
.Optional => {
var opt_buf: Type.Payload.ElemType = undefined;
@@ -831,7 +833,7 @@ pub const DeclGen = struct {
return writer.writeByte('}');
},
- .Packed => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, Value.undef)}),
+ .Packed => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, Value.undef, .Other)}),
},
.Union => {
if (!location.isInitializer()) {
@@ -854,7 +856,7 @@ pub const DeclGen = struct {
if (!field.ty.hasRuntimeBits()) continue;
try dg.renderValue(writer, field.ty, val, initializer_type);
break;
- } else try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)});
+ } else try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef, .Other)});
if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}');
return writer.writeByte('}');
},
@@ -868,7 +870,7 @@ pub const DeclGen = struct {
try writer.writeAll("{ .payload = ");
try dg.renderValue(writer, ty.errorUnionPayload(), val, initializer_type);
return writer.print(", .error = {x} }}", .{
- try dg.fmtIntLiteral(ty.errorUnionSet(), val),
+ try dg.fmtIntLiteral(ty.errorUnionSet(), val, .Other),
});
},
.Array, .Vector => {
@@ -927,7 +929,7 @@ pub const DeclGen = struct {
.decl_ref_mut,
.decl_ref,
=> try dg.renderParentPtr(writer, val, ty, location),
- else => try writer.print("{}", .{try dg.fmtIntLiteralLoc(ty, val, location)}),
+ else => try writer.print("{}", .{try dg.fmtIntLiteral(ty, val, location)}),
},
.Float => {
const bits = ty.floatBits(target);
@@ -999,8 +1001,9 @@ pub const DeclGen = struct {
// return dg.fail("Only quiet nans are supported in global variable initializers", .{});
}
- try writer.writeAll("zig_make_special_");
- if (location == .StaticInitializer) try writer.writeAll("constant_");
+ try writer.writeAll("zig_");
+ try writer.writeAll(if (location == .StaticInitializer) "init" else "make");
+ try writer.writeAll("_special_");
try dg.renderTypeForBuiltinFnName(writer, ty);
try writer.writeByte('(');
if (std.math.signbit(f128_val)) try writer.writeByte('-');
@@ -1020,7 +1023,7 @@ pub const DeclGen = struct {
try writer.writeAll(", ");
empty = false;
}
- try writer.print("{x}", .{try dg.fmtIntLiteralLoc(int_ty, int_val, location)});
+ try writer.print("{x}", .{try dg.fmtIntLiteral(int_ty, int_val, location)});
if (!empty) try writer.writeByte(')');
return;
},
@@ -1069,7 +1072,7 @@ pub const DeclGen = struct {
.int_u64, .one => {
try writer.writeAll("((");
try dg.renderType(writer, ty);
- return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val)});
+ return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val, .Other)});
},
.field_ptr,
.elem_ptr,
@@ -1561,6 +1564,10 @@ pub const DeclGen = struct {
return dg.ctypes.typeToCType(dg.gpa, ty, dg.module, kind);
}
+ fn byteSize(dg: *DeclGen, cty: CType) u64 {
+ return cty.byteSize(dg.ctypes.set, dg.module.getTarget());
+ }
+
/// Renders a type as a single identifier, generating intermediate typedefs
/// if necessary.
///
@@ -1573,9 +1580,12 @@ pub const DeclGen = struct {
/// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
///
fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void {
+ try dg.renderCType(w, try dg.typeToIndex(t, .complete));
+ }
+
+ fn renderCType(dg: *DeclGen, w: anytype, idx: CType.Index) error{ OutOfMemory, AnalysisFail }!void {
const store = &dg.ctypes.set;
const module = dg.module;
- const idx = try dg.typeToIndex(t, .complete);
_ = try renderTypePrefix(dg.decl_index, store.*, module, w, idx, .suffix, .{});
try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix, .{});
}
@@ -1584,6 +1594,7 @@ pub const DeclGen = struct {
c_value: struct {
f: *Function,
value: CValue,
+ v: Vectorizer,
},
value: struct {
value: Value,
@@ -1593,6 +1604,7 @@ pub const DeclGen = struct {
switch (self.*) {
.c_value => |v| {
try v.f.writeCValue(w, v.value, location);
+ try v.v.elem(v.f, w);
},
.value => |v| {
try dg.renderValue(w, value_ty, v.value, location);
@@ -1829,79 +1841,67 @@ pub const DeclGen = struct {
dg.module.markDeclAlive(decl);
if (dg.module.decl_exports.get(decl_index)) |exports| {
- return writer.writeAll(exports.items[export_index].options.name);
+ try writer.writeAll(exports.items[export_index].options.name);
} else if (decl.isExtern()) {
- return writer.writeAll(mem.sliceTo(decl.name, 0));
- } else if (dg.module.test_functions.get(decl_index)) |_| {
- const gpa = dg.gpa;
- const name = try decl.getFullyQualifiedName(dg.module);
- defer gpa.free(name);
- return writer.print("{}_{d}", .{ fmtIdent(name), @enumToInt(decl_index) });
+ try writer.writeAll(mem.sliceTo(decl.name, 0));
} else {
- const gpa = dg.gpa;
- const name = try decl.getFullyQualifiedName(dg.module);
- defer gpa.free(name);
-
- // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case), expand
- // to 3x the length of its input
- if (name.len > 1365) {
- var hash = ident_hasher_init;
- hash.update(name);
- const ident_hash = hash.finalInt();
- try writer.writeAll("zig_D_");
- return std.fmt.formatIntValue(ident_hash, "x", .{}, writer);
- } else {
- return writer.print("{}", .{fmtIdent(name)});
- }
+ // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case),
+ // expand to 3x the length of its input, but let's cut it off at a much shorter limit.
+ var name: [100]u8 = undefined;
+ var name_stream = std.io.fixedBufferStream(&name);
+ decl.renderFullyQualifiedName(dg.module, name_stream.writer()) catch |err| switch (err) {
+ error.NoSpaceLeft => {},
+ };
+ try writer.print("{}__{d}", .{
+ fmtIdent(name_stream.getWritten()),
+ @enumToInt(decl_index),
+ });
}
}
fn renderTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, ty: Type) !void {
- const target = dg.module.getTarget();
- if (ty.isAbiInt()) {
- const int_info = ty.intInfo(target);
- const c_bits = toCIntBits(int_info.bits) orelse
- return dg.fail("TODO: C backend: implement integer types larger than 128 bits", .{});
- try writer.print("{c}{d}", .{ signAbbrev(int_info.signedness), c_bits });
- } else if (ty.isRuntimeFloat()) {
- try ty.print(writer, dg.module);
- } else if (ty.isPtrAtRuntime()) {
- try writer.print("p{d}", .{ty.bitSize(target)});
- } else if (ty.zigTypeTag() == .Bool) {
- try writer.print("u8", .{});
- } else return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for type {}", .{
- ty.fmt(dg.module),
- });
+ try dg.renderCTypeForBuiltinFnName(writer, try dg.typeToCType(ty, .complete));
+ }
+
+ fn renderCTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, cty: CType) !void {
+ switch (cty.tag()) {
+ else => try writer.print("{c}{d}", .{
+ if (cty.isBool())
+ signAbbrev(.unsigned)
+ else if (cty.isInteger())
+ signAbbrev(cty.signedness() orelse .unsigned)
+ else if (cty.isFloat())
+ @as(u8, 'f')
+ else if (cty.isPointer())
+ @as(u8, 'p')
+ else
+ return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for type {}", .{
+ cty.tag(),
+ }),
+ if (cty.isFloat()) cty.floatActiveBits(dg.module.getTarget()) else dg.byteSize(cty) * 8,
+ }),
+ .array => try writer.writeAll("big"),
+ }
}
fn renderBuiltinInfo(dg: *DeclGen, writer: anytype, ty: Type, info: BuiltinInfo) !void {
- const target = dg.module.getTarget();
switch (info) {
- .None => {},
- .Range => {
- var arena = std.heap.ArenaAllocator.init(dg.gpa);
- defer arena.deinit();
-
- const ExpectedContents = union { u: Value.Payload.U64, i: Value.Payload.I64 };
- var stack align(@alignOf(ExpectedContents)) =
- std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator());
-
- const int_info = ty.intInfo(target);
- if (int_info.signedness == .signed) {
- const min_val = try ty.minInt(stack.get(), target);
- try writer.print(", {x}", .{try dg.fmtIntLiteral(ty, min_val)});
- }
-
- const max_val = try ty.maxInt(stack.get(), target);
- try writer.print(", {x}", .{try dg.fmtIntLiteral(ty, max_val)});
- },
- .Bits => {
- var bits_pl = Value.Payload.U64{
- .base = .{ .tag = .int_u64 },
- .data = ty.bitSize(target),
+ .none => {},
+ .bits => {
+ const target = dg.module.getTarget();
+ const int_info = if (ty.isAbiInt()) ty.intInfo(target) else std.builtin.Type.Int{
+ .signedness = .unsigned,
+ .bits = @intCast(u16, ty.bitSize(target)),
};
- const bits_val = Value.initPayload(&bits_pl.base);
- try writer.print(", {}", .{try dg.fmtIntLiteral(Type.u8, bits_val)});
+
+ const cty = try dg.typeToCType(ty, .complete);
+ if (cty.tag() == .array) try writer.print(", {}", .{int_info.signedness == .signed});
+
+ var bits_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = int_info.bits };
+ try writer.print(", {}", .{try dg.fmtIntLiteral(switch (cty.tag()) {
+ else => Type.u8,
+ .array => Type.u16,
+ }, Value.initPayload(&bits_pl.base), .FunctionArgument)});
},
}
}
@@ -1910,30 +1910,21 @@ pub const DeclGen = struct {
dg: *DeclGen,
ty: Type,
val: Value,
+ loc: ValueRenderLocation,
) !std.fmt.Formatter(formatIntLiteral) {
- const int_info = ty.intInfo(dg.module.getTarget());
- const c_bits = toCIntBits(int_info.bits);
- if (c_bits == null or c_bits.? > 128)
- return dg.fail("TODO implement integer constants larger than 128 bits", .{});
+ const kind: CType.Kind = switch (loc) {
+ .FunctionArgument => .parameter,
+ .Initializer, .Other => .complete,
+ .StaticInitializer => .global,
+ };
return std.fmt.Formatter(formatIntLiteral){ .data = .{
- .ty = ty,
+ .dg = dg,
+ .int_info = ty.intInfo(dg.module.getTarget()),
+ .kind = kind,
+ .cty = try dg.typeToCType(ty, kind),
.val = val,
- .mod = dg.module,
} };
}
-
- fn fmtIntLiteralLoc(
- dg: *DeclGen,
- ty: Type,
- val: Value,
- location: ValueRenderLocation, // TODO: Instead add this as optional arg to fmtIntLiteral
- ) !std.fmt.Formatter(formatIntLiteral) {
- const int_info = ty.intInfo(dg.module.getTarget());
- const c_bits = toCIntBits(int_info.bits);
- if (c_bits == null or c_bits.? > 128)
- return dg.fail("TODO implement integer constants larger than 128 bits", .{});
- return std.fmt.Formatter(formatIntLiteral){ .data = .{ .ty = ty, .val = val, .mod = dg.module, .location = location } };
- }
};
const CTypeFix = enum { prefix, suffix };
@@ -2450,7 +2441,7 @@ pub fn genErrDecls(o: *Object) !void {
const len_val = Value.initPayload(&len_pl.base);
try writer.print("{{" ++ name_prefix ++ "{}, {}}}", .{
- fmtIdent(name), try o.dg.fmtIntLiteral(Type.usize, len_val),
+ fmtIdent(name), try o.dg.fmtIntLiteral(Type.usize, len_val, .Other),
});
}
try writer.writeAll("};\n");
@@ -2501,7 +2492,10 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
var int_pl: Value.Payload.U64 = undefined;
const int_val = tag_val.enumToInt(enum_ty, &int_pl);
- var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len };
+ var name_ty_pl = Type.Payload.Len{
+ .base = .{ .tag = .array_u8_sentinel_0 },
+ .data = name.len,
+ };
const name_ty = Type.initPayload(&name_ty_pl.base);
var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name };
@@ -2510,14 +2504,16 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };
const len_val = Value.initPayload(&len_pl.base);
- try w.print(" case {}: {{\n static ", .{try o.dg.fmtIntLiteral(enum_ty, int_val)});
+ try w.print(" case {}: {{\n static ", .{
+ try o.dg.fmtIntLiteral(enum_ty, int_val, .Other),
+ });
try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, 0, .complete);
try w.writeAll(" = ");
try o.dg.renderValue(w, name_ty, name_val, .Initializer);
try w.writeAll(";\n return (");
try o.dg.renderType(w, name_slice_ty);
try w.print("){{{}, {}}};\n", .{
- fmtIdent("name"), try o.dg.fmtIntLiteral(Type.usize, len_val),
+ fmtIdent("name"), try o.dg.fmtIntLiteral(Type.usize, len_val, .Other),
});
try w.writeAll(" }\n");
@@ -2535,7 +2531,12 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
const fwd_decl_writer = o.dg.fwd_decl.writer();
try fwd_decl_writer.print("static zig_{s} ", .{@tagName(key)});
- try o.dg.renderFunctionSignature(fwd_decl_writer, fn_decl_index, .forward, .{ .string = fn_name });
+ try o.dg.renderFunctionSignature(
+ fwd_decl_writer,
+ fn_decl_index,
+ .forward,
+ .{ .string = fn_name },
+ );
try fwd_decl_writer.writeAll(";\n");
try w.print("static zig_{s} ", .{@tagName(key)});
@@ -2753,35 +2754,35 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
// TODO use a different strategy for add, sub, mul, div
// that communicates to the optimizer that wrapping is UB.
- .add => try airBinOp(f, inst, "+", "add", .None),
- .sub => try airBinOp(f, inst, "-", "sub", .None),
- .mul => try airBinOp(f, inst, "*", "mul", .None),
+ .add => try airBinOp(f, inst, "+", "add", .none),
+ .sub => try airBinOp(f, inst, "-", "sub", .none),
+ .mul => try airBinOp(f, inst, "*", "mul", .none),
.neg => try airFloatNeg(f, inst),
- .div_float => try airBinBuiltinCall(f, inst, "div", .None),
+ .div_float => try airBinBuiltinCall(f, inst, "div", .none),
- .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .None),
+ .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .none),
.rem => blk: {
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
- const lhs_ty = f.air.typeOf(bin_op.lhs);
+ const lhs_scalar_ty = f.air.typeOf(bin_op.lhs).scalarType();
// For binary operations @TypeOf(lhs)==@TypeOf(rhs),
// so we only check one.
- break :blk if (lhs_ty.isInt())
- try airBinOp(f, inst, "%", "rem", .None)
+ break :blk if (lhs_scalar_ty.isInt())
+ try airBinOp(f, inst, "%", "rem", .none)
else
try airBinFloatOp(f, inst, "fmod");
},
- .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .None),
- .mod => try airBinBuiltinCall(f, inst, "mod", .None),
+ .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .none),
+ .mod => try airBinBuiltinCall(f, inst, "mod", .none),
- .addwrap => try airBinBuiltinCall(f, inst, "addw", .Bits),
- .subwrap => try airBinBuiltinCall(f, inst, "subw", .Bits),
- .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .Bits),
+ .addwrap => try airBinBuiltinCall(f, inst, "addw", .bits),
+ .subwrap => try airBinBuiltinCall(f, inst, "subw", .bits),
+ .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .bits),
- .add_sat => try airBinBuiltinCall(f, inst, "adds", .Bits),
- .sub_sat => try airBinBuiltinCall(f, inst, "subs", .Bits),
- .mul_sat => try airBinBuiltinCall(f, inst, "muls", .Bits),
- .shl_sat => try airBinBuiltinCall(f, inst, "shls", .Bits),
+ .add_sat => try airBinBuiltinCall(f, inst, "adds", .bits),
+ .sub_sat => try airBinBuiltinCall(f, inst, "subs", .bits),
+ .mul_sat => try airBinBuiltinCall(f, inst, "muls", .bits),
+ .shl_sat => try airBinBuiltinCall(f, inst, "shls", .bits),
.sqrt => try airUnFloatOp(f, inst, "sqrt"),
.sin => try airUnFloatOp(f, inst, "sin"),
@@ -2800,34 +2801,38 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
.mul_add => try airMulAdd(f, inst),
- .add_with_overflow => try airOverflow(f, inst, "add", .Bits),
- .sub_with_overflow => try airOverflow(f, inst, "sub", .Bits),
- .mul_with_overflow => try airOverflow(f, inst, "mul", .Bits),
- .shl_with_overflow => try airOverflow(f, inst, "shl", .Bits),
+ .add_with_overflow => try airOverflow(f, inst, "add", .bits),
+ .sub_with_overflow => try airOverflow(f, inst, "sub", .bits),
+ .mul_with_overflow => try airOverflow(f, inst, "mul", .bits),
+ .shl_with_overflow => try airOverflow(f, inst, "shl", .bits),
.min => try airMinMax(f, inst, '<', "fmin"),
.max => try airMinMax(f, inst, '>', "fmax"),
.slice => try airSlice(f, inst),
- .cmp_gt => try airCmpOp(f, inst, ">", "gt"),
- .cmp_gte => try airCmpOp(f, inst, ">=", "ge"),
- .cmp_lt => try airCmpOp(f, inst, "<", "lt"),
- .cmp_lte => try airCmpOp(f, inst, "<=", "le"),
+ .cmp_gt => try airCmpOp(f, inst, f.air.instructions.items(.data)[inst].bin_op, .gt),
+ .cmp_gte => try airCmpOp(f, inst, f.air.instructions.items(.data)[inst].bin_op, .gte),
+ .cmp_lt => try airCmpOp(f, inst, f.air.instructions.items(.data)[inst].bin_op, .lt),
+ .cmp_lte => try airCmpOp(f, inst, f.air.instructions.items(.data)[inst].bin_op, .lte),
- .cmp_eq => try airEquality(f, inst, "((", "==", "eq"),
- .cmp_neq => try airEquality(f, inst, "!((", "!=", "ne"),
+ .cmp_eq => try airEquality(f, inst, .eq),
+ .cmp_neq => try airEquality(f, inst, .neq),
- .cmp_vector => return f.fail("TODO: C backend: implement cmp_vector", .{}),
+ .cmp_vector => blk: {
+ const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
+ const extra = f.air.extraData(Air.VectorCmp, ty_pl.payload).data;
+ break :blk try airCmpOp(f, inst, extra, extra.compareOperator());
+ },
.cmp_lt_errors_len => try airCmpLtErrorsLen(f, inst),
// bool_and and bool_or are non-short-circuit operations
- .bool_and, .bit_and => try airBinOp(f, inst, "&", "and", .None),
- .bool_or, .bit_or => try airBinOp(f, inst, "|", "or", .None),
- .xor => try airBinOp(f, inst, "^", "xor", .None),
- .shr, .shr_exact => try airBinBuiltinCall(f, inst, "shr", .None),
- .shl, => try airBinBuiltinCall(f, inst, "shlw", .Bits),
- .shl_exact => try airBinOp(f, inst, "<<", "shl", .None),
+ .bool_and, .bit_and => try airBinOp(f, inst, "&", "and", .none),
+ .bool_or, .bit_or => try airBinOp(f, inst, "|", "or", .none),
+ .xor => try airBinOp(f, inst, "^", "xor", .none),
+ .shr, .shr_exact => try airBinBuiltinCall(f, inst, "shr", .none),
+ .shl, => try airBinBuiltinCall(f, inst, "shlw", .bits),
+ .shl_exact => try airBinOp(f, inst, "<<", "shl", .none),
.not => try airNot (f, inst),
.optional_payload => try airOptionalPayload(f, inst),
@@ -2872,11 +2877,11 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
.memcpy => try airMemcpy(f, inst),
.set_union_tag => try airSetUnionTag(f, inst),
.get_union_tag => try airGetUnionTag(f, inst),
- .clz => try airUnBuiltinCall(f, inst, "clz", .Bits),
- .ctz => try airUnBuiltinCall(f, inst, "ctz", .Bits),
- .popcount => try airUnBuiltinCall(f, inst, "popcount", .Bits),
- .byte_swap => try airUnBuiltinCall(f, inst, "byte_swap", .Bits),
- .bit_reverse => try airUnBuiltinCall(f, inst, "bit_reverse", .Bits),
+ .clz => try airUnBuiltinCall(f, inst, "clz", .bits),
+ .ctz => try airUnBuiltinCall(f, inst, "ctz", .bits),
+ .popcount => try airUnBuiltinCall(f, inst, "popcount", .bits),
+ .byte_swap => try airUnBuiltinCall(f, inst, "byte_swap", .bits),
+ .bit_reverse => try airUnBuiltinCall(f, inst, "bit_reverse", .bits),
.tag_name => try airTagName(f, inst),
.error_name => try airErrorName(f, inst),
.splat => try airSplat(f, inst),
@@ -3267,7 +3272,10 @@ fn airArg(f: *Function, inst: Air.Inst.Index) !CValue {
fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
- const ptr_info = f.air.typeOf(ty_op.operand).ptrInfo().data;
+
+ const ptr_ty = f.air.typeOf(ty_op.operand);
+ const ptr_scalar_ty = ptr_ty.scalarType();
+ const ptr_info = ptr_scalar_ty.ptrInfo().data;
const src_ty = ptr_info.pointee_type;
if (!src_ty.hasRuntimeBitsIgnoreComptime() or
@@ -3285,20 +3293,23 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
const is_aligned = ptr_info.@"align" == 0 or ptr_info.@"align" >= src_ty.abiAlignment(target);
const is_array = lowersToArray(src_ty, target);
const need_memcpy = !is_aligned or is_array;
- const writer = f.object.writer();
+ const writer = f.object.writer();
const local = try f.allocLocal(inst, src_ty);
+ const v = try Vectorizer.start(f, inst, writer, ptr_ty);
if (need_memcpy) {
try writer.writeAll("memcpy(");
if (!is_array) try writer.writeByte('&');
- try f.writeCValue(writer, local, .FunctionArgument);
+ try f.writeCValue(writer, local, .Other);
+ try v.elem(f, writer);
try writer.writeAll(", (const char *)");
try f.writeCValue(writer, operand, .Other);
+ try v.elem(f, writer);
try writer.writeAll(", sizeof(");
try f.renderType(writer, src_ty);
try writer.writeAll("))");
- } else if (ptr_info.host_size != 0) {
+ } else if (ptr_info.host_size > 0 and ptr_info.vector_index == .none) {
var host_pl = Type.Payload.Bits{
.base = .{ .tag = .int_unsigned },
.data = ptr_info.host_size * 8,
@@ -3324,6 +3335,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
const field_ty = Type.initPayload(&field_pl.base);
try f.writeCValue(writer, local, .Other);
+ try v.elem(f, writer);
try writer.writeAll(" = (");
try f.renderType(writer, src_ty);
try writer.writeAll(")zig_wrap_");
@@ -3342,16 +3354,21 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);
try writer.writeByte('(');
try f.writeCValueDeref(writer, operand);
+ try v.elem(f, writer);
try writer.print(", {})", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)});
if (cant_cast) try writer.writeByte(')');
- try f.object.dg.renderBuiltinInfo(writer, field_ty, .Bits);
+ try f.object.dg.renderBuiltinInfo(writer, field_ty, .bits);
try writer.writeByte(')');
} else {
try f.writeCValue(writer, local, .Other);
+ try v.elem(f, writer);
try writer.writeAll(" = ");
try f.writeCValueDeref(writer, operand);
+ try v.elem(f, writer);
}
try writer.writeAll(";\n");
+ try v.end(f, inst, writer);
+
return local;
}
@@ -3417,15 +3434,22 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
const operand = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
- const writer = f.object.writer();
+
const inst_ty = f.air.typeOfIndex(inst);
- const local = try f.allocLocal(inst, inst_ty);
+ const inst_scalar_ty = inst_ty.scalarType();
const operand_ty = f.air.typeOf(ty_op.operand);
+ const scalar_ty = operand_ty.scalarType();
+ const writer = f.object.writer();
+ const local = try f.allocLocal(inst, inst_ty);
+ const v = try Vectorizer.start(f, inst, writer, operand_ty);
try f.writeCValue(writer, local, .Other);
+ try v.elem(f, writer);
try writer.writeAll(" = ");
- try f.renderIntCast(writer, inst_ty, operand, operand_ty, .Other);
+ try f.renderIntCast(writer, inst_scalar_ty, operand, v, scalar_ty, .Other);
try writer.writeAll(";\n");
+ try v.end(f, inst, writer);
+
return local;
}
@@ -3439,34 +3463,40 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
const operand = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
const inst_ty = f.air.typeOfIndex(inst);
- const writer = f.object.writer();
- const local = try f.allocLocal(inst, inst_ty);
+ const inst_scalar_ty = inst_ty.scalarType();
const target = f.object.dg.module.getTarget();
- const dest_int_info = inst_ty.intInfo(target);
+ const dest_int_info = inst_scalar_ty.intInfo(target);
const dest_bits = dest_int_info.bits;
const dest_c_bits = toCIntBits(dest_int_info.bits) orelse
return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{});
const operand_ty = f.air.typeOf(ty_op.operand);
- const operand_int_info = operand_ty.intInfo(target);
+ const scalar_ty = operand_ty.scalarType();
+ const scalar_int_info = scalar_ty.intInfo(target);
+
+ const writer = f.object.writer();
+ const local = try f.allocLocal(inst, inst_ty);
+ const v = try Vectorizer.start(f, inst, writer, operand_ty);
try f.writeCValue(writer, local, .Other);
+ try v.elem(f, writer);
try writer.writeAll(" = ");
if (dest_c_bits < 64) {
try writer.writeByte('(');
- try f.renderType(writer, inst_ty);
+ try f.renderType(writer, inst_scalar_ty);
try writer.writeByte(')');
}
- const needs_lo = operand_int_info.bits > 64 and dest_bits <= 64;
+ const needs_lo = scalar_int_info.bits > 64 and dest_bits <= 64;
if (needs_lo) {
try writer.writeAll("zig_lo_");
- try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
+ try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
try writer.writeByte('(');
}
if (dest_bits >= 8 and std.math.isPowerOfTwo(dest_bits)) {
try f.writeCValue(writer, operand, .Other);
+ try v.elem(f, writer);
} else switch (dest_int_info.signedness) {
.unsigned => {
var arena = std.heap.ArenaAllocator.init(f.object.dg.gpa);
@@ -3476,15 +3506,16 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
var stack align(@alignOf(ExpectedContents)) =
std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator());
- const mask_val = try inst_ty.maxInt(stack.get(), target);
+ const mask_val = try inst_scalar_ty.maxInt(stack.get(), target);
try writer.writeAll("zig_and_");
- try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
+ try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
try writer.writeByte('(');
try f.writeCValue(writer, operand, .FunctionArgument);
- try writer.print(", {x})", .{try f.fmtIntLiteral(operand_ty, mask_val)});
+ try v.elem(f, writer);
+ try writer.print(", {x})", .{try f.fmtIntLiteral(scalar_ty, mask_val)});
},
.signed => {
- const c_bits = toCIntBits(operand_int_info.bits) orelse
+ const c_bits = toCIntBits(scalar_int_info.bits) orelse
return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{});
var shift_pl = Value.Payload.U64{
.base = .{ .tag = .int_u64 },
@@ -3493,7 +3524,7 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
const shift_val = Value.initPayload(&shift_pl.base);
try writer.writeAll("zig_shr_");
- try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
+ try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
if (c_bits == 128) {
try writer.print("(zig_bitcast_i{d}(", .{c_bits});
} else {
@@ -3506,6 +3537,7 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
try writer.print("(uint{d}_t)", .{c_bits});
}
try f.writeCValue(writer, operand, .FunctionArgument);
+ try v.elem(f, writer);
if (c_bits == 128) try writer.writeByte(')');
try writer.print(", {})", .{try f.fmtIntLiteral(Type.u8, shift_val)});
if (c_bits == 128) try writer.writeByte(')');
@@ -3515,6 +3547,8 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
if (needs_lo) try writer.writeByte(')');
try writer.writeAll(";\n");
+ try v.end(f, inst, writer);
+
return local;
}
@@ -3551,7 +3585,10 @@ fn storeUndefined(f: *Function, lhs_child_ty: Type, dest_ptr: CValue) !CValue {
fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
// *a = b;
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
- const ptr_info = f.air.typeOf(bin_op.lhs).ptrInfo().data;
+
+ const ptr_ty = f.air.typeOf(bin_op.lhs);
+ const ptr_scalar_ty = ptr_ty.scalarType();
+ const ptr_info = ptr_scalar_ty.ptrInfo().data;
if (!ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) {
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
return .none;
@@ -3574,11 +3611,13 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
ptr_info.@"align" >= ptr_info.pointee_type.abiAlignment(target);
const is_array = lowersToArray(ptr_info.pointee_type, target);
const need_memcpy = !is_aligned or is_array;
- const writer = f.object.writer();
const src_val = try f.resolveInst(bin_op.rhs);
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
+ const writer = f.object.writer();
+ const v = try Vectorizer.start(f, inst, writer, ptr_ty);
+
if (need_memcpy) {
// For this memcpy to safely work we need the rhs to have the same
// underlying type as the lhs (i.e. they must both be arrays of the same underlying type).
@@ -3599,16 +3638,18 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
try writer.writeAll("memcpy((char *)");
try f.writeCValue(writer, ptr_val, .FunctionArgument);
+ try v.elem(f, writer);
try writer.writeAll(", ");
if (!is_array) try writer.writeByte('&');
try f.writeCValue(writer, array_src, .FunctionArgument);
+ try v.elem(f, writer);
try writer.writeAll(", sizeof(");
try f.renderType(writer, src_ty);
try writer.writeAll("))");
if (src_val == .constant) {
try freeLocal(f, inst, array_src.new_local, 0);
}
- } else if (ptr_info.host_size != 0) {
+ } else if (ptr_info.host_size > 0 and ptr_info.vector_index == .none) {
const host_bits = ptr_info.host_size * 8;
var host_pl = Type.Payload.Bits{ .base = .{ .tag = .int_unsigned }, .data = host_bits };
const host_ty = Type.initPayload(&host_pl.base);
@@ -3645,12 +3686,14 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
const mask_val = Value.initPayload(&mask_pl.base);
try f.writeCValueDeref(writer, ptr_val);
+ try v.elem(f, writer);
try writer.writeAll(" = zig_or_");
try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);
try writer.writeAll("(zig_and_");
try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);
try writer.writeByte('(');
try f.writeCValueDeref(writer, ptr_val);
+ try v.elem(f, writer);
try writer.print(", {x}), zig_shl_", .{try f.fmtIntLiteral(host_ty, mask_val)});
try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);
try writer.writeByte('(');
@@ -3672,14 +3715,19 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
try writer.writeByte(')');
}
try f.writeCValue(writer, src_val, .Other);
+ try v.elem(f, writer);
if (cant_cast) try writer.writeByte(')');
try writer.print(", {}))", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)});
} else {
try f.writeCValueDeref(writer, ptr_val);
+ try v.elem(f, writer);
try writer.writeAll(" = ");
try f.writeCValue(writer, src_val, .Other);
+ try v.elem(f, writer);
}
try writer.writeAll(";\n");
+ try v.end(f, inst, writer);
+
return .none;
}
@@ -3697,51 +3745,39 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
const inst_ty = f.air.typeOfIndex(inst);
- const vector_ty = f.air.typeOf(bin_op.lhs);
- const scalar_ty = vector_ty.scalarType();
- const w = f.object.writer();
+ const operand_ty = f.air.typeOf(bin_op.lhs);
+ const scalar_ty = operand_ty.scalarType();
+ const w = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
-
- 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(", ");
- },
- }
-
+ const v = try Vectorizer.start(f, inst, w, operand_ty);
+ try f.writeCValueMember(w, local, .{ .field = 1 });
+ try v.elem(f, w);
+ 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 v.elem(f, w);
+ try w.writeAll(", ");
try f.writeCValue(w, lhs, .FunctionArgument);
+ try v.elem(f, w);
try w.writeAll(", ");
try f.writeCValue(w, rhs, .FunctionArgument);
+ try v.elem(f, w);
try f.object.dg.renderBuiltinInfo(w, scalar_ty, info);
try w.writeAll(");\n");
+ try v.end(f, inst, w);
return local;
}
fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
- const inst_ty = f.air.typeOfIndex(inst);
- if (inst_ty.tag() != .bool)
- return try airUnBuiltinCall(f, inst, "not", .Bits);
-
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
+ const operand_ty = f.air.typeOf(ty_op.operand);
+ const scalar_ty = operand_ty.scalarType();
+ if (scalar_ty.tag() != .bool) return try airUnBuiltinCall(f, inst, "not", .bits);
if (f.liveness.isUnused(inst)) {
try reap(f, inst, &.{ty_op.operand});
@@ -3751,14 +3787,20 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
const op = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
+ const inst_ty = f.air.typeOfIndex(inst);
+
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
-
+ const v = try Vectorizer.start(f, inst, writer, operand_ty);
try f.writeCValue(writer, local, .Other);
+ try v.elem(f, writer);
try writer.writeAll(" = ");
try writer.writeByte('!');
try f.writeCValue(writer, op, .Other);
+ try v.elem(f, writer);
try writer.writeAll(";\n");
+ try v.end(f, inst, writer);
+
return local;
}
@@ -3771,63 +3813,89 @@ fn airBinOp(
) !CValue {
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
const operand_ty = f.air.typeOf(bin_op.lhs);
+ const scalar_ty = operand_ty.scalarType();
const target = f.object.dg.module.getTarget();
- if ((operand_ty.isInt() and operand_ty.bitSize(target) > 64) or operand_ty.isRuntimeFloat())
+ if ((scalar_ty.isInt() and scalar_ty.bitSize(target) > 64) or scalar_ty.isRuntimeFloat())
return try airBinBuiltinCall(f, inst, operation, info);
+ if (f.liveness.isUnused(inst)) {
+ try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
+ return .none;
+ }
+
const lhs = try f.resolveInst(bin_op.lhs);
const rhs = try f.resolveInst(bin_op.rhs);
-
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- if (f.liveness.isUnused(inst)) return .none;
-
const inst_ty = f.air.typeOfIndex(inst);
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
+ const v = try Vectorizer.start(f, inst, writer, operand_ty);
try f.writeCValue(writer, local, .Other);
+ try v.elem(f, writer);
try writer.writeAll(" = ");
try f.writeCValue(writer, lhs, .Other);
+ try v.elem(f, writer);
try writer.writeByte(' ');
try writer.writeAll(operator);
try writer.writeByte(' ');
try f.writeCValue(writer, rhs, .Other);
+ try v.elem(f, writer);
try writer.writeAll(";\n");
+ try v.end(f, inst, writer);
return local;
}
-fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation: []const u8) !CValue {
- const bin_op = f.air.instructions.items(.data)[inst].bin_op;
-
+fn airCmpOp(
+ f: *Function,
+ inst: Air.Inst.Index,
+ data: anytype,
+ operator: std.math.CompareOperator,
+) !CValue {
if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
+ try reap(f, inst, &.{ data.lhs, data.rhs });
return .none;
}
- const operand_ty = f.air.typeOf(bin_op.lhs);
+ const operand_ty = f.air.typeOf(data.lhs);
+ const scalar_ty = operand_ty.scalarType();
+
const target = f.object.dg.module.getTarget();
- if (operand_ty.isInt() and operand_ty.bitSize(target) > 64)
- return try cmpBuiltinCall(f, inst, operator, "cmp");
- if (operand_ty.isRuntimeFloat())
- return try cmpBuiltinCall(f, inst, operator, operation);
+ const scalar_bits = scalar_ty.bitSize(target);
+ if (scalar_ty.isInt() and scalar_bits > 64)
+ return airCmpBuiltinCall(
+ f,
+ inst,
+ data,
+ operator,
+ .cmp,
+ if (scalar_bits > 128) .bits else .none,
+ );
+ if (scalar_ty.isRuntimeFloat())
+ return airCmpBuiltinCall(f, inst, data, operator, .operator, .none);
const inst_ty = f.air.typeOfIndex(inst);
- const lhs = try f.resolveInst(bin_op.lhs);
- const rhs = try f.resolveInst(bin_op.rhs);
- try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
+ const lhs = try f.resolveInst(data.lhs);
+ const rhs = try f.resolveInst(data.rhs);
+ try reap(f, inst, &.{ data.lhs, data.rhs });
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
+ const v = try Vectorizer.start(f, inst, writer, operand_ty);
try f.writeCValue(writer, local, .Other);
+ try v.elem(f, writer);
try writer.writeAll(" = ");
try f.writeCValue(writer, lhs, .Other);
+ try v.elem(f, writer);
try writer.writeByte(' ');
- try writer.writeAll(operator);
+ try writer.writeAll(compareOperatorC(operator));
try writer.writeByte(' ');
try f.writeCValue(writer, rhs, .Other);
+ try v.elem(f, writer);
try writer.writeAll(";\n");
+ try v.end(f, inst, writer);
return local;
}
@@ -3835,9 +3903,7 @@ fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation:
fn airEquality(
f: *Function,
inst: Air.Inst.Index,
- negate_prefix: []const u8,
- operator: []const u8,
- operation: []const u8,
+ operator: std.math.CompareOperator,
) !CValue {
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
@@ -3848,10 +3914,18 @@ fn airEquality(
const operand_ty = f.air.typeOf(bin_op.lhs);
const target = f.object.dg.module.getTarget();
- if (operand_ty.isInt() and operand_ty.bitSize(target) > 64)
- return try cmpBuiltinCall(f, inst, operator, "cmp");
+ const operand_bits = operand_ty.bitSize(target);
+ if (operand_ty.isInt() and operand_bits > 64)
+ return airCmpBuiltinCall(
+ f,
+ inst,
+ bin_op,
+ operator,
+ .cmp,
+ if (operand_bits > 128) .bits else .none,
+ );
if (operand_ty.isRuntimeFloat())
- return try cmpBuiltinCall(f, inst, operator, operation);
+ return airCmpBuiltinCall(f, inst, bin_op, operator, .operator, .none);
const lhs = try f.resolveInst(bin_op.lhs);
const rhs = try f.resolveInst(bin_op.rhs);
@@ -3867,7 +3941,12 @@ fn airEquality(
// (A && B) || (C && (A == B))
// A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload
- try writer.writeAll(negate_prefix);
+ switch (operator) {
+ .eq => {},
+ .neq => try writer.writeByte('!'),
+ else => unreachable,
+ }
+ try writer.writeAll("((");
try f.writeCValue(writer, lhs, .Other);
try writer.writeAll(".is_null && ");
try f.writeCValue(writer, rhs, .Other);
@@ -3886,7 +3965,7 @@ fn airEquality(
try f.writeCValue(writer, lhs, .Other);
try writer.writeByte(' ');
- try writer.writeAll(operator);
+ try writer.writeAll(compareOperatorC(operator));
try writer.writeByte(' ');
try f.writeCValue(writer, rhs, .Other);
try writer.writeAll(";\n");
@@ -3928,11 +4007,14 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
const inst_ty = f.air.typeOfIndex(inst);
- const elem_ty = inst_ty.elemType2();
+ const inst_scalar_ty = inst_ty.scalarType();
+ const elem_ty = inst_scalar_ty.elemType2();
const local = try f.allocLocal(inst, inst_ty);
const writer = f.object.writer();
+ const v = try Vectorizer.start(f, inst, writer, inst_ty);
try f.writeCValue(writer, local, .Other);
+ try v.elem(f, writer);
try writer.writeAll(" = ");
if (elem_ty.hasRuntimeBitsIgnoreComptime()) {
@@ -3940,19 +4022,26 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
// results in a NULL pointer, or if LHS is NULL. The operation is only UB
// if the result is NULL and then dereferenced.
try writer.writeByte('(');
- try f.renderType(writer, inst_ty);
+ try f.renderType(writer, inst_scalar_ty);
try writer.writeAll(")(((uintptr_t)");
try f.writeCValue(writer, lhs, .Other);
+ try v.elem(f, writer);
try writer.writeAll(") ");
try writer.writeByte(operator);
try writer.writeAll(" (");
try f.writeCValue(writer, rhs, .Other);
+ try v.elem(f, writer);
try writer.writeAll("*sizeof(");
try f.renderType(writer, elem_ty);
try writer.writeAll(")))");
- } else try f.writeCValue(writer, lhs, .Initializer);
+ } else {
+ try f.writeCValue(writer, lhs, .Other);
+ try v.elem(f, writer);
+ }
try writer.writeAll(";\n");
+ try v.end(f, inst, writer);
+
return local;
}
@@ -3965,10 +4054,12 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons
}
const inst_ty = f.air.typeOfIndex(inst);
+ const inst_scalar_ty = inst_ty.scalarType();
+
const target = f.object.dg.module.getTarget();
- if (inst_ty.isInt() and inst_ty.bitSize(target) > 64)
- return try airBinBuiltinCall(f, inst, operation[1..], .None);
- if (inst_ty.isRuntimeFloat())
+ if (inst_scalar_ty.isInt() and inst_scalar_ty.bitSize(target) > 64)
+ return try airBinBuiltinCall(f, inst, operation[1..], .none);
+ if (inst_scalar_ty.isRuntimeFloat())
return try airBinFloatOp(f, inst, operation);
const lhs = try f.resolveInst(bin_op.lhs);
@@ -3977,19 +4068,26 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
+ const v = try Vectorizer.start(f, inst, writer, inst_ty);
try f.writeCValue(writer, local, .Other);
+ try v.elem(f, writer);
// (lhs <> rhs) ? lhs : rhs
try writer.writeAll(" = (");
try f.writeCValue(writer, lhs, .Other);
+ try v.elem(f, writer);
try writer.writeByte(' ');
try writer.writeByte(operator);
try writer.writeByte(' ');
try f.writeCValue(writer, rhs, .Other);
+ try v.elem(f, writer);
try writer.writeAll(") ? ");
try f.writeCValue(writer, lhs, .Other);
+ try v.elem(f, writer);
try writer.writeAll(" : ");
try f.writeCValue(writer, rhs, .Other);
+ try v.elem(f, writer);
try writer.writeAll(";\n");
+ try v.end(f, inst, writer);
return local;
}
@@ -4413,12 +4511,56 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
// Ensure padding bits have the expected value.
if (dest_ty.isAbiInt()) {
+ const dest_cty = try f.typeToCType(dest_ty, .complete);
+ const dest_info = dest_ty.intInfo(target);
+ var info_ty_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dest_info.signedness) {
+ .unsigned => .int_unsigned,
+ .signed => .int_signed,
+ } }, .data = dest_info.bits };
+ var wrap_cty: ?CType = null;
+ var need_bitcasts = false;
+
try f.writeCValue(writer, local, .Other);
- try writer.writeAll(" = zig_wrap_");
- try f.object.dg.renderTypeForBuiltinFnName(writer, dest_ty);
+ if (dest_cty.castTag(.array)) |pl| {
+ try writer.print("[{d}]", .{switch (target.cpu.arch.endian()) {
+ .Little => pl.data.len - 1,
+ .Big => 0,
+ }});
+ const elem_cty = f.indexToCType(pl.data.elem_type);
+ wrap_cty = elem_cty.toSignedness(dest_info.signedness);
+ need_bitcasts = wrap_cty.?.tag() == .zig_i128;
+ info_ty_pl.data -= 1;
+ info_ty_pl.data %= @intCast(u16, f.byteSize(elem_cty) * 8);
+ info_ty_pl.data += 1;
+ }
+ try writer.writeAll(" = ");
+ if (need_bitcasts) {
+ try writer.writeAll("zig_bitcast_");
+ try f.object.dg.renderCTypeForBuiltinFnName(writer, wrap_cty.?.toUnsigned());
+ try writer.writeByte('(');
+ }
+ try writer.writeAll("zig_wrap_");
+ const info_ty = Type.initPayload(&info_ty_pl.base);
+ if (wrap_cty) |cty|
+ try f.object.dg.renderCTypeForBuiltinFnName(writer, cty)
+ else
+ try f.object.dg.renderTypeForBuiltinFnName(writer, info_ty);
try writer.writeByte('(');
+ if (need_bitcasts) {
+ try writer.writeAll("zig_bitcast_");
+ try f.object.dg.renderCTypeForBuiltinFnName(writer, wrap_cty.?);
+ try writer.writeByte('(');
+ }
try f.writeCValue(writer, local, .Other);
- try f.object.dg.renderBuiltinInfo(writer, dest_ty, .Bits);
+ if (dest_cty.castTag(.array)) |pl| {
+ try writer.print("[{d}]", .{switch (target.cpu.arch.endian()) {
+ .Little => pl.data.len - 1,
+ .Big => 0,
+ }});
+ }
+ if (need_bitcasts) try writer.writeByte(')');
+ try f.object.dg.renderBuiltinInfo(writer, info_ty, .bits);
+ if (need_bitcasts) try writer.writeByte(')');
try writer.writeAll(");\n");
}
@@ -5433,7 +5575,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
try writer.writeByte(')');
if (cant_cast) try writer.writeByte(')');
- try f.object.dg.renderBuiltinInfo(writer, field_int_ty, .Bits);
+ try f.object.dg.renderBuiltinInfo(writer, field_int_ty, .bits);
try writer.writeAll(");\n");
if (inst_ty.eql(field_int_ty, f.object.dg.module)) return temp_local;
@@ -5866,7 +6008,7 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
try f.writeCValue(writer, operand, .FunctionArgument);
try writer.writeByte(')');
if (inst_ty.isInt() and operand_ty.isRuntimeFloat()) {
- try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits);
+ try f.object.dg.renderBuiltinInfo(writer, inst_ty, .bits);
try writer.writeByte(')');
}
try writer.writeAll(";\n");
@@ -5912,19 +6054,35 @@ fn airUnBuiltinCall(
const operand = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
const inst_ty = f.air.typeOfIndex(inst);
+ const inst_scalar_ty = inst_ty.scalarType();
const operand_ty = f.air.typeOf(ty_op.operand);
+ const scalar_ty = operand_ty.scalarType();
+
+ const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete);
+ const ref_ret = inst_scalar_cty.tag() == .array;
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
- try f.writeCValue(writer, local, .Other);
- try writer.writeAll(" = zig_");
- try writer.writeAll(operation);
- try writer.writeByte('_');
- try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
+ const v = try Vectorizer.start(f, inst, writer, operand_ty);
+ if (!ref_ret) {
+ try f.writeCValue(writer, local, .Other);
+ try v.elem(f, writer);
+ try writer.writeAll(" = ");
+ }
+ try writer.print("zig_{s}_", .{operation});
+ try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
try writer.writeByte('(');
+ if (ref_ret) {
+ try f.writeCValue(writer, local, .FunctionArgument);
+ try v.elem(f, writer);
+ try writer.writeAll(", ");
+ }
try f.writeCValue(writer, operand, .FunctionArgument);
- try f.object.dg.renderBuiltinInfo(writer, operand_ty, info);
+ try v.elem(f, writer);
+ try f.object.dg.renderBuiltinInfo(writer, scalar_ty, info);
try writer.writeAll(");\n");
+ try v.end(f, inst, writer);
+
return local;
}
@@ -5946,50 +6104,99 @@ fn airBinBuiltinCall(
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
const inst_ty = f.air.typeOfIndex(inst);
+ const inst_scalar_ty = inst_ty.scalarType();
const operand_ty = f.air.typeOf(bin_op.lhs);
+ const scalar_ty = operand_ty.scalarType();
+
+ const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete);
+ const ref_ret = inst_scalar_cty.tag() == .array;
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
- try f.writeCValue(writer, local, .Other);
- try writer.writeAll(" = zig_");
- try writer.writeAll(operation);
- try writer.writeByte('_');
- try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
+ const v = try Vectorizer.start(f, inst, writer, operand_ty);
+ if (!ref_ret) {
+ try f.writeCValue(writer, local, .Other);
+ try v.elem(f, writer);
+ try writer.writeAll(" = ");
+ }
+ try writer.print("zig_{s}_", .{operation});
+ try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
try writer.writeByte('(');
+ if (ref_ret) {
+ try f.writeCValue(writer, local, .FunctionArgument);
+ try v.elem(f, writer);
+ try writer.writeAll(", ");
+ }
try f.writeCValue(writer, lhs, .FunctionArgument);
+ try v.elem(f, writer);
try writer.writeAll(", ");
try f.writeCValue(writer, rhs, .FunctionArgument);
- try f.object.dg.renderBuiltinInfo(writer, operand_ty, info);
+ try v.elem(f, writer);
+ try f.object.dg.renderBuiltinInfo(writer, scalar_ty, info);
try writer.writeAll(");\n");
+ try v.end(f, inst, writer);
+
return local;
}
-fn cmpBuiltinCall(
+fn airCmpBuiltinCall(
f: *Function,
inst: Air.Inst.Index,
- operator: []const u8,
- operation: []const u8,
+ data: anytype,
+ operator: std.math.CompareOperator,
+ operation: enum { cmp, operator },
+ info: BuiltinInfo,
) !CValue {
+ if (f.liveness.isUnused(inst)) {
+ try reap(f, inst, &.{ data.lhs, data.rhs });
+ return .none;
+ }
+
+ const lhs = try f.resolveInst(data.lhs);
+ const rhs = try f.resolveInst(data.rhs);
+ try reap(f, inst, &.{ data.lhs, data.rhs });
+
const inst_ty = f.air.typeOfIndex(inst);
- const bin_op = f.air.instructions.items(.data)[inst].bin_op;
- const operand_ty = f.air.typeOf(bin_op.lhs);
+ const inst_scalar_ty = inst_ty.scalarType();
+ const operand_ty = f.air.typeOf(data.lhs);
+ const scalar_ty = operand_ty.scalarType();
- const lhs = try f.resolveInst(bin_op.lhs);
- const rhs = try f.resolveInst(bin_op.rhs);
- try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
+ const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete);
+ const ref_ret = inst_scalar_cty.tag() == .array;
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
- try f.writeCValue(writer, local, .Other);
- try writer.writeAll(" = zig_");
- try writer.writeAll(operation);
- try writer.writeByte('_');
- try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
+ const v = try Vectorizer.start(f, inst, writer, operand_ty);
+ if (!ref_ret) {
+ try f.writeCValue(writer, local, .Other);
+ try v.elem(f, writer);
+ try writer.writeAll(" = ");
+ }
+ try writer.print("zig_{s}_", .{switch (operation) {
+ else => @tagName(operation),
+ .operator => compareOperatorAbbrev(operator),
+ }});
+ try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
try writer.writeByte('(');
+ if (ref_ret) {
+ try f.writeCValue(writer, local, .FunctionArgument);
+ try v.elem(f, writer);
+ try writer.writeAll(", ");
+ }
try f.writeCValue(writer, lhs, .FunctionArgument);
+ try v.elem(f, writer);
try writer.writeAll(", ");
try f.writeCValue(writer, rhs, .FunctionArgument);
- try writer.print(") {s} {};\n", .{ operator, try f.fmtIntLiteral(Type.initTag(.i32), Value.zero) });
+ try v.elem(f, writer);
+ try f.object.dg.renderBuiltinInfo(writer, scalar_ty, info);
+ try writer.writeByte(')');
+ if (!ref_ret) try writer.print(" {s} {}", .{
+ compareOperatorC(operator),
+ try f.fmtIntLiteral(Type.initTag(.i32), Value.zero),
+ });
+ try writer.writeAll(";\n");
+ try v.end(f, inst, writer);
+
return local;
}
@@ -6334,33 +6541,120 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
+
if (f.liveness.isUnused(inst)) {
try reap(f, inst, &.{ty_op.operand});
return .none;
}
- const inst_ty = f.air.typeOfIndex(inst);
const operand = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
+
+ const inst_ty = f.air.typeOfIndex(inst);
+ const inst_scalar_ty = inst_ty.scalarType();
+ const inst_scalar_cty = try f.typeToIndex(inst_scalar_ty, .complete);
+ const need_memcpy = f.indexToCType(inst_scalar_cty).tag() == .array;
+
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
+ const v = try Vectorizer.start(f, inst, writer, inst_ty);
+ if (need_memcpy) try writer.writeAll("memcpy(&");
try f.writeCValue(writer, local, .Other);
- try writer.writeAll(" = ");
+ try v.elem(f, writer);
+ try writer.writeAll(if (need_memcpy) ", &" else " = ");
+ try f.writeCValue(writer, operand, .Other);
+ if (need_memcpy) {
+ try writer.writeAll(", sizeof(");
+ try f.renderCType(writer, inst_scalar_cty);
+ try writer.writeAll("))");
+ }
+ try writer.writeAll(";\n");
+ try v.end(f, inst, writer);
- _ = operand;
- return f.fail("TODO: C backend: implement airSplat", .{});
+ return local;
}
fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue {
- if (f.liveness.isUnused(inst)) return .none;
+ const pl_op = f.air.instructions.items(.data)[inst].pl_op;
+ const extra = f.air.extraData(Air.Bin, pl_op.payload).data;
- return f.fail("TODO: C backend: implement airSelect", .{});
+ if (f.liveness.isUnused(inst)) {
+ try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });
+ return .none;
+ }
+
+ const pred = try f.resolveInst(pl_op.operand);
+ const lhs = try f.resolveInst(extra.lhs);
+ const rhs = try f.resolveInst(extra.rhs);
+ try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });
+
+ const inst_ty = f.air.typeOfIndex(inst);
+
+ const writer = f.object.writer();
+ const local = try f.allocLocal(inst, inst_ty);
+ const v = try Vectorizer.start(f, inst, writer, inst_ty);
+ try f.writeCValue(writer, local, .Other);
+ try v.elem(f, writer);
+ try writer.writeAll(" = ");
+ try f.writeCValue(writer, pred, .Other);
+ try v.elem(f, writer);
+ try writer.writeAll(" ? ");
+ try f.writeCValue(writer, lhs, .Other);
+ try v.elem(f, writer);
+ try writer.writeAll(" : ");
+ try f.writeCValue(writer, rhs, .Other);
+ try v.elem(f, writer);
+ try writer.writeAll(";\n");
+ try v.end(f, inst, writer);
+
+ return local;
}
fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {
- if (f.liveness.isUnused(inst)) return .none;
+ const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
+ const extra = f.air.extraData(Air.Shuffle, ty_pl.payload).data;
+
+ if (f.liveness.isUnused(inst)) {
+ try reap(f, inst, &.{ extra.a, extra.b });
+ return .none;
+ }
- return f.fail("TODO: C backend: implement airShuffle", .{});
+ const mask = f.air.values[extra.mask];
+ const lhs = try f.resolveInst(extra.a);
+ const rhs = try f.resolveInst(extra.b);
+
+ const module = f.object.dg.module;
+ const target = module.getTarget();
+ const inst_ty = f.air.typeOfIndex(inst);
+
+ const writer = f.object.writer();
+ const local = try f.allocLocal(inst, inst_ty);
+ try reap(f, inst, &.{ extra.a, extra.b }); // local cannot alias operands
+ for (0..extra.mask_len) |index| {
+ var dst_pl = Value.Payload.U64{
+ .base = .{ .tag = .int_u64 },
+ .data = @intCast(u64, index),
+ };
+
+ try f.writeCValue(writer, local, .Other);
+ try writer.writeByte('[');
+ try f.object.dg.renderValue(writer, Type.usize, Value.initPayload(&dst_pl.base), .Other);
+ try writer.writeAll("] = ");
+
+ var buf: Value.ElemValueBuffer = undefined;
+ const mask_elem = mask.elemValueBuffer(module, index, &buf).toSignedInt(target);
+ var src_pl = Value.Payload.U64{
+ .base = .{ .tag = .int_u64 },
+ .data = @intCast(u64, mask_elem ^ mask_elem >> 63),
+ };
+
+ try f.writeCValue(writer, if (mask_elem >= 0) lhs else rhs, .Other);
+ try writer.writeByte('[');
+ try f.object.dg.renderValue(writer, Type.usize, Value.initPayload(&src_pl.base), .Other);
+ try writer.writeAll("];\n");
+ }
+
+ return local;
}
fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
@@ -6376,65 +6670,45 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
const operand = try f.resolveInst(reduce.operand);
try reap(f, inst, &.{reduce.operand});
const operand_ty = f.air.typeOf(reduce.operand);
- const vector_len = operand_ty.vectorLen();
const writer = f.object.writer();
- const Op = union(enum) {
- call_fn: []const u8,
+ const use_operator = scalar_ty.bitSize(target) <= 64;
+ const op: union(enum) {
+ const Func = struct { operation: []const u8, info: BuiltinInfo = .none };
+ float_op: Func,
+ builtin: Func,
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 = " ^= " },
+ } = switch (reduce.operation) {
+ .And => if (use_operator) .{ .infix = " &= " } else .{ .builtin = .{ .operation = "and" } },
+ .Or => if (use_operator) .{ .infix = " |= " } else .{ .builtin = .{ .operation = "or" } },
+ .Xor => if (use_operator) .{ .infix = " ^= " } else .{ .builtin = .{ .operation = "xor" } },
.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,
- };
+ .Int => if (use_operator) .{ .ternary = " < " } else .{
+ .builtin = .{ .operation = "min" },
},
+ .Float => .{ .float_op = .{ .operation = "fmin" } },
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,
- };
+ .Int => if (use_operator) .{ .ternary = " > " } else .{
+ .builtin = .{ .operation = "max" },
},
+ .Float => .{ .float_op = .{ .operation = "fmax" } },
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,
- };
+ .Int => if (use_operator) .{ .infix = " += " } else .{
+ .builtin = .{ .operation = "addw", .info = .bits },
},
+ .Float => .{ .builtin = .{ .operation = "add" } },
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,
- };
+ .Int => if (use_operator) .{ .infix = " *= " } else .{
+ .builtin = .{ .operation = "mulw", .info = .bits },
},
+ .Float => .{ .builtin = .{ .operation = "mul" } },
else => unreachable,
},
};
@@ -6450,75 +6724,96 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
// }
// break :reduce accum;
// }
- const it = try f.allocLocal(inst, Type.usize);
- try f.writeCValue(writer, it, .Other);
- try writer.writeAll(" = 0;\n");
const accum = try f.allocLocal(inst, scalar_ty);
try f.writeCValue(writer, accum, .Other);
try writer.writeAll(" = ");
- const init_val = switch (reduce.operation) {
- .And, .Or, .Xor, .Add => "0",
+ var arena = std.heap.ArenaAllocator.init(f.object.dg.gpa);
+ defer arena.deinit();
+
+ const ExpectedContents = union {
+ u: Value.Payload.U64,
+ i: Value.Payload.I64,
+ f16: Value.Payload.Float_16,
+ f32: Value.Payload.Float_32,
+ f64: Value.Payload.Float_64,
+ f80: Value.Payload.Float_80,
+ f128: Value.Payload.Float_128,
+ };
+ var stack align(@alignOf(ExpectedContents)) =
+ std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator());
+
+ try f.object.dg.renderValue(writer, scalar_ty, switch (reduce.operation) {
+ .Or, .Xor, .Add => Value.zero,
+ .And => switch (scalar_ty.zigTypeTag()) {
+ .Bool => Value.one,
+ else => switch (scalar_ty.intInfo(target).signedness) {
+ .unsigned => try scalar_ty.maxInt(stack.get(), target),
+ .signed => Value.negative_one,
+ },
+ },
.Min => switch (scalar_ty.zigTypeTag()) {
- .Int => "TODO_intmax",
- .Float => "TODO_nan",
+ .Bool => Value.one,
+ .Int => try scalar_ty.maxInt(stack.get(), target),
+ .Float => try Value.floatToValue(std.math.nan(f128), stack.get(), scalar_ty, target),
else => unreachable,
},
.Max => switch (scalar_ty.zigTypeTag()) {
- .Int => "TODO_intmin",
- .Float => "TODO_nan",
+ .Bool => Value.zero,
+ .Int => try scalar_ty.minInt(stack.get(), target),
+ .Float => try Value.floatToValue(std.math.nan(f128), stack.get(), scalar_ty, target),
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);
+ .Mul => Value.one,
+ }, .Initializer);
+ try writer.writeAll(";\n");
+ const v = try Vectorizer.start(f, inst, writer, operand_ty);
+ try f.writeCValue(writer, accum, .Other);
switch (op) {
- .call_fn => |fn_name| {
- try writer.print(" = {s}(", .{fn_name});
+ .float_op => |func| {
+ try writer.writeAll(" = zig_libc_name_");
+ try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
+ try writer.print("({s})(", .{func.operation});
+ try f.writeCValue(writer, accum, .FunctionArgument);
+ try writer.writeAll(", ");
+ try f.writeCValue(writer, operand, .Other);
+ try v.elem(f, writer);
+ try f.object.dg.renderBuiltinInfo(writer, scalar_ty, func.info);
+ try writer.writeByte(')');
+ },
+ .builtin => |func| {
+ try writer.print(" = zig_{s}_", .{func.operation});
+ try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
+ try writer.writeByte('(');
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("])");
+ try v.elem(f, writer);
+ try f.object.dg.renderBuiltinInfo(writer, scalar_ty, func.info);
+ try writer.writeByte(')');
},
.infix => |ass| {
try writer.writeAll(ass);
try f.writeCValue(writer, operand, .Other);
- try writer.writeAll("[");
- try f.writeCValue(writer, it, .Other);
- try writer.writeAll("]");
+ try v.elem(f, writer);
},
.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 v.elem(f, writer);
+ 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 v.elem(f, writer);
},
}
-
try writer.writeAll(";\n");
-
- try freeLocal(f, inst, it.new_local, 0);
+ try v.end(f, inst, writer);
return accum;
}
@@ -6652,7 +6947,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
try writer.writeByte('(');
if (inst_ty.isAbiInt() and (field_ty.isAbiInt() or field_ty.isPtrAtRuntime())) {
- try f.renderIntCast(writer, inst_ty, element, field_ty, .FunctionArgument);
+ try f.renderIntCast(writer, inst_ty, element, .{}, field_ty, .FunctionArgument);
} else {
try writer.writeByte('(');
try f.renderType(writer, inst_ty);
@@ -6670,7 +6965,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
try writer.writeAll(", ");
try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
- try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits);
+ try f.object.dg.renderBuiltinInfo(writer, inst_ty, .bits);
try writer.writeByte(')');
if (!empty) try writer.writeByte(')');
@@ -6794,7 +7089,6 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue {
}
fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {
- const inst_ty = f.air.typeOfIndex(inst);
const un_op = f.air.instructions.items(.data)[inst].un_op;
if (f.liveness.isUnused(inst)) {
try reap(f, inst, &.{un_op});
@@ -6803,16 +7097,23 @@ fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {
const operand = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
+
const operand_ty = f.air.typeOf(un_op);
+ const scalar_ty = operand_ty.scalarType();
const writer = f.object.writer();
- const local = try f.allocLocal(inst, inst_ty);
+ const local = try f.allocLocal(inst, operand_ty);
+ const v = try Vectorizer.start(f, inst, writer, operand_ty);
try f.writeCValue(writer, local, .Other);
+ try v.elem(f, writer);
try writer.writeAll(" = zig_neg_");
- try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
+ try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
try writer.writeByte('(');
try f.writeCValue(writer, operand, .FunctionArgument);
+ try v.elem(f, writer);
try writer.writeAll(");\n");
+ try v.end(f, inst, writer);
+
return local;
}
@@ -6822,19 +7123,28 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal
try reap(f, inst, &.{un_op});
return .none;
}
+
const operand = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
- const writer = f.object.writer();
+
const inst_ty = f.air.typeOfIndex(inst);
+ const inst_scalar_ty = inst_ty.scalarType();
+
+ const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
+ const v = try Vectorizer.start(f, inst, writer, inst_ty);
try f.writeCValue(writer, local, .Other);
+ try v.elem(f, writer);
try writer.writeAll(" = zig_libc_name_");
- try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
+ try f.object.dg.renderTypeForBuiltinFnName(writer, inst_scalar_ty);
try writer.writeByte('(');
try writer.writeAll(operation);
try writer.writeAll(")(");
try f.writeCValue(writer, operand, .FunctionArgument);
+ try v.elem(f, writer);
try writer.writeAll(");\n");
+ try v.end(f, inst, writer);
+
return local;
}
@@ -6844,23 +7154,32 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
return .none;
}
+
const lhs = try f.resolveInst(bin_op.lhs);
const rhs = try f.resolveInst(bin_op.rhs);
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- const writer = f.object.writer();
const inst_ty = f.air.typeOfIndex(inst);
+ const inst_scalar_ty = inst_ty.scalarType();
+
+ const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
+ const v = try Vectorizer.start(f, inst, writer, inst_ty);
try f.writeCValue(writer, local, .Other);
+ try v.elem(f, writer);
try writer.writeAll(" = zig_libc_name_");
- try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
+ try f.object.dg.renderTypeForBuiltinFnName(writer, inst_scalar_ty);
try writer.writeByte('(');
try writer.writeAll(operation);
try writer.writeAll(")(");
try f.writeCValue(writer, lhs, .FunctionArgument);
+ try v.elem(f, writer);
try writer.writeAll(", ");
try f.writeCValue(writer, rhs, .FunctionArgument);
+ try v.elem(f, writer);
try writer.writeAll(");\n");
+ try v.end(f, inst, writer);
+
return local;
}
@@ -6871,23 +7190,34 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs, pl_op.operand });
return .none;
}
- const inst_ty = f.air.typeOfIndex(inst);
+
const mulend1 = try f.resolveInst(bin_op.lhs);
const mulend2 = try f.resolveInst(bin_op.rhs);
const addend = try f.resolveInst(pl_op.operand);
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs, pl_op.operand });
+
+ const inst_ty = f.air.typeOfIndex(inst);
+ const inst_scalar_ty = inst_ty.scalarType();
+
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
+ const v = try Vectorizer.start(f, inst, writer, inst_ty);
try f.writeCValue(writer, local, .Other);
+ try v.elem(f, writer);
try writer.writeAll(" = zig_libc_name_");
- try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
+ try f.object.dg.renderTypeForBuiltinFnName(writer, inst_scalar_ty);
try writer.writeAll("(fma)(");
try f.writeCValue(writer, mulend1, .FunctionArgument);
+ try v.elem(f, writer);
try writer.writeAll(", ");
try f.writeCValue(writer, mulend2, .FunctionArgument);
+ try v.elem(f, writer);
try writer.writeAll(", ");
try f.writeCValue(writer, addend, .FunctionArgument);
+ try v.elem(f, writer);
try writer.writeAll(");\n");
+ try v.end(f, inst, writer);
+
return local;
}
@@ -7089,6 +7419,28 @@ fn compilerRtAbbrev(ty: Type, target: std.Target) []const u8 {
} else unreachable;
}
+fn compareOperatorAbbrev(operator: std.math.CompareOperator) []const u8 {
+ return switch (operator) {
+ .lt => "lt",
+ .lte => "le",
+ .eq => "eq",
+ .gte => "ge",
+ .gt => "gt",
+ .neq => "ne",
+ };
+}
+
+fn compareOperatorC(operator: std.math.CompareOperator) []const u8 {
+ return switch (operator) {
+ .lt => "<",
+ .lte => "<=",
+ .eq => "==",
+ .gte => ">=",
+ .gt => ">",
+ .neq => "!=",
+ };
+}
+
fn StringLiteral(comptime WriterType: type) type {
// MSVC has a length limit of 16380 per string literal (before concatenation)
const max_char_len = 4;
@@ -7177,30 +7529,33 @@ fn undefPattern(comptime IntType: type) IntType {
return @bitCast(IntType, @as(UnsignedType, (1 << (int_info.bits | 1)) / 3));
}
-const FormatIntLiteralContext = struct { ty: Type, val: Value, mod: *Module, location: ?ValueRenderLocation = null };
+const FormatIntLiteralContext = struct {
+ dg: *DeclGen,
+ int_info: std.builtin.Type.Int,
+ kind: CType.Kind,
+ cty: CType,
+ val: Value,
+};
fn formatIntLiteral(
data: FormatIntLiteralContext,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) @TypeOf(writer).Error!void {
- const target = data.mod.getTarget();
- const int_info = data.ty.intInfo(target);
+ const target = data.dg.module.getTarget();
const ExpectedContents = struct {
const base = 10;
- const limbs_count_128 = BigInt.calcTwosCompLimbCount(128);
- const expected_needed_limbs_count = BigInt.calcToStringLimbsBufferLen(limbs_count_128, base);
- const worst_case_int = BigInt.Const{
- .limbs = &([1]BigIntLimb{std.math.maxInt(BigIntLimb)} ** expected_needed_limbs_count),
- .positive = false,
- };
+ const bits = 128;
+ const limbs_count = BigInt.calcTwosCompLimbCount(bits);
- undef_limbs: [limbs_count_128]BigIntLimb,
- wrap_limbs: [limbs_count_128]BigIntLimb,
+ undef_limbs: [limbs_count]BigIntLimb,
+ wrap_limbs: [limbs_count]BigIntLimb,
+ to_string_buf: [bits]u8,
+ to_string_limbs: [BigInt.calcToStringLimbsBufferLen(limbs_count, base)]BigIntLimb,
};
var stack align(@alignOf(ExpectedContents)) =
- std.heap.stackFallback(@sizeOf(ExpectedContents), data.mod.gpa);
+ std.heap.stackFallback(@sizeOf(ExpectedContents), data.dg.gpa);
const allocator = stack.get();
var undef_limbs: []BigIntLimb = &.{};
@@ -7208,7 +7563,7 @@ fn formatIntLiteral(
var int_buf: Value.BigIntSpace = undefined;
const int = if (data.val.isUndefDeep()) blk: {
- undef_limbs = try allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(int_info.bits));
+ undef_limbs = try allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(data.int_info.bits));
std.mem.set(BigIntLimb, undef_limbs, undefPattern(BigIntLimb));
var undef_int = BigInt.Mutable{
@@ -7216,164 +7571,193 @@ fn formatIntLiteral(
.len = undef_limbs.len,
.positive = true,
};
- undef_int.truncate(undef_int.toConst(), int_info.signedness, int_info.bits);
+ undef_int.truncate(undef_int.toConst(), data.int_info.signedness, data.int_info.bits);
break :blk undef_int.toConst();
} else data.val.toBigInt(&int_buf, target);
- assert(int.fitsInTwosComp(int_info.signedness, int_info.bits));
+ assert(int.fitsInTwosComp(data.int_info.signedness, data.int_info.bits));
- const c_bits = toCIntBits(int_info.bits) orelse unreachable;
+ const c_bits = @intCast(usize, data.cty.byteSize(data.dg.ctypes.set, target) * 8);
var one_limbs: [BigInt.calcLimbLen(1)]BigIntLimb = undefined;
const one = BigInt.Mutable.init(&one_limbs, 1).toConst();
- const wrap_limbs = try allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(c_bits));
- defer allocator.free(wrap_limbs);
- var wrap = BigInt.Mutable{ .limbs = wrap_limbs, .len = undefined, .positive = undefined };
- if (wrap.addWrap(int, one, int_info.signedness, c_bits) or
- int_info.signedness == .signed and wrap.subWrap(int, one, int_info.signedness, c_bits))
- {
- const abbrev = switch (data.ty.tag()) {
- .c_short, .c_ushort => "SHRT",
- .c_int, .c_uint => "INT",
- .c_long, .c_ulong => "LONG",
- .c_longlong, .c_ulonglong => "LLONG",
- .isize, .usize => "INTPTR",
- else => return writer.print("zig_{s}Int_{c}{d}", .{
- if (int.positive) "max" else "min", signAbbrev(int_info.signedness), c_bits,
- }),
- };
- if (int_info.signedness == .unsigned) try writer.writeByte('U');
- return writer.print("{s}_{s}", .{ abbrev, if (int.positive) "MAX" else "MIN" });
- }
-
- var use_twos_comp = false;
- if (!int.positive) {
- if (c_bits > 64) {
- // TODO: Can this be done for decimal literals as well?
- if (fmt.len == 1 and fmt[0] != 'd') {
- use_twos_comp = true;
- } else {
- // TODO: Use fmtIntLiteral for 0?
- try writer.print("zig_sub_{c}{d}(zig_make_{c}{d}(0, 0), ", .{ signAbbrev(int_info.signedness), c_bits, signAbbrev(int_info.signedness), c_bits });
- }
- } else {
- try writer.writeByte('-');
- }
- }
-
- switch (data.ty.tag()) {
- .c_short, .c_ushort, .c_int, .c_uint, .c_long, .c_ulong, .c_longlong, .c_ulonglong => {},
- else => {
- if (int_info.bits <= 64) {
- try writer.print("{s}INT{d}_C(", .{ switch (int_info.signedness) {
- .signed => "",
- .unsigned => "U",
- }, c_bits });
- } else if (data.location != null and data.location.? == .StaticInitializer) {
- // MSVC treats casting the struct initializer as not constant (C2099), so an alternate form is used in global initializers
- try writer.print("zig_make_constant_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits });
- } else {
- try writer.print("zig_make_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits });
- }
+ var wrap = BigInt.Mutable{
+ .limbs = try allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(c_bits)),
+ .len = undefined,
+ .positive = undefined,
+ };
+ defer allocator.free(wrap.limbs);
+
+ const c_limb_info: struct {
+ cty: CType,
+ count: usize,
+ endian: std.builtin.Endian,
+ homogeneous: bool,
+ } = switch (data.cty.tag()) {
+ else => .{
+ .cty = CType.initTag(.void),
+ .count = 1,
+ .endian = .Little,
+ .homogeneous = true,
},
- }
+ .zig_u128, .zig_i128 => .{
+ .cty = CType.initTag(.uint64_t),
+ .count = 2,
+ .endian = .Big,
+ .homogeneous = false,
+ },
+ .array => info: {
+ const array_data = data.cty.castTag(.array).?.data;
+ break :info .{
+ .cty = data.dg.indexToCType(array_data.elem_type),
+ .count = @intCast(usize, array_data.len),
+ .endian = target.cpu.arch.endian(),
+ .homogeneous = true,
+ };
+ },
+ };
+ if (c_limb_info.count == 1) {
+ if (wrap.addWrap(int, one, data.int_info.signedness, c_bits) or
+ data.int_info.signedness == .signed and wrap.subWrap(int, one, data.int_info.signedness, c_bits))
+ return writer.print("{s}_{s}", .{
+ data.cty.getStandardDefineAbbrev() orelse return writer.print("zig_{s}Int_{c}{d}", .{
+ if (int.positive) "max" else "min", signAbbrev(data.int_info.signedness), c_bits,
+ }),
+ if (int.positive) "MAX" else "MIN",
+ });
- const limbs_count_64 = @divExact(64, @bitSizeOf(BigIntLimb));
- if (c_bits <= 64) {
- var base: u8 = undefined;
- var case: std.fmt.Case = undefined;
- switch (fmt.len) {
- 0 => base = 10,
+ if (!int.positive) try writer.writeByte('-');
+ try data.cty.renderLiteralPrefix(writer, data.kind);
+
+ const style: struct { base: u8, case: std.fmt.Case = undefined } = switch (fmt.len) {
+ 0 => .{ .base = 10 },
1 => switch (fmt[0]) {
- 'b' => {
- base = 2;
+ 'b' => style: {
try writer.writeAll("0b");
+ break :style .{ .base = 2 };
},
- 'o' => {
- base = 8;
+ 'o' => style: {
try writer.writeByte('0');
+ break :style .{ .base = 8 };
},
- 'd' => base = 10,
- 'x' => {
- base = 16;
- case = .lower;
- try writer.writeAll("0x");
- },
- 'X' => {
- base = 16;
- case = .upper;
+ 'd' => .{ .base = 10 },
+ 'x', 'X' => |base| style: {
try writer.writeAll("0x");
+ break :style .{ .base = 16, .case = switch (base) {
+ 'x' => .lower,
+ 'X' => .upper,
+ else => unreachable,
+ } };
},
else => @compileError("Invalid fmt: " ++ fmt),
},
else => @compileError("Invalid fmt: " ++ fmt),
- }
+ };
- var str: [64]u8 = undefined;
- var limbs_buf: [BigInt.calcToStringLimbsBufferLen(limbs_count_64, 10)]BigIntLimb = undefined;
- try writer.writeAll(str[0..int.abs().toString(&str, base, case, &limbs_buf)]);
+ const string = try int.abs().toStringAlloc(allocator, style.base, style.case);
+ defer allocator.free(string);
+ try writer.writeAll(string);
} else {
- assert(c_bits == 128);
- const split = std.math.min(int.limbs.len, limbs_count_64);
- var twos_comp_limbs: [BigInt.calcTwosCompLimbCount(128)]BigIntLimb = undefined;
-
- // Adding a negation in the C code before the doesn't work in all cases:
- // - struct versions would require an extra zig_sub_ call to negate, which wouldn't work in constant expressions
- // - negating the f80 int representation (i128) doesn't make sense
- // Instead we write out the literal as a negative number in twos complement
- var limbs = int.limbs;
-
- if (use_twos_comp) {
- var twos_comp = BigInt.Mutable{
- .limbs = &twos_comp_limbs,
- .positive = undefined,
+ try data.cty.renderLiteralPrefix(writer, data.kind);
+ wrap.convertToTwosComplement(int, data.int_info.signedness, c_bits);
+ std.mem.set(BigIntLimb, wrap.limbs[wrap.len..], 0);
+ wrap.len = wrap.limbs.len;
+ const limbs_per_c_limb = @divExact(wrap.len, c_limb_info.count);
+
+ var c_limb_int_info = std.builtin.Type.Int{
+ .signedness = undefined,
+ .bits = @intCast(u16, @divExact(c_bits, c_limb_info.count)),
+ };
+ var c_limb_cty: CType = undefined;
+
+ var limb_offset: usize = 0;
+ const most_significant_limb_i = wrap.len - limbs_per_c_limb;
+ while (limb_offset < wrap.len) : (limb_offset += limbs_per_c_limb) {
+ const limb_i = switch (c_limb_info.endian) {
+ .Little => limb_offset,
+ .Big => most_significant_limb_i - limb_offset,
+ };
+ var c_limb_mut = BigInt.Mutable{
+ .limbs = wrap.limbs[limb_i..][0..limbs_per_c_limb],
.len = undefined,
+ .positive = true,
};
+ c_limb_mut.normalize(limbs_per_c_limb);
- twos_comp.convertToTwosComplement(int, .signed, int_info.bits);
- limbs = twos_comp.limbs;
+ if (limb_i == most_significant_limb_i and
+ !c_limb_info.homogeneous and data.int_info.signedness == .signed)
+ {
+ // most significant limb is actually signed
+ c_limb_int_info.signedness = .signed;
+ c_limb_cty = c_limb_info.cty.toSigned();
+
+ c_limb_mut.positive = wrap.positive;
+ c_limb_mut.truncate(
+ c_limb_mut.toConst(),
+ .signed,
+ data.int_info.bits - limb_i * @bitSizeOf(BigIntLimb),
+ );
+ } else {
+ c_limb_int_info.signedness = .unsigned;
+ c_limb_cty = c_limb_info.cty;
+ }
+ var c_limb_val_pl = Value.Payload.BigInt{
+ .base = .{ .tag = if (c_limb_mut.positive) .int_big_positive else .int_big_negative },
+ .data = c_limb_mut.limbs[0..c_limb_mut.len],
+ };
+
+ if (limb_offset > 0) try writer.writeAll(", ");
+ try formatIntLiteral(.{
+ .dg = data.dg,
+ .int_info = c_limb_int_info,
+ .kind = data.kind,
+ .cty = c_limb_cty,
+ .val = Value.initPayload(&c_limb_val_pl.base),
+ }, fmt, options, writer);
}
+ }
+ try data.cty.renderLiteralSuffix(writer);
+}
- var upper_pl = Value.Payload.BigInt{
- .base = .{ .tag = .int_big_positive },
- .data = limbs[split..],
- };
- const upper_val = Value.initPayload(&upper_pl.base);
- try formatIntLiteral(.{
- .ty = switch (int_info.signedness) {
- .unsigned => Type.u64,
- .signed => if (use_twos_comp) Type.u64 else Type.i64,
- },
- .val = upper_val,
- .mod = data.mod,
- }, fmt, options, writer);
+const Vectorizer = struct {
+ index: CValue = .none,
- try writer.writeAll(", ");
+ pub fn start(f: *Function, inst: Air.Inst.Index, writer: anytype, ty: Type) !Vectorizer {
+ return if (ty.zigTypeTag() == .Vector) index: {
+ var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = ty.vectorLen() };
- var lower_pl = Value.Payload.BigInt{
- .base = .{ .tag = .int_big_positive },
- .data = limbs[0..split],
- };
- const lower_val = Value.initPayload(&lower_pl.base);
- try formatIntLiteral(.{
- .ty = Type.u64,
- .val = lower_val,
- .mod = data.mod,
- }, fmt, options, writer);
+ const local = try f.allocLocal(inst, Type.usize);
- if (!int.positive and c_bits > 64 and !use_twos_comp) try writer.writeByte(')');
- return writer.writeByte(')');
+ try writer.writeAll("for (");
+ try f.writeCValue(writer, local, .Other);
+ try writer.print(" = {d}; ", .{try f.fmtIntLiteral(Type.usize, Value.zero)});
+ try f.writeCValue(writer, local, .Other);
+ try writer.print(" < {d}; ", .{
+ try f.fmtIntLiteral(Type.usize, Value.initPayload(&len_pl.base)),
+ });
+ try f.writeCValue(writer, local, .Other);
+ try writer.print(" += {d}) {{\n", .{try f.fmtIntLiteral(Type.usize, Value.one)});
+ f.object.indent_writer.pushIndent();
+
+ break :index .{ .index = local };
+ } else .{};
+ }
+
+ pub fn elem(self: Vectorizer, f: *Function, writer: anytype) !void {
+ if (self.index != .none) {
+ try writer.writeByte('[');
+ try f.writeCValue(writer, self.index, .Other);
+ try writer.writeByte(']');
+ }
}
- switch (data.ty.tag()) {
- .c_short, .c_ushort, .c_int => {},
- .c_uint => try writer.writeAll("u"),
- .c_long => try writer.writeAll("l"),
- .c_ulong => try writer.writeAll("ul"),
- .c_longlong => try writer.writeAll("ll"),
- .c_ulonglong => try writer.writeAll("ull"),
- else => try writer.writeByte(')'),
+ pub fn end(self: Vectorizer, f: *Function, inst: Air.Inst.Index, writer: anytype) !void {
+ if (self.index != .none) {
+ f.object.indent_writer.popIndent();
+ try writer.writeAll("}\n");
+ try freeLocal(f, inst, self.index.new_local, 0);
+ }
}
-}
+};
fn isByRef(ty: Type) bool {
_ = ty;
diff --git a/src/codegen/c/type.zig b/src/codegen/c/type.zig
index 1f1a220cd2..038f53f186 100644
--- a/src/codegen/c/type.zig
+++ b/src/codegen/c/type.zig
@@ -496,6 +496,427 @@ pub const CType = extern union {
}
};
+ pub fn isBool(self: CType) bool {
+ return switch (self.tag()) {
+ ._Bool,
+ .bool,
+ => true,
+ else => false,
+ };
+ }
+
+ pub fn isInteger(self: CType) bool {
+ return switch (self.tag()) {
+ .char,
+ .@"signed char",
+ .short,
+ .int,
+ .long,
+ .@"long long",
+ .@"unsigned char",
+ .@"unsigned short",
+ .@"unsigned int",
+ .@"unsigned long",
+ .@"unsigned long long",
+ .size_t,
+ .ptrdiff_t,
+ .uint8_t,
+ .int8_t,
+ .uint16_t,
+ .int16_t,
+ .uint32_t,
+ .int32_t,
+ .uint64_t,
+ .int64_t,
+ .uintptr_t,
+ .intptr_t,
+ .zig_u128,
+ .zig_i128,
+ => true,
+ else => false,
+ };
+ }
+
+ pub fn signedness(self: CType) ?std.builtin.Signedness {
+ return switch (self.tag()) {
+ .char => null, // unknown signedness
+ .@"signed char",
+ .short,
+ .int,
+ .long,
+ .@"long long",
+ .ptrdiff_t,
+ .int8_t,
+ .int16_t,
+ .int32_t,
+ .int64_t,
+ .intptr_t,
+ .zig_i128,
+ => .signed,
+ .@"unsigned char",
+ .@"unsigned short",
+ .@"unsigned int",
+ .@"unsigned long",
+ .@"unsigned long long",
+ .size_t,
+ .uint8_t,
+ .uint16_t,
+ .uint32_t,
+ .uint64_t,
+ .uintptr_t,
+ .zig_u128,
+ => .unsigned,
+ else => unreachable,
+ };
+ }
+
+ pub fn isFloat(self: CType) bool {
+ return switch (self.tag()) {
+ .float,
+ .double,
+ .@"long double",
+ .zig_f16,
+ .zig_f32,
+ .zig_f64,
+ .zig_f80,
+ .zig_f128,
+ .zig_c_longdouble,
+ => true,
+ else => false,
+ };
+ }
+
+ pub fn isPointer(self: CType) bool {
+ return switch (self.tag()) {
+ .pointer,
+ .pointer_const,
+ .pointer_volatile,
+ .pointer_const_volatile,
+ => true,
+ else => false,
+ };
+ }
+
+ pub fn isFunction(self: CType) bool {
+ return switch (self.tag()) {
+ .function,
+ .varargs_function,
+ => true,
+ else => false,
+ };
+ }
+
+ pub fn toSigned(self: CType) CType {
+ return CType.initTag(switch (self.tag()) {
+ .char, .@"signed char", .@"unsigned char" => .@"signed char",
+ .short, .@"unsigned short" => .short,
+ .int, .@"unsigned int" => .int,
+ .long, .@"unsigned long" => .long,
+ .@"long long", .@"unsigned long long" => .@"long long",
+ .size_t, .ptrdiff_t => .ptrdiff_t,
+ .uint8_t, .int8_t => .int8_t,
+ .uint16_t, .int16_t => .int16_t,
+ .uint32_t, .int32_t => .int32_t,
+ .uint64_t, .int64_t => .int64_t,
+ .uintptr_t, .intptr_t => .intptr_t,
+ .zig_u128, .zig_i128 => .zig_i128,
+ .float,
+ .double,
+ .@"long double",
+ .zig_f16,
+ .zig_f32,
+ .zig_f80,
+ .zig_f128,
+ .zig_c_longdouble,
+ => |t| t,
+ else => unreachable,
+ });
+ }
+
+ pub fn toUnsigned(self: CType) CType {
+ return CType.initTag(switch (self.tag()) {
+ .char, .@"signed char", .@"unsigned char" => .@"unsigned char",
+ .short, .@"unsigned short" => .@"unsigned short",
+ .int, .@"unsigned int" => .@"unsigned int",
+ .long, .@"unsigned long" => .@"unsigned long",
+ .@"long long", .@"unsigned long long" => .@"unsigned long long",
+ .size_t, .ptrdiff_t => .size_t,
+ .uint8_t, .int8_t => .uint8_t,
+ .uint16_t, .int16_t => .uint16_t,
+ .uint32_t, .int32_t => .uint32_t,
+ .uint64_t, .int64_t => .uint64_t,
+ .uintptr_t, .intptr_t => .uintptr_t,
+ .zig_u128, .zig_i128 => .zig_u128,
+ else => unreachable,
+ });
+ }
+
+ pub fn toSignedness(self: CType, s: std.builtin.Signedness) CType {
+ return switch (s) {
+ .unsigned => self.toUnsigned(),
+ .signed => self.toSigned(),
+ };
+ }
+
+ pub fn getStandardDefineAbbrev(self: CType) ?[]const u8 {
+ return switch (self.tag()) {
+ .char => "CHAR",
+ .@"signed char" => "SCHAR",
+ .short => "SHRT",
+ .int => "INT",
+ .long => "LONG",
+ .@"long long" => "LLONG",
+ .@"unsigned char" => "UCHAR",
+ .@"unsigned short" => "USHRT",
+ .@"unsigned int" => "UINT",
+ .@"unsigned long" => "ULONG",
+ .@"unsigned long long" => "ULLONG",
+ .float => "FLT",
+ .double => "DBL",
+ .@"long double" => "LDBL",
+ .size_t => "SIZE",
+ .ptrdiff_t => "PTRDIFF",
+ .uint8_t => "UINT8",
+ .int8_t => "INT8",
+ .uint16_t => "UINT16",
+ .int16_t => "INT16",
+ .uint32_t => "UINT32",
+ .int32_t => "INT32",
+ .uint64_t => "UINT64",
+ .int64_t => "INT64",
+ .uintptr_t => "UINTPTR",
+ .intptr_t => "INTPTR",
+ else => null,
+ };
+ }
+
+ pub fn renderLiteralPrefix(self: CType, writer: anytype, kind: Kind) @TypeOf(writer).Error!void {
+ switch (self.tag()) {
+ .void => unreachable,
+ ._Bool,
+ .char,
+ .@"signed char",
+ .short,
+ .@"unsigned short",
+ .bool,
+ .size_t,
+ .ptrdiff_t,
+ .uintptr_t,
+ .intptr_t,
+ => |t| switch (kind) {
+ else => try writer.print("({s})", .{@tagName(t)}),
+ .global => {},
+ },
+ .int,
+ .long,
+ .@"long long",
+ .@"unsigned char",
+ .@"unsigned int",
+ .@"unsigned long",
+ .@"unsigned long long",
+ .float,
+ .double,
+ .@"long double",
+ => {},
+ .uint8_t,
+ .int8_t,
+ .uint16_t,
+ .int16_t,
+ .uint32_t,
+ .int32_t,
+ .uint64_t,
+ .int64_t,
+ => try writer.print("{s}_C(", .{self.getStandardDefineAbbrev().?}),
+ .zig_u128,
+ .zig_i128,
+ .zig_f16,
+ .zig_f32,
+ .zig_f64,
+ .zig_f80,
+ .zig_f128,
+ .zig_c_longdouble,
+ => |t| try writer.print("zig_{s}_{s}(", .{
+ switch (kind) {
+ else => "make",
+ .global => "init",
+ },
+ @tagName(t)["zig_".len..],
+ }),
+ .pointer,
+ .pointer_const,
+ .pointer_volatile,
+ .pointer_const_volatile,
+ => unreachable,
+ .array,
+ .vector,
+ => try writer.writeByte('{'),
+ .fwd_anon_struct,
+ .fwd_anon_union,
+ .fwd_struct,
+ .fwd_union,
+ .unnamed_struct,
+ .unnamed_union,
+ .packed_unnamed_struct,
+ .packed_unnamed_union,
+ .anon_struct,
+ .anon_union,
+ .@"struct",
+ .@"union",
+ .packed_struct,
+ .packed_union,
+ .function,
+ .varargs_function,
+ => unreachable,
+ }
+ }
+
+ pub fn renderLiteralSuffix(self: CType, writer: anytype) @TypeOf(writer).Error!void {
+ switch (self.tag()) {
+ .void => unreachable,
+ ._Bool => {},
+ .char,
+ .@"signed char",
+ .short,
+ .int,
+ => {},
+ .long => try writer.writeByte('l'),
+ .@"long long" => try writer.writeAll("ll"),
+ .@"unsigned char",
+ .@"unsigned short",
+ .@"unsigned int",
+ => try writer.writeByte('u'),
+ .@"unsigned long",
+ .size_t,
+ .uintptr_t,
+ => try writer.writeAll("ul"),
+ .@"unsigned long long" => try writer.writeAll("ull"),
+ .float => try writer.writeByte('f'),
+ .double => {},
+ .@"long double" => try writer.writeByte('l'),
+ .bool,
+ .ptrdiff_t,
+ .intptr_t,
+ => {},
+ .uint8_t,
+ .int8_t,
+ .uint16_t,
+ .int16_t,
+ .uint32_t,
+ .int32_t,
+ .uint64_t,
+ .int64_t,
+ .zig_u128,
+ .zig_i128,
+ .zig_f16,
+ .zig_f32,
+ .zig_f64,
+ .zig_f80,
+ .zig_f128,
+ .zig_c_longdouble,
+ => try writer.writeByte(')'),
+ .pointer,
+ .pointer_const,
+ .pointer_volatile,
+ .pointer_const_volatile,
+ => unreachable,
+ .array,
+ .vector,
+ => try writer.writeByte('}'),
+ .fwd_anon_struct,
+ .fwd_anon_union,
+ .fwd_struct,
+ .fwd_union,
+ .unnamed_struct,
+ .unnamed_union,
+ .packed_unnamed_struct,
+ .packed_unnamed_union,
+ .anon_struct,
+ .anon_union,
+ .@"struct",
+ .@"union",
+ .packed_struct,
+ .packed_union,
+ .function,
+ .varargs_function,
+ => unreachable,
+ }
+ }
+
+ pub fn floatActiveBits(self: CType, target: Target) u16 {
+ return switch (self.tag()) {
+ .float => target.c_type_bit_size(.float),
+ .double => target.c_type_bit_size(.double),
+ .@"long double", .zig_c_longdouble => target.c_type_bit_size(.longdouble),
+ .zig_f16 => 16,
+ .zig_f32 => 32,
+ .zig_f64 => 64,
+ .zig_f80 => 80,
+ .zig_f128 => 128,
+ else => unreachable,
+ };
+ }
+
+ pub fn byteSize(self: CType, store: Store.Set, target: Target) u64 {
+ return switch (self.tag()) {
+ .void => 0,
+ .char, .@"signed char", ._Bool, .@"unsigned char", .bool, .uint8_t, .int8_t => 1,
+ .short => target.c_type_byte_size(.short),
+ .int => target.c_type_byte_size(.int),
+ .long => target.c_type_byte_size(.long),
+ .@"long long" => target.c_type_byte_size(.longlong),
+ .@"unsigned short" => target.c_type_byte_size(.ushort),
+ .@"unsigned int" => target.c_type_byte_size(.uint),
+ .@"unsigned long" => target.c_type_byte_size(.ulong),
+ .@"unsigned long long" => target.c_type_byte_size(.ulonglong),
+ .float => target.c_type_byte_size(.float),
+ .double => target.c_type_byte_size(.double),
+ .@"long double" => target.c_type_byte_size(.longdouble),
+ .size_t,
+ .ptrdiff_t,
+ .uintptr_t,
+ .intptr_t,
+ .pointer,
+ .pointer_const,
+ .pointer_volatile,
+ .pointer_const_volatile,
+ => @divExact(target.cpu.arch.ptrBitWidth(), 8),
+ .uint16_t, .int16_t, .zig_f16 => 2,
+ .uint32_t, .int32_t, .zig_f32 => 4,
+ .uint64_t, .int64_t, .zig_f64 => 8,
+ .zig_u128, .zig_i128, .zig_f128 => 16,
+ .zig_f80 => if (target.c_type_bit_size(.longdouble) == 80)
+ target.c_type_byte_size(.longdouble)
+ else
+ 16,
+ .zig_c_longdouble => target.c_type_byte_size(.longdouble),
+
+ .array,
+ .vector,
+ => {
+ const data = self.cast(Payload.Sequence).?.data;
+ return data.len * store.indexToCType(data.elem_type).byteSize(store, target);
+ },
+
+ .fwd_anon_struct,
+ .fwd_anon_union,
+ .fwd_struct,
+ .fwd_union,
+ .unnamed_struct,
+ .unnamed_union,
+ .packed_unnamed_struct,
+ .packed_unnamed_union,
+ .anon_struct,
+ .anon_union,
+ .@"struct",
+ .@"union",
+ .packed_struct,
+ .packed_union,
+ .function,
+ .varargs_function,
+ => unreachable,
+ };
+ }
+
pub fn isPacked(self: CType) bool {
return switch (self.tag()) {
else => false,
@@ -787,26 +1208,26 @@ pub const CType = extern union {
};
}
- fn tagFromIntInfo(signedness: std.builtin.Signedness, bits: u16) Tag {
- return switch (bits) {
+ fn tagFromIntInfo(int_info: std.builtin.Type.Int) Tag {
+ return switch (int_info.bits) {
0 => .void,
- 1...8 => switch (signedness) {
+ 1...8 => switch (int_info.signedness) {
.unsigned => .uint8_t,
.signed => .int8_t,
},
- 9...16 => switch (signedness) {
+ 9...16 => switch (int_info.signedness) {
.unsigned => .uint16_t,
.signed => .int16_t,
},
- 17...32 => switch (signedness) {
+ 17...32 => switch (int_info.signedness) {
.unsigned => .uint32_t,
.signed => .int32_t,
},
- 33...64 => switch (signedness) {
+ 33...64 => switch (int_info.signedness) {
.unsigned => .uint64_t,
.signed => .int64_t,
},
- 65...128 => switch (signedness) {
+ 65...128 => switch (int_info.signedness) {
.unsigned => .zig_u128,
.signed => .zig_i128,
},
@@ -945,31 +1366,27 @@ pub const CType = extern union {
.c_ulong => self.init(.@"unsigned long"),
.c_longlong => self.init(.@"long long"),
.c_ulonglong => self.init(.@"unsigned long long"),
- else => {
- const info = ty.intInfo(target);
- const t = tagFromIntInfo(info.signedness, info.bits);
- switch (t) {
- .void => unreachable,
- else => self.init(t),
- .array => switch (kind) {
- .forward, .complete, .global => {
- const abi_size = ty.abiSize(target);
- const abi_align = ty.abiAlignment(target);
- self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{
- .len = @divExact(abi_size, abi_align),
- .elem_type = tagFromIntInfo(
- .unsigned,
- @intCast(u16, abi_align * 8),
- ).toIndex(),
- } } };
- self.value = .{ .cty = initPayload(&self.storage.seq) };
- },
- .forward_parameter,
- .parameter,
- => try self.initArrayParameter(ty, kind, lookup),
- .payload => unreachable,
+ else => switch (tagFromIntInfo(ty.intInfo(target))) {
+ .void => unreachable,
+ else => |t| self.init(t),
+ .array => switch (kind) {
+ .forward, .complete, .global => {
+ const abi_size = ty.abiSize(target);
+ const abi_align = ty.abiAlignment(target);
+ self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{
+ .len = @divExact(abi_size, abi_align),
+ .elem_type = tagFromIntInfo(.{
+ .signedness = .unsigned,
+ .bits = @intCast(u16, abi_align * 8),
+ }).toIndex(),
+ } } };
+ self.value = .{ .cty = initPayload(&self.storage.seq) };
},
- }
+ .forward_parameter,
+ .parameter,
+ => try self.initArrayParameter(ty, kind, lookup),
+ .payload => unreachable,
+ },
},
} else switch (ty.zigTypeTag()) {
.Frame => unreachable,
@@ -1048,7 +1465,7 @@ pub const CType = extern union {
.base = .{ .tag = .int_unsigned },
.data = info.host_size * 8,
};
- const pointee_ty = if (info.host_size > 0)
+ const pointee_ty = if (info.host_size > 0 and info.vector_index == .none)
Type.initPayload(&host_int_pl.base)
else
info.pointee_type;
diff --git a/src/link/C.zig b/src/link/C.zig
index 5663ba71e2..7e3ad2eddd 100644
--- a/src/link/C.zig
+++ b/src/link/C.zig
@@ -221,14 +221,19 @@ pub fn flush(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) !void
return self.flushModule(comp, prog_node);
}
-fn abiDefine(comp: *Compilation) ?[]const u8 {
- return switch (comp.getTarget().abi) {
- .msvc => "#define ZIG_TARGET_ABI_MSVC\n",
- else => null,
- };
+fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) {
+ var defines = std.ArrayList(u8).init(self.base.allocator);
+ errdefer defines.deinit();
+ const writer = defines.writer();
+ switch (target.abi) {
+ .msvc => try writer.writeAll("#define ZIG_TARGET_ABI_MSVC\n"),
+ else => {},
+ }
+ try writer.print("#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n", .{target.maxIntAlignment()});
+ return defines;
}
-pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) !void {
+pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !void {
const tracy = trace(@src());
defer tracy.end();
@@ -245,12 +250,13 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
var f: Flush = .{};
defer f.deinit(gpa);
- const abi_define = abiDefine(comp);
+ const abi_defines = try self.abiDefines(module.getTarget());
+ defer abi_defines.deinit();
// Covers defines, zig.h, ctypes, asm, lazy fwd.
try f.all_buffers.ensureUnusedCapacity(gpa, 5);
- if (abi_define) |buf| f.appendBufAssumeCapacity(buf);
+ f.appendBufAssumeCapacity(abi_defines.items);
f.appendBufAssumeCapacity(zig_h);
const ctypes_index = f.all_buffers.items.len;
diff --git a/src/value.zig b/src/value.zig
index 4a5683df36..00bf59ca38 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -3319,7 +3319,7 @@ pub const Value = extern union {
}
}
- fn floatToValue(float: f128, arena: Allocator, dest_ty: Type, target: Target) !Value {
+ pub fn floatToValue(float: f128, arena: Allocator, dest_ty: Type, target: Target) !Value {
switch (dest_ty.floatBits(target)) {
16 => return Value.Tag.float_16.create(arena, @floatCast(f16, float)),
32 => return Value.Tag.float_32.create(arena, @floatCast(f32, float)),