[OPENMP 4.0] Codegen for 'declare simd' directive.

OpenMP 4.0 adds support for elemental functions using declarative
directive '#pragma omp declare simd'. Patch adds mangling for simd
functions in accordance with
https://sourceware.org/glibc/wiki/libmvec?action=AttachFile&do=view&target=VectorABI.txt

llvm-svn: 268721
This commit is contained in:
Alexey Bataev 2016-05-06 09:40:08 +00:00
parent f578140ba6
commit c7a82b41a7
4 changed files with 522 additions and 0 deletions

View File

@ -6042,3 +6042,228 @@ void CGOpenMPRuntime::emitTargetEnterOrExitDataCall(
ThenGenRCG(CGF);
}
}
namespace {
/// Kind of parameter in a function with 'declare simd' directive.
enum ParamKindTy { LinearWithVarStride, Linear, Uniform, Vector };
/// Attribute set of the parameter.
struct ParamAttrTy {
ParamKindTy Kind = Vector;
llvm::APSInt StrideOrArg;
llvm::APSInt Alignment;
};
} // namespace
static unsigned evaluateCDTSize(const FunctionDecl *FD,
ArrayRef<ParamAttrTy> ParamAttrs) {
// Every vector variant of a SIMD-enabled function has a vector length (VLEN).
// If OpenMP clause "simdlen" is used, the VLEN is the value of the argument
// of that clause. The VLEN value must be power of 2.
// In other case the notion of the function`s "characteristic data type" (CDT)
// is used to compute the vector length.
// CDT is defined in the following order:
// a) For non-void function, the CDT is the return type.
// b) If the function has any non-uniform, non-linear parameters, then the
// CDT is the type of the first such parameter.
// c) If the CDT determined by a) or b) above is struct, union, or class
// type which is pass-by-value (except for the type that maps to the
// built-in complex data type), the characteristic data type is int.
// d) If none of the above three cases is applicable, the CDT is int.
// The VLEN is then determined based on the CDT and the size of vector
// register of that ISA for which current vector version is generated. The
// VLEN is computed using the formula below:
// VLEN = sizeof(vector_register) / sizeof(CDT),
// where vector register size specified in section 3.2.1 Registers and the
// Stack Frame of original AMD64 ABI document.
QualType RetType = FD->getReturnType();
if (RetType.isNull())
return 0;
ASTContext &C = FD->getASTContext();
QualType CDT;
if (!RetType.isNull() && !RetType->isVoidType())
CDT = RetType;
else {
unsigned Offset = 0;
if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
if (ParamAttrs[Offset].Kind == Vector)
CDT = C.getPointerType(C.getRecordType(MD->getParent()));
++Offset;
}
if (CDT.isNull()) {
for (unsigned I = 0, E = FD->getNumParams(); I < E; ++I) {
if (ParamAttrs[I + Offset].Kind == Vector) {
CDT = FD->getParamDecl(I)->getType();
break;
}
}
}
}
if (CDT.isNull())
CDT = C.IntTy;
CDT = CDT->getCanonicalTypeUnqualified();
if (CDT->isRecordType() || CDT->isUnionType())
CDT = C.IntTy;
return C.getTypeSize(CDT);
}
static void
emitX86DeclareSimdFunction(const FunctionDecl *FD, llvm::Function *Fn,
llvm::APSInt VLENVal,
ArrayRef<ParamAttrTy> ParamAttrs,
OMPDeclareSimdDeclAttr::BranchStateTy State) {
struct ISADataTy {
char ISA;
unsigned VecRegSize;
};
ISADataTy ISAData[] = {
{
'b', 128
}, // SSE
{
'c', 256
}, // AVX
{
'd', 256
}, // AVX2
{
'e', 512
}, // AVX512
};
llvm::SmallVector<char, 2> Masked;
switch (State) {
case OMPDeclareSimdDeclAttr::BS_Undefined:
Masked.push_back('N');
Masked.push_back('M');
break;
case OMPDeclareSimdDeclAttr::BS_Notinbranch:
Masked.push_back('N');
break;
case OMPDeclareSimdDeclAttr::BS_Inbranch:
Masked.push_back('M');
break;
}
for (auto Mask : Masked) {
for (auto &Data : ISAData) {
SmallString<256> Buffer;
llvm::raw_svector_ostream Out(Buffer);
Out << "_ZGV" << Data.ISA << Mask;
if (!VLENVal) {
Out << llvm::APSInt::getUnsigned(Data.VecRegSize /
evaluateCDTSize(FD, ParamAttrs));
} else
Out << VLENVal;
for (auto &ParamAttr : ParamAttrs) {
switch (ParamAttr.Kind){
case LinearWithVarStride:
Out << 's' << ParamAttr.StrideOrArg;
break;
case Linear:
Out << 'l';
if (!!ParamAttr.StrideOrArg)
Out << ParamAttr.StrideOrArg;
break;
case Uniform:
Out << 'u';
break;
case Vector:
Out << 'v';
break;
}
if (!!ParamAttr.Alignment)
Out << 'a' << ParamAttr.Alignment;
}
Out << '_' << Fn->getName();
Fn->addFnAttr(Out.str());
}
}
}
void CGOpenMPRuntime::emitDeclareSimdFunction(const FunctionDecl *FD,
llvm::Function *Fn) {
ASTContext &C = CGM.getContext();
FD = FD->getCanonicalDecl();
// Map params to their positions in function decl.
llvm::DenseMap<const Decl *, unsigned> ParamPositions;
if (isa<CXXMethodDecl>(FD))
ParamPositions.insert({FD, 0});
unsigned ParamPos = ParamPositions.size();
for (auto *P : FD->params()) {
ParamPositions.insert({P->getCanonicalDecl(), ParamPos});
++ParamPos;
}
for (auto *Attr : FD->specific_attrs<OMPDeclareSimdDeclAttr>()) {
llvm::SmallVector<ParamAttrTy, 8> ParamAttrs(ParamPositions.size());
// Mark uniform parameters.
for (auto *E : Attr->uniforms()) {
E = E->IgnoreParenImpCasts();
unsigned Pos;
if (isa<CXXThisExpr>(E))
Pos = ParamPositions[FD];
else {
auto *PVD = cast<ParmVarDecl>(cast<DeclRefExpr>(E)->getDecl())
->getCanonicalDecl();
Pos = ParamPositions[PVD];
}
ParamAttrs[Pos].Kind = Uniform;
}
// Get alignment info.
auto NI = Attr->alignments_begin();
for (auto *E : Attr->aligneds()) {
E = E->IgnoreParenImpCasts();
unsigned Pos;
QualType ParmTy;
if (isa<CXXThisExpr>(E)) {
Pos = ParamPositions[FD];
ParmTy = E->getType();
} else {
auto *PVD = cast<ParmVarDecl>(cast<DeclRefExpr>(E)->getDecl())
->getCanonicalDecl();
Pos = ParamPositions[PVD];
ParmTy = PVD->getType();
}
ParamAttrs[Pos].Alignment =
(*NI) ? (*NI)->EvaluateKnownConstInt(C)
: llvm::APSInt::getUnsigned(
C.toCharUnitsFromBits(C.getOpenMPDefaultSimdAlign(ParmTy))
.getQuantity());
++NI;
}
// Mark linear parameters.
auto SI = Attr->steps_begin();
auto MI = Attr->modifiers_begin();
for (auto *E : Attr->linears()) {
E = E->IgnoreParenImpCasts();
unsigned Pos;
if (isa<CXXThisExpr>(E))
Pos = ParamPositions[FD];
else {
auto *PVD = cast<ParmVarDecl>(cast<DeclRefExpr>(E)->getDecl())
->getCanonicalDecl();
Pos = ParamPositions[PVD];
}
auto &ParamAttr = ParamAttrs[Pos];
ParamAttr.Kind = Linear;
if (*SI) {
if (!(*SI)->EvaluateAsInt(ParamAttr.StrideOrArg, C,
Expr::SE_AllowSideEffects)) {
if (auto *DRE = cast<DeclRefExpr>((*SI)->IgnoreParenImpCasts())) {
if (auto *StridePVD = cast<ParmVarDecl>(DRE->getDecl())) {
ParamAttr.Kind = LinearWithVarStride;
ParamAttr.StrideOrArg = llvm::APSInt::getUnsigned(
ParamPositions[StridePVD->getCanonicalDecl()]);
}
}
}
}
++SI;
++MI;
}
llvm::APSInt VLENVal;
if (const Expr *VLEN = Attr->getSimdlen())
VLENVal = VLEN->EvaluateKnownConstInt(C);
OMPDeclareSimdDeclAttr::BranchStateTy State = Attr->getBranchState();
if (CGM.getTriple().getArch() == llvm::Triple::x86 ||
CGM.getTriple().getArch() == llvm::Triple::x86_64)
emitX86DeclareSimdFunction(FD, Fn, VLENVal, ParamAttrs, State);
}
}

View File

@ -1013,6 +1013,13 @@ public:
const OMPExecutableDirective &D,
const Expr *IfCond,
const Expr *Device);
/// Marks function \a Fn with properly mangled versions of vector functions.
/// \param FD Function marked as 'declare simd'.
/// \param Fn LLVM function that must be marked with 'declare simd'
/// attributes.
virtual void emitDeclareSimdFunction(const FunctionDecl *FD,
llvm::Function *Fn);
};
} // namespace CodeGen

View File

@ -710,6 +710,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
}
} else if (!FD->hasAttr<AlwaysInlineAttr>())
Fn->addFnAttr(llvm::Attribute::NoInline);
if (CGM.getLangOpts().OpenMP && FD->hasAttr<OMPDeclareSimdDeclAttr>())
CGM.getOpenMPRuntime().emitDeclareSimdFunction(FD, Fn);
}
// Add no-jump-tables value.

View File

@ -0,0 +1,288 @@
// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -x c++ -emit-llvm %s -o - -femit-all-decls | FileCheck %s
// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - -femit-all-decls | FileCheck %s
// expected-no-diagnostics
// REQUIRES: x86-registered-target
#ifndef HEADER
#define HEADER
#pragma omp declare simd linear(d : 8)
#pragma omp declare simd inbranch simdlen(32)
#pragma omp declare simd notinbranch
void add_1(float *d) {}
#pragma omp declare simd aligned(hp, hp2)
template <class C>
void h(C *hp, C *hp2, C *hq, C *lin) {
}
// Explicit specialization with <C=int>.
// Pragmas need to be same, otherwise standard says that's undefined behavior.
#pragma omp declare simd aligned(hp, hp2)
template <>
void h(int *hp, int *hp2, int *hq, int *lin) {
// Implicit specialization with <C=float>.
// This is special case where the directive is stored by Sema and is
// generated together with the (pending) function instatiation.
h((float *)hp, (float *)hp2, (float *)hq, (float *)lin);
}
class VV {
public:
#pragma omp declare simd uniform(this, a) linear(val(b) : a)
int add(int a, int b) __attribute__((cold)) { return a + b; }
#pragma omp declare simd aligned(b : 4) aligned(a) linear(ref(b) : 4) linear(this, a)
float taddpf(float *a, float *&b) { return *a + *b; }
#pragma omp declare simd linear(uval(c) : 8)
#pragma omp declare simd aligned(b : 8)
int tadd(int (&b)[], int &c) { return x[b[0]] + b[0]; }
private:
int x[10];
} vv;
template <int X, typename T>
class TVV {
public:
#pragma omp declare simd simdlen(X)
int tadd(int a, int b) { return a + b; }
#pragma omp declare simd aligned(a : X * 2) aligned(b) linear(ref(b) : X)
float taddpf(float *a, T *&b) { return *a + *b; }
#pragma omp declare simd
#pragma omp declare simd uniform(this, b)
int tadd(int b) { return x[b] + b; }
private:
int x[X];
};
#pragma omp declare simd simdlen(N) aligned(b : N * 2) linear(uval(c) : N)
template <int N>
void foo(int (&b)[N], float *&c) {}
TVV<16, float> t16;
void f(int (&g)[]) {
float a = 1.0f, b = 2.0f;
float *p = &b;
float r = t16.taddpf(&a, p);
int res = t16.tadd(b);
int c[64];
vv.add(res, res);
vv.taddpf(p, p);
vv.tadd(g, res);
foo(c, p);
}
#pragma omp declare simd
#pragma omp declare simd notinbranch aligned(a : 32)
int bar(VV v, float *a) { return 0; }
#pragma omp declare simd
#pragma omp declare simd notinbranch aligned(a)
float baz(VV v, int a[]) { return 0; }
#pragma omp declare simd
#pragma omp declare simd notinbranch aligned(a)
double bay(VV v, double *&a) { return 0; }
#pragma omp declare simd
#pragma omp declare simd inbranch linear(a : b) uniform(v, b)
void bax(VV v, double *a, int b) {}
#pragma omp declare simd uniform(q) aligned(q : 16) linear(k : 1)
float foo(float *q, float x, int k) { return 0; }
#pragma omp declare simd notinbranch
double foo(double x) { return 0; }
// CHECK-DAG: define {{.+}}@_Z5add_1Pf(
// CHECK-DAG: define {{.+}}@_Z1hIiEvPT_S1_S1_S1_(
// CHECK-DAG: define {{.+}}@_Z1hIfEvPT_S1_S1_S1_(
// CHECK-DAG: define {{.+}}@_ZN2VV3addEii(
// CHECK-DAG: define {{.+}}@_ZN2VV6taddpfEPfRS0_(
// CHECK-DAG: define {{.+}}@_ZN2VV4taddERA_iRi(
// CHECK-DAG: define {{.+}}@_Z1fRA_i(
// CHECK-DAG: define {{.+}}@_ZN3TVVILi16EfE6taddpfEPfRS1_(
// CHECK-DAG: define {{.+}}@_ZN3TVVILi16EfE4taddEi(
// CHECK-DAG: define {{.+}}@_Z3fooILi64EEvRAT__iRPf(
// CHECK-DAG: define {{.+}}@_Z3bar2VVPf(
// CHECK-DAG: define {{.+}}@_Z3baz2VVPi(
// CHECK-DAG: define {{.+}}@_Z3bay2VVRPd(
// CHECK-DAG: define {{.+}}@_Z3bax2VVPdi(
// CHECK-DAG: define {{.+}}@_Z3fooPffi(
// CHECK-DAG: define {{.+}}@_Z3food(
// CHECK-DAG: "_ZGVbM4l8__Z5add_1Pf"
// CHECK-DAG: "_ZGVbN4l8__Z5add_1Pf"
// CHECK-DAG: "_ZGVcM8l8__Z5add_1Pf"
// CHECK-DAG: "_ZGVcN8l8__Z5add_1Pf"
// CHECK-DAG: "_ZGVdM8l8__Z5add_1Pf"
// CHECK-DAG: "_ZGVdN8l8__Z5add_1Pf"
// CHECK-DAG: "_ZGVeM16l8__Z5add_1Pf"
// CHECK-DAG: "_ZGVeN16l8__Z5add_1Pf"
// CHECK-DAG: "_ZGVbM32v__Z5add_1Pf"
// CHECK-DAG: "_ZGVcM32v__Z5add_1Pf"
// CHECK-DAG: "_ZGVdM32v__Z5add_1Pf"
// CHECK-DAG: "_ZGVeM32v__Z5add_1Pf"
// CHECK-DAG: "_ZGVbN2v__Z5add_1Pf"
// CHECK-DAG: "_ZGVcN4v__Z5add_1Pf"
// CHECK-DAG: "_ZGVdN4v__Z5add_1Pf"
// CHECK-DAG: "_ZGVeN8v__Z5add_1Pf"
// CHECK-DAG: "_ZGVbM2va16va16vv__Z1hIiEvPT_S1_S1_S1_"
// CHECK-DAG: "_ZGVbN2va16va16vv__Z1hIiEvPT_S1_S1_S1_"
// CHECK-DAG: "_ZGVcM4va16va16vv__Z1hIiEvPT_S1_S1_S1_"
// CHECK-DAG: "_ZGVcN4va16va16vv__Z1hIiEvPT_S1_S1_S1_"
// CHECK-DAG: "_ZGVdM4va16va16vv__Z1hIiEvPT_S1_S1_S1_"
// CHECK-DAG: "_ZGVdN4va16va16vv__Z1hIiEvPT_S1_S1_S1_"
// CHECK-DAG: "_ZGVeM8va16va16vv__Z1hIiEvPT_S1_S1_S1_"
// CHECK-DAG: "_ZGVeN8va16va16vv__Z1hIiEvPT_S1_S1_S1_"
// CHECK-DAG: "_ZGVbM2va16va16vv__Z1hIfEvPT_S1_S1_S1_"
// CHECK-DAG: "_ZGVbN2va16va16vv__Z1hIfEvPT_S1_S1_S1_"
// CHECK-DAG: "_ZGVcM4va16va16vv__Z1hIfEvPT_S1_S1_S1_"
// CHECK-DAG: "_ZGVcN4va16va16vv__Z1hIfEvPT_S1_S1_S1_"
// CHECK-DAG: "_ZGVdM4va16va16vv__Z1hIfEvPT_S1_S1_S1_"
// CHECK-DAG: "_ZGVdN4va16va16vv__Z1hIfEvPT_S1_S1_S1_"
// CHECK-DAG: "_ZGVeM8va16va16vv__Z1hIfEvPT_S1_S1_S1_"
// CHECK-DAG: "_ZGVeN8va16va16vv__Z1hIfEvPT_S1_S1_S1_"
// CHECK-DAG: "_ZGVbM4uus1__ZN2VV3addEii"
// CHECK-DAG: "_ZGVbN4uus1__ZN2VV3addEii"
// CHECK-DAG: "_ZGVcM8uus1__ZN2VV3addEii"
// CHECK-DAG: "_ZGVcN8uus1__ZN2VV3addEii"
// CHECK-DAG: "_ZGVdM8uus1__ZN2VV3addEii"
// CHECK-DAG: "_ZGVdN8uus1__ZN2VV3addEii"
// CHECK-DAG: "_ZGVeM16uus1__ZN2VV3addEii"
// CHECK-DAG: "_ZGVeN16uus1__ZN2VV3addEii"
// CHECK-DAG: "_ZGVbM4lla16l4a4__ZN2VV6taddpfEPfRS0_"
// CHECK-DAG: "_ZGVbN4lla16l4a4__ZN2VV6taddpfEPfRS0_"
// CHECK-DAG: "_ZGVcM8lla16l4a4__ZN2VV6taddpfEPfRS0_"
// CHECK-DAG: "_ZGVcN8lla16l4a4__ZN2VV6taddpfEPfRS0_"
// CHECK-DAG: "_ZGVdM8lla16l4a4__ZN2VV6taddpfEPfRS0_"
// CHECK-DAG: "_ZGVdN8lla16l4a4__ZN2VV6taddpfEPfRS0_"
// CHECK-DAG: "_ZGVeM16lla16l4a4__ZN2VV6taddpfEPfRS0_"
// CHECK-DAG: "_ZGVeN16lla16l4a4__ZN2VV6taddpfEPfRS0_"
// CHECK-DAG: "_ZGVbM4vvl8__ZN2VV4taddERA_iRi"
// CHECK-DAG: "_ZGVbN4vvl8__ZN2VV4taddERA_iRi"
// CHECK-DAG: "_ZGVcM8vvl8__ZN2VV4taddERA_iRi"
// CHECK-DAG: "_ZGVcN8vvl8__ZN2VV4taddERA_iRi"
// CHECK-DAG: "_ZGVdM8vvl8__ZN2VV4taddERA_iRi"
// CHECK-DAG: "_ZGVdN8vvl8__ZN2VV4taddERA_iRi"
// CHECK-DAG: "_ZGVeM16vvl8__ZN2VV4taddERA_iRi"
// CHECK-DAG: "_ZGVeN16vvl8__ZN2VV4taddERA_iRi"
// CHECK-DAG: "_ZGVbM4vva8v__ZN2VV4taddERA_iRi"
// CHECK-DAG: "_ZGVbN4vva8v__ZN2VV4taddERA_iRi"
// CHECK-DAG: "_ZGVcM8vva8v__ZN2VV4taddERA_iRi"
// CHECK-DAG: "_ZGVcN8vva8v__ZN2VV4taddERA_iRi"
// CHECK-DAG: "_ZGVdM8vva8v__ZN2VV4taddERA_iRi"
// CHECK-DAG: "_ZGVdN8vva8v__ZN2VV4taddERA_iRi"
// CHECK-DAG: "_ZGVeM16vva8v__ZN2VV4taddERA_iRi"
// CHECK-DAG: "_ZGVeN16vva8v__ZN2VV4taddERA_iRi"
// CHECK-DAG: "_ZGVbM4vva32l16a16__ZN3TVVILi16EfE6taddpfEPfRS1_"
// CHECK-DAG: "_ZGVbN4vva32l16a16__ZN3TVVILi16EfE6taddpfEPfRS1_"
// CHECK-DAG: "_ZGVcM8vva32l16a16__ZN3TVVILi16EfE6taddpfEPfRS1_"
// CHECK-DAG: "_ZGVcN8vva32l16a16__ZN3TVVILi16EfE6taddpfEPfRS1_"
// CHECK-DAG: "_ZGVdM8vva32l16a16__ZN3TVVILi16EfE6taddpfEPfRS1_"
// CHECK-DAG: "_ZGVdN8vva32l16a16__ZN3TVVILi16EfE6taddpfEPfRS1_"
// CHECK-DAG: "_ZGVeM16vva32l16a16__ZN3TVVILi16EfE6taddpfEPfRS1_"
// CHECK-DAG: "_ZGVeN16vva32l16a16__ZN3TVVILi16EfE6taddpfEPfRS1_"
// CHECK-DAG: "_ZGVbM4uu__ZN3TVVILi16EfE4taddEi"
// CHECK-DAG: "_ZGVbN4uu__ZN3TVVILi16EfE4taddEi"
// CHECK-DAG: "_ZGVcM8uu__ZN3TVVILi16EfE4taddEi"
// CHECK-DAG: "_ZGVcN8uu__ZN3TVVILi16EfE4taddEi"
// CHECK-DAG: "_ZGVdM8uu__ZN3TVVILi16EfE4taddEi"
// CHECK-DAG: "_ZGVdN8uu__ZN3TVVILi16EfE4taddEi"
// CHECK-DAG: "_ZGVeM16uu__ZN3TVVILi16EfE4taddEi"
// CHECK-DAG: "_ZGVeN16uu__ZN3TVVILi16EfE4taddEi"
// CHECK-DAG: "_ZGVbM4vv__ZN3TVVILi16EfE4taddEi"
// CHECK-DAG: "_ZGVbN4vv__ZN3TVVILi16EfE4taddEi"
// CHECK-DAG: "_ZGVcM8vv__ZN3TVVILi16EfE4taddEi"
// CHECK-DAG: "_ZGVcN8vv__ZN3TVVILi16EfE4taddEi"
// CHECK-DAG: "_ZGVdM8vv__ZN3TVVILi16EfE4taddEi"
// CHECK-DAG: "_ZGVdN8vv__ZN3TVVILi16EfE4taddEi"
// CHECK-DAG: "_ZGVeM16vv__ZN3TVVILi16EfE4taddEi"
// CHECK-DAG: "_ZGVeN16vv__ZN3TVVILi16EfE4taddEi"
// CHECK-DAG: "_ZGVbM64va128l64__Z3fooILi64EEvRAT__iRPf"
// CHECK-DAG: "_ZGVbN64va128l64__Z3fooILi64EEvRAT__iRPf"
// CHECK-DAG: "_ZGVcM64va128l64__Z3fooILi64EEvRAT__iRPf"
// CHECK-DAG: "_ZGVcN64va128l64__Z3fooILi64EEvRAT__iRPf"
// CHECK-DAG: "_ZGVdM64va128l64__Z3fooILi64EEvRAT__iRPf"
// CHECK-DAG: "_ZGVdN64va128l64__Z3fooILi64EEvRAT__iRPf"
// CHECK-DAG: "_ZGVeM64va128l64__Z3fooILi64EEvRAT__iRPf"
// CHECK-DAG: "_ZGVeN64va128l64__Z3fooILi64EEvRAT__iRPf"
// CHECK-DAG: "_ZGVbM4vv__Z3bar2VVPf"
// CHECK-DAG: "_ZGVbN4vv__Z3bar2VVPf"
// CHECK-DAG: "_ZGVcM8vv__Z3bar2VVPf"
// CHECK-DAG: "_ZGVcN8vv__Z3bar2VVPf"
// CHECK-DAG: "_ZGVdM8vv__Z3bar2VVPf"
// CHECK-DAG: "_ZGVdN8vv__Z3bar2VVPf"
// CHECK-DAG: "_ZGVeM16vv__Z3bar2VVPf"
// CHECK-DAG: "_ZGVeN16vv__Z3bar2VVPf"
// CHECK-DAG: "_ZGVbN4vva32__Z3bar2VVPf"
// CHECK-DAG: "_ZGVcN8vva32__Z3bar2VVPf"
// CHECK-DAG: "_ZGVdN8vva32__Z3bar2VVPf"
// CHECK-DAG: "_ZGVeN16vva32__Z3bar2VVPf"
// CHECK-DAG: "_ZGVbM4vv__Z3baz2VVPi"
// CHECK-DAG: "_ZGVbN4vv__Z3baz2VVPi"
// CHECK-DAG: "_ZGVcM8vv__Z3baz2VVPi"
// CHECK-DAG: "_ZGVcN8vv__Z3baz2VVPi"
// CHECK-DAG: "_ZGVdM8vv__Z3baz2VVPi"
// CHECK-DAG: "_ZGVdN8vv__Z3baz2VVPi"
// CHECK-DAG: "_ZGVeM16vv__Z3baz2VVPi"
// CHECK-DAG: "_ZGVeN16vv__Z3baz2VVPi"
// CHECK-DAG: "_ZGVbN4vva16__Z3baz2VVPi"
// CHECK-DAG: "_ZGVcN8vva16__Z3baz2VVPi"
// CHECK-DAG: "_ZGVdN8vva16__Z3baz2VVPi"
// CHECK-DAG: "_ZGVeN16vva16__Z3baz2VVPi"
// CHECK-DAG: "_ZGVbM2vv__Z3bay2VVRPd"
// CHECK-DAG: "_ZGVbN2vv__Z3bay2VVRPd"
// CHECK-DAG: "_ZGVcM4vv__Z3bay2VVRPd"
// CHECK-DAG: "_ZGVcN4vv__Z3bay2VVRPd"
// CHECK-DAG: "_ZGVdM4vv__Z3bay2VVRPd"
// CHECK-DAG: "_ZGVdN4vv__Z3bay2VVRPd"
// CHECK-DAG: "_ZGVeM8vv__Z3bay2VVRPd"
// CHECK-DAG: "_ZGVeN8vv__Z3bay2VVRPd"
// CHECK-DAG: "_ZGVbN2vva16__Z3bay2VVRPd"
// CHECK-DAG: "_ZGVcN4vva16__Z3bay2VVRPd"
// CHECK-DAG: "_ZGVdN4vva16__Z3bay2VVRPd"
// CHECK-DAG: "_ZGVeN8vva16__Z3bay2VVRPd"
// CHECK-DAG: "_ZGVbM4us2u__Z3bax2VVPdi"
// CHECK-DAG: "_ZGVcM8us2u__Z3bax2VVPdi"
// CHECK-DAG: "_ZGVdM8us2u__Z3bax2VVPdi"
// CHECK-DAG: "_ZGVeM16us2u__Z3bax2VVPdi"
// CHECK-DAG: "_ZGVbM4vvv__Z3bax2VVPdi"
// CHECK-DAG: "_ZGVbN4vvv__Z3bax2VVPdi"
// CHECK-DAG: "_ZGVcM8vvv__Z3bax2VVPdi"
// CHECK-DAG: "_ZGVcN8vvv__Z3bax2VVPdi"
// CHECK-DAG: "_ZGVdM8vvv__Z3bax2VVPdi"
// CHECK-DAG: "_ZGVdN8vvv__Z3bax2VVPdi"
// CHECK-DAG: "_ZGVeM16vvv__Z3bax2VVPdi"
// CHECK-DAG: "_ZGVeN16vvv__Z3bax2VVPdi"
// CHECK-DAG: "_ZGVbM4ua16vl1__Z3fooPffi"
// CHECK-DAG: "_ZGVbN4ua16vl1__Z3fooPffi"
// CHECK-DAG: "_ZGVcM8ua16vl1__Z3fooPffi"
// CHECK-DAG: "_ZGVcN8ua16vl1__Z3fooPffi"
// CHECK-DAG: "_ZGVdM8ua16vl1__Z3fooPffi"
// CHECK-DAG: "_ZGVdN8ua16vl1__Z3fooPffi"
// CHECK-DAG: "_ZGVeM16ua16vl1__Z3fooPffi"
// CHECK-DAG: "_ZGVeN16ua16vl1__Z3fooPffi"
// CHECK-DAG: "_ZGVbN2v__Z3food"
// CHECK-DAG: "_ZGVcN4v__Z3food"
// CHECK-DAG: "_ZGVdN4v__Z3food"
// CHECK-DAG: "_ZGVeN8v__Z3food"
// CHECK-NOT: "_ZGV{{.+}}__Z1fRA_i
#endif