Skip to content

Commit b55341b

Browse files
[IRGen][wasm] Disable manual indirection for coroutine yielding results
`clang::CodeGen::swiftcall::shouldPassIndirectly` now returns true for multiple scalar values on wasm targets because the Wasm MVP does not support multiple return values. For such targets where we can't directly return two pointers, we should not attempt to indirect at this stage because the later MC lowering will also indirect the return.
1 parent 5cc8264 commit b55341b

File tree

4 files changed

+138
-64
lines changed

4 files changed

+138
-64
lines changed

lib/IRGen/GenCall.cpp

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -870,26 +870,30 @@ void SignatureExpansion::expandCoroutineResult(bool forContinuation) {
870870
}
871871

872872
// Find the maximal sequence of the component types that we can
873-
// convince the ABI to pass directly.
873+
// convince the ABI to pass directly if the target supports
874+
// directly returning at least two pointers.
874875
// When counting components, ignore the continuation pointer.
875-
unsigned numDirectComponents = components.size() - 1;
876876
SmallVector<llvm::Type*, 8> overflowTypes;
877-
while (clang::CodeGen::swiftcall::
878-
shouldPassIndirectly(IGM.ClangCodeGen->CGM(), components,
879-
/*asReturnValue*/ true)) {
880-
// If we added a pointer to the end of components, remove it.
881-
if (!overflowTypes.empty()) components.pop_back();
877+
unsigned numDirectComponents = components.size() - 1;
878+
if (IGM.TargetInfo.SupportsDirectReturningAtLeastTwoPointers) {
879+
while (clang::CodeGen::swiftcall::shouldPassIndirectly(
880+
IGM.ClangCodeGen->CGM(), components,
881+
/*asReturnValue*/ true)) {
882+
// If we added a pointer to the end of components, remove it.
883+
if (!overflowTypes.empty())
884+
components.pop_back();
882885

883-
// Remove the last component and add it as an overflow type.
884-
overflowTypes.push_back(components.pop_back_val());
885-
--numDirectComponents;
886+
// Remove the last component and add it as an overflow type.
887+
overflowTypes.push_back(components.pop_back_val());
888+
--numDirectComponents;
886889

887-
// Add a pointer to the end of components.
888-
components.push_back(IGM.Int8PtrTy);
889-
}
890+
// Add a pointer to the end of components.
891+
components.push_back(IGM.Int8PtrTy);
892+
}
890893

891-
// We'd better have been able to pass at least two pointers.
892-
assert(components.size() >= 2 || overflowTypes.empty());
894+
// We'd better have been able to pass at least two pointers.
895+
assert(components.size() >= 2 || overflowTypes.empty());
896+
}
893897
CoroInfo.NumDirectYieldComponents = numDirectComponents;
894898

895899
// Replace the pointer type we added to components with the real

lib/IRGen/LoadableByAddress.cpp

Lines changed: 106 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ class LargeSILTypeMapper {
6363

6464
public:
6565
SILType getNewSILType(GenericEnvironment *GenericEnv, SILType storageType,
66-
irgen::IRGenModule &Mod);
66+
irgen::IRGenModule &Mod,
67+
bool useResultConvention = false);
6768
bool shouldTransformResults(GenericEnvironment *env,
6869
CanSILFunctionType fnType,
6970
irgen::IRGenModule &IGM);
@@ -72,9 +73,11 @@ class LargeSILTypeMapper {
7273
irgen::IRGenModule &IGM);
7374
SILParameterInfo getNewParameter(GenericEnvironment *env,
7475
SILParameterInfo param,
75-
irgen::IRGenModule &IGM);
76+
irgen::IRGenModule &IGM,
77+
bool useResultConvention);
7678
bool shouldTransformParameter(GenericEnvironment *env, SILParameterInfo param,
77-
irgen::IRGenModule &IGM);
79+
irgen::IRGenModule &IGM,
80+
bool useResultConvention);
7881
SmallVector<SILParameterInfo, 4> getNewParameters(GenericEnvironment *env,
7982
CanSILFunctionType fnType,
8083
irgen::IRGenModule &IGM);
@@ -95,25 +98,59 @@ class LargeSILTypeMapper {
9598
SILType getNewTupleType(GenericEnvironment *GenericEnv,
9699
irgen::IRGenModule &Mod,
97100
const SILType &nonOptionalType,
98-
const SILType &storageType);
101+
const SILType &storageType, bool useResultConvention);
99102
bool newResultsDiffer(GenericEnvironment *GenericEnv,
100103
ArrayRef<SILResultInfo> origResults,
101104
irgen::IRGenModule &Mod);
102105
bool shouldConvertBBArg(SILArgument *arg, irgen::IRGenModule &Mod);
103106
bool containsDifferentFunctionSignature(GenericEnvironment *genEnv,
104107
irgen::IRGenModule &Mod,
105108
SILType storageType,
106-
SILType newSILType);
109+
SILType newSILType,
110+
bool useResultConvention = false);
111+
112+
struct NewTypeCacheKey {
113+
GenericEnvironment *GenericEnv;
114+
SILType storageType;
115+
bool useResultConvention;
116+
};
107117

108118
private:
109119
// Cache of already computed type transforms
110-
llvm::MapVector<std::pair<GenericEnvironment *, SILType>, SILType>
111-
oldToNewTypeMap;
120+
llvm::MapVector<NewTypeCacheKey, SILType> oldToNewTypeMap;
121+
};
122+
123+
namespace llvm {
124+
125+
template <>
126+
struct DenseMapInfo<LargeSILTypeMapper::NewTypeCacheKey> {
127+
static bool isEqual(const LargeSILTypeMapper::NewTypeCacheKey &lhs,
128+
const LargeSILTypeMapper::NewTypeCacheKey &rhs) {
129+
return lhs.GenericEnv == rhs.GenericEnv &&
130+
lhs.storageType == rhs.storageType &&
131+
lhs.useResultConvention == rhs.useResultConvention;
132+
}
133+
static inline LargeSILTypeMapper::NewTypeCacheKey getEmptyKey() {
134+
return {nullptr, SILType(), false};
135+
}
136+
static inline LargeSILTypeMapper::NewTypeCacheKey getTombstoneKey() {
137+
return {DenseMapInfo<GenericEnvironment *>::getTombstoneKey(),
138+
DenseMapInfo<SILType>::getTombstoneKey(), false};
139+
}
140+
static unsigned getHashValue(const LargeSILTypeMapper::NewTypeCacheKey &Val) {
141+
return hash_combine(
142+
DenseMapInfo<GenericEnvironment *>::getHashValue(Val.GenericEnv),
143+
DenseMapInfo<SILType>::getHashValue(Val.storageType),
144+
Val.useResultConvention ? 1 : 0);
145+
}
112146
};
113147

148+
} // end namespace llvm
149+
114150
/// Utility to determine if this is a large loadable type
115151
static bool isLargeLoadableType(GenericEnvironment *GenericEnv, SILType t,
116-
irgen::IRGenModule &Mod) {
152+
irgen::IRGenModule &Mod,
153+
bool useResultConvention = false) {
117154
if (t.isAddress() || t.isClassOrClassMetatype()) {
118155
return false;
119156
}
@@ -128,7 +165,9 @@ static bool isLargeLoadableType(GenericEnvironment *GenericEnv, SILType t,
128165
assert(t.isObject() && "Expected only two categories: address and object");
129166
assert(!canType->hasTypeParameter());
130167
const TypeInfo &TI = Mod.getTypeInfoForLowered(canType);
131-
auto &nativeSchemaOrigParam = TI.nativeParameterValueSchema(Mod);
168+
auto &nativeSchemaOrigParam = useResultConvention
169+
? TI.nativeReturnValueSchema(Mod)
170+
: TI.nativeParameterValueSchema(Mod);
132171
return nativeSchemaOrigParam.requiresIndirect();
133172
}
134173
return false;
@@ -144,8 +183,9 @@ static bool modifiableFunction(CanSILFunctionType funcType) {
144183

145184
bool LargeSILTypeMapper::shouldTransformParameter(GenericEnvironment *env,
146185
SILParameterInfo param,
147-
irgen::IRGenModule &IGM) {
148-
auto newParam = getNewParameter(env, param, IGM);
186+
irgen::IRGenModule &IGM,
187+
bool useResultConvention) {
188+
auto newParam = getNewParameter(env, param, IGM, useResultConvention);
149189
return (param != newParam);
150190
}
151191

@@ -170,12 +210,13 @@ bool LargeSILTypeMapper::shouldTransformFunctionType(GenericEnvironment *env,
170210
return true;
171211

172212
for (auto param : fnType->getParameters()) {
173-
if (shouldTransformParameter(env, param, IGM))
213+
if (shouldTransformParameter(env, param, IGM,
214+
/*useResultConvention*/ false))
174215
return true;
175216
}
176217

177218
for (auto yield : fnType->getYields()) {
178-
if (shouldTransformParameter(env, yield, IGM))
219+
if (shouldTransformParameter(env, yield, IGM, /*useResultConvention*/ true))
179220
return true;
180221
}
181222

@@ -205,7 +246,7 @@ static SILType getNonOptionalType(SILType t) {
205246

206247
bool LargeSILTypeMapper::containsDifferentFunctionSignature(
207248
GenericEnvironment *genEnv, irgen::IRGenModule &Mod, SILType storageType,
208-
SILType newSILType) {
249+
SILType newSILType, bool useResultConvention) {
209250
if (storageType == newSILType) {
210251
return false;
211252
}
@@ -218,8 +259,9 @@ bool LargeSILTypeMapper::containsDifferentFunctionSignature(
218259
for (TupleTypeElt canElem : origType->getElements()) {
219260
auto origCanType = CanType(canElem.getType());
220261
auto elem = SILType::getPrimitiveObjectType(origCanType);
221-
auto newElem = getNewSILType(genEnv, elem, Mod);
222-
if (containsDifferentFunctionSignature(genEnv, Mod, elem, newElem)) {
262+
auto newElem = getNewSILType(genEnv, elem, Mod, useResultConvention);
263+
if (containsDifferentFunctionSignature(genEnv, Mod, elem, newElem,
264+
useResultConvention)) {
223265
return true;
224266
}
225267
}
@@ -384,8 +426,8 @@ static bool shouldTransformYields(GenericEnvironment *genEnv,
384426
for (auto &yield : loweredTy->getYields()) {
385427
auto yieldStorageType = yield.getSILStorageType(Mod.getSILModule(),
386428
loweredTy, expansion);
387-
auto newYieldStorageType =
388-
Mapper.getNewSILType(genEnv, yieldStorageType, Mod);
429+
auto newYieldStorageType = Mapper.getNewSILType(
430+
genEnv, yieldStorageType, Mod, /*useResultConvention*/ true);
389431
if (yieldStorageType != newYieldStorageType)
390432
return true;
391433
}
@@ -403,7 +445,8 @@ static bool modYieldType(SILFunction *F, irgen::IRGenModule &Mod,
403445

404446
SILParameterInfo LargeSILTypeMapper::getNewParameter(GenericEnvironment *env,
405447
SILParameterInfo param,
406-
irgen::IRGenModule &IGM) {
448+
irgen::IRGenModule &IGM,
449+
bool useResultConvention) {
407450
SILType storageType = param.getSILStorageInterfaceType();
408451
SILType newOptFuncType =
409452
getNewOptionalFunctionType(env, storageType, IGM);
@@ -418,7 +461,7 @@ SILParameterInfo LargeSILTypeMapper::getNewParameter(GenericEnvironment *env,
418461
} else {
419462
return param;
420463
}
421-
} else if (isLargeLoadableType(env, storageType, IGM)) {
464+
} else if (isLargeLoadableType(env, storageType, IGM, useResultConvention)) {
422465
if (param.getConvention() == ParameterConvention::Direct_Owned) {
423466
return SILParameterInfo(storageType.getASTType(),
424467
ParameterConvention::Indirect_In,
@@ -430,7 +473,7 @@ SILParameterInfo LargeSILTypeMapper::getNewParameter(GenericEnvironment *env,
430473
ParameterConvention::Indirect_In_Guaranteed,
431474
param.getOptions());
432475
} else {
433-
auto newType = getNewSILType(env, storageType, IGM);
476+
auto newType = getNewSILType(env, storageType, IGM, useResultConvention);
434477
return SILParameterInfo(newType.getASTType(), param.getConvention(),
435478
param.getOptions());
436479
}
@@ -442,7 +485,8 @@ LargeSILTypeMapper::getNewParameters(GenericEnvironment *env,
442485
irgen::IRGenModule &IGM) {
443486
SmallVector<SILParameterInfo, 4> newParams;
444487
for (SILParameterInfo param : fnType->getParameters()) {
445-
auto newParam = getNewParameter(env, param, IGM);
488+
auto newParam =
489+
getNewParameter(env, param, IGM, /*useResultConvention*/ false);
446490
newParams.push_back(newParam);
447491
}
448492
return newParams;
@@ -454,7 +498,8 @@ LargeSILTypeMapper::getNewYields(GenericEnvironment *env,
454498
irgen::IRGenModule &IGM) {
455499
SmallVector<SILYieldInfo, 2> newYields;
456500
for (auto oldYield : fnType->getYields()) {
457-
auto newYieldAsParam = getNewParameter(env, oldYield, IGM);
501+
auto newYieldAsParam =
502+
getNewParameter(env, oldYield, IGM, /*useResultConvention*/ true);
458503
newYields.push_back(SILYieldInfo(newYieldAsParam.getInterfaceType(),
459504
newYieldAsParam.getConvention()));
460505
}
@@ -464,14 +509,15 @@ LargeSILTypeMapper::getNewYields(GenericEnvironment *env,
464509
SILType LargeSILTypeMapper::getNewTupleType(GenericEnvironment *GenericEnv,
465510
irgen::IRGenModule &Mod,
466511
const SILType &nonOptionalType,
467-
const SILType &storageType) {
512+
const SILType &storageType,
513+
bool useResultConvention) {
468514
auto origType = nonOptionalType.getAs<TupleType>();
469515
assert(origType && "Expected a tuple type");
470516
SmallVector<TupleTypeElt, 2> newElems;
471517
for (TupleTypeElt canElem : origType->getElements()) {
472518
auto origCanType = CanType(canElem.getType());
473519
auto elem = SILType::getPrimitiveObjectType(origCanType);
474-
auto newElem = getNewSILType(GenericEnv, elem, Mod);
520+
auto newElem = getNewSILType(GenericEnv, elem, Mod, useResultConvention);
475521
newElems.emplace_back(newElem.getASTType(), canElem.getName());
476522
}
477523
auto type = TupleType::get(newElems, nonOptionalType.getASTContext());
@@ -491,9 +537,10 @@ SILType LargeSILTypeMapper::getNewTupleType(GenericEnvironment *GenericEnv,
491537

492538
SILType LargeSILTypeMapper::getNewSILType(GenericEnvironment *GenericEnv,
493539
SILType storageType,
494-
irgen::IRGenModule &Mod) {
540+
irgen::IRGenModule &Mod,
541+
bool useResultConvention) {
495542
// See if the type is already in the cache:
496-
auto typePair = std::make_pair(GenericEnv, storageType);
543+
NewTypeCacheKey typePair = {GenericEnv, storageType, useResultConvention};
497544
if (oldToNewTypeMap.find(typePair) != oldToNewTypeMap.end()) {
498545
return oldToNewTypeMap[typePair];
499546
}
@@ -503,11 +550,12 @@ SILType LargeSILTypeMapper::getNewSILType(GenericEnvironment *GenericEnv,
503550
nonOptionalType = optType;
504551
}
505552
if (nonOptionalType.getAs<TupleType>()) {
506-
SILType newSILType =
507-
getNewTupleType(GenericEnv, Mod, nonOptionalType, storageType);
508-
auto typeToRet = isLargeLoadableType(GenericEnv, newSILType, Mod)
509-
? newSILType.getAddressType()
510-
: newSILType;
553+
SILType newSILType = getNewTupleType(GenericEnv, Mod, nonOptionalType,
554+
storageType, useResultConvention);
555+
auto typeToRet =
556+
isLargeLoadableType(GenericEnv, newSILType, Mod, useResultConvention)
557+
? newSILType.getAddressType()
558+
: newSILType;
511559
oldToNewTypeMap[typePair] = typeToRet;
512560
return typeToRet;
513561
}
@@ -522,7 +570,8 @@ SILType LargeSILTypeMapper::getNewSILType(GenericEnvironment *GenericEnv,
522570
newSILType = SILType::getPrimitiveType(newFnType,
523571
storageType.getCategory());
524572
}
525-
} else if (isLargeLoadableType(GenericEnv, storageType, Mod)) {
573+
} else if (isLargeLoadableType(GenericEnv, storageType, Mod,
574+
useResultConvention)) {
526575
newSILType = storageType.getAddressType();
527576
}
528577
oldToNewTypeMap[typePair] = newSILType;
@@ -589,18 +638,23 @@ struct StructLoweringState {
589638
LargeSILTypeMapper &Mapper)
590639
: F(F), Mod(Mod), Mapper(Mapper) {}
591640

592-
bool isLargeLoadableType(CanSILFunctionType fnTy, SILType type) {
593-
return ::isLargeLoadableType(getSubstGenericEnvironment(fnTy), type, Mod);
641+
bool isLargeLoadableType(CanSILFunctionType fnTy, SILType type,
642+
bool useResultConvention = false) {
643+
return ::isLargeLoadableType(getSubstGenericEnvironment(fnTy), type, Mod,
644+
useResultConvention);
594645
}
595646

596-
SILType getNewSILType(CanSILFunctionType fnTy, SILType type) {
597-
return Mapper.getNewSILType(getSubstGenericEnvironment(fnTy), type, Mod);
647+
SILType getNewSILType(CanSILFunctionType fnTy, SILType type,
648+
bool useResultConvention = false) {
649+
return Mapper.getNewSILType(getSubstGenericEnvironment(fnTy), type, Mod,
650+
useResultConvention);
598651
}
599652

600-
bool containsDifferentFunctionSignature(CanSILFunctionType fnTy,
601-
SILType type) {
653+
bool containsDifferentFunctionSignature(CanSILFunctionType fnTy, SILType type,
654+
bool useResultConvention = false) {
602655
return Mapper.containsDifferentFunctionSignature(
603-
getSubstGenericEnvironment(fnTy), Mod, type, getNewSILType(fnTy, type));
656+
getSubstGenericEnvironment(fnTy), Mod, type,
657+
getNewSILType(fnTy, type, useResultConvention), useResultConvention);
604658
}
605659

606660
bool hasLargeLoadableYields() {
@@ -609,7 +663,8 @@ struct StructLoweringState {
609663

610664
auto env = getSubstGenericEnvironment(fnType);
611665
for (auto yield : fnType->getYields()) {
612-
if (Mapper.shouldTransformParameter(env, yield, Mod))
666+
if (Mapper.shouldTransformParameter(env, yield, Mod,
667+
/*useResultConvention*/ true))
613668
return true;
614669
}
615670
return false;
@@ -1227,7 +1282,8 @@ static bool isYieldUseRewritable(StructLoweringState &pass,
12271282
YieldInst *inst, Operand *operand) {
12281283
assert(inst == operand->getUser());
12291284
return pass.isLargeLoadableType(pass.F->getLoweredFunctionType(),
1230-
operand->get()->getType());
1285+
operand->get()->getType(),
1286+
/*useResultConvention*/ true);
12311287
}
12321288

12331289
/// Does the value's uses contain instructions that *must* be rewrites?
@@ -1914,14 +1970,15 @@ static void allocateAndSet(StructLoweringState &pass,
19141970
static void allocateAndSetAll(StructLoweringState &pass,
19151971
LoadableStorageAllocation &allocator,
19161972
SILInstruction *user,
1917-
MutableArrayRef<Operand> operands) {
1973+
MutableArrayRef<Operand> operands,
1974+
bool useResultConvention) {
19181975
PrettyStackTraceSILNode backtrace("Running allocateAndSetAll on ", user);
19191976

19201977
for (Operand &operand : operands) {
19211978
SILValue value = operand.get();
19221979
SILType silType = value->getType();
1923-
if (pass.isLargeLoadableType(pass.F->getLoweredFunctionType(),
1924-
silType)) {
1980+
if (pass.isLargeLoadableType(pass.F->getLoweredFunctionType(), silType,
1981+
useResultConvention)) {
19251982
allocateAndSet(pass, allocator, value, user, operand);
19261983
}
19271984
}
@@ -2100,12 +2157,14 @@ static void rewriteFunction(StructLoweringState &pass,
21002157
}
21012158
ApplySite applySite = ApplySite(applyInst);
21022159
allocateAndSetAll(pass, allocator, applyInst,
2103-
applySite.getArgumentOperands());
2160+
applySite.getArgumentOperands(),
2161+
/*useResultConvention*/ false);
21042162
}
21052163

21062164
while (!pass.modYieldInsts.empty()) {
21072165
YieldInst *inst = pass.modYieldInsts.pop_back_val();
2108-
allocateAndSetAll(pass, allocator, inst, inst->getAllOperands());
2166+
allocateAndSetAll(pass, allocator, inst, inst->getAllOperands(),
2167+
/*useResultConvention*/ true);
21092168
}
21102169

21112170
repeat = !pass.switchEnumInstsToMod.empty() ||

0 commit comments

Comments
 (0)