Skip to content

Commit 290e05c

Browse files
[WASM] Implement thin-to-thick semantic for wasm
Add indirect function call test case for WebAssembly and implement IRGen for thin-to-thick thunk emission
1 parent 50db842 commit 290e05c

File tree

13 files changed

+197
-1
lines changed

13 files changed

+197
-1
lines changed

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ CONTEXT_NODE(Structure)
200200
CONTEXT_NODE(Subscript)
201201
NODE(Suffix)
202202
NODE(ThinFunctionType)
203+
NODE(ThinToThickForwarder)
203204
NODE(Tuple)
204205
NODE(TupleElement)
205206
NODE(TupleElementName)

lib/Demangling/Context.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ bool Context::isThunkSymbol(llvm::StringRef MangledName) {
8888
MangledName = stripSuffix(MangledName);
8989
// First do a quick check
9090
if (MangledName.endswith("TA") || // partial application forwarder
91+
MangledName.endswith("Tu")|| // thin-to-thick forwarder
9192
MangledName.endswith("Ta") || // ObjC partial application forwarder
9293
MangledName.endswith("To") || // swift-as-ObjC thunk
9394
MangledName.endswith("TO") || // ObjC-as-swift thunk
@@ -107,6 +108,7 @@ bool Context::isThunkSymbol(llvm::StringRef MangledName) {
107108
case Node::Kind::NonObjCAttribute:
108109
case Node::Kind::PartialApplyObjCForwarder:
109110
case Node::Kind::PartialApplyForwarder:
111+
case Node::Kind::ThinToThickForwarder:
110112
case Node::Kind::ReabstractionThunkHelper:
111113
case Node::Kind::ReabstractionThunk:
112114
case Node::Kind::ProtocolWitness:

lib/Demangling/Demangler.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ bool swift::Demangle::isFunctionAttr(Node::Kind kind) {
113113
case Node::Kind::DirectMethodReferenceAttribute:
114114
case Node::Kind::VTableAttribute:
115115
case Node::Kind::PartialApplyForwarder:
116+
case Node::Kind::ThinToThickForwarder:
116117
case Node::Kind::PartialApplyObjCForwarder:
117118
case Node::Kind::OutlinedVariable:
118119
case Node::Kind::OutlinedBridgedMethod:
@@ -549,7 +550,8 @@ NodePointer Demangler::demangleSymbol(StringRef MangledName,
549550
while (NodePointer FuncAttr = popNode(isFunctionAttr)) {
550551
Parent->addChild(FuncAttr, *this);
551552
if (FuncAttr->getKind() == Node::Kind::PartialApplyForwarder ||
552-
FuncAttr->getKind() == Node::Kind::PartialApplyObjCForwarder)
553+
FuncAttr->getKind() == Node::Kind::PartialApplyObjCForwarder ||
554+
FuncAttr->getKind() == Node::Kind::ThinToThickForwarder)
553555
Parent = FuncAttr;
554556
}
555557
for (Node *Nd : NodeStack) {
@@ -2146,6 +2148,7 @@ NodePointer Demangler::demangleThunkOrSpecialization() {
21462148
case 'd': return createNode(Node::Kind::DirectMethodReferenceAttribute);
21472149
case 'a': return createNode(Node::Kind::PartialApplyObjCForwarder);
21482150
case 'A': return createNode(Node::Kind::PartialApplyForwarder);
2151+
case 'u': return createNode(Node::Kind::ThinToThickForwarder);
21492152
case 'm': return createNode(Node::Kind::MergedFunction);
21502153
case 'X': return createNode(Node::Kind::DynamicallyReplaceableFunctionVar);
21512154
case 'x': return createNode(Node::Kind::DynamicallyReplaceableFunctionKey);

lib/Demangling/NodePrinter.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ class NodePrinter {
466466
case Node::Kind::Subscript:
467467
case Node::Kind::Suffix:
468468
case Node::Kind::ThinFunctionType:
469+
case Node::Kind::ThinToThickForwarder:
469470
case Node::Kind::TupleElement:
470471
case Node::Kind::TypeMangling:
471472
case Node::Kind::TypeMetadata:
@@ -1207,6 +1208,14 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
12071208
Printer << "@convention(thin) ";
12081209
printFunctionType(nullptr, Node);
12091210
return nullptr;
1211+
case Node::Kind::ThinToThickForwarder:
1212+
Printer << "thin-to-thick forwarder";
1213+
1214+
if (Node->hasChildren()) {
1215+
Printer << " for ";
1216+
printChildren(Node);
1217+
}
1218+
return nullptr;
12101219
case Node::Kind::FunctionType:
12111220
case Node::Kind::UncurriedFunctionType:
12121221
printFunctionType(nullptr, Node);

lib/Demangling/OldDemangler.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,15 @@ class OldDemangler {
364364
DEMANGLE_CHILD_OR_RETURN(forwarder, Global);
365365
return forwarder;
366366
}
367+
368+
// thin-to-thick thunks.
369+
if (Mangled.nextIf("Pu")) {
370+
Node::Kind kind = Node::Kind::ThinToThickForwarder;
371+
auto forwarder = Factory.createNode(kind);
372+
if (Mangled.nextIf("__T"))
373+
DEMANGLE_CHILD_OR_RETURN(forwarder, Global);
374+
return forwarder;
375+
}
367376

368377
// Top-level types, for various consumers.
369378
if (Mangled.nextIf('t')) {

lib/Demangling/OldRemangler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,11 @@ void Remangler::mangleProtocolSelfConformanceDescriptor(Node *node) {
574574
mangleProtocol(node->begin()[0]);
575575
}
576576

577+
void Remangler::mangleThinToThickForwarder(Node *node) {
578+
Buffer << "Pu__T";
579+
mangleSingleChildNode(node); // global
580+
}
581+
577582
void Remangler::manglePartialApplyForwarder(Node *node) {
578583
Buffer << "PA__T";
579584
mangleSingleChildNode(node); // global

lib/Demangling/Remangler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1721,6 +1721,11 @@ void Remangler::mangleOwningMutableAddressor(Node *node) {
17211721
mangleAbstractStorage(node->getFirstChild(), "aO");
17221722
}
17231723

1724+
void Remangler::mangleThinToThickForwarder(Node *node) {
1725+
mangleChildNodesReversed(node);
1726+
Buffer << "Tu";
1727+
}
1728+
17241729
void Remangler::manglePartialApplyForwarder(Node *node) {
17251730
mangleChildNodesReversed(node);
17261731
Buffer << "TA";

lib/IRGen/GenFunc.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,62 @@ static unsigned findSinglePartiallyAppliedParameterIndexIgnoringEmptyTypes(
681681
return firstNonEmpty;
682682
}
683683

684+
685+
llvm::Function *irgen::getThinToThickForwarder(IRGenModule &IGM,
686+
const Optional<FunctionPointer> &staticFnPtr,
687+
const CanSILFunctionType origType) {
688+
auto origSig = IGM.getSignature(origType);
689+
llvm::FunctionType *origFnTy = origSig.getType();
690+
auto origTy = origSig.getType()->getPointerTo();
691+
692+
llvm::SmallVector<llvm::Type *, 4> thunkParams;
693+
694+
for (unsigned i = 0; i < origFnTy->getNumParams(); ++i)
695+
thunkParams.push_back(origFnTy->getParamType(i));
696+
697+
thunkParams.push_back(IGM.RefCountedPtrTy);
698+
699+
auto thunkType = llvm::FunctionType::get(origFnTy->getReturnType(),
700+
thunkParams,
701+
/*vararg*/ false);
702+
703+
StringRef FnName;
704+
if (staticFnPtr)
705+
FnName = staticFnPtr->getPointer()->getName();
706+
707+
IRGenMangler Mangler;
708+
std::string thunkName = Mangler.mangleThinToThickForwarder(FnName);
709+
710+
711+
// FIXME: Maybe cache the thunk by function and closure types?.
712+
llvm::Function *fwd =
713+
llvm::Function::Create(thunkType, llvm::Function::InternalLinkage,
714+
llvm::StringRef(thunkName), &IGM.Module);
715+
716+
fwd->setAttributes(origSig.getAttributes());
717+
fwd->addAttribute(llvm::AttributeList::FirstArgIndex + origFnTy->getNumParams(), llvm::Attribute::SwiftSelf);
718+
IRGenFunction IGF(IGM, fwd);
719+
if (IGM.DebugInfo)
720+
IGM.DebugInfo->emitArtificialFunction(IGF, fwd);
721+
auto args = IGF.collectParameters();
722+
auto rawFnPtr = args.takeLast();
723+
724+
// It comes out of the context as an i8*. Cast to the function type.
725+
rawFnPtr = IGF.Builder.CreateBitCast(rawFnPtr, origTy);
726+
727+
auto fnPtr = FunctionPointer(rawFnPtr, origSig);
728+
729+
auto result = IGF.Builder.CreateCall(fnPtr, args.claimAll());
730+
731+
// Return the result, if we have one.
732+
if (result->getType()->isVoidTy())
733+
IGF.Builder.CreateRetVoid();
734+
else
735+
IGF.Builder.CreateRet(result);
736+
return fwd;
737+
}
738+
739+
684740
/// Emit the forwarding stub function for a partial application.
685741
///
686742
/// If 'layout' is null, there is a single captured value of

lib/IRGen/GenFunc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ namespace irgen {
5454
CanSILFunctionType origType, CanSILFunctionType substType,
5555
CanSILFunctionType outType, Explosion &out, bool isOutlined);
5656

57+
58+
llvm::Function *getThinToThickForwarder(IRGenModule &IGM,
59+
const Optional<FunctionPointer> &staticFnPtr,
60+
const CanSILFunctionType origType);
5761
} // end namespace irgen
5862
} // end namespace swift
5963

lib/IRGen/IRGenMangler.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,21 @@ std::string IRGenMangler::manglePartialApplyForwarder(StringRef FuncName) {
7878
return finalize();
7979
}
8080

81+
std::string IRGenMangler::mangleThinToThickForwarder(StringRef FuncName) {
82+
if (FuncName.empty()) {
83+
beginMangling();
84+
} else {
85+
if (FuncName.startswith(MANGLING_PREFIX_STR)) {
86+
Buffer << FuncName;
87+
} else {
88+
beginMangling();
89+
appendIdentifier(FuncName);
90+
}
91+
}
92+
appendOperator("Tu");
93+
return finalize();
94+
}
95+
8196
SymbolicMangling
8297
IRGenMangler::withSymbolicReferences(IRGenModule &IGM,
8398
llvm::function_ref<void ()> body) {

lib/IRGen/IRGenMangler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ class IRGenMangler : public Mangle::ASTMangler {
492492
}
493493

494494
std::string manglePartialApplyForwarder(StringRef FuncName);
495+
std::string mangleThinToThickForwarder(StringRef FuncName);
495496

496497
std::string mangleTypeForForeignMetadataUniquing(Type type) {
497498
return mangleTypeWithoutPrefix(type);

lib/IRGen/IRGenSIL.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4691,8 +4691,61 @@ void IRGenSILFunction::visit##KIND##Inst(swift::KIND##Inst *i) { \
46914691
#include "swift/AST/ReferenceStorage.def"
46924692
#undef NOOP_CONVERSION
46934693

4694+
4695+
static FunctionPointer
4696+
getLoweredFunctionPointer(IRGenSILFunction &IGF, SILValue v) {
4697+
LoweredValue &lv = IGF.getLoweredValue(v);
4698+
auto fnType = v->getType().castTo<SILFunctionType>();
4699+
4700+
switch (lv.kind) {
4701+
case LoweredValue::Kind::ContainedAddress:
4702+
case LoweredValue::Kind::StackAddress:
4703+
case LoweredValue::Kind::DynamicallyEnforcedAddress:
4704+
case LoweredValue::Kind::OwnedAddress:
4705+
case LoweredValue::Kind::EmptyExplosion:
4706+
case LoweredValue::Kind::CoroutineState:
4707+
case LoweredValue::Kind::ObjCMethod:
4708+
llvm_unreachable("not a valid function");
4709+
4710+
case LoweredValue::Kind::FunctionPointer: {
4711+
return lv.getFunctionPointer();
4712+
}
4713+
case LoweredValue::Kind::SingletonExplosion: {
4714+
llvm::Value *fnPtr = lv.getKnownSingletonExplosion();
4715+
return FunctionPointer::forExplosionValue(IGF, fnPtr, fnType);
4716+
}
4717+
case LoweredValue::Kind::ExplosionVector: {
4718+
Explosion ex = lv.getExplosion(IGF, v->getType());
4719+
llvm::Value *fnPtr = ex.claimNext();
4720+
auto fn = FunctionPointer::forExplosionValue(IGF, fnPtr, fnType);
4721+
return fn;
4722+
}
4723+
}
4724+
llvm_unreachable("bad kind");
4725+
}
4726+
46944727
void IRGenSILFunction::visitThinToThickFunctionInst(
46954728
swift::ThinToThickFunctionInst *i) {
4729+
4730+
if (IGM.TargetInfo.OutputObjectFormat == llvm::Triple::Wasm) {
4731+
auto fn = getLoweredFunctionPointer(*this, i->getCallee());
4732+
auto fnTy = i->getCallee()->getType().castTo<SILFunctionType>();
4733+
Optional<FunctionPointer> staticFn;
4734+
if (fn.isConstant()) staticFn = fn;
4735+
auto thunkFn = getThinToThickForwarder(IGM, staticFn, fnTy);
4736+
Explosion from = getLoweredExplosion(i->getOperand());
4737+
Explosion to;
4738+
auto fnPtr = Builder.CreateBitCast(thunkFn, IGM.Int8PtrTy);
4739+
to.add(fnPtr);
4740+
llvm::Value *ctx = from.claimNext();
4741+
if (fnTy->isNoEscape())
4742+
ctx = Builder.CreateBitCast(ctx, IGM.OpaquePtrTy);
4743+
else
4744+
ctx = Builder.CreateBitCast(ctx, IGM.RefCountedPtrTy);
4745+
to.add(ctx);
4746+
setLoweredExplosion(i, to);
4747+
return;
4748+
}
46964749
// Take the incoming function pointer and add a null context pointer to it.
46974750
Explosion from = getLoweredExplosion(i->getOperand());
46984751
Explosion to;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %target-swift-frontend %s -emit-ir | %FileCheck %s
2+
3+
// REQUIRES: CPU=wasm32
4+
5+
// CHECK-LABEL: define swiftcc void @closureToConvert()
6+
// CHECK: entry:
7+
// CHECK: ret void
8+
// CHECK: }
9+
sil @closureToConvert : $@convention(thin) () -> () {
10+
%99 = tuple ()
11+
return %99 : $()
12+
}
13+
// CHECK-LABEL: define swiftcc void @testConvertFunc()
14+
// CHECK: entry:
15+
// CHECK: call swiftcc void @"$s{{.*}}Tu"(%swift.refcounted* swiftself bitcast (void ()* @closureToConvert to %swift.refcounted*))
16+
// CHECK: ret void
17+
// CHECK-LABEL: }
18+
19+
sil @testConvertFunc : $@convention(thin) () -> () {
20+
bb0:
21+
%f = function_ref @closureToConvert : $@convention(thin) () -> ()
22+
%cf = convert_function %f : $@convention(thin) () -> () to $@noescape @convention(thin) () -> ()
23+
%thick = thin_to_thick_function %cf : $@noescape @convention(thin) () -> () to $@noescape @callee_owned () -> ()
24+
%apply = apply %thick() : $@noescape @callee_owned () -> ()
25+
%99 = tuple ()
26+
return %99 : $()
27+
}
28+
29+
// CHECK-LABEL: define internal void @"$s{{.*}}Tu"(%swift.refcounted* swiftself %0)
30+
// CHECK: entry:
31+
// CHECK: %1 = bitcast %swift.refcounted* %0 to void ()*
32+
// CHECK: call swiftcc void %1()
33+
// CHECK: ret void

0 commit comments

Comments
 (0)