@@ -1637,59 +1637,118 @@ emitGenericTypeMetadataAccessFunction(IRGenFunction &IGF,
1637
1637
Explosion ¶ms,
1638
1638
NominalTypeDecl *nominal,
1639
1639
GenericArguments &genericArgs) {
1640
- llvm::Value *descriptor =
1641
- IGF.IGM .getAddrOfTypeContextDescriptor (nominal, RequireMetadata);
1640
+ auto &IGM = IGF.IGM ;
1641
+
1642
+ llvm::Constant *descriptor =
1643
+ IGM.getAddrOfTypeContextDescriptor (nominal, RequireMetadata);
1642
1644
1643
1645
auto request = params.claimNext ();
1644
1646
1645
1647
auto numArguments = genericArgs.Types .size ();
1646
1648
1647
- bool allocatedBuffer = false ;
1648
- Address argsBuffer;
1649
+ llvm::Value *result;
1649
1650
if (numArguments > NumDirectGenericTypeMetadataAccessFunctionArgs) {
1650
- // The caller provided a buffer with enough space for all of the arguments;
1651
- // use that.
1652
- argsBuffer = Address (params.claimNext (), IGF.IGM .getPointerAlignment ());
1651
+ // swift_getGenericMetadata's calling convention is already cleverly
1652
+ // laid out to minimize the assembly language size of the thunk.
1653
+ // The caller passed us an appropriate buffer with the arguments.
1654
+ auto argsBuffer = Address (params.claimNext (), IGM.getPointerAlignment ());
1655
+ llvm::Value *arguments =
1656
+ IGF.Builder .CreateBitCast (argsBuffer.getAddress (), IGM.Int8PtrTy );
1657
+
1658
+ // Make the call.
1659
+ auto call = IGF.Builder .CreateCall (IGM.getGetGenericMetadataFn (),
1660
+ {request, arguments, descriptor});
1661
+ call->setDoesNotThrow ();
1662
+ call->setCallingConv (IGM.SwiftCC );
1663
+ call->addAttribute (llvm::AttributeList::FunctionIndex,
1664
+ llvm::Attribute::ReadOnly);
1665
+ result = call;
1653
1666
} else {
1654
- // Allocate a buffer with enough storage for the arguments.
1655
- auto argsBufferTy =
1656
- llvm::StructType::get (IGF.IGM .LLVMContext , genericArgs.Types );
1657
- argsBuffer = IGF.createAlloca (argsBufferTy,
1658
- IGF.IGM .getPointerAlignment (),
1659
- " generic.arguments" );
1660
- IGF.Builder .CreateLifetimeStart (argsBuffer,
1661
- IGF.IGM .getPointerSize () * genericArgs.Values .size ());
1662
- allocatedBuffer = true ;
1663
-
1664
- // Store direct arguments into the buffer.
1665
- for (auto i : range (numArguments)) {
1666
- Address elt = IGF.Builder .CreateStructGEP (argsBuffer, i,
1667
- IGF.IGM .getPointerSize () * i);
1668
-
1669
- auto *arg =
1670
- IGF.Builder .CreateBitCast (params.claimNext (),
1671
- elt.getType ()->getPointerElementType ());
1672
- IGF.Builder .CreateStore (arg, elt);
1667
+ static_assert (NumDirectGenericTypeMetadataAccessFunctionArgs == 3 ,
1668
+ " adjust this if you change "
1669
+ " NumDirectGenericTypeMetadataAccessFunctionArgs" );
1670
+ // Factor out the buffer shuffling for metadata accessors that take their
1671
+ // arguments directly, so that the accessor function itself only needs to
1672
+ // materialize the nominal type descriptor and call this thunk.
1673
+ auto thunkFn = cast<llvm::Function>(
1674
+ IGM.getModule ()
1675
+ ->getOrInsertFunction (" __swift_instantiateGenericMetadata" ,
1676
+ IGM.TypeMetadataResponseTy ,
1677
+ IGM.SizeTy , // request
1678
+ IGM.Int8PtrTy , // arg 0
1679
+ IGM.Int8PtrTy , // arg 1
1680
+ IGM.Int8PtrTy , // arg 2
1681
+ IGM.TypeContextDescriptorPtrTy ) // type context descriptor
1682
+ ->stripPointerCasts ());
1683
+
1684
+ if (thunkFn->empty ()) {
1685
+ ApplyIRLinkage (IRLinkage::InternalLinkOnceODR)
1686
+ .to (thunkFn);
1687
+ thunkFn->setDoesNotAccessMemory ();
1688
+ thunkFn->setDoesNotThrow ();
1689
+ thunkFn->setCallingConv (IGM.SwiftCC );
1690
+ thunkFn->addAttribute (llvm::AttributeList::FunctionIndex,
1691
+ llvm::Attribute::NoInline);
1692
+
1693
+ [&IGM, thunkFn]{
1694
+ IRGenFunction subIGF (IGM, thunkFn);
1695
+
1696
+ auto params = subIGF.collectParameters ();
1697
+ auto request = params.claimNext ();
1698
+ auto arg0 = params.claimNext ();
1699
+ auto arg1 = params.claimNext ();
1700
+ auto arg2 = params.claimNext ();
1701
+ auto descriptor = params.claimNext ();
1702
+
1703
+ // Allocate a buffer with enough storage for the arguments.
1704
+ auto argsBufferTy =
1705
+ llvm::ArrayType::get (IGM.Int8PtrTy ,
1706
+ NumDirectGenericTypeMetadataAccessFunctionArgs);
1707
+ auto argsBuffer = subIGF.createAlloca (argsBufferTy,
1708
+ IGM.getPointerAlignment (),
1709
+ " generic.arguments" );
1710
+ subIGF.Builder .CreateLifetimeStart (argsBuffer,
1711
+ IGM.getPointerSize () * NumDirectGenericTypeMetadataAccessFunctionArgs);
1712
+
1713
+ auto arg0Buf = subIGF.Builder .CreateConstInBoundsGEP2_32 (argsBufferTy,
1714
+ argsBuffer.getAddress (), 0 , 0 );
1715
+ subIGF.Builder .CreateStore (arg0, arg0Buf, IGM.getPointerAlignment ());
1716
+ auto arg1Buf = subIGF.Builder .CreateConstInBoundsGEP2_32 (argsBufferTy,
1717
+ argsBuffer.getAddress (), 0 , 1 );
1718
+ subIGF.Builder .CreateStore (arg1, arg1Buf, IGM.getPointerAlignment ());
1719
+ auto arg2Buf = subIGF.Builder .CreateConstInBoundsGEP2_32 (argsBufferTy,
1720
+ argsBuffer.getAddress (), 0 , 2 );
1721
+ subIGF.Builder .CreateStore (arg2, arg2Buf, IGM.getPointerAlignment ());
1722
+
1723
+ // Make the call.
1724
+ auto argsAddr = subIGF.Builder .CreateBitCast (argsBuffer.getAddress (),
1725
+ IGM.Int8PtrTy );
1726
+ auto result = subIGF.Builder .CreateCall (IGM.getGetGenericMetadataFn (),
1727
+ {request, argsAddr, descriptor});
1728
+ subIGF.Builder .CreateRet (result);
1729
+ }();
1673
1730
}
1731
+
1732
+ // Call out to the helper.
1733
+ auto arg0 = numArguments >= 1
1734
+ ? IGF.Builder .CreateBitCast (params.claimNext (), IGM.Int8PtrTy )
1735
+ : llvm::UndefValue::get (IGM.Int8PtrTy );
1736
+ auto arg1 = numArguments >= 2
1737
+ ? IGF.Builder .CreateBitCast (params.claimNext (), IGM.Int8PtrTy )
1738
+ : llvm::UndefValue::get (IGM.Int8PtrTy );
1739
+ auto arg2 = numArguments >= 3
1740
+ ? IGF.Builder .CreateBitCast (params.claimNext (), IGM.Int8PtrTy )
1741
+ : llvm::UndefValue::get (IGM.Int8PtrTy );
1742
+
1743
+ auto call = IGF.Builder .CreateCall (thunkFn,
1744
+ {request, arg0, arg1, arg2, descriptor});
1745
+ call->setDoesNotAccessMemory ();
1746
+ call->setDoesNotThrow ();
1747
+ call->setCallingConv (IGM.SwiftCC );
1748
+
1749
+ result = call;
1674
1750
}
1675
-
1676
- llvm::Value *arguments =
1677
- IGF.Builder .CreateBitCast (argsBuffer.getAddress (), IGF.IGM .Int8PtrTy );
1678
-
1679
- // Make the call.
1680
- auto result = IGF.Builder .CreateCall (IGF.IGM .getGetGenericMetadataFn (),
1681
- {request, arguments, descriptor});
1682
- result->setDoesNotThrow ();
1683
- result->setCallingConv (IGF.IGM .SwiftCC );
1684
- result->addAttribute (llvm::AttributeList::FunctionIndex,
1685
- llvm::Attribute::ReadOnly);
1686
-
1687
- // If we allocated the array ourselves, end its lifetime.
1688
- if (allocatedBuffer) {
1689
- IGF.Builder .CreateLifetimeEnd (argsBuffer,
1690
- IGF.IGM .getPointerSize () * genericArgs.Values .size ());
1691
- }
1692
-
1751
+
1693
1752
return MetadataResponse::handle (IGF, DynamicMetadataRequest (request), result);
1694
1753
}
1695
1754
0 commit comments