IRGen: Emitting metadata for function types containing pack expansion parameters

This commit is contained in:
Slava Pestov
2023-08-03 14:06:07 -04:00
parent 0f3c43089a
commit 59fd29551e
5 changed files with 132 additions and 2 deletions

View File

@@ -1349,3 +1349,63 @@ irgen::emitDynamicTupleTypeLabels(IRGenFunction &IGF,
return labelString;
}
StackAddress
irgen::emitDynamicFunctionParameterFlags(IRGenFunction &IGF,
AnyFunctionType::CanParamArrayRef params,
CanPackType packType,
llvm::Value *shapeExpression) {
auto array =
IGF.emitDynamicAlloca(IGF.IGM.Int32Ty, shapeExpression,
Alignment(4), /*allowTaskAlloc=*/true);
unsigned numExpansions = 0;
auto visitFn = [&](CanType eltTy,
unsigned scalarIndex,
llvm::Value *dynamicIndex,
llvm::Value *dynamicLength) {
if (scalarIndex != 0 || dynamicIndex == nullptr) {
auto *constant = llvm::ConstantInt::get(IGF.IGM.SizeTy, scalarIndex);
accumulateSum(IGF, dynamicIndex, constant);
}
auto elt = params[scalarIndex + numExpansions];
auto flags = getABIParameterFlags(elt.getParameterFlags());
auto flagsVal = llvm::ConstantInt::get(
IGF.IGM.Int32Ty, flags.getIntValue());
assert(eltTy == elt.getPlainType());
// If we're looking at a pack expansion, insert the appropriate
// number of flags fields.
if (auto expansionTy = dyn_cast<PackExpansionType>(eltTy)) {
emitPackExpansionPack(IGF, array.getAddress(), expansionTy,
dynamicIndex, dynamicLength,
[&](llvm::Value *) -> llvm::Value * {
return flagsVal;
});
// We consumed an expansion.
numExpansions += 1;
return;
}
// The destination address, where we put the current element's flags field.
Address eltAddr(
IGF.Builder.CreateInBoundsGEP(array.getAddress().getElementType(),
array.getAddressPointer(),
dynamicIndex),
array.getAddress().getElementType(),
array.getAlignment());
// Otherwise, we have a single scalar element, which deposits a single
// flags field.
IGF.Builder.CreateStore(flagsVal, eltAddr);
};
(void) visitPackExplosion(IGF, packType, visitFn);
return array;
}

View File

@@ -120,6 +120,12 @@ emitDynamicTupleTypeLabels(IRGenFunction &IGF,
CanPackType packType,
llvm::Value *shapeExpression);
StackAddress
emitDynamicFunctionParameterFlags(IRGenFunction &IGF,
AnyFunctionType::CanParamArrayRef params,
CanPackType packType,
llvm::Value *shapeExpression);
} // end namespace irgen
} // end namespace swift

View File

@@ -1371,7 +1371,7 @@ static llvm::Value *getFunctionParameterRef(IRGenFunction &IGF,
}
/// Mapping type-level parameter flags to ABI parameter flags.
static ParameterFlags getABIParameterFlags(ParameterTypeFlags flags) {
ParameterFlags irgen::getABIParameterFlags(ParameterTypeFlags flags) {
return ParameterFlags()
.withValueOwnership(flags.getValueOwnership())
.withVariadic(flags.isVariadic())
@@ -1489,7 +1489,27 @@ emitDynamicFunctionTypeMetadataParams(IRGenFunction &IGF,
CanPackType packType,
DynamicMetadataRequest request,
SmallVectorImpl<llvm::Value *> &arguments) {
assert(false);
assert(!params.empty());
FunctionTypeMetadataParamInfo info;
llvm::Value *shape;
std::tie(info.parameters, shape) = emitTypeMetadataPack(
IGF, packType, MetadataState::Abstract);
arguments.push_back(info.parameters.getAddress().getAddress());
if (flags.hasParameterFlags()) {
info.paramFlags = emitDynamicFunctionParameterFlags(
IGF, params, packType, shape);
arguments.push_back(info.paramFlags.getAddress().getAddress());
} else {
arguments.push_back(llvm::ConstantPointerNull::get(
IGF.IGM.Int32Ty->getPointerTo()));
}
return info;
}
static void cleanupFunctionTypeMetadataParams(IRGenFunction &IGF,

View File

@@ -709,6 +709,8 @@ MetadataResponse emitCheckTypeMetadataState(IRGenFunction &IGF,
OperationCost getCheckTypeMetadataStateCost(DynamicMetadataRequest request,
MetadataResponse response);
ParameterFlags getABIParameterFlags(ParameterTypeFlags flags);
} // end namespace irgen
} // end namespace swift

View File

@@ -0,0 +1,42 @@
// RUN: %target-run-simple-swift
// REQUIRES: executable_test
import StdlibUnittest
var funcs = TestSuite("VariadicGenericFuncTypes")
func makeFunctionType1<each T>(_: repeat (each T).Type) -> Any.Type {
return ((repeat each T) -> ()).self
}
func makeFunctionType2<each T>(_: repeat (each T).Type) -> Any.Type {
return ((Character, repeat each T, Bool) -> ()).self
}
func makeFunctionType3<each T>(_: repeat (each T).Type) -> Any.Type {
return ((inout Character, repeat each T, inout Bool) -> ()).self
}
funcs.test("makeFunctionType1") {
expectEqual("() -> ()", _typeName(makeFunctionType1()))
expectEqual("(Swift.Int) -> ()", _typeName(makeFunctionType1(Int.self)))
expectEqual("(Swift.Int, Swift.String) -> ()", _typeName(makeFunctionType1(Int.self, String.self)))
expectEqual("(Swift.Int, Swift.Float, Swift.String) -> ()", _typeName(makeFunctionType1(Int.self, Float.self, String.self)))
}
funcs.test("makeFunctionType2") {
expectEqual("(Swift.Character, Swift.Bool) -> ()", _typeName(makeFunctionType2()))
expectEqual("(Swift.Character, Swift.Int, Swift.Bool) -> ()", _typeName(makeFunctionType2(Int.self)))
expectEqual("(Swift.Character, Swift.Int, Swift.String, Swift.Bool) -> ()", _typeName(makeFunctionType2(Int.self, String.self)))
expectEqual("(Swift.Character, Swift.Int, Swift.Float, Swift.String, Swift.Bool) -> ()", _typeName(makeFunctionType2(Int.self, Float.self, String.self)))
}
funcs.test("makeFunctionType3") {
expectEqual("(inout Swift.Character, inout Swift.Bool) -> ()", _typeName(makeFunctionType3()))
expectEqual("(inout Swift.Character, Swift.Int, inout Swift.Bool) -> ()", _typeName(makeFunctionType3(Int.self)))
expectEqual("(inout Swift.Character, Swift.Int, Swift.String, inout Swift.Bool) -> ()", _typeName(makeFunctionType3(Int.self, String.self)))
expectEqual("(inout Swift.Character, Swift.Int, Swift.Float, Swift.String, inout Swift.Bool) -> ()", _typeName(makeFunctionType3(Int.self, Float.self, String.self)))
}
runAllTests()