diff --git a/lib/SILOptimizer/Utils/CastOptimizer.cpp b/lib/SILOptimizer/Utils/CastOptimizer.cpp index c1c5da4bc3fdc..3a15d568afc0a 100644 --- a/lib/SILOptimizer/Utils/CastOptimizer.cpp +++ b/lib/SILOptimizer/Utils/CastOptimizer.cpp @@ -918,25 +918,32 @@ SILInstruction *CastOptimizer::simplifyCheckedCastAddrBranchInst( return nullptr; } - // For CopyOnSuccess casts, we could insert an explicit copy here, but this - // case does not happen in practice. - // // Both TakeOnSuccess and TakeAlways can be reduced to an // UnconditionalCheckedCast, since the failure path is irrelevant. + AllocStackInst *copiedSrc = nullptr; switch (Inst->getConsumptionKind()) { case CastConsumptionKind::BorrowAlways: llvm_unreachable("checked_cast_addr_br never has BorrowAlways"); case CastConsumptionKind::CopyOnSuccess: - return nullptr; + if (!Src->getType().isTrivial(*BB->getParent())) { + copiedSrc = Builder.createAllocStack(Loc, Src->getType()); + Builder.createCopyAddr(Loc, Src, copiedSrc, IsNotTake, IsInitialization); + Src = copiedSrc; + } + break; case CastConsumptionKind::TakeAlways: case CastConsumptionKind::TakeOnSuccess: break; } - if (!emitSuccessfulIndirectUnconditionalCast(Builder, Loc, dynamicCast)) { - // No optimization was possible. - return nullptr; - } + bool result = emitSuccessfulIndirectUnconditionalCast( + Builder, Builder.getModule().getSwiftModule(), Loc, Src, + Inst->getSourceFormalType(), Dest, Inst->getTargetFormalType(), Inst); + (void)result; + assert(result && "emit cannot fail for an checked_cast_addr_br"); + + if (copiedSrc) + Builder.createDeallocStack(Loc, copiedSrc); eraseInstAction(Inst); } SILInstruction *NewI = &BB->back(); diff --git a/test/SILOptimizer/floating_point_conversion.swift b/test/SILOptimizer/floating_point_conversion.swift new file mode 100644 index 0000000000000..fb3c84fdc05b0 --- /dev/null +++ b/test/SILOptimizer/floating_point_conversion.swift @@ -0,0 +1,25 @@ +// RUN: %target-swift-frontend -O -module-name=test -emit-sil %s | %FileCheck %s + +func convert< + T: BinaryFloatingPoint, U: BinaryFloatingPoint + >(_ value: T, to: U.Type) -> U { + U(value) +} + +// Check that the follwing functions can be optimized to no-ops. + +// CHECK-LABEL: sil @$s4test0A6DoubleyS2dF +// CHECK: return %0 +// CHECK: } // end sil function '$s4test0A6DoubleyS2dF' +public func testDouble(_ x: Double) -> Double { + return convert(x, to: Double.self) +} + +// CHECK-LABEL: sil @$s4test0A5FloatyS2fF +// CHECK: return %0 +// CHECK: } // end sil function '$s4test0A5FloatyS2fF' +public func testFloat(_ x: Float) -> Float { + return convert(x, to: Float.self) +} + + diff --git a/test/SILOptimizer/simplify_cfg.sil b/test/SILOptimizer/simplify_cfg.sil index 6adb3f9859dbc..d19fb986fa0aa 100644 --- a/test/SILOptimizer/simplify_cfg.sil +++ b/test/SILOptimizer/simplify_cfg.sil @@ -2980,6 +2980,70 @@ bb3: br bb2(%z : $Builtin.Int1) } +// CHECK-LABEL: sil @trivial_checked_cast_addr_br : $@convention(thin) (@guaranteed Int, @guaranteed Int) -> @owned Int +// CHECK: [[SRC:%.*]] = alloc_stack $Int +// CHECK: store %0 to [[SRC]] +// CHECK: [[DST:%.*]] = alloc_stack $Int +// CHECK: [[LD1:%.*]] = load [[SRC]] +// CHECK: store [[LD1]] to [[DST]] +// CHECK: [[LD2:%.*]] = load [[DST]] +// CHECK: return [[LD2]] +// CHECK: } // end sil function 'trivial_checked_cast_addr_br' +sil @trivial_checked_cast_addr_br : $@convention(thin) (@guaranteed Int, @guaranteed Int) -> @owned Int { +bb0(%0 : $Int, %1 : $Int): + %6 = alloc_stack $Int + store %0 to %6 : $*Int + %8 = alloc_stack $Int + checked_cast_addr_br copy_on_success Int in %6 : $*Int to Int in %8 : $*Int, bb1, bb2 + +bb1: + %10 = load %8 : $*Int + dealloc_stack %8 : $*Int + br bb3(%10 : $Int) + +bb2: + retain_value %1: $Int + dealloc_stack %8 : $*Int + br bb3(%1 : $Int) + +bb3(%11 : $Int): + dealloc_stack %6 : $*Int + return %11 : $Int +} + +// CHECK-LABEL: sil @non_trivial_checked_cast_addr_br : $@convention(thin) (@guaranteed String, @guaranteed String) -> @owned String +// CHECK: [[SRC:%.*]] = alloc_stack $String +// CHECK: store %0 to [[SRC]] +// CHECK: [[DST:%.*]] = alloc_stack $String +// CHECK: [[TEMP:%.*]] = alloc_stack $String +// CHECK: copy_addr [[SRC]] to [initialization] [[TEMP]] +// CHECK: [[LD1:%.*]] = load [[TEMP]] +// CHECK: store [[LD1]] to [[DST]] +// CHECK: [[LD2:%.*]] = load [[DST]] +// CHECK: return [[LD2]] +// CHECK: } // end sil function 'non_trivial_checked_cast_addr_br' +sil @non_trivial_checked_cast_addr_br : $@convention(thin) (@guaranteed String, @guaranteed String) -> @owned String { +bb0(%0 : $String, %1 : $String): + %6 = alloc_stack $String + store %0 to %6 : $*String + %8 = alloc_stack $String + checked_cast_addr_br copy_on_success String in %6 : $*String to String in %8 : $*String, bb1, bb2 + +bb1: + %10 = load %8 : $*String + dealloc_stack %8 : $*String + br bb3(%10 : $String) + +bb2: + retain_value %1: $String + dealloc_stack %8 : $*String + br bb3(%1 : $String) + +bb3(%11 : $String): + dealloc_stack %6 : $*String + return %11 : $String +} + // CHECK-LABEL: sil @dont_hang // CHECK: bb6: // CHECK: integer_literal $Builtin.Int64, 1