Skip to content

Commit 8afcdff

Browse files
authored
Merge pull request #73157 from kubamracek/cp-6.0-embedded-array-destroy-fix-offset
[6.0 cherry-pick][embedded] Fix miscompile in IRGen in offset computation of Builtin.destroyArray
2 parents fed6976 + fde0c78 commit 8afcdff

File tree

3 files changed

+60
-12
lines changed

3 files changed

+60
-12
lines changed

lib/IRGen/GenBuiltin.cpp

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,9 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
10951095
auto valueTy = getLoweredTypeAndTypeInfo(IGF.IGM,
10961096
substitutions.getReplacementTypes()[0]);
10971097

1098+
// In Embedded Swift we don't have metadata and witness tables, so we can't
1099+
// just use TypeInfo's destroyArray, which needs metadata to emit a call to
1100+
// swift_arrayDestroy. Emit a loop to destroy elements directly instead.
10981101
if (IGF.IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
10991102
SILType elemTy = valueTy.first;
11001103
const TypeInfo &elemTI = valueTy.second;
@@ -1103,8 +1106,9 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
11031106
IsTriviallyDestroyable)
11041107
return;
11051108

1106-
llvm::Value *firstElem = IGF.Builder.CreateBitCast(
1107-
ptr, elemTI.getStorageType()->getPointerTo());
1109+
llvm::Value *firstElem =
1110+
IGF.Builder.CreatePtrToInt(IGF.Builder.CreateBitCast(
1111+
ptr, elemTI.getStorageType()->getPointerTo()), IGF.IGM.IntPtrTy);
11081112

11091113
auto *origBB = IGF.Builder.GetInsertBlock();
11101114
auto *headerBB = IGF.createBasicBlock("loop_header");
@@ -1118,8 +1122,12 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
11181122
IGF.Builder.CreateCondBr(cmp, loopBB, exitBB);
11191123

11201124
IGF.Builder.emitBlock(loopBB);
1121-
auto *addr = IGF.Builder.CreateInBoundsGEP(elemTI.getStorageType(),
1122-
firstElem, phi);
1125+
1126+
llvm::Value *offset =
1127+
IGF.Builder.CreateMul(phi, elemTI.getStaticStride(IGF.IGM));
1128+
llvm::Value *added = IGF.Builder.CreateAdd(firstElem, offset);
1129+
llvm::Value *addr = IGF.Builder.CreateIntToPtr(
1130+
added, elemTI.getStorageType()->getPointerTo());
11231131

11241132
bool isOutlined = false;
11251133
elemTI.destroy(IGF, elemTI.getAddressForPointer(addr), elemTy,
@@ -1157,6 +1165,9 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
11571165
llvm::Value *src = args.claimNext();
11581166
llvm::Value *count = args.claimNext();
11591167

1168+
// In Embedded Swift we don't have metadata and witness tables, so we can't
1169+
// just use TypeInfo's initialize... and assign... APIs, which need
1170+
// metadata to emit calls. Emit a loop to process elements directly instead.
11601171
if (IGF.IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
11611172
auto tyPair = getLoweredTypeAndTypeInfo(
11621173
IGF.IGM, substitutions.getReplacementTypes()[0]);
@@ -1172,10 +1183,14 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
11721183
return;
11731184
}
11741185

1175-
llvm::Value *firstSrcElem = IGF.Builder.CreateBitCast(
1176-
src, elemTI.getStorageType()->getPointerTo());
1177-
llvm::Value *firstDestElem = IGF.Builder.CreateBitCast(
1178-
dest, elemTI.getStorageType()->getPointerTo());
1186+
llvm::Value *firstSrcElem = IGF.Builder.CreatePtrToInt(
1187+
IGF.Builder.CreateBitCast(src,
1188+
elemTI.getStorageType()->getPointerTo()),
1189+
IGF.IGM.IntPtrTy);
1190+
llvm::Value *firstDestElem = IGF.Builder.CreatePtrToInt(
1191+
IGF.Builder.CreateBitCast(dest,
1192+
elemTI.getStorageType()->getPointerTo()),
1193+
IGF.IGM.IntPtrTy);
11791194

11801195
auto *origBB = IGF.Builder.GetInsertBlock();
11811196
auto *headerBB = IGF.createBasicBlock("loop_header");
@@ -1203,10 +1218,16 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
12031218
break;
12041219
}
12051220

1206-
auto *srcElem = IGF.Builder.CreateInBoundsGEP(elemTI.getStorageType(),
1207-
firstSrcElem, idx);
1208-
auto *destElem = IGF.Builder.CreateInBoundsGEP(elemTI.getStorageType(),
1209-
firstDestElem, idx);
1221+
llvm::Value *offset =
1222+
IGF.Builder.CreateMul(idx, elemTI.getStaticStride(IGF.IGM));
1223+
1224+
llvm::Value *srcAdded = IGF.Builder.CreateAdd(firstSrcElem, offset);
1225+
auto *srcElem = IGF.Builder.CreateIntToPtr(
1226+
srcAdded, elemTI.getStorageType()->getPointerTo());
1227+
llvm::Value *dstAdded = IGF.Builder.CreateAdd(firstDestElem, offset);
1228+
auto *destElem = IGF.Builder.CreateIntToPtr(
1229+
dstAdded, elemTI.getStorageType()->getPointerTo());
1230+
12101231
Address destAddr = elemTI.getAddressForPointer(destElem);
12111232
Address srcAddr = elemTI.getAddressForPointer(srcElem);
12121233

test/embedded/array-builtins-exec.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ struct Large : P {
3131
}
3232
}
3333

34+
enum Enum {
35+
case nontrivial(Noisy)
36+
case trivial(Int)
37+
}
38+
3439
func exerciseArrayValueWitnesses<T>(_ value: T) {
3540
let buf = UnsafeMutablePointer<T>.allocate(capacity: 5)
3641

@@ -52,6 +57,8 @@ func test() {
5257
exerciseArrayValueWitnesses(44)
5358
exerciseArrayValueWitnesses(Noisy())
5459
exerciseArrayValueWitnesses(Large())
60+
exerciseArrayValueWitnesses(Enum.trivial(42))
61+
exerciseArrayValueWitnesses(Enum.nontrivial(Noisy()))
5562
}
5663
precondition(NoisyLifeCount == NoisyDeathCount)
5764
print("Checks out")

test/embedded/arrays-enums.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %target-run-simple-swift(-enable-experimental-feature Embedded -parse-as-library -runtime-compatibility-version none -wmo -Xfrontend -disable-objc-interop) | %FileCheck %s
2+
3+
// REQUIRES: swift_in_compiler
4+
// REQUIRES: executable_test
5+
// REQUIRES: optimized_stdlib
6+
// REQUIRES: OS=macosx || OS=linux-gnu
7+
8+
enum Node {
9+
indirect case inner(Node, Node)
10+
case leaf(Int)
11+
}
12+
13+
@main
14+
struct Main {
15+
static func main() {
16+
_ = [Node.leaf(42), Node.leaf(42)]
17+
print("OK!")
18+
// CHECK: OK!
19+
}
20+
}

0 commit comments

Comments
 (0)