@@ -1373,11 +1373,16 @@ struct SpecializationContext
1373
1373
if (!isExistentialType (param->getDataType ()))
1374
1374
continue ;
1375
1375
1376
+ // Is arg in the most simplified form for specialization? If not we are
1377
+ // not ready to consider specialization yet.
1378
+ if (!isSimplifiedExistentialArg (arg))
1379
+ return false ;
1380
+
1376
1381
// We *cannot* specialize unless the argument value corresponding
1377
1382
// to such a parameter is one we can specialize.
1378
1383
//
1379
1384
if (!canSpecializeExistentialArg (arg))
1380
- return false ;
1385
+ continue ;
1381
1386
1382
1387
argumentNeedSpecialization = true ;
1383
1388
}
@@ -1416,7 +1421,6 @@ struct SpecializationContext
1416
1421
auto arg = inst->getArg (argCounter++);
1417
1422
if (!isExistentialType (param->getDataType ()))
1418
1423
continue ;
1419
-
1420
1424
if (auto makeExistential = as<IRMakeExistential>(arg))
1421
1425
{
1422
1426
// Note that we use the *type* stored in the
@@ -1426,25 +1430,32 @@ struct SpecializationContext
1426
1430
// call sites that pass in the exact same argument).
1427
1431
//
1428
1432
auto val = makeExistential->getWrappedValue ();
1429
- auto valType = val->getFullType ();
1430
- key.vals .add (valType);
1431
-
1432
- // We are also including the witness table in the key.
1433
- // This isn't required with our current language model,
1434
- // since a given type can only conform to a given interface
1435
- // in one way (so there can be only one witness table).
1436
- // That means that the `valType` and the existential
1437
- // type of `param` above should uniquely determine
1438
- // the witness table we see.
1439
- //
1440
- // There are forward-looking cases where supporting
1441
- // "overlapping conformances" could be required, and
1442
- // there is low incremental cost to future-proofing
1443
- // this code, so we go ahead and add the witness
1444
- // table even if it is redundant.
1445
- //
1446
- auto witnessTable = makeExistential->getWitnessTable ();
1447
- key.vals .add (witnessTable);
1433
+ auto valType = val->getDataType ();
1434
+ if (isCompileTimeConstantType (valType))
1435
+ {
1436
+ key.vals .add (valType);
1437
+
1438
+ // We are also including the witness table in the key.
1439
+ // This isn't required with our current language model,
1440
+ // since a given type can only conform to a given interface
1441
+ // in one way (so there can be only one witness table).
1442
+ // That means that the `valType` and the existential
1443
+ // type of `param` above should uniquely determine
1444
+ // the witness table we see.
1445
+ //
1446
+ // There are forward-looking cases where supporting
1447
+ // "overlapping conformances" could be required, and
1448
+ // there is low incremental cost to future-proofing
1449
+ // this code, so we go ahead and add the witness
1450
+ // table even if it is redundant.
1451
+ //
1452
+ auto witnessTable = makeExistential->getWitnessTable ();
1453
+ key.vals .add (witnessTable);
1454
+ }
1455
+ else
1456
+ {
1457
+ key.vals .add (param->getDataType ());
1458
+ }
1448
1459
}
1449
1460
else if (auto wrapExistential = as<IRWrapExistential>(arg))
1450
1461
{
@@ -1508,7 +1519,11 @@ struct SpecializationContext
1508
1519
if (auto makeExistential = as<IRMakeExistential>(arg))
1509
1520
{
1510
1521
auto val = makeExistential->getWrappedValue ();
1511
- newArgs.add (val);
1522
+ auto valType = val->getDataType ();
1523
+ if (isCompileTimeConstantType (valType))
1524
+ newArgs.add (val);
1525
+ else
1526
+ newArgs.add (arg);
1512
1527
}
1513
1528
else if (auto wrapExistential = as<IRWrapExistential>(arg))
1514
1529
{
@@ -1634,6 +1649,18 @@ struct SpecializationContext
1634
1649
return true ;
1635
1650
}
1636
1651
1652
+
1653
+ // Returns true if `inst` is a simplified existential argument ready for specialization.
1654
+ bool isSimplifiedExistentialArg (IRInst* inst)
1655
+ {
1656
+ if (as<IRMakeExistential>(inst))
1657
+ return true ;
1658
+ if (as<IRWrapExistential>(inst))
1659
+ return true ;
1660
+ return false ;
1661
+ }
1662
+
1663
+
1637
1664
// Similarly, we want to be able to test whether an instruction
1638
1665
// used as an argument for an existential-type parameter is
1639
1666
// suitable for use in specialization.
@@ -1760,21 +1787,33 @@ struct SpecializationContext
1760
1787
// created.
1761
1788
//
1762
1789
auto valType = val->getFullType ();
1763
- auto newParam = builder->createParam (valType);
1764
- newParams.add (newParam);
1790
+ if (auto extractExistentialType = as<IRExtractExistentialType>(valType))
1791
+ {
1792
+ valType = extractExistentialType->getOperand (0 )->getDataType ();
1793
+ auto newParam = builder->createParam (valType);
1794
+ newParams.add (newParam);
1795
+ replacementVal = newParam;
1796
+ }
1797
+ else
1798
+ {
1799
+ auto newParam = builder->createParam (valType);
1800
+ newParams.add (newParam);
1765
1801
1766
- // Within the body of the function we cannot just use `val`
1767
- // directly, because the existing code expects an existential
1768
- // value, including its witness table.
1769
- //
1770
- // Therefore we will create a `makeExistential(newParam, witnessTable)`
1771
- // in the body of the new function and use *that* as the replacement
1772
- // value for the original parameter (since it will have the
1773
- // correct existential type, and stores the right witness table).
1774
- //
1775
- auto newMakeExistential =
1776
- builder->emitMakeExistential (oldParam->getFullType (), newParam, witnessTable);
1777
- replacementVal = newMakeExistential;
1802
+ // Within the body of the function we cannot just use `val`
1803
+ // directly, because the existing code expects an existential
1804
+ // value, including its witness table.
1805
+ //
1806
+ // Therefore we will create a `makeExistential(newParam, witnessTable)`
1807
+ // in the body of the new function and use *that* as the replacement
1808
+ // value for the original parameter (since it will have the
1809
+ // correct existential type, and stores the right witness table).
1810
+ //
1811
+ auto newMakeExistential = builder->emitMakeExistential (
1812
+ oldParam->getFullType (),
1813
+ newParam,
1814
+ witnessTable);
1815
+ replacementVal = newMakeExistential;
1816
+ }
1778
1817
}
1779
1818
else if (auto oldWrapExistential = as<IRWrapExistential>(arg))
1780
1819
{
0 commit comments