Skip to content

Commit a02573e

Browse files
committed
Implement CoerceAndExpand in Swift. NFC for now, since only swiftcall
uses this and there's no way to round-trip a SILFunctionType as a foreign type using swiftcall.
1 parent 5810073 commit a02573e

File tree

3 files changed

+182
-3
lines changed

3 files changed

+182
-3
lines changed

lib/IRGen/GenCall.cpp

Lines changed: 166 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,28 @@ static void addIndirectResultAttributes(IRGenModule &IGM,
179179
attrs = attrs.addAttributes(IGM.LLVMContext, paramIndex + 1, resultAttrs);
180180
}
181181

182+
static void addSwiftSelfAttributes(IRGenModule &IGM,
183+
llvm::AttributeSet &attrs,
184+
unsigned argIndex) {
185+
static const llvm::Attribute::AttrKind attrKinds[] = {
186+
llvm::Attribute::SwiftSelf,
187+
};
188+
auto argAttrs =
189+
llvm::AttributeSet::get(IGM.LLVMContext, argIndex + 1, attrKinds);
190+
attrs = attrs.addAttributes(IGM.LLVMContext, argIndex + 1, argAttrs);
191+
}
192+
193+
static void addSwiftErrorAttributes(IRGenModule &IGM,
194+
llvm::AttributeSet &attrs,
195+
unsigned argIndex) {
196+
static const llvm::Attribute::AttrKind attrKinds[] = {
197+
llvm::Attribute::SwiftError,
198+
};
199+
auto argAttrs =
200+
llvm::AttributeSet::get(IGM.LLVMContext, argIndex + 1, attrKinds);
201+
attrs = attrs.addAttributes(IGM.LLVMContext, argIndex + 1, argAttrs);
202+
}
203+
182204
void irgen::addByvalArgumentAttributes(IRGenModule &IGM,
183205
llvm::AttributeSet &attrs,
184206
unsigned argIndex,
@@ -721,8 +743,9 @@ llvm::Type *SignatureExpansion::expandExternalSignatureTypes() {
721743
}
722744

723745
// If we return indirectly, that is the first parameter type.
724-
if (returnInfo.isIndirect())
746+
if (returnInfo.isIndirect()) {
725747
addIndirectResult();
748+
}
726749

727750
size_t firstParamToLowerNormally = 0;
728751

@@ -750,6 +773,20 @@ llvm::Type *SignatureExpansion::expandExternalSignatureTypes() {
750773
SWIFT_FALLTHROUGH;
751774
}
752775
case clang::CodeGen::ABIArgInfo::Direct: {
776+
switch (FI.getExtParameterInfo(i).getABI()) {
777+
case clang::ParameterABI::Ordinary:
778+
break;
779+
case clang::ParameterABI::SwiftContext:
780+
addSwiftSelfAttributes(IGM, Attrs, getCurParamIndex());
781+
break;
782+
case clang::ParameterABI::SwiftErrorResult:
783+
addSwiftErrorAttributes(IGM, Attrs, getCurParamIndex());
784+
break;
785+
case clang::ParameterABI::SwiftIndirectResult:
786+
addIndirectResultAttributes(IGM, Attrs, getCurParamIndex(),claimSRet());
787+
break;
788+
}
789+
753790
// If the coercion type is a struct, we need to expand it.
754791
auto type = AI.getCoerceToType();
755792
if (auto expandedType = dyn_cast<llvm::StructType>(type)) {
@@ -760,6 +797,11 @@ llvm::Type *SignatureExpansion::expandExternalSignatureTypes() {
760797
}
761798
break;
762799
}
800+
case clang::CodeGen::ABIArgInfo::CoerceAndExpand: {
801+
auto types = AI.getCoerceAndExpandTypeSequence();
802+
ParamIRTypes.append(types.begin(), types.end());
803+
break;
804+
}
763805
case clang::CodeGen::ABIArgInfo::Indirect: {
764806
assert(i >= clangToSwiftParamOffset &&
765807
"Unexpected index for indirect byval argument");
@@ -1276,6 +1318,102 @@ bool irgen::canCoerceToSchema(IRGenModule &IGM,
12761318
return true;
12771319
}
12781320

1321+
static llvm::Type *getOutputType(TranslationDirection direction, unsigned index,
1322+
const ExplosionSchema &nativeSchema,
1323+
ArrayRef<llvm::Type*> expandedForeignTys) {
1324+
assert(nativeSchema.size() == expandedForeignTys.size());
1325+
return (direction == TranslationDirection::ToForeign
1326+
? expandedForeignTys[index]
1327+
: nativeSchema[index].getScalarType());
1328+
}
1329+
1330+
1331+
static void emitCoerceAndExpand(IRGenFunction &IGF,
1332+
Explosion &in, Explosion &out, SILType paramTy,
1333+
const LoadableTypeInfo &paramTI,
1334+
llvm::StructType *coercionTy,
1335+
ArrayRef<llvm::Type*> expandedTys,
1336+
TranslationDirection direction) {
1337+
// If we can directly coerce the scalar values, avoid going through memory.
1338+
auto schema = paramTI.getSchema();
1339+
if (canCoerceToSchema(IGF.IGM, expandedTys, schema)) {
1340+
for (auto index : indices(expandedTys)) {
1341+
llvm::Value *arg = in.claimNext();
1342+
assert(arg->getType() ==
1343+
getOutputType(reverse(direction), index, schema, expandedTys));
1344+
auto outputTy = getOutputType(direction, index, schema, expandedTys);
1345+
1346+
if (arg->getType() != outputTy)
1347+
arg = IGF.coerceValue(arg, outputTy, IGF.IGM.DataLayout);
1348+
out.add(arg);
1349+
}
1350+
return;
1351+
}
1352+
1353+
// Otherwise, materialize to a temporary.
1354+
Address temporary =
1355+
paramTI.allocateStack(IGF, paramTy, "coerce-and-expand.temp").getAddress();
1356+
1357+
auto coercionTyLayout = IGF.IGM.DataLayout.getStructLayout(coercionTy);
1358+
1359+
// Make the alloca at least as aligned as the coercion struct, just
1360+
// so that the element accesses we make don't end up under-aligned.
1361+
Alignment coercionTyAlignment = Alignment(coercionTyLayout->getAlignment());
1362+
auto alloca = cast<llvm::AllocaInst>(temporary.getAddress());
1363+
if (alloca->getAlignment() < coercionTyAlignment.getValue()) {
1364+
alloca->setAlignment(coercionTyAlignment.getValue());
1365+
temporary = Address(temporary.getAddress(), coercionTyAlignment);
1366+
}
1367+
1368+
// If we're translating *to* the foreign expansion, do an ordinary
1369+
// initialization from the input explosion.
1370+
if (direction == TranslationDirection::ToForeign) {
1371+
paramTI.initialize(IGF, in, temporary);
1372+
}
1373+
1374+
Address coercedTemporary =
1375+
IGF.Builder.CreateElementBitCast(temporary, coercionTy);
1376+
1377+
#ifndef NDEBUG
1378+
size_t expandedTyIndex = 0;
1379+
#endif
1380+
1381+
for (auto eltIndex : indices(coercionTy->elements())) {
1382+
auto eltTy = coercionTy->getElementType(eltIndex);
1383+
1384+
// Skip padding fields.
1385+
if (eltTy->isArrayTy()) continue;
1386+
assert(expandedTys[expandedTyIndex++] == eltTy);
1387+
1388+
// Project down to the field.
1389+
Address eltAddr =
1390+
IGF.Builder.CreateStructGEP(coercedTemporary, eltIndex, coercionTyLayout);
1391+
1392+
// If we're translating *to* the foreign expansion, pull the value out
1393+
// of the field and add it to the output.
1394+
if (direction == TranslationDirection::ToForeign) {
1395+
llvm::Value *value = IGF.Builder.CreateLoad(eltAddr);
1396+
out.add(value);
1397+
1398+
// Otherwise, claim the next value from the input and store that
1399+
// in the field.
1400+
} else {
1401+
llvm::Value *value = in.claimNext();
1402+
IGF.Builder.CreateStore(value, eltAddr);
1403+
}
1404+
}
1405+
1406+
assert(expandedTyIndex == expandedTys.size());
1407+
1408+
// If we're translating *from* the foreign expansion, do an ordinary
1409+
// load into the output explosion.
1410+
if (direction == TranslationDirection::ToNative) {
1411+
paramTI.loadAsTake(IGF, temporary, out);
1412+
}
1413+
1414+
paramTI.deallocateStack(IGF, temporary, paramTy);
1415+
}
1416+
12791417
static void emitDirectExternalArgument(IRGenFunction &IGF,
12801418
SILType argType, llvm::Type *toTy,
12811419
Explosion &in, Explosion &out) {
@@ -1448,6 +1586,11 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
14481586
auto clangParamTy = FI.arg_begin()[i].type;
14491587
auto &AI = FI.arg_begin()[i].info;
14501588

1589+
// We don't need to do anything to handle the Swift parameter-ABI
1590+
// attributes here because we shouldn't be trying to round-trip
1591+
// swiftcall function pointers through SIL as C functions anyway.
1592+
assert(FI.getExtParameterInfo(i).getABI() == clang::ParameterABI::Ordinary);
1593+
14511594
// Add a padding argument if required.
14521595
if (auto *padType = AI.getPaddingType())
14531596
out.add(llvm::UndefValue::get(padType));
@@ -1487,6 +1630,14 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
14871630
out.add(addr.getAddress());
14881631
break;
14891632
}
1633+
case clang::CodeGen::ABIArgInfo::CoerceAndExpand: {
1634+
auto &paramTI = cast<LoadableTypeInfo>(IGF.getTypeInfo(paramType));
1635+
emitCoerceAndExpand(IGF, in, out, paramType, paramTI,
1636+
AI.getCoerceAndExpandType(),
1637+
AI.getCoerceAndExpandTypeSequence(),
1638+
TranslationDirection::ToForeign);
1639+
break;
1640+
}
14901641
case clang::CodeGen::ABIArgInfo::Expand:
14911642
emitClangExpandedArgument(IGF, in, out, clangParamTy, paramType,
14921643
cast<LoadableTypeInfo>(IGF.getTypeInfo(paramType)));
@@ -1614,6 +1765,12 @@ void irgen::emitForeignParameter(IRGenFunction &IGF, Explosion &params,
16141765
auto clangArgTy = FI.arg_begin()[foreignParamIndex].type;
16151766
auto AI = FI.arg_begin()[foreignParamIndex].info;
16161767

1768+
// We don't need to do anything to handle the Swift parameter-ABI
1769+
// attributes here because we shouldn't be trying to round-trip
1770+
// swiftcall function pointers through SIL as C functions anyway.
1771+
assert(FI.getExtParameterInfo(foreignParamIndex).getABI()
1772+
== clang::ParameterABI::Ordinary);
1773+
16171774
// Drop padding arguments.
16181775
if (AI.getPaddingType())
16191776
params.claimNext();
@@ -1635,6 +1792,14 @@ void irgen::emitForeignParameter(IRGenFunction &IGF, Explosion &params,
16351792
paramTy, paramTI);
16361793
return;
16371794
}
1795+
case clang::CodeGen::ABIArgInfo::CoerceAndExpand: {
1796+
auto &paramTI = cast<LoadableTypeInfo>(IGF.getTypeInfo(paramTy));
1797+
emitCoerceAndExpand(IGF, params, paramExplosion, paramTy, paramTI,
1798+
AI.getCoerceAndExpandType(),
1799+
AI.getCoerceAndExpandTypeSequence(),
1800+
TranslationDirection::ToNative);
1801+
break;
1802+
}
16381803

16391804
case clang::CodeGen::ABIArgInfo::Ignore:
16401805
return;

lib/IRGen/GenCall.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ namespace irgen {
5353
class Size;
5454
class TypeInfo;
5555

56+
enum class TranslationDirection : bool {
57+
ToForeign,
58+
ToNative
59+
};
60+
inline TranslationDirection reverse(TranslationDirection direction) {
61+
return TranslationDirection(!bool(direction));
62+
}
63+
5664
llvm::CallingConv::ID expandCallingConv(IRGenModule &IGM,
5765
SILFunctionTypeRepresentation convention);
5866

lib/IRGen/IRBuilder.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,12 +177,18 @@ class IRBuilder : public IRBuilderBase {
177177
llvm::StoreInst *CreateStore(llvm::Value *value, llvm::Value *addr) = delete;
178178

179179
using IRBuilderBase::CreateStructGEP;
180-
Address CreateStructGEP(Address address, unsigned index, Size size,
180+
Address CreateStructGEP(Address address, unsigned index, Size offset,
181181
const llvm::Twine &name = "") {
182182
llvm::Value *addr = CreateStructGEP(
183183
address.getType()->getElementType(), address.getAddress(),
184184
index, name);
185-
return Address(addr, address.getAlignment().alignmentAtOffset(size));
185+
return Address(addr, address.getAlignment().alignmentAtOffset(offset));
186+
}
187+
Address CreateStructGEP(Address address, unsigned index,
188+
const llvm::StructLayout *layout,
189+
const llvm::Twine &name = "") {
190+
Size offset = Size(layout->getElementOffset(index));
191+
return CreateStructGEP(address, index, offset, name);
186192
}
187193

188194
/// Given a pointer to an array element, GEP to the array element

0 commit comments

Comments
 (0)