Author: rsmith Date: Sun Aug 14 20:33:41 2016 New Revision: 278642 URL: http://llvm.org/viewvc/llvm-project?rev=278642&view=rev Log: P0217R3: code generation support for decomposition declarations.
Added: cfe/trunk/test/CodeGenCXX/cxx1z-decomposition.cpp Modified: cfe/trunk/lib/AST/ASTContext.cpp cfe/trunk/lib/AST/ItaniumMangle.cpp cfe/trunk/lib/AST/MicrosoftMangle.cpp cfe/trunk/lib/CodeGen/CGDecl.cpp cfe/trunk/lib/CodeGen/CGExpr.cpp cfe/trunk/lib/CodeGen/CodeGenModule.cpp cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp Modified: cfe/trunk/lib/AST/ASTContext.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=278642&r1=278641&r2=278642&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp (original) +++ cfe/trunk/lib/AST/ASTContext.cpp Sun Aug 14 20:33:41 2016 @@ -8721,6 +8721,14 @@ bool ASTContext::DeclMustBeEmitted(const !VD->evaluateValue()) return true; + // Likewise, variables with tuple-like bindings are required if their + // bindings have side-effects. + if (auto *DD = dyn_cast<DecompositionDecl>(VD)) + for (auto *BD : DD->bindings()) + if (auto *BindingVD = BD->getHoldingVar()) + if (DeclMustBeEmitted(BindingVD)) + return true; + return false; } Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=278642&r1=278641&r2=278642&view=diff ============================================================================== --- cfe/trunk/lib/AST/ItaniumMangle.cpp (original) +++ cfe/trunk/lib/AST/ItaniumMangle.cpp Sun Aug 14 20:33:41 2016 @@ -1195,18 +1195,21 @@ void CXXNameMangler::mangleUnqualifiedNa case DeclarationName::Identifier: { const IdentifierInfo *II = Name.getAsIdentifierInfo(); - // We mangle decomposition declarations as the name of their first binding. + // We mangle decomposition declarations as the names of their bindings. if (auto *DD = dyn_cast<DecompositionDecl>(ND)) { - auto B = DD->bindings(); - if (B.begin() == B.end()) { - // FIXME: This is ill-formed but we accept it as an extension. - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle global empty decomposition decl"); - Diags.Report(DD->getLocation(), DiagID); - break; - } - II = (*B.begin())->getIdentifier(); + // FIXME: Non-standard mangling for decomposition declarations: + // + // <unqualified-name> ::= DC <source-name>* E + // + // These can never be referenced across translation units, so we do + // not need a cross-vendor mangling for anything other than demanglers. + // Proposed on cxx-abi-dev on 2016-08-12 + Out << "DC"; + for (auto *BD : DD->bindings()) + mangleSourceName(BD->getDeclName().getAsIdentifierInfo()); + Out << 'E'; + writeAbiTags(ND, AdditionalAbiTags); + break; } if (II) { Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=278642&r1=278641&r2=278642&view=diff ============================================================================== --- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original) +++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Sun Aug 14 20:33:41 2016 @@ -394,7 +394,8 @@ bool MicrosoftMangleContextImpl::shouldM if (!getASTContext().getLangOpts().CPlusPlus) return false; - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + const VarDecl *VD = dyn_cast<VarDecl>(D); + if (VD && !isa<DecompositionDecl>(D)) { // C variables are not mangled. if (VD->isExternC()) return false; @@ -780,6 +781,21 @@ void MicrosoftCXXNameMangler::mangleUnqu } } + if (const DecompositionDecl *DD = dyn_cast<DecompositionDecl>(ND)) { + // FIXME: Invented mangling for decomposition declarations: + // [X,Y,Z] + // where X,Y,Z are the names of the bindings. + llvm::SmallString<128> Name("["); + for (auto *BD : DD->bindings()) { + if (Name.size() > 1) + Name += ','; + Name += BD->getDeclName().getAsIdentifierInfo()->getName(); + } + Name += ']'; + mangleSourceName(Name); + break; + } + if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) { // We must have an anonymous union or struct declaration. const CXXRecordDecl *RD = VD->getType()->getAsCXXRecordDecl(); Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=278642&r1=278641&r2=278642&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGDecl.cpp (original) +++ cfe/trunk/lib/CodeGen/CGDecl.cpp Sun Aug 14 20:33:41 2016 @@ -87,6 +87,7 @@ void CodeGenFunction::EmitDecl(const Dec case Decl::UsingShadow: case Decl::ConstructorUsingShadow: case Decl::ObjCTypeParam: + case Decl::Binding: llvm_unreachable("Declaration should not be in declstmts!"); case Decl::Function: // void X(); case Decl::Record: // struct/union/class X; @@ -119,10 +120,13 @@ void CodeGenFunction::EmitDecl(const Dec const VarDecl &VD = cast<VarDecl>(D); assert(VD.isLocalVarDecl() && "Should not see file-scope variables inside a function!"); - return EmitVarDecl(VD); + EmitVarDecl(VD); + if (auto *DD = dyn_cast<DecompositionDecl>(&VD)) + for (auto *B : DD->bindings()) + if (auto *HD = B->getHoldingVar()) + EmitVarDecl(*HD); + return; } - case Decl::Binding: - return CGM.ErrorUnsupported(&D, "structured binding"); case Decl::OMPDeclareReduction: return CGM.EmitOMPDeclareReduction(cast<OMPDeclareReductionDecl>(&D), this); Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=278642&r1=278641&r2=278642&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExpr.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExpr.cpp Sun Aug 14 20:33:41 2016 @@ -2206,6 +2206,12 @@ LValue CodeGenFunction::EmitDeclRefLValu if (const auto *FD = dyn_cast<FunctionDecl>(ND)) return EmitFunctionDeclLValue(*this, E, FD); + // FIXME: While we're emitting a binding from an enclosing scope, all other + // DeclRefExprs we see should be implicitly treated as if they also refer to + // an enclosing scope. + if (const auto *BD = dyn_cast<BindingDecl>(ND)) + return EmitLValue(BD->getBinding()); + llvm_unreachable("Unhandled DeclRefExpr"); } Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=278642&r1=278641&r2=278642&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Sun Aug 14 20:33:41 2016 @@ -3772,6 +3772,10 @@ void CodeGenModule::EmitTopLevelDecl(Dec return; case Decl::VarTemplateSpecialization: EmitGlobal(cast<VarDecl>(D)); + if (auto *DD = dyn_cast<DecompositionDecl>(D)) + for (auto *B : DD->bindings()) + if (auto *HD = B->getHoldingVar()) + EmitGlobal(HD); break; // Indirect fields from global anonymous structs and unions can be Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=278642&r1=278641&r2=278642&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sun Aug 14 20:33:41 2016 @@ -1160,6 +1160,7 @@ static bool checkTupleLikeDecomposition( RefVD->setImplicit(); if (Src->isInlineSpecified()) RefVD->setInlineSpecified(); + RefVD->getLexicalDeclContext()->addHiddenDecl(RefVD); InitializedEntity Entity = InitializedEntity::InitializeBinding(RefVD); InitializationKind Kind = InitializationKind::CreateCopy(Loc, Loc); @@ -1167,11 +1168,12 @@ static bool checkTupleLikeDecomposition( E = Seq.Perform(S, Entity, Kind, Init); if (E.isInvalid()) return true; + E = S.ActOnFinishFullExpr(E.get(), Loc); + if (E.isInvalid()) + return true; RefVD->setInit(E.get()); RefVD->checkInitIsICE(); - RefVD->getLexicalDeclContext()->addHiddenDecl(RefVD); - E = S.BuildDeclarationNameExpr(CXXScopeSpec(), DeclarationNameInfo(B->getDeclName(), Loc), RefVD); Added: cfe/trunk/test/CodeGenCXX/cxx1z-decomposition.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx1z-decomposition.cpp?rev=278642&view=auto ============================================================================== --- cfe/trunk/test/CodeGenCXX/cxx1z-decomposition.cpp (added) +++ cfe/trunk/test/CodeGenCXX/cxx1z-decomposition.cpp Sun Aug 14 20:33:41 2016 @@ -0,0 +1,118 @@ +// RUN: %clang_cc1 -std=c++1z -emit-llvm -o - %s | FileCheck %s + +namespace std { + using size_t = decltype(sizeof(0)); + template<typename> struct tuple_size; + template<size_t, typename> struct tuple_element; +} + +struct Y { int n; }; +struct X { X(); X(Y); X(const X&); ~X(); }; + +struct A { int a : 13; bool b; }; + +struct B {}; +template<> struct std::tuple_size<B> { enum { value = 2 }; }; +template<> struct std::tuple_element<0,B> { using type = X; }; +template<> struct std::tuple_element<1,B> { using type = const int&; }; +template<int N> auto get(B) { + if constexpr (N == 0) + return Y(); + else + return 0.0; +} + +using C = int[2]; + +typedef int D __attribute__((ext_vector_type(2))); + +using E = _Complex int; + +template<typename T> T &make(); + +// CHECK: @_ZDC2a12a2E = global {{.*}} zeroinitializer, align 4 +auto [a1, a2] = make<A>(); +// CHECK: @_ZDC2b12b2E = global {{.*}} zeroinitializer, align 1 +// CHECK: @b1 = global {{.*}}* null, align 8 +// CHECK: @_ZGR2b1_ = internal global {{.*}} zeroinitializer, align 1 +// CHECK: @b2 = global i32* null, align 8 +// CHECK: @_ZGR2b2_ = internal global i32 0, align 4 +auto [b1, b2] = make<B>(); +// CHECK: @_ZDC2c12c2E = global [2 x i32]* null, align 8 +auto &[c1, c2] = make<C>(); +// CHECK: @_ZDC2d12d2E = global <2 x i32> zeroinitializer, align 8 +auto [d1, d2] = make<D>(); +// CHECK: @_ZDC2e12e2E = global { i32, i32 } zeroinitializer, align 4 +auto [e1, e2] = make<E>(); + +// CHECK: call {{.*}}* @_Z4makeI1AERT_v() +// CHECK: call {{.*}}memcpy{{.*}}@_ZDC2a12a2E + +// CHECK: @_Z4makeI1BERT_v() +// CHECK: call i32 @_Z3getILi0EEDa1B() +// CHECK: call void @_ZN1XC1E1Y({{.*}}* @_ZGR2b1_, i32 +// CHECK: call i32 @__cxa_atexit({{.*}}@_ZN1XD1Ev{{.*}}@_ZGR2b1_ +// CHECK: store {{.*}}* @_ZGR2b1_, +// +// CHECK: call double @_Z3getILi1EEDa1B() +// CHECK: fptosi double %{{.*}} to i32 +// CHECK: store i32 %{{.*}}, i32* @_ZGR2b2_ +// CHECK: store i32* @_ZGR2b2_, i32** @b2 + +// CHECK: call {{.*}}* @_Z4makeIA2_iERT_v() +// CHECK: store {{.*}}, [2 x i32]** @_ZDC2c12c2E + +// CHECK: call {{.*}}* @_Z4makeIDv2_iERT_v() +// CHECK: store {{.*}}, <2 x i32>* @_ZDC2d12d2E, align 8 + +// CHECK: call {{.*}}* @_Z4makeICiERT_v() +// CHECK: store i32 %{{.*}}, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @_ZDC2e12e2E, i32 0, i32 0) +// CHECK: store i32 %{{.*}}, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @_ZDC2e12e2E, i32 0, i32 1) + +// CHECK: define i32 @_Z12test_globalsv() +int test_globals() { + return a2 + b2 + c2 + d2 + e2; + // CHECK: load i8, i8* getelementptr inbounds (%struct.A, %struct.A* @_ZDC2a12a2E, i32 0, i32 1) + // + // CHECK: %[[b2:.*]] = load i32*, i32** @b2 + // CHECK: load i32, i32* %[[b2]] + // + // CHECK: %[[c1c2:.*]] = load [2 x i32]*, [2 x i32]** @_ZDC2c12c2E + // CHECK: %[[c2:.*]] = getelementptr inbounds [2 x i32], [2 x i32]* %[[c1c2]], i64 0, i64 1 + // CHECK: load i32, i32* %[[c2]] + // + // CHECK: %[[d1d2:.*]] = load <2 x i32>, <2 x i32>* @_ZDC2d12d2E + // CHECK: extractelement <2 x i32> %[[d1d2]], i32 1 + // + // CHECK: load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @_ZDC2e12e2E, i32 0, i32 1) +} + +// CHECK: define i32 @_Z11test_localsv() +int test_locals() { + auto [b1, b2] = make<B>(); + + // CHECK: @_Z4makeI1BERT_v() + // CHECK: call i32 @_Z3getILi0EEDa1B() + // CHECK: call void @_ZN1XC1E1Y({{.*}}* %[[b1:.*]], i32 + // + // CHECK: call double @_Z3getILi1EEDa1B() + // CHECK: %[[cvt:.*]] = fptosi double %{{.*}} to i32 + // CHECK: store i32 %[[cvt]], i32* %[[b2:.*]], + // CHECK: store i32* %[[b2]], i32** %[[b2ref:.*]], + + return b2; + // CHECK: %[[b2:.*]] = load i32*, i32** %[[b2ref]] + // CHECK: load i32, i32* %[[b2]] + + // CHECK: call {{.*}}@_ZN1XD1Ev({{.*}}%[[b1]]) +} + +// CHECK: define void @_Z13test_bitfieldR1A( +void test_bitfield(A &a) { + auto &[a1, a2] = a; + a1 = 5; + // CHECK: load i16, i16* %[[BITFIELD:.*]], + // CHECK: and i16 %{{.*}}, -8192 + // CHECK: or i16 %{{.*}}, 5 + // CHECK: store i16 %{{.*}}, i16* %[[BITFIELD]], +} Modified: cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp?rev=278642&r1=278641&r2=278642&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp (original) +++ cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp Sun Aug 14 20:33:41 2016 @@ -38,4 +38,3 @@ constexpr bool g(S &&s) { static_assert(g({1, 2})); // FIXME: by-value array copies -// FIXME: code generation _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits