| // TARGET_BACKEND: NATIVE | |
| // FILECHECK_STAGE: CStubs | |
| // FREE_COMPILER_ARGS: -Xbinary=genericSafeCasts=true | |
| // IGNORE_NATIVE: optimizationMode=OPT && cacheMode=STATIC_ONLY_DIST | |
| // IGNORE_NATIVE: optimizationMode=OPT && cacheMode=STATIC_EVERYWHERE | |
| // KT-86959: OptimizeCasts must not share a "complex" term (here, the result of bar()) | |
| // between different loop iterations. `previousBar` holds the previous iteration's bar() | |
| // while `currentBar` holds the current one, so `previousBar && !currentBar` is not always false. | |
| class A | |
| var count = 0 | |
| fun bar(): Boolean { | |
| count += 1 | |
| return count % 2 == 0 | |
| } | |
| // CHECK-LABEL: define {{i1|zeroext i1}} @"kfun:#foo(kotlin.Any){}kotlin.Boolean" | |
| fun foo(x: Any): Boolean { | |
| var previousBar = false | |
| var iterations = 0 | |
| do { | |
| iterations++ | |
| val currentBar = bar() | |
| if (previousBar && !currentBar) { | |
| // This branch is reachable (previousBar and currentBar are different bar() calls), | |
| // so `x is A` must be kept, not folded to a constant. | |
| // CHECK-DEBUG: {{call|call zeroext}} i1 @IsSubtype | |
| // CHECK-OPT: {{call|call zeroext}} i1 @IsSubclassFast | |
| return x is A | |
| } | |
| previousBar = currentBar | |
| } while (iterations < 10) | |
| return false | |
| // CHECK-LABEL: epilogue: | |
| } | |
| // CHECK-LABEL: define ptr @"kfun:#box(){}kotlin.String" | |
| fun box(): String { | |
| return if (foo(Any())) "fail" else "OK" | |
| } |