Skip to content

Commit 396b055

Browse files
Implement Builtin.freeze for integer and integer-vector types. (#73519)
* Implement Builtin.freeze for integer and integer-vector types. https://llvm.org/docs/LangRef.html#freeze-instruction > If the argument is undef or poison, ‘freeze’ returns an arbitrary, but fixed, value of type ‘ty’. Otherwise, this instruction is a no-op and returns the input argument. All uses of a value returned by the same ‘freeze’ instruction are guaranteed to always observe the same value, while different ‘freeze’ instructions may yield different values. It's most importation for integer and integer-vector types because floating-point results are generally not poison (except in the case of conversion from poison integer values). However, we might want to implement this for other types as well in the future. * Make builtin.freeze TrivialUse Also fix filecheck patterns for its test to work with asserts build.
1 parent b2bd176 commit 396b055

File tree

5 files changed

+59
-0
lines changed

5 files changed

+59
-0
lines changed

include/swift/AST/Builtins.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ BUILTIN_UNARY_OPERATION(FNeg, "fneg", "n", FloatOrVector)
175175
BUILTIN_UNARY_OPERATION(AssumeNonNegative, "assumeNonNegative", "n", Integer)
176176
// It only works on i1.
177177
BUILTIN_UNARY_OPERATION(AssumeTrue, "assume", "", Integer)
178+
// Converts poison/undef to an indeterminate but valid value.
179+
BUILTIN_UNARY_OPERATION(Freeze, "freeze", "n", IntegerOrVector)
178180

179181
// Binary predicates have type (T,T) -> i1 or (T, T) -> Vector<i1> for scalars
180182
// and vectors, respectively.

lib/IRGen/GenBuiltin.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,9 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
637637
// Don't generate any code for the builtin.
638638
return out.add(v);
639639
}
640+
if (Builtin.ID == BuiltinValueKind::Freeze) {
641+
return out.add(IGF.Builder.CreateFreeze(args.claimNext()));
642+
}
640643

641644
if (Builtin.ID == BuiltinValueKind::AllocRaw) {
642645
auto size = args.claimNext();

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,7 @@ BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericFRem)
810810
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FSub)
811811
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericFSub)
812812
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Fence)
813+
BUILTIN_OPERAND_OWNERSHIP(TrivialUse, Freeze)
813814
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Ifdef)
814815
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GetObjCTypeEncoding)
815816
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ICMP_EQ)

lib/SIL/IR/ValueOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,7 @@ CONSTANT_OWNERSHIP_BUILTIN(None, FRem)
491491
CONSTANT_OWNERSHIP_BUILTIN(None, GenericFRem)
492492
CONSTANT_OWNERSHIP_BUILTIN(None, FSub)
493493
CONSTANT_OWNERSHIP_BUILTIN(None, GenericFSub)
494+
CONSTANT_OWNERSHIP_BUILTIN(None, Freeze)
494495
CONSTANT_OWNERSHIP_BUILTIN(None, ICMP_EQ)
495496
CONSTANT_OWNERSHIP_BUILTIN(None, ICMP_NE)
496497
CONSTANT_OWNERSHIP_BUILTIN(None, ICMP_SGE)

test/IRGen/builtin_freeze.swift

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// RUN: %target-swift-frontend -O -module-name builtin_freeze -enable-experimental-feature BuiltinModule -primary-file %s -emit-ir -o - | %FileCheck %s --check-prefix=CHECK
2+
3+
import Builtin
4+
5+
func fptosi(_ x: Float) -> Int32 {
6+
Int32(Builtin.fptosi_FPIEEE32_Int32(x._value))
7+
// CHECK: fptosi float %{{.+}} to i32
8+
}
9+
10+
func fptosiWithFreeze(_ x: Float) -> Int32 {
11+
Int32(Builtin.freeze_Int32(Builtin.fptosi_FPIEEE32_Int32(x._value)))
12+
// CHECK: fptosi float %{{.+}} to i32
13+
// CHECK-NEXT: freeze i32 %{{.+}}
14+
}
15+
16+
func yuck() -> Int32 {
17+
fptosi(0x1.0p32)
18+
// CHECK: poison
19+
}
20+
21+
func yum() -> Int32 {
22+
fptosiWithFreeze(0x1.0p32)
23+
// CHECK-NOT: poison
24+
}
25+
26+
func fptosi(_ x: SIMD2<Float>) -> SIMD2<Int32> {
27+
let maybePoison = Builtin.fptosi_Vec2xFPIEEE32_Vec2xInt32(x._storage._value)
28+
var result = SIMD2<Int32>()
29+
result._storage._value = maybePoison
30+
return result
31+
// CHECK: fptosi <2 x float> %{{.+}} to <2 x i32>
32+
}
33+
34+
func fptosiWithFreeze(_ x: SIMD2<Float>) -> SIMD2<Int32> {
35+
let maybePoison = Builtin.fptosi_Vec2xFPIEEE32_Vec2xInt32(x._storage._value)
36+
let frozen = Builtin.freeze_Vec2xInt32(maybePoison)
37+
var result = SIMD2<Int32>()
38+
result._storage._value = frozen
39+
return result
40+
// CHECK: fptosi <2 x float> %{{.+}} to <2 x i32>
41+
// CHECK-NEXT: freeze <2 x i32> %{{.+}}
42+
}
43+
44+
func doubleYuck(_ x: SIMD2<Float>) -> SIMD2<Int32> {
45+
fptosi(SIMD2<Float>(repeating: 0x1.0p32))
46+
// CHECK: poison
47+
}
48+
49+
func DoubleYum(_ x: SIMD2<Float>) -> SIMD2<Int32> {
50+
fptosiWithFreeze(SIMD2<Float>(repeating: 0x1.0p32))
51+
// CHECK-NOT: poison
52+
}

0 commit comments

Comments
 (0)