diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2025-05-18 14:36:33 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-18 14:36:33 -0400 |
| commit | b77e6013422a6e7066a14dbe82e8512636ba13d2 (patch) | |
| tree | 0ce64ba78449b0cfdee7d926fb1f3c35ad364e7f /src/codegen | |
| parent | 74a3ae492797b1b2cf1936f0c91560585efdf6c6 (diff) | |
| parent | a4eabd39794014c871670937155c94e11fce991b (diff) | |
| download | zig-b77e6013422a6e7066a14dbe82e8512636ba13d2.tar.gz zig-b77e6013422a6e7066a14dbe82e8512636ba13d2.zip | |
Merge pull request #23834 from jacobly0/x86_64-rewrite
x86_64: finish rewriting scalar overflow and saturate operations
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/c/Type.zig | 60 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 65 |
2 files changed, 110 insertions, 15 deletions
diff --git a/src/codegen/c/Type.zig b/src/codegen/c/Type.zig index 0b3066f9bd..98edeb54a6 100644 --- a/src/codegen/c/Type.zig +++ b/src/codegen/c/Type.zig @@ -1443,6 +1443,21 @@ pub const Pool = struct { return pool.fromFields(allocator, .@"struct", &fields, kind); }, + .vector_8_i8_type => { + const vector_ctype = try pool.getVector(allocator, .{ + .elem_ctype = .i8, + .len = 8, + }); + if (!kind.isParameter()) return vector_ctype; + var fields = [_]Info.Field{ + .{ + .name = .{ .index = .array }, + .ctype = vector_ctype, + .alignas = AlignAs.fromAbiAlignment(Type.i8.abiAlignment(zcu)), + }, + }; + return pool.fromFields(allocator, .@"struct", &fields, kind); + }, .vector_16_i8_type => { const vector_ctype = try pool.getVector(allocator, .{ .elem_ctype = .i8, @@ -1563,6 +1578,21 @@ pub const Pool = struct { }; return pool.fromFields(allocator, .@"struct", &fields, kind); }, + .vector_4_i16_type => { + const vector_ctype = try pool.getVector(allocator, .{ + .elem_ctype = .i16, + .len = 4, + }); + if (!kind.isParameter()) return vector_ctype; + var fields = [_]Info.Field{ + .{ + .name = .{ .index = .array }, + .ctype = vector_ctype, + .alignas = AlignAs.fromAbiAlignment(Type.i16.abiAlignment(zcu)), + }, + }; + return pool.fromFields(allocator, .@"struct", &fields, kind); + }, .vector_8_i16_type => { const vector_ctype = try pool.getVector(allocator, .{ .elem_ctype = .i16, @@ -1593,6 +1623,21 @@ pub const Pool = struct { }; return pool.fromFields(allocator, .@"struct", &fields, kind); }, + .vector_4_u16_type => { + const vector_ctype = try pool.getVector(allocator, .{ + .elem_ctype = .u16, + .len = 4, + }); + if (!kind.isParameter()) return vector_ctype; + var fields = [_]Info.Field{ + .{ + .name = .{ .index = .array }, + .ctype = vector_ctype, + .alignas = AlignAs.fromAbiAlignment(Type.u16.abiAlignment(zcu)), + }, + }; + return pool.fromFields(allocator, .@"struct", &fields, kind); + }, .vector_8_u16_type => { const vector_ctype = try pool.getVector(allocator, .{ .elem_ctype = .u16, @@ -1743,6 +1788,21 @@ pub const Pool = struct { }; return pool.fromFields(allocator, .@"struct", &fields, kind); }, + .vector_2_u128_type => { + const vector_ctype = try pool.getVector(allocator, .{ + .elem_ctype = .u128, + .len = 2, + }); + if (!kind.isParameter()) return vector_ctype; + var fields = [_]Info.Field{ + .{ + .name = .{ .index = .array }, + .ctype = vector_ctype, + .alignas = AlignAs.fromAbiAlignment(Type.u128.abiAlignment(zcu)), + }, + }; + return pool.fromFields(allocator, .@"struct", &fields, kind); + }, .vector_4_f16_type => { const vector_ctype = try pool.getVector(allocator, .{ .elem_ctype = .f16, diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 050e47b68a..6a18b49e33 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -9023,19 +9023,25 @@ pub const FuncGen = struct { const rhs = try self.resolveInst(bin_op.rhs); const lhs_ty = self.typeOf(bin_op.lhs); - const lhs_scalar_ty = lhs_ty.scalarType(zcu); - const lhs_bits = lhs_scalar_ty.bitSize(zcu); - - const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty), ""); - + const lhs_info = lhs_ty.intInfo(zcu); const llvm_lhs_ty = try o.lowerType(lhs_ty); const llvm_lhs_scalar_ty = llvm_lhs_ty.scalarType(&o.builder); + + const rhs_ty = self.typeOf(bin_op.rhs); + const rhs_info = rhs_ty.intInfo(zcu); + assert(rhs_info.signedness == .unsigned); + const llvm_rhs_ty = try o.lowerType(rhs_ty); + const llvm_rhs_scalar_ty = llvm_rhs_ty.scalarType(&o.builder); + const result = try self.wip.callIntrinsic( .normal, .none, - if (lhs_scalar_ty.isSignedInt(zcu)) .@"sshl.sat" else .@"ushl.sat", + switch (lhs_info.signedness) { + .signed => .@"sshl.sat", + .unsigned => .@"ushl.sat", + }, &.{llvm_lhs_ty}, - &.{ lhs, casted_rhs }, + &.{ lhs, try self.wip.conv(.unsigned, rhs, llvm_lhs_ty, "") }, "", ); @@ -9044,16 +9050,45 @@ pub const FuncGen = struct { // poison value." // However Zig semantics says that saturating shift left can never produce // undefined; instead it saturates. + if (rhs_info.bits <= math.log2_int(u16, lhs_info.bits)) return result; const bits = try o.builder.splatValue( - llvm_lhs_ty, - try o.builder.intConst(llvm_lhs_scalar_ty, lhs_bits), - ); - const lhs_max = try o.builder.splatValue( - llvm_lhs_ty, - try o.builder.intConst(llvm_lhs_scalar_ty, -1), + llvm_rhs_ty, + try o.builder.intConst(llvm_rhs_scalar_ty, lhs_info.bits), ); - const in_range = try self.wip.icmp(.ult, casted_rhs, bits, ""); - return self.wip.select(.normal, in_range, result, lhs_max, ""); + const in_range = try self.wip.icmp(.ult, rhs, bits, ""); + const lhs_sat = lhs_sat: switch (lhs_info.signedness) { + .signed => { + const zero = try o.builder.splatValue( + llvm_lhs_ty, + try o.builder.intConst(llvm_lhs_scalar_ty, 0), + ); + const smin = try o.builder.splatValue( + llvm_lhs_ty, + try minIntConst(&o.builder, lhs_ty, llvm_lhs_ty, zcu), + ); + const smax = try o.builder.splatValue( + llvm_lhs_ty, + try maxIntConst(&o.builder, lhs_ty, llvm_lhs_ty, zcu), + ); + const lhs_lt_zero = try self.wip.icmp(.slt, lhs, zero, ""); + const slimit = try self.wip.select(.normal, lhs_lt_zero, smin, smax, ""); + const lhs_eq_zero = try self.wip.icmp(.eq, lhs, zero, ""); + break :lhs_sat try self.wip.select(.normal, lhs_eq_zero, zero, slimit, ""); + }, + .unsigned => { + const zero = try o.builder.splatValue( + llvm_lhs_ty, + try o.builder.intConst(llvm_lhs_scalar_ty, 0), + ); + const umax = try o.builder.splatValue( + llvm_lhs_ty, + try o.builder.intConst(llvm_lhs_scalar_ty, -1), + ); + const lhs_eq_zero = try self.wip.icmp(.eq, lhs, zero, ""); + break :lhs_sat try self.wip.select(.normal, lhs_eq_zero, zero, umax, ""); + }, + }; + return self.wip.select(.normal, in_range, result, lhs_sat, ""); } fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) !Builder.Value { |
