Skip to content

Commit f3ec56e

Browse files
authored
Merge pull request #42267 from meg-gupta/opaquecasts
[SIL Opaque Value] Address Lowering: Add support for unconditional_checked_cast
2 parents 770c681 + d110b6d commit f3ec56e

File tree

2 files changed

+115
-6
lines changed

2 files changed

+115
-6
lines changed

lib/SILOptimizer/Mandatory/AddressLowering.cpp

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2560,6 +2560,37 @@ class UseRewriter : SILInstructionVisitor<UseRewriter> {
25602560
markRewritten(uncheckedCastInst, destAddr);
25612561
}
25622562

2563+
void visitUnconditionalCheckedCastInst(
2564+
UnconditionalCheckedCastInst *uncondCheckedCast) {
2565+
SILValue srcVal = uncondCheckedCast->getOperand();
2566+
assert(srcVal->getType().isAddressOnly(*pass.function));
2567+
SILValue srcAddr = pass.valueStorageMap.getStorage(srcVal).storageAddress;
2568+
2569+
if (uncondCheckedCast->getType().isAddressOnly(*pass.function)) {
2570+
// When cast destination has address only type, use the storage address
2571+
SILValue destAddr = addrMat.materializeAddress(uncondCheckedCast);
2572+
markRewritten(uncondCheckedCast, destAddr);
2573+
builder.createUnconditionalCheckedCastAddr(
2574+
uncondCheckedCast->getLoc(), srcAddr, srcAddr->getType().getASTType(),
2575+
destAddr, destAddr->getType().getASTType());
2576+
return;
2577+
}
2578+
// For loadable cast destination type, create a stack temporary
2579+
SILValue destAddr = builder.createAllocStack(uncondCheckedCast->getLoc(),
2580+
uncondCheckedCast->getType());
2581+
builder.createUnconditionalCheckedCastAddr(
2582+
uncondCheckedCast->getLoc(), srcAddr, srcAddr->getType().getASTType(),
2583+
destAddr, destAddr->getType().getASTType());
2584+
auto nextBuilder =
2585+
pass.getBuilder(uncondCheckedCast->getNextInstruction()->getIterator());
2586+
auto dest = nextBuilder.createLoad(
2587+
uncondCheckedCast->getLoc(), destAddr,
2588+
destAddr->getType().isTrivial(*uncondCheckedCast->getFunction())
2589+
? LoadOwnershipQualifier::Trivial
2590+
: LoadOwnershipQualifier::Copy);
2591+
nextBuilder.createDeallocStack(uncondCheckedCast->getLoc(), destAddr);
2592+
uncondCheckedCast->replaceAllUsesWith(dest);
2593+
}
25632594
void visitUncheckedEnumDataInst(UncheckedEnumDataInst *enumDataInst);
25642595
};
25652596
} // end anonymous namespace
@@ -2869,6 +2900,14 @@ class DefRewriter : SILInstructionVisitor<DefRewriter> {
28692900
storage.storageAddress = addrMat.materializeAddress(arg);
28702901
}
28712902

2903+
void setStorageAddress(SILValue oldValue, SILValue addr) {
2904+
auto &storage = pass.valueStorageMap.getStorage(oldValue);
2905+
// getReusedStorageOperand() ensures that oldValue does not already have
2906+
// separate storage. So there's no need to delete its alloc_stack.
2907+
assert(!storage.storageAddress || storage.storageAddress == addr);
2908+
storage.storageAddress = addr;
2909+
}
2910+
28722911
void beforeVisit(SILInstruction *inst) {
28732912
LLVM_DEBUG(llvm::dbgs() << "REWRITE DEF "; inst->dump());
28742913
if (storage.storageAddress)
@@ -2972,12 +3011,27 @@ class DefRewriter : SILInstructionVisitor<DefRewriter> {
29723011
addrMat.initializeComposingUse(&operand);
29733012
}
29743013

2975-
void setStorageAddress(SILValue oldValue, SILValue addr) {
2976-
auto &storage = pass.valueStorageMap.getStorage(oldValue);
2977-
// getReusedStorageOperand() ensures that oldValue does not already have
2978-
// separate storage. So there's no need to delete its alloc_stack.
2979-
assert(!storage.storageAddress || storage.storageAddress == addr);
2980-
storage.storageAddress = addr;
3014+
void visitUnconditionalCheckedCastInst(
3015+
UnconditionalCheckedCastInst *uncondCheckedCast) {
3016+
SILValue srcVal = uncondCheckedCast->getOperand();
3017+
assert(srcVal->getType().isLoadable(*pass.function));
3018+
assert(uncondCheckedCast->getType().isAddressOnly(*pass.function));
3019+
3020+
// Create a stack temporary to store the srcVal
3021+
SILValue srcAddr = builder.createAllocStack(uncondCheckedCast->getLoc(),
3022+
srcVal->getType());
3023+
builder.createStore(uncondCheckedCast->getLoc(), srcVal, srcAddr,
3024+
srcVal->getType().isTrivial(*srcVal->getFunction())
3025+
? StoreOwnershipQualifier::Trivial
3026+
: StoreOwnershipQualifier::Init);
3027+
// Use the storage address as destination
3028+
SILValue destAddr = addrMat.materializeAddress(uncondCheckedCast);
3029+
builder.createUnconditionalCheckedCastAddr(
3030+
uncondCheckedCast->getLoc(), srcAddr, srcAddr->getType().getASTType(),
3031+
destAddr, destAddr->getType().getASTType());
3032+
3033+
pass.getBuilder(uncondCheckedCast->getNextInstruction()->getIterator())
3034+
.createDeallocStack(uncondCheckedCast->getLoc(), srcAddr);
29813035
}
29823036
};
29833037
} // end anonymous namespace

test/SILOptimizer/address_lowering.sil

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,3 +1188,58 @@ bb0(%0 : @guaranteed $T, %1 : $@thick U.Type):
11881188
return %6 : $U
11891189
}
11901190

1191+
// CHECK-LABEL: sil hidden [ossa] @test_unconditional_checked_cast1 : $@convention(thin) <T> (Builtin.Int64) -> @out T {
1192+
// CHECK: bb0(%0 : $*T, %1 : $Builtin.Int64):
1193+
// CHECK: [[INT:%.*]] = alloc_stack $Builtin.Int64
1194+
// CHECK: store %1 to [trivial] [[INT]] : $*Builtin.Int64
1195+
// CHECK: unconditional_checked_cast_addr Builtin.Int64 in [[INT]] : $*Builtin.Int64 to T in %0 : $*T
1196+
// CHECK: %5 = tuple ()
1197+
// CHECK: dealloc_stack %2 : $*Builtin.Int64
1198+
// CHECK: return %5 : $()
1199+
// CHECK: } // end sil function 'test_unconditional_checked_cast1'
1200+
sil hidden [ossa] @test_unconditional_checked_cast1 : $@convention(thin) <T> (Int) -> @out T {
1201+
bb0(%0 : $Int):
1202+
%2 = unconditional_checked_cast %0 : $Int to T
1203+
return %2 : $T
1204+
}
1205+
1206+
// CHECK: sil hidden [ossa] @test_unconditional_checked_cast2 : $@convention(thin) <T> (@in_guaranteed T) -> Builtin.Int64 {
1207+
// CHECK: bb0(%0 : $*T):
1208+
// CHECK: [[SRC:%.*]] = alloc_stack $T
1209+
// CHECK: copy_addr %0 to [initialization] [[SRC]] : $*T
1210+
// CHECK: [[INT:%.*]] = alloc_stack $Builtin.Int64
1211+
// CHECK: unconditional_checked_cast_addr T in [[SRC]] : $*T to Builtin.Int64 in [[INT]] : $*Builtin.Int64
1212+
// CHECK: [[RES:%.*]] = load [trivial] [[INT]] : $*Builtin.Int64
1213+
// CHECK: return [[RES]] : $Builtin.Int64
1214+
// CHECK: } // end sil function 'test_unconditional_checked_cast2'
1215+
sil hidden [ossa] @test_unconditional_checked_cast2 : $@convention(thin) <T> (@in_guaranteed T) -> Int {
1216+
bb0(%0 : @guaranteed $T):
1217+
%2 = copy_value %0 : $T
1218+
%3 = unconditional_checked_cast %2 : $T to Int
1219+
return %3 : $Int
1220+
}
1221+
1222+
// CHECK-LABEL: sil hidden [ossa] @test_unconditional_checked_cast3 : $@convention(thin) <T, U> (@in_guaranteed T) -> @out U {
1223+
// CHECK: bb0(%0 : $*U, %1 : $*T):
1224+
// CHECK: [[TTMP:%.*]] = alloc_stack $T
1225+
// CHECK: [[UTMP:%.*]] = alloc_stack [lexical] $U
1226+
// CHECK: copy_addr %1 to [initialization] [[TTMP]] : $*T
1227+
// CHECK: unconditional_checked_cast_addr T in [[TTMP]] : $*T to U in [[UTMP]] : $*U
1228+
// CHECK: copy_addr [[UTMP]] to [initialization] %0 : $*U
1229+
// CHECK: destroy_addr [[UTMP]] : $*U
1230+
// CHECK: %8 = tuple ()
1231+
// CHECK: dealloc_stack [[UTMP]] : $*U
1232+
// CHECK: dealloc_stack [[TTMP]] : $*T
1233+
// CHECK: return %8 : $()
1234+
// CHECK-LABEL: } // end sil function 'test_unconditional_checked_cast3'
1235+
sil hidden [ossa] @test_unconditional_checked_cast3 : $@convention(thin) <T, U> (@in_guaranteed T) -> @out U {
1236+
bb0(%0 : @guaranteed $T):
1237+
%2 = copy_value %0 : $T
1238+
%3 = unconditional_checked_cast %2 : $T to U
1239+
%4 = begin_borrow [lexical] %3 : $U
1240+
%6 = copy_value %4 : $U
1241+
end_borrow %4 : $U
1242+
destroy_value %3 : $U
1243+
return %6 : $U
1244+
}
1245+

0 commit comments

Comments
 (0)