Skip to content

Commit d589d85

Browse files
authored
Merge pull request #67940 from slavapestov/irgen-pack-expansion-metadata-5.9
IRGen: Emit labeled tuple and function type metadata containing pack expansions [5.9]
2 parents 5889c59 + bb4db6f commit d589d85

File tree

8 files changed

+690
-271
lines changed

8 files changed

+690
-271
lines changed

lib/IRGen/GenPack.cpp

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "swift/SIL/SILType.h"
2727
#include "llvm/IR/DerivedTypes.h"
2828

29+
#include "GenTuple.h"
2930
#include "GenType.h"
3031
#include "IRGenFunction.h"
3132
#include "IRGenModule.h"
@@ -1184,3 +1185,227 @@ void irgen::deallocatePack(IRGenFunction &IGF, StackAddress addr, CanSILPackType
11841185
IGF.Builder.CreateLifetimeEnd(addr.getAddress(),
11851186
elementSize * elementCount);
11861187
}
1188+
1189+
static unsigned getConstantLabelsLength(CanTupleType type) {
1190+
unsigned total = 0;
1191+
1192+
for (auto elt : type->getElements()) {
1193+
if (elt.getType()->is<PackExpansionType>()) {
1194+
assert(!elt.hasName());
1195+
continue;
1196+
}
1197+
1198+
if (elt.hasName()) {
1199+
assert(!elt.getType()->is<PackExpansionType>());
1200+
total += elt.getName().getLength();
1201+
}
1202+
1203+
++total;
1204+
}
1205+
1206+
return total;
1207+
}
1208+
1209+
/// Emit the dynamic label string for a tuple type containing pack
1210+
/// expansions.
1211+
///
1212+
/// The basic idea is that the static label string is "stretched out".
1213+
/// Pack expansion elements are unlabeled, so they appear as a single
1214+
/// blank space in the static label string. We replace this with the
1215+
/// appropriate number of blank spaces, given the dynamic length of
1216+
/// the pack.
1217+
llvm::Optional<StackAddress>
1218+
irgen::emitDynamicTupleTypeLabels(IRGenFunction &IGF,
1219+
CanTupleType type,
1220+
CanPackType packType,
1221+
llvm::Value *shapeExpression) {
1222+
bool hasLabels = false;
1223+
for (auto elt : type->getElements()) {
1224+
hasLabels |= elt.hasName();
1225+
}
1226+
1227+
if (!hasLabels)
1228+
return llvm::None;
1229+
1230+
// Elements of pack expansion type are unlabeled, so the length of
1231+
// the label string is the number of elements in the pack, plus the
1232+
// sum of the lengths of the labels.
1233+
llvm::Value *labelLength = llvm::ConstantInt::get(
1234+
IGF.IGM.SizeTy, getConstantLabelsLength(type));
1235+
labelLength = IGF.Builder.CreateAdd(shapeExpression, labelLength);
1236+
1237+
// Leave root for a null byte at the end.
1238+
labelLength = IGF.Builder.CreateAdd(labelLength,
1239+
llvm::ConstantInt::get(IGF.IGM.SizeTy, 1));
1240+
1241+
// Allocate space for the label string; we fill it in below.
1242+
StackAddress labelString = IGF.emitDynamicAlloca(
1243+
IGF.IGM.Int8Ty, labelLength,
1244+
IGF.IGM.getPointerAlignment(),
1245+
/*allowTaskAlloc=*/true);
1246+
1247+
// Get the static label string, where each pack expansion is one element.
1248+
auto *staticLabelString = getTupleLabelsString(IGF.IGM, type);
1249+
1250+
// The position in the static label string for to the current element.
1251+
unsigned staticPosition = 0;
1252+
1253+
// The position in the dynamic label string for to the current element.
1254+
llvm::Value *dynamicPosition = llvm::ConstantInt::get(IGF.IGM.SizeTy, 0);
1255+
1256+
// Number of expansions we've seen so far.
1257+
unsigned numExpansions = 0;
1258+
1259+
// Was there at least one label?
1260+
bool sawLabel = false;
1261+
1262+
auto visitFn = [&](CanType eltTy,
1263+
unsigned scalarIndex,
1264+
llvm::Value *dynamicIndex,
1265+
llvm::Value *dynamicLength) {
1266+
auto elt = type->getElements()[scalarIndex + numExpansions];
1267+
assert(eltTy == CanType(elt.getType()));
1268+
1269+
// The destination address, where we put the current element's label.
1270+
auto eltAddr = IGF.Builder.CreateArrayGEP(labelString.getAddress(),
1271+
dynamicPosition, Size(1));
1272+
1273+
// If we're looking at a pack expansion, insert the appropriate
1274+
// number of blank spaces in the dynamic label string.
1275+
if (isa<PackExpansionType>(eltTy)) {
1276+
assert(!elt.hasName() && "Pack expansions cannot have labels");
1277+
// Fill the dynamic label string with a blank label for each
1278+
// dynamic element.
1279+
IGF.Builder.CreateMemSet(
1280+
eltAddr, llvm::ConstantInt::get(IGF.IGM.Int8Ty, ' '),
1281+
dynamicLength);
1282+
1283+
// We consumed one static label.
1284+
staticPosition += 1;
1285+
1286+
// We produced some number of dynamic labels.
1287+
dynamicPosition = IGF.Builder.CreateAdd(dynamicPosition, dynamicLength);
1288+
1289+
// We consumed an expansion.
1290+
numExpansions += 1;
1291+
1292+
return;
1293+
}
1294+
1295+
// Otherwise, we have a single scalar element, which deposits a single
1296+
// label in the dynamic label string.
1297+
unsigned length = 0;
1298+
1299+
// Scalar elements may have labels.
1300+
if (elt.hasName()) {
1301+
// Index into the static label string.
1302+
llvm::Constant *indices[] = {
1303+
llvm::ConstantInt::get(IGF.IGM.SizeTy, staticPosition)
1304+
};
1305+
1306+
// The source address in the static label string.
1307+
Address srcAddr(
1308+
llvm::ConstantExpr::getInBoundsGetElementPtr(
1309+
IGF.IGM.Int8Ty, staticLabelString,
1310+
indices),
1311+
IGF.IGM.Int8Ty, Alignment(1));
1312+
1313+
// The number of bytes to copy; add one for the space at the end.
1314+
length = elt.getName().getLength() + 1;
1315+
1316+
// Desposit the label for this element in the dynamic label string.
1317+
IGF.Builder.CreateMemCpy(eltAddr, srcAddr, Size(length));
1318+
1319+
sawLabel = true;
1320+
} else {
1321+
length = 1;
1322+
1323+
// There is no label. The static label string stores a blank space,
1324+
// and we need to update the dynamic string for the same.
1325+
IGF.Builder.CreateStore(
1326+
llvm::ConstantInt::get(IGF.IGM.Int8Ty, ' '),
1327+
eltAddr);
1328+
}
1329+
1330+
// We consumed one static label.
1331+
staticPosition += length;
1332+
1333+
// We produced one dynamic label.
1334+
auto *constant = llvm::ConstantInt::get(IGF.IGM.SizeTy, length);
1335+
accumulateSum(IGF, dynamicPosition, constant);
1336+
};
1337+
1338+
(void) visitPackExplosion(IGF, packType, visitFn);
1339+
1340+
// Null-terminate the dynamic label string.
1341+
auto eltAddr = IGF.Builder.CreateArrayGEP(labelString.getAddress(),
1342+
dynamicPosition, Size(1));
1343+
IGF.Builder.CreateStore(
1344+
llvm::ConstantInt::get(IGF.IGM.Int8Ty, '\0'),
1345+
eltAddr);
1346+
1347+
assert(sawLabel);
1348+
(void) sawLabel;
1349+
1350+
return labelString;
1351+
}
1352+
1353+
StackAddress
1354+
irgen::emitDynamicFunctionParameterFlags(IRGenFunction &IGF,
1355+
AnyFunctionType::CanParamArrayRef params,
1356+
CanPackType packType,
1357+
llvm::Value *shapeExpression) {
1358+
auto array =
1359+
IGF.emitDynamicAlloca(IGF.IGM.Int32Ty, shapeExpression,
1360+
Alignment(4), /*allowTaskAlloc=*/true);
1361+
1362+
unsigned numExpansions = 0;
1363+
1364+
auto visitFn = [&](CanType eltTy,
1365+
unsigned scalarIndex,
1366+
llvm::Value *dynamicIndex,
1367+
llvm::Value *dynamicLength) {
1368+
if (scalarIndex != 0 || dynamicIndex == nullptr) {
1369+
auto *constant = llvm::ConstantInt::get(IGF.IGM.SizeTy, scalarIndex);
1370+
accumulateSum(IGF, dynamicIndex, constant);
1371+
}
1372+
1373+
auto elt = params[scalarIndex + numExpansions];
1374+
auto flags = getABIParameterFlags(elt.getParameterFlags());
1375+
auto flagsVal = llvm::ConstantInt::get(
1376+
IGF.IGM.Int32Ty, flags.getIntValue());
1377+
1378+
assert(eltTy == elt.getPlainType());
1379+
1380+
// If we're looking at a pack expansion, insert the appropriate
1381+
// number of flags fields.
1382+
if (auto expansionTy = dyn_cast<PackExpansionType>(eltTy)) {
1383+
emitPackExpansionPack(IGF, array.getAddress(), expansionTy,
1384+
dynamicIndex, dynamicLength,
1385+
[&](llvm::Value *) -> llvm::Value * {
1386+
return flagsVal;
1387+
});
1388+
1389+
// We consumed an expansion.
1390+
numExpansions += 1;
1391+
1392+
return;
1393+
}
1394+
1395+
// The destination address, where we put the current element's flags field.
1396+
Address eltAddr(
1397+
IGF.Builder.CreateInBoundsGEP(array.getAddress().getElementType(),
1398+
array.getAddressPointer(),
1399+
dynamicIndex),
1400+
array.getAddress().getElementType(),
1401+
array.getAlignment());
1402+
1403+
// Otherwise, we have a single scalar element, which deposits a single
1404+
// flags field.
1405+
IGF.Builder.CreateStore(flagsVal, eltAddr);
1406+
};
1407+
1408+
(void) visitPackExplosion(IGF, packType, visitFn);
1409+
1410+
return array;
1411+
}

lib/IRGen/GenPack.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,18 @@ StackAddress allocatePack(IRGenFunction &IGF, CanSILPackType packType);
114114

115115
void deallocatePack(IRGenFunction &IGF, StackAddress addr, CanSILPackType packType);
116116

117+
llvm::Optional<StackAddress>
118+
emitDynamicTupleTypeLabels(IRGenFunction &IGF,
119+
CanTupleType tupleType,
120+
CanPackType packType,
121+
llvm::Value *shapeExpression);
122+
123+
StackAddress
124+
emitDynamicFunctionParameterFlags(IRGenFunction &IGF,
125+
AnyFunctionType::CanParamArrayRef params,
126+
CanPackType packType,
127+
llvm::Value *shapeExpression);
128+
117129
} // end namespace irgen
118130
} // end namespace swift
119131

lib/IRGen/GenTuple.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,3 +640,28 @@ irgen::getPhysicalTupleElementStructIndex(IRGenModule &IGM, SILType tupleType,
640640
unsigned fieldNo) {
641641
FOR_TUPLE_IMPL(IGM, tupleType, getElementStructIndex, fieldNo);
642642
}
643+
644+
/// Emit a string encoding the labels in the given tuple type.
645+
llvm::Constant *irgen::getTupleLabelsString(IRGenModule &IGM,
646+
CanTupleType type) {
647+
bool hasLabels = false;
648+
llvm::SmallString<128> buffer;
649+
for (auto &elt : type->getElements()) {
650+
if (elt.hasName()) {
651+
hasLabels = true;
652+
buffer.append(elt.getName().str());
653+
}
654+
655+
// Each label is space-terminated.
656+
buffer += ' ';
657+
}
658+
659+
// If there are no labels, use a null pointer.
660+
if (!hasLabels) {
661+
return llvm::ConstantPointerNull::get(IGM.Int8PtrTy);
662+
}
663+
664+
// Otherwise, create a new string literal.
665+
// This method implicitly adds a null terminator.
666+
return IGM.getAddrOfGlobalString(buffer);
667+
}

lib/IRGen/GenTuple.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ namespace irgen {
6767
llvm::Optional<unsigned> getPhysicalTupleElementStructIndex(IRGenModule &IGM,
6868
SILType tupleType,
6969
unsigned fieldNo);
70+
71+
/// Emit a string encoding the labels in the given tuple type.
72+
llvm::Constant *getTupleLabelsString(IRGenModule &IGM,
73+
CanTupleType type);
74+
7075
} // end namespace irgen
7176
} // end namespace swift
7277

0 commit comments

Comments
 (0)