authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-04-27 13:51:53-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-04-27 14:18:34-07:00
log087aedfa38e0eb2a8f0e3055be18625017060b29
treedaf083d2a0ffccea4b4764ebd94ddb0704eb5333
parent7d6a6ce87fde465ffc3bd6b0a8bb6e039c67268f

stage2: fix recent LLVM backend code

* std.math.snan: fix compilation error. Also make it and nan inline. * LLVM: use a proper enum type for float op instead of enum literal. Also various cleanups. * LLVM: use LLVMBuildVectorSplat for vector splat AIR instruction. - also the bindings had parameter order wrong * LLVM: additionally handle f16 lowering. For now all targets report OK but I think we will need to add some exceptions to this list.

3 files changed, 147 insertions(+), 135 deletions(-)

lib/std/math/nan.zig+5-12
......@@ -1,7 +1,7 @@
11const math = @import("../math.zig");
22
33/// Returns the nan representation for type T.
4pub fn nan(comptime T: type) T {
4pub inline fn nan(comptime T: type) T {
55 return switch (@typeInfo(T).Float.bits) {
66 16 => math.nan_f16,
77 32 => math.nan_f32,
......@@ -13,15 +13,8 @@ pub fn nan(comptime T: type) T {
1313}
1414
1515/// Returns the signalling nan representation for type T.
16pub fn snan(comptime T: type) T {
17 // Note: A signalling nan is identical to a standard right now by may have a different bit
18 // representation in the future when required.
19 return switch (@typeInfo(T).Float.bits) {
20 16 => math.nan_u16,
21 32 => math.nan_u32,
22 64 => math.nan_u64,
23 80 => math.nan_u80,
24 128 => math.nan_u128,
25 else => @compileError("unreachable"),
26 };
16/// Note: A signalling nan is identical to a standard right now by may have a different bit
17/// representation in the future when required.
18pub inline fn snan(comptime T: type) T {
19 return nan(T);
2720}
src/codegen/llvm.zig+141-119
......@@ -3983,7 +3983,7 @@ pub const FuncGen = struct {
39833983 );
39843984 return phi_node;
39853985 },
3986 .Float => return self.buildFloatCmp(op, operand_ty, &.{ lhs, rhs }),
3986 .Float => return self.buildFloatCmp(op, operand_ty, .{ lhs, rhs }),
39873987 else => unreachable,
39883988 };
39893989 const is_signed = int_ty.isSignedInt();
......@@ -5211,7 +5211,7 @@ pub const FuncGen = struct {
52115211 const inst_ty = self.air.typeOfIndex(inst);
52125212 const scalar_ty = inst_ty.scalarType();
52135213
5214 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.add, inst_ty, &.{ lhs, rhs });
5214 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.add, inst_ty, 2, .{ lhs, rhs });
52155215 if (scalar_ty.isSignedInt()) return self.builder.buildNSWAdd(lhs, rhs, "");
52165216 return self.builder.buildNUWAdd(lhs, rhs, "");
52175217 }
......@@ -5250,7 +5250,7 @@ pub const FuncGen = struct {
52505250 const inst_ty = self.air.typeOfIndex(inst);
52515251 const scalar_ty = inst_ty.scalarType();
52525252
5253 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.sub, inst_ty, &.{ lhs, rhs });
5253 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.sub, inst_ty, 2, .{ lhs, rhs });
52545254 if (scalar_ty.isSignedInt()) return self.builder.buildNSWSub(lhs, rhs, "");
52555255 return self.builder.buildNUWSub(lhs, rhs, "");
52565256 }
......@@ -5288,7 +5288,7 @@ pub const FuncGen = struct {
52885288 const inst_ty = self.air.typeOfIndex(inst);
52895289 const scalar_ty = inst_ty.scalarType();
52905290
5291 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.mul, inst_ty, &.{ lhs, rhs });
5291 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.mul, inst_ty, 2, .{ lhs, rhs });
52925292 if (scalar_ty.isSignedInt()) return self.builder.buildNSWMul(lhs, rhs, "");
52935293 return self.builder.buildNUWMul(lhs, rhs, "");
52945294 }
......@@ -5325,7 +5325,7 @@ pub const FuncGen = struct {
53255325 const rhs = try self.resolveInst(bin_op.rhs);
53265326 const inst_ty = self.air.typeOfIndex(inst);
53275327
5328 return self.buildFloatOp(.div, inst_ty, &.{ lhs, rhs });
5328 return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
53295329 }
53305330
53315331 fn airDivTrunc(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
......@@ -5338,8 +5338,8 @@ pub const FuncGen = struct {
53385338 const scalar_ty = inst_ty.scalarType();
53395339
53405340 if (scalar_ty.isRuntimeFloat()) {
5341 const result = try self.buildFloatOp(.div, inst_ty, &.{ lhs, rhs });
5342 return self.buildFloatOp(.trunc, inst_ty, &.{result});
5341 const result = try self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
5342 return self.buildFloatOp(.trunc, inst_ty, 1, .{result});
53435343 }
53445344 if (scalar_ty.isSignedInt()) return self.builder.buildSDiv(lhs, rhs, "");
53455345 return self.builder.buildUDiv(lhs, rhs, "");
......@@ -5355,8 +5355,8 @@ pub const FuncGen = struct {
53555355 const scalar_ty = inst_ty.scalarType();
53565356
53575357 if (scalar_ty.isRuntimeFloat()) {
5358 const result = try self.buildFloatOp(.div, inst_ty, &.{ lhs, rhs });
5359 return self.buildFloatOp(.floor, inst_ty, &.{result});
5358 const result = try self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
5359 return self.buildFloatOp(.floor, inst_ty, 1, .{result});
53605360 }
53615361 if (scalar_ty.isSignedInt()) {
53625362 // const d = @divTrunc(a, b);
......@@ -5386,7 +5386,7 @@ pub const FuncGen = struct {
53865386 const inst_ty = self.air.typeOfIndex(inst);
53875387 const scalar_ty = inst_ty.scalarType();
53885388
5389 if (scalar_ty.isRuntimeFloat()) return self.buildFloatOp(.div, inst_ty, &.{ lhs, rhs });
5389 if (scalar_ty.isRuntimeFloat()) return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
53905390 if (scalar_ty.isSignedInt()) return self.builder.buildExactSDiv(lhs, rhs, "");
53915391 return self.builder.buildExactUDiv(lhs, rhs, "");
53925392 }
......@@ -5400,7 +5400,7 @@ pub const FuncGen = struct {
54005400 const inst_ty = self.air.typeOfIndex(inst);
54015401 const scalar_ty = inst_ty.scalarType();
54025402
5403 if (scalar_ty.isRuntimeFloat()) return self.buildFloatOp(.rem, inst_ty, &.{ lhs, rhs });
5403 if (scalar_ty.isRuntimeFloat()) return self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs });
54045404 if (scalar_ty.isSignedInt()) return self.builder.buildSRem(lhs, rhs, "");
54055405 return self.builder.buildURem(lhs, rhs, "");
54065406 }
......@@ -5416,11 +5416,11 @@ pub const FuncGen = struct {
54165416 const scalar_ty = inst_ty.scalarType();
54175417
54185418 if (scalar_ty.isRuntimeFloat()) {
5419 const a = try self.buildFloatOp(.rem, inst_ty, &.{ lhs, rhs });
5420 const b = try self.buildFloatOp(.add, inst_ty, &.{ a, rhs });
5421 const c = try self.buildFloatOp(.rem, inst_ty, &.{ b, rhs });
5419 const a = try self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs });
5420 const b = try self.buildFloatOp(.add, inst_ty, 2, .{ a, rhs });
5421 const c = try self.buildFloatOp(.fmod, inst_ty, 2, .{ b, rhs });
54225422 const zero = inst_llvm_ty.constNull();
5423 const ltz = try self.buildFloatCmp(.lt, inst_ty, &.{ lhs, zero });
5423 const ltz = try self.buildFloatCmp(.lt, inst_ty, .{ lhs, zero });
54245424 return self.builder.buildSelect(ltz, c, a, "");
54255425 }
54265426 if (scalar_ty.isSignedInt()) {
......@@ -5508,18 +5508,18 @@ pub const FuncGen = struct {
55085508 ) !*const llvm.Value {
55095509 const args_len = @intCast(c_uint, args_vectors.len);
55105510 const llvm_i32 = self.context.intType(32);
5511 assert(args_len <= 8);
5511 assert(args_len <= 3);
55125512
55135513 var i: usize = 0;
55145514 var result = result_vector;
55155515 while (i < vector_len) : (i += 1) {
55165516 const index_i32 = llvm_i32.constInt(i, .False);
55175517
5518 var args: [8]*const llvm.Value = undefined;
5518 var args: [3]*const llvm.Value = undefined;
55195519 for (args_vectors) |arg_vector, k| {
55205520 args[k] = self.builder.buildExtractElement(arg_vector, index_i32, "");
55215521 }
5522 const result_elem = self.builder.buildCall(llvm_fn, args[0..], args_len, .C, .Auto, "");
5522 const result_elem = self.builder.buildCall(llvm_fn, &args, args_len, .C, .Auto, "");
55235523 result = self.builder.buildInsertElement(result, result_elem, index_i32, "");
55245524 }
55255525 return result;
......@@ -5542,20 +5542,27 @@ pub const FuncGen = struct {
55425542 };
55435543 }
55445544
5545 fn getMathHTypeAbbrev(ty: Type) []const u8 {
5546 return switch (ty.tag()) {
5547 .f16 => "h", // Non-standard
5548 .f32 => "s",
5549 .f64 => "",
5550 .f80 => "x", // Non-standard
5551 .c_longdouble => "l",
5552 .f128 => "q", // Non-standard (mimics convention in GCC libquadmath)
5545 fn libcFloatPrefix(float_bits: u16) []const u8 {
5546 return switch (float_bits) {
5547 16, 80 => "__",
5548 32, 64, 128 => "",
55535549 else => unreachable,
55545550 };
55555551 }
55565552
5557 fn getCompilerRtTypeAbbrev(ty: Type, target: std.Target) []const u8 {
5558 return switch (ty.floatBits(target)) {
5553 fn libcFloatSuffix(float_bits: u16) []const u8 {
5554 return switch (float_bits) {
5555 16 => "h", // Non-standard
5556 32 => "s",
5557 64 => "",
5558 80 => "x", // Non-standard
5559 128 => "q", // Non-standard (mimics convention in GCC libquadmath)
5560 else => unreachable,
5561 };
5562 }
5563
5564 fn compilerRtFloatAbbrev(float_bits: u16) []const u8 {
5565 return switch (float_bits) {
55595566 16 => "h",
55605567 32 => "s",
55615568 64 => "d",
......@@ -5571,20 +5578,13 @@ pub const FuncGen = struct {
55715578 self: *FuncGen,
55725579 pred: math.CompareOperator,
55735580 ty: Type,
5574 params: []const *const llvm.Value,
5581 params: [2]*const llvm.Value,
55755582 ) !*const llvm.Value {
55765583 const target = self.dg.module.getTarget();
55775584 const scalar_ty = ty.scalarType();
55785585 const scalar_llvm_ty = try self.dg.llvmType(scalar_ty);
55795586
5580 // LLVM does not support all floating point comparisons for all targets, so we
5581 // may need to manually generate a libc call
5582 const intrinsics_allowed = switch (scalar_ty.tag()) {
5583 .f80 => target.longDoubleIs(f80) and backendSupportsF80(target),
5584 .f128 => target.longDoubleIs(f128),
5585 else => true,
5586 };
5587 if (intrinsics_allowed) {
5587 if (intrinsicsAllowed(scalar_ty, target)) {
55885588 const llvm_predicate: llvm.RealPredicate = switch (pred) {
55895589 .eq => .OEQ,
55905590 .neq => .UNE,
......@@ -5596,7 +5596,8 @@ pub const FuncGen = struct {
55965596 return self.builder.buildFCmp(llvm_predicate, params[0], params[1], "");
55975597 }
55985598
5599 const compiler_rt_type_abbrev = getCompilerRtTypeAbbrev(scalar_ty, target);
5599 const float_bits = scalar_ty.floatBits(target);
5600 const compiler_rt_float_abbrev = compilerRtFloatAbbrev(float_bits);
56005601 var fn_name_buf: [64]u8 = undefined;
56015602 const fn_base_name = switch (pred) {
56025603 .neq => "ne",
......@@ -5606,9 +5607,10 @@ pub const FuncGen = struct {
56065607 .gt => "gt",
56075608 .gte => "ge",
56085609 };
5609 const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__{s}{s}f2", .{ fn_base_name, compiler_rt_type_abbrev }) catch unreachable;
5610 const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__{s}{s}f2", .{
5611 fn_base_name, compiler_rt_float_abbrev,
5612 }) catch unreachable;
56105613
5611 assert(params.len == 2);
56125614 const param_types = [2]*const llvm.Type{ scalar_llvm_ty, scalar_llvm_ty };
56135615 const llvm_i32 = self.context.intType(32);
56145616 const libc_fn = self.getLibcFunction(fn_name, param_types[0..], llvm_i32);
......@@ -5628,110 +5630,119 @@ pub const FuncGen = struct {
56285630 const vector_result_ty = llvm_i32.vectorType(vec_len);
56295631
56305632 var result = vector_result_ty.getUndef();
5631 result = try self.buildElementwiseCall(libc_fn, params[0..], result, vec_len);
5633 result = try self.buildElementwiseCall(libc_fn, &params, result, vec_len);
56325634
5633 const zero_vector = self.builder.buildVectorSplat(zero, vec_len, "");
5635 const zero_vector = self.builder.buildVectorSplat(vec_len, zero, "");
56345636 return self.builder.buildICmp(int_pred, result, zero_vector, "");
56355637 }
56365638
5637 const result = self.builder.buildCall(libc_fn, params.ptr, 2, .C, .Auto, "");
5639 const result = self.builder.buildCall(libc_fn, &params, params.len, .C, .Auto, "");
56385640 return self.builder.buildICmp(int_pred, result, zero, "");
56395641 }
56405642
5643 const FloatOp = enum {
5644 add,
5645 ceil,
5646 cos,
5647 div,
5648 exp,
5649 exp2,
5650 fabs,
5651 floor,
5652 fma,
5653 log,
5654 log10,
5655 log2,
5656 fmax,
5657 fmin,
5658 mul,
5659 fmod,
5660 round,
5661 sin,
5662 sqrt,
5663 sub,
5664 trunc,
5665 };
5666
5667 const FloatOpStrat = union(enum) {
5668 intrinsic: []const u8,
5669 libc: [:0]const u8,
5670 };
5671
56415672 /// Creates a floating point operation (add, sub, fma, sqrt, exp, etc.)
56425673 /// by lowering to the appropriate hardware instruction or softfloat
56435674 /// routine for the target
56445675 fn buildFloatOp(
56455676 self: *FuncGen,
5646 comptime op: @TypeOf(.EnumLiteral),
5677 comptime op: FloatOp,
56475678 ty: Type,
5648 params: []const *const llvm.Value,
5679 comptime params_len: usize,
5680 params: [params_len]*const llvm.Value,
56495681 ) !*const llvm.Value {
56505682 const target = self.dg.module.getTarget();
56515683 const scalar_ty = ty.scalarType();
56525684 const llvm_ty = try self.dg.llvmType(ty);
56535685 const scalar_llvm_ty = try self.dg.llvmType(scalar_ty);
56545686
5655 const Strat = union(enum) {
5656 intrinsic: []const u8,
5657 libc: [:0]const u8,
5658 };
5659
5660 // LLVM does not support all relevant intrinsics for all targets, so we
5661 // may need to manually generate a libc call
5662 const intrinsics_allowed = switch (scalar_ty.tag()) {
5663 .f80 => target.longDoubleIs(f80) and backendSupportsF80(target),
5664 .f128 => target.longDoubleIs(f128),
5665 else => true,
5666 };
5667 const strat: Strat = if (intrinsics_allowed) b: {
5687 const intrinsics_allowed = intrinsicsAllowed(scalar_ty, target);
5688 var fn_name_buf: [64]u8 = undefined;
5689 const strat: FloatOpStrat = if (intrinsics_allowed) switch (op) {
56685690 // Some operations are dedicated LLVM instructions, not available as intrinsics
5669 switch (op) {
5670 .add => return self.builder.buildFAdd(params[0], params[1], ""),
5671 .sub => return self.builder.buildFSub(params[0], params[1], ""),
5672 .mul => return self.builder.buildFMul(params[0], params[1], ""),
5673 .div => return self.builder.buildFDiv(params[0], params[1], ""),
5674 .rem => return self.builder.buildFRem(params[0], params[1], ""),
5675 else => {},
5676 }
5677 // All other operations are available as intrinsics
5678 break :b .{
5679 .intrinsic = "llvm." ++ switch (op) {
5680 .max => "maximum",
5681 .min => "minimum",
5682 .fma, .sqrt, .sin, .cos, .exp, .exp2, .log, .log2, .log10, .fabs, .floor, .ceil, .round, .trunc => @tagName(op),
5683 .add, .sub, .mul, .div, .rem => unreachable,
5684 else => unreachable,
5685 },
5686 };
5691 .add => return self.builder.buildFAdd(params[0], params[1], ""),
5692 .sub => return self.builder.buildFSub(params[0], params[1], ""),
5693 .mul => return self.builder.buildFMul(params[0], params[1], ""),
5694 .div => return self.builder.buildFDiv(params[0], params[1], ""),
5695 .fmod => return self.builder.buildFRem(params[0], params[1], ""),
5696 .fmax => return self.builder.buildMaxNum(params[0], params[1], ""),
5697 .fmin => return self.builder.buildMinNum(params[0], params[1], ""),
5698 else => .{ .intrinsic = "llvm." ++ @tagName(op) },
56875699 } else b: {
5688 const math_h_type_abbrev = getMathHTypeAbbrev(scalar_ty);
5689 const compiler_rt_type_abbrev = getCompilerRtTypeAbbrev(scalar_ty, target);
5690 var fn_name_buf: [64]u8 = undefined;
5700 const float_bits = scalar_ty.floatBits(target);
56915701 break :b switch (op) {
5692 .fma => Strat{
5693 .libc = switch (scalar_ty.floatBits(target)) {
5694 80 => "__fmax",
5695 else => std.fmt.bufPrintZ(&fn_name_buf, "fma{s}", .{math_h_type_abbrev}) catch unreachable,
5696 },
5697 },
5698 .add, .sub, .div, .mul => Strat{
5699 .libc = std.fmt.bufPrintZ(&fn_name_buf, "__{s}{s}f3", .{ @tagName(op), compiler_rt_type_abbrev }) catch unreachable,
5700 },
5701 .rem => Strat{
5702 .libc = std.fmt.bufPrintZ(&fn_name_buf, "fmod{s}", .{math_h_type_abbrev}) catch unreachable,
5703 },
5704 .max, .min => Strat{
5705 .libc = std.fmt.bufPrintZ(&fn_name_buf, "f{s}{s}", .{ @tagName(op), math_h_type_abbrev }) catch unreachable,
5702 .add, .sub, .div, .mul => FloatOpStrat{
5703 .libc = std.fmt.bufPrintZ(&fn_name_buf, "__{s}{s}f3", .{
5704 @tagName(op), compilerRtFloatAbbrev(float_bits),
5705 }) catch unreachable,
57065706 },
5707 .sqrt, .sin, .cos, .exp, .exp2, .log, .log2, .log10, .fabs, .floor, .ceil, .round, .trunc => Strat{
5708 .libc = std.fmt.bufPrintZ(&fn_name_buf, "{s}{s}", .{ @tagName(op), math_h_type_abbrev }) catch unreachable,
5707 .ceil,
5708 .cos,
5709 .exp,
5710 .exp2,
5711 .fabs,
5712 .floor,
5713 .fma,
5714 .fmax,
5715 .fmin,
5716 .fmod,
5717 .log,
5718 .log10,
5719 .log2,
5720 .round,
5721 .sin,
5722 .sqrt,
5723 .trunc,
5724 => FloatOpStrat{
5725 .libc = std.fmt.bufPrintZ(&fn_name_buf, "{s}{s}{s}", .{
5726 libcFloatPrefix(float_bits), @tagName(op), libcFloatSuffix(float_bits),
5727 }) catch unreachable,
57095728 },
5710 else => unreachable,
57115729 };
57125730 };
57135731
5714 var llvm_fn: *const llvm.Value = switch (strat) {
5732 const llvm_fn: *const llvm.Value = switch (strat) {
57155733 .intrinsic => |fn_name| self.getIntrinsic(fn_name, &.{llvm_ty}),
57165734 .libc => |fn_name| b: {
5717 assert(params.len == switch (op) {
5718 .fma => 3,
5719 .add, .sub, .div, .mul, .rem, .max, .min => 2,
5720 .sqrt, .sin, .cos, .exp, .exp2, .log, .log2, .log10, .fabs, .floor, .ceil, .round, .trunc => 1,
5721 else => unreachable,
5722 });
57235735 const param_types = [3]*const llvm.Type{ scalar_llvm_ty, scalar_llvm_ty, scalar_llvm_ty };
57245736 const libc_fn = self.getLibcFunction(fn_name, param_types[0..params.len], scalar_llvm_ty);
57255737 if (ty.zigTypeTag() == .Vector) {
57265738 const result = llvm_ty.getUndef();
5727 return self.buildElementwiseCall(libc_fn, params[0..], result, ty.vectorLen());
5739 return self.buildElementwiseCall(libc_fn, &params, result, ty.vectorLen());
57285740 }
57295741
57305742 break :b libc_fn;
57315743 },
57325744 };
5733 const params_len = @intCast(c_uint, params.len);
5734 return self.builder.buildCall(llvm_fn, params.ptr, params_len, .C, .Auto, "");
5745 return self.builder.buildCall(llvm_fn, &params, params_len, .C, .Auto, "");
57355746 }
57365747
57375748 fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
......@@ -5745,7 +5756,7 @@ pub const FuncGen = struct {
57455756 const addend = try self.resolveInst(pl_op.operand);
57465757
57475758 const ty = self.air.typeOfIndex(inst);
5748 return self.buildFloatOp(.fma, ty, &.{ mulend1, mulend2, addend });
5759 return self.buildFloatOp(.fma, ty, 3, .{ mulend1, mulend2, addend });
57495760 }
57505761
57515762 fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
......@@ -6550,15 +6561,14 @@ pub const FuncGen = struct {
65506561 }
65516562 }
65526563
6553 fn airUnaryOp(self: *FuncGen, inst: Air.Inst.Index, comptime op: @TypeOf(.EnumLiteral)) !?*const llvm.Value {
6564 fn airUnaryOp(self: *FuncGen, inst: Air.Inst.Index, comptime op: FloatOp) !?*const llvm.Value {
65546565 if (self.liveness.isUnused(inst)) return null;
65556566
65566567 const un_op = self.air.instructions.items(.data)[inst].un_op;
65576568 const operand = try self.resolveInst(un_op);
65586569 const operand_ty = self.air.typeOf(un_op);
65596570
6560 const params = [_]*const llvm.Value{operand};
6561 return self.buildFloatOp(op, operand_ty, &params);
6571 return self.buildFloatOp(op, operand_ty, 1, .{operand});
65626572 }
65636573
65646574 fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*const llvm.Value {
......@@ -6822,17 +6832,9 @@ pub const FuncGen = struct {
68226832
68236833 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
68246834 const scalar = try self.resolveInst(ty_op.operand);
6825 const scalar_ty = self.air.typeOf(ty_op.operand);
68266835 const vector_ty = self.air.typeOfIndex(inst);
68276836 const len = vector_ty.vectorLen();
6828 const scalar_llvm_ty = try self.dg.llvmType(scalar_ty);
6829 const op_llvm_ty = scalar_llvm_ty.vectorType(1);
6830 const u32_llvm_ty = self.context.intType(32);
6831 const mask_llvm_ty = u32_llvm_ty.vectorType(len);
6832 const undef_vector = op_llvm_ty.getUndef();
6833 const u32_zero = u32_llvm_ty.constNull();
6834 const op_vector = self.builder.buildInsertElement(undef_vector, scalar, u32_zero, "");
6835 return self.builder.buildShuffleVector(op_vector, undef_vector, mask_llvm_ty.constNull(), "");
6837 return self.builder.buildVectorSplat(len, scalar, "");
68366838 }
68376839
68386840 fn airSelect(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
......@@ -8183,6 +8185,26 @@ fn backendSupportsF80(target: std.Target) bool {
81838185 };
81848186}
81858187
8188/// This function returns true if we expect LLVM to lower f16 correctly
8189/// and false if we expect LLVM to crash if it counters an f16 type or
8190/// if it produces miscompilations.
8191fn backendSupportsF16(target: std.Target) bool {
8192 return switch (target.cpu.arch) {
8193 else => true,
8194 };
8195}
8196
8197/// LLVM does not support all relevant intrinsics for all targets, so we
8198/// may need to manually generate a libc call
8199fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool {
8200 return switch (scalar_ty.tag()) {
8201 .f16 => backendSupportsF16(target),
8202 .f80 => target.longDoubleIs(f80) and backendSupportsF80(target),
8203 .f128 => target.longDoubleIs(f128),
8204 else => true,
8205 };
8206}
8207
81868208/// We need to insert extra padding if LLVM's isn't enough.
81878209/// However we don't want to ever call LLVMABIAlignmentOfType or
81888210/// LLVMABISizeOfType because these functions will trip assertions
src/codegen/llvm/bindings.zig+1-4
......@@ -295,9 +295,6 @@ pub const Type = opaque {
295295
296296 pub const countStructElementTypes = LLVMCountStructElementTypes;
297297 extern fn LLVMCountStructElementTypes(StructTy: *const Type) c_uint;
298
299 pub const getVectorSize = LLVMGetVectorSize;
300 extern fn LLVMGetVectorSize(VectorTy: *const Type) c_uint;
301298};
302299
303300pub const Module = opaque {
......@@ -681,8 +678,8 @@ pub const Builder = opaque {
681678 pub const buildVectorSplat = LLVMBuildVectorSplat;
682679 extern fn LLVMBuildVectorSplat(
683680 *const Builder,
684 EltVal: *const Value,
685681 ElementCount: c_uint,
682 EltVal: *const Value,
686683 Name: [*:0]const u8,
687684 ) *const Value;
688685