erichkeane created this revision. erichkeane added reviewers: rjmccall, aaron.ballman. Herald added subscribers: mgrang, kristof.beyls. erichkeane requested review of this revision.
As described here: https://devblogs.microsoft.com/oldnewthing/20150220-00/?p=44623 In order to allow Lambdas to be used with traditional Win32 APIs, they emit a conversion function for (what Raymond Chen claims is all) a number of the calling conventions. Through experimentation, we discovered that the list isn't quite 'all'. This patch implements this by taking the list of conversions that MSVC emits (across 'all' architectures, I don't see any CCs on ARM), then emits them if they are supported by the current target. However, we also add 3 other options (which may be duplicates): free-function, member-function, and operator() calling conventions. We do this because we have an extension where we generate both free and member for these cases so th at people specifying a calling convention on the lambda will have the expected behavior when specifying one of those two. MSVC doesn't seem to permit specifying calling-convention on lambdas, but we do, so we need to make sure those are emitted as well. We do this so that clang-only conventions are supported if the user specifies them. https://reviews.llvm.org/D90634 Files: clang/lib/Sema/SemaLambda.cpp clang/test/CodeGenCXX/lambda-conversion-op-cc.cpp
Index: clang/test/CodeGenCXX/lambda-conversion-op-cc.cpp =================================================================== --- clang/test/CodeGenCXX/lambda-conversion-op-cc.cpp +++ clang/test/CodeGenCXX/lambda-conversion-op-cc.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,LIN64 // RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-linux-gnu -DCC="__attribute__((vectorcall))" | FileCheck %s --check-prefixes=CHECK,VECCALL -// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-windows-pc -DWIN32 | FileCheck %s --check-prefixes=WIN32 +// RUN: %clang_cc1 -emit-llvm %s -o - -fms-compatibility -triple=i386-windows-pc -DWIN32 | FileCheck %s --check-prefixes=WIN32 #ifndef CC #define CC @@ -10,20 +10,31 @@ auto lambda = [](int i, float f, double d) CC { return i + f + d; }; double (*CC fp)(int, float, double) = lambda; - fp(0, 1.1, 2.2); #ifdef WIN32 double (*__attribute__((thiscall)) fp2)(int, float, double) = lambda; + double (*__attribute__((stdcall)) fp3)(int, float, double) = lambda; + double (*__attribute__((fastcall)) fp4)(int, float, double) = lambda; + double (*__attribute__((vectorcall)) fp5)(int, float, double) = lambda; +#endif // WIN32 + fp(0, 1.1, 2.2); +#ifdef WIN32 fp2(0, 1.1, 2.2); + fp3(0, 1.1, 2.2); + fp4(0, 1.1, 2.2); + fp5(0, 1.1, 2.2); #endif // WIN32 } -// void usage function, calls convrsion operator. +// void usage function, calls conversion operator. // LIN64: define void @_Z5usagev() // VECCALL: define void @_Z5usagev() // WIN32: define dso_local void @"?usage@@YAXXZ"() // CHECK: call double (i32, float, double)* @"_ZZ5usagevENK3$_0cvPFdifdEEv" // WIN32: call x86_thiscallcc double (i32, float, double)* @"??B<lambda_0>@?0??usage@@YAXXZ@QBEP6A?A?<auto>@@HMN@ZXZ" // WIN32: call x86_thiscallcc double (i32, float, double)* @"??B<lambda_0>@?0??usage@@YAXXZ@QBEP6E?A?<auto>@@HMN@ZXZ" +// WIN32: call x86_thiscallcc double (i32, float, double)* @"??B<lambda_0>@?0??usage@@YAXXZ@QBEP6G?A?<auto>@@HMN@ZXZ" +// WIN32: call x86_thiscallcc double (i32, float, double)* @"??B<lambda_0>@?0??usage@@YAXXZ@QBEP6I?A?<auto>@@HMN@ZXZ" +// WIN32: call x86_thiscallcc double (i32, float, double)* @"??B<lambda_0>@?0??usage@@YAXXZ@QBEP6Q?A?<auto>@@HMN@ZXZ" // // Conversion operator, returns __invoke. // CHECK: define internal double (i32, float, double)* @"_ZZ5usagevENK3$_0cvPFdifdEEv" @@ -32,6 +43,12 @@ // WIN32: ret double (i32, float, double)* @"?__invoke@<lambda_0>@?0??usage@@YAXXZ@CA?A?<auto>@@HMN@Z" // WIN32: define internal x86_thiscallcc double (i32, float, double)* @"??B<lambda_0>@?0??usage@@YAXXZ@QBEP6E?A?<auto>@@HMN@ZXZ" // WIN32: ret double (i32, float, double)* @"?__invoke@<lambda_0>@?0??usage@@YAXXZ@CE?A?<auto>@@HMN@Z" +// WIN32: define internal x86_thiscallcc double (i32, float, double)* @"??B<lambda_0>@?0??usage@@YAXXZ@QBEP6G?A?<auto>@@HMN@ZXZ" +// WIN32: ret double (i32, float, double)* @"?__invoke@<lambda_0>@?0??usage@@YAXXZ@CG?A?<auto>@@HMN@Z" +// WIN32: define internal x86_thiscallcc double (i32, float, double)* @"??B<lambda_0>@?0??usage@@YAXXZ@QBEP6I?A?<auto>@@HMN@ZXZ" +// WIN32: ret double (i32, float, double)* @"?__invoke@<lambda_0>@?0??usage@@YAXXZ@CI?A?<auto>@@HMN@Z" +// WIN32: define internal x86_thiscallcc double (i32, float, double)* @"??B<lambda_0>@?0??usage@@YAXXZ@QBEP6Q?A?<auto>@@HMN@ZXZ" +// WIN32: ret double (i32, float, double)* @"?__invoke@<lambda_0>@?0??usage@@YAXXZ@CQ?A?<auto>@@HMN@Z" // // __invoke function, calls operator(). Win32 should call both. // LIN64: define internal double @"_ZZ5usagevEN3$_08__invokeEifd" @@ -42,3 +59,9 @@ // WIN32: call x86_thiscallcc double @"??R<lambda_0>@?0??usage@@YAXXZ@QBE?A?<auto>@@HMN@Z" // WIN32: define internal x86_thiscallcc double @"?__invoke@<lambda_0>@?0??usage@@YAXXZ@CE?A?<auto>@@HMN@Z" // WIN32: call x86_thiscallcc double @"??R<lambda_0>@?0??usage@@YAXXZ@QBE?A?<auto>@@HMN@Z" +// WIN32: define internal x86_stdcallcc double @"?__invoke@<lambda_0>@?0??usage@@YAXXZ@CG?A?<auto>@@HMN@Z" +// WIN32: call x86_thiscallcc double @"??R<lambda_0>@?0??usage@@YAXXZ@QBE?A?<auto>@@HMN@Z" +// WIN32: define internal x86_fastcallcc double @"?__invoke@<lambda_0>@?0??usage@@YAXXZ@CI?A?<auto>@@HMN@Z" +// WIN32: call x86_thiscallcc double @"??R<lambda_0>@?0??usage@@YAXXZ@QBE?A?<auto>@@HMN@Z" +// WIN32: define internal x86_vectorcallcc double @"?__invoke@<lambda_0>@?0??usage@@YAXXZ@CQ?A?<auto>@@HMN@Z" +// WIN32: call x86_thiscallcc double @"??R<lambda_0>@?0??usage@@YAXXZ@QBE?A?<auto>@@HMN@Z" Index: clang/lib/Sema/SemaLambda.cpp =================================================================== --- clang/lib/Sema/SemaLambda.cpp +++ clang/lib/Sema/SemaLambda.cpp @@ -1272,6 +1272,29 @@ CallOpProto.isVariadic(), /*IsCXXMethod=*/true); CallingConv CallOpCC = CallOpProto.getCallConv(); + /// Implement emitting a version of the operator for many of the calling + /// conventions for MSVC, as described here: + /// https://devblogs.microsoft.com/oldnewthing/20150220-00/?p=44623. + /// Experimentally, we determined that cdecl, stdcall, fastcall, and + /// vectorcall are generated by MSVC when it is supported by the target. + /// Additionally, we are ensuring that the default-free/default-member and + /// call-operator calling convention are generated as well. + if (S.getLangOpts().MSVCCompat) { + CallingConv Convs[] = { + CC_C, CC_X86StdCall, CC_X86FastCall, CC_X86VectorCall, + DefaultFree, DefaultMember, CallOpCC}; + llvm::sort(Convs); + llvm::iterator_range<CallingConv *> Range( + std::begin(Convs), std::unique(std::begin(Convs), std::end(Convs))); + const TargetInfo &TI = S.getASTContext().getTargetInfo(); + + for (CallingConv C : Range) { + if (TI.checkCallingConvention(C) == TargetInfo::CCCR_OK) + F(C); + } + return; + } + if (CallOpCC == DefaultMember && DefaultMember != DefaultFree) { F(DefaultFree); F(DefaultMember); @@ -1475,9 +1498,6 @@ /// C++11 [expr.prim.lambda]p6. Note that in most cases, this should emit only a /// single pointer conversion. In the event that the default calling convention /// for free and member functions is different, it will emit both conventions. -/// FIXME: Implement emitting a version of the operator for EVERY calling -/// convention for MSVC, as described here: -/// https://devblogs.microsoft.com/oldnewthing/20150220-00/?p=44623. static void addFunctionPointerConversions(Sema &S, SourceRange IntroducerRange, CXXRecordDecl *Class, CXXMethodDecl *CallOperator) {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits