|
26 | 26 | #include "swift/SIL/SILType.h"
|
27 | 27 | #include "llvm/IR/DerivedTypes.h"
|
28 | 28 |
|
| 29 | +#include "GenTuple.h" |
29 | 30 | #include "GenType.h"
|
30 | 31 | #include "IRGenFunction.h"
|
31 | 32 | #include "IRGenModule.h"
|
@@ -1184,3 +1185,167 @@ void irgen::deallocatePack(IRGenFunction &IGF, StackAddress addr, CanSILPackType
|
1184 | 1185 | IGF.Builder.CreateLifetimeEnd(addr.getAddress(),
|
1185 | 1186 | elementSize * elementCount);
|
1186 | 1187 | }
|
| 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 | +} |
0 commit comments