diff --git a/include/swift/AST/Builtins.def b/include/swift/AST/Builtins.def index f1b4b6b23e076..f0369e86c9635 100644 --- a/include/swift/AST/Builtins.def +++ b/include/swift/AST/Builtins.def @@ -175,6 +175,8 @@ BUILTIN_UNARY_OPERATION(FNeg, "fneg", "n", FloatOrVector) BUILTIN_UNARY_OPERATION(AssumeNonNegative, "assumeNonNegative", "n", Integer) // It only works on i1. BUILTIN_UNARY_OPERATION(AssumeTrue, "assume", "", Integer) +// Converts poison/undef to an indeterminate but valid value. +BUILTIN_UNARY_OPERATION(Freeze, "freeze", "n", IntegerOrVector) // Binary predicates have type (T,T) -> i1 or (T, T) -> Vector for scalars // and vectors, respectively. diff --git a/lib/IRGen/GenBuiltin.cpp b/lib/IRGen/GenBuiltin.cpp index cac9788268130..c34954d3acbba 100644 --- a/lib/IRGen/GenBuiltin.cpp +++ b/lib/IRGen/GenBuiltin.cpp @@ -637,6 +637,9 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin, // Don't generate any code for the builtin. return out.add(v); } + if (Builtin.ID == BuiltinValueKind::Freeze) { + return out.add(IGF.Builder.CreateFreeze(args.claimNext())); + } if (Builtin.ID == BuiltinValueKind::AllocRaw) { auto size = args.claimNext(); diff --git a/lib/SIL/IR/OperandOwnership.cpp b/lib/SIL/IR/OperandOwnership.cpp index 9af138bc6195a..70baa169c7917 100644 --- a/lib/SIL/IR/OperandOwnership.cpp +++ b/lib/SIL/IR/OperandOwnership.cpp @@ -810,6 +810,7 @@ BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericFRem) BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FSub) BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericFSub) BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Fence) +BUILTIN_OPERAND_OWNERSHIP(TrivialUse, Freeze) BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Ifdef) BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GetObjCTypeEncoding) BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ICMP_EQ) diff --git a/lib/SIL/IR/ValueOwnership.cpp b/lib/SIL/IR/ValueOwnership.cpp index c7ed8453476f0..24e21097abb4f 100644 --- a/lib/SIL/IR/ValueOwnership.cpp +++ b/lib/SIL/IR/ValueOwnership.cpp @@ -491,6 +491,7 @@ CONSTANT_OWNERSHIP_BUILTIN(None, FRem) CONSTANT_OWNERSHIP_BUILTIN(None, GenericFRem) CONSTANT_OWNERSHIP_BUILTIN(None, FSub) CONSTANT_OWNERSHIP_BUILTIN(None, GenericFSub) +CONSTANT_OWNERSHIP_BUILTIN(None, Freeze) CONSTANT_OWNERSHIP_BUILTIN(None, ICMP_EQ) CONSTANT_OWNERSHIP_BUILTIN(None, ICMP_NE) CONSTANT_OWNERSHIP_BUILTIN(None, ICMP_SGE) diff --git a/test/IRGen/builtin_freeze.swift b/test/IRGen/builtin_freeze.swift new file mode 100644 index 0000000000000..8efc01616730e --- /dev/null +++ b/test/IRGen/builtin_freeze.swift @@ -0,0 +1,52 @@ +// RUN: %target-swift-frontend -O -module-name builtin_freeze -enable-experimental-feature BuiltinModule -primary-file %s -emit-ir -o - | %FileCheck %s --check-prefix=CHECK + +import Builtin + +func fptosi(_ x: Float) -> Int32 { + Int32(Builtin.fptosi_FPIEEE32_Int32(x._value)) + // CHECK: fptosi float %{{.+}} to i32 +} + +func fptosiWithFreeze(_ x: Float) -> Int32 { + Int32(Builtin.freeze_Int32(Builtin.fptosi_FPIEEE32_Int32(x._value))) + // CHECK: fptosi float %{{.+}} to i32 + // CHECK-NEXT: freeze i32 %{{.+}} +} + +func yuck() -> Int32 { + fptosi(0x1.0p32) + // CHECK: poison +} + +func yum() -> Int32 { + fptosiWithFreeze(0x1.0p32) + // CHECK-NOT: poison +} + +func fptosi(_ x: SIMD2) -> SIMD2 { + let maybePoison = Builtin.fptosi_Vec2xFPIEEE32_Vec2xInt32(x._storage._value) + var result = SIMD2() + result._storage._value = maybePoison + return result + // CHECK: fptosi <2 x float> %{{.+}} to <2 x i32> +} + +func fptosiWithFreeze(_ x: SIMD2) -> SIMD2 { + let maybePoison = Builtin.fptosi_Vec2xFPIEEE32_Vec2xInt32(x._storage._value) + let frozen = Builtin.freeze_Vec2xInt32(maybePoison) + var result = SIMD2() + result._storage._value = frozen + return result + // CHECK: fptosi <2 x float> %{{.+}} to <2 x i32> + // CHECK-NEXT: freeze <2 x i32> %{{.+}} +} + +func doubleYuck(_ x: SIMD2) -> SIMD2 { + fptosi(SIMD2(repeating: 0x1.0p32)) + // CHECK: poison +} + +func DoubleYum(_ x: SIMD2) -> SIMD2 { + fptosiWithFreeze(SIMD2(repeating: 0x1.0p32)) + // CHECK-NOT: poison +}