Code reformatting and improvement for OpenMP.

Moved CGOpenMPRegionInfo from CGOpenMPRuntime.h to CGOpenMPRuntime.cpp file and reworked the code for this change. Also added processing of ThreadID variable passed as an argument in outlined functions in parallel and task directives.

llvm-svn: 219490
This commit is contained in:
Alexey Bataev 2014-10-10 12:19:54 +00:00
parent 1a8093c3a7
commit 1809571c76
5 changed files with 148 additions and 108 deletions

View File

@ -13,6 +13,7 @@
#include "CGOpenMPRuntime.h" #include "CGOpenMPRuntime.h"
#include "CodeGenFunction.h" #include "CodeGenFunction.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/Decl.h" #include "clang/AST/Decl.h"
#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/ArrayRef.h"
#include "llvm/IR/DerivedTypes.h" #include "llvm/IR/DerivedTypes.h"
@ -24,6 +25,49 @@
using namespace clang; using namespace clang;
using namespace CodeGen; using namespace CodeGen;
/// \brief API for captured statement code generation in OpenMP constructs.
class CGOpenMPRegionInfo : public CodeGenFunction::CGCapturedStmtInfo {
public:
CGOpenMPRegionInfo(const OMPExecutableDirective &D, const CapturedStmt &CS,
const VarDecl *ThreadIDVar)
: CGCapturedStmtInfo(CS, CR_OpenMP), ThreadIDVar(ThreadIDVar),
Directive(D) {
assert(ThreadIDVar != nullptr && "No ThreadID in OpenMP region.");
}
virtual ~CGOpenMPRegionInfo() override{};
/// \brief Gets a variable or parameter for storing global thread id
/// inside OpenMP construct.
const VarDecl *getThreadIDVariable() const { return ThreadIDVar; }
/// \brief Gets an LValue for the current ThreadID variable.
LValue getThreadIDVariableLValue(CodeGenFunction &CGF);
static bool classof(const CGCapturedStmtInfo *Info) {
return Info->getKind() == CR_OpenMP;
}
/// \brief Emit the captured statement body.
virtual void EmitBody(CodeGenFunction &CGF, Stmt *S) override;
/// \brief Get the name of the capture helper.
virtual StringRef getHelperName() const override { return ".omp_outlined."; }
private:
/// \brief A variable or parameter storing global thread id for OpenMP
/// constructs.
const VarDecl *ThreadIDVar;
/// \brief OpenMP executable directive associated with the region.
const OMPExecutableDirective &Directive;
};
LValue CGOpenMPRegionInfo::getThreadIDVariableLValue(CodeGenFunction &CGF) {
return CGF.MakeNaturalAlignAddrLValue(
CGF.GetAddrOfLocalVar(ThreadIDVar),
CGF.getContext().getPointerType(ThreadIDVar->getType()));
}
void CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, Stmt *S) { void CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, Stmt *S) {
CodeGenFunction::OMPPrivateScope PrivateScope(CGF); CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
CGF.EmitOMPFirstprivateClause(Directive, PrivateScope); CGF.EmitOMPFirstprivateClause(Directive, PrivateScope);
@ -51,6 +95,16 @@ CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)
KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8); KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8);
} }
llvm::Value *
CGOpenMPRuntime::EmitOpenMPOutlinedFunction(const OMPExecutableDirective &D,
const VarDecl *ThreadIDVar) {
const CapturedStmt *CS = cast<CapturedStmt>(D.getAssociatedStmt());
CodeGenFunction CGF(CGM, true);
CGOpenMPRegionInfo CGInfo(D, *CS, ThreadIDVar);
CGF.CapturedStmtInfo = &CGInfo;
return CGF.GenerateCapturedStmtFunction(*CS);
}
llvm::Value * llvm::Value *
CGOpenMPRuntime::GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags) { CGOpenMPRuntime::GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags) {
llvm::Value *Entry = OpenMPDefaultLocMap.lookup(Flags); llvm::Value *Entry = OpenMPDefaultLocMap.lookup(Flags);
@ -92,14 +146,15 @@ llvm::Value *CGOpenMPRuntime::EmitOpenMPUpdateLocation(
assert(CGF.CurFn && "No function in current CodeGenFunction."); assert(CGF.CurFn && "No function in current CodeGenFunction.");
llvm::Value *LocValue = nullptr; llvm::Value *LocValue = nullptr;
OpenMPLocMapTy::iterator I = OpenMPLocMap.find(CGF.CurFn); OpenMPLocThreadIDMapTy::iterator I = OpenMPLocThreadIDMap.find(CGF.CurFn);
if (I != OpenMPLocMap.end()) { if (I != OpenMPLocThreadIDMap.end()) {
LocValue = I->second; LocValue = I->second.DebugLoc;
} else { } else {
// Generate "ident_t .kmpc_loc.addr;" // Generate "ident_t .kmpc_loc.addr;"
llvm::AllocaInst *AI = CGF.CreateTempAlloca(IdentTy, ".kmpc_loc.addr"); llvm::AllocaInst *AI = CGF.CreateTempAlloca(IdentTy, ".kmpc_loc.addr");
AI->setAlignment(CGM.getDataLayout().getPrefTypeAlignment(IdentTy)); AI->setAlignment(CGM.getDataLayout().getPrefTypeAlignment(IdentTy));
OpenMPLocMap[CGF.CurFn] = AI; auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn);
Elem.second.DebugLoc = AI;
LocValue = AI; LocValue = AI;
CGBuilderTy::InsertPointGuard IPG(CGF.Builder); CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
@ -139,46 +194,46 @@ llvm::Value *CGOpenMPRuntime::GetOpenMPThreadID(CodeGenFunction &CGF,
assert(CGF.CurFn && "No function in current CodeGenFunction."); assert(CGF.CurFn && "No function in current CodeGenFunction.");
llvm::Value *ThreadID = nullptr; llvm::Value *ThreadID = nullptr;
OpenMPThreadIDMapTy::iterator I = OpenMPThreadIDMap.find(CGF.CurFn); // Check whether we've already cached a load of the thread id in this
if (I != OpenMPThreadIDMap.end()) { // function.
ThreadID = I->second; OpenMPLocThreadIDMapTy::iterator I = OpenMPLocThreadIDMap.find(CGF.CurFn);
} else { if (I != OpenMPLocThreadIDMap.end()) {
// Check if current function is a function which has first parameter ThreadID = I->second.ThreadID;
// with type int32 and name ".global_tid.". } else if (auto OMPRegionInfo =
if (!CGF.CurFn->arg_empty() && dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
CGF.CurFn->arg_begin()->getType()->isPointerTy() && // Check if this an outlined function with thread id passed as argument.
CGF.CurFn->arg_begin() auto ThreadIDVar = OMPRegionInfo->getThreadIDVariable();
->getType() auto LVal = OMPRegionInfo->getThreadIDVariableLValue(CGF);
->getPointerElementType() auto RVal = CGF.EmitLoadOfLValue(LVal, Loc);
->isIntegerTy() && LVal = CGF.MakeNaturalAlignAddrLValue(RVal.getScalarVal(),
CGF.CurFn->arg_begin() ThreadIDVar->getType());
->getType() ThreadID = CGF.EmitLoadOfLValue(LVal, Loc).getScalarVal();
->getPointerElementType() // If value loaded in entry block, cache it and use it everywhere in
->getIntegerBitWidth() == 32 && // function.
CGF.CurFn->arg_begin()->hasName() && if (CGF.Builder.GetInsertBlock() == CGF.AllocaInsertPt->getParent()) {
CGF.CurFn->arg_begin()->getName() == ".global_tid.") { auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn);
CGBuilderTy::InsertPointGuard IPG(CGF.Builder); Elem.second.ThreadID = ThreadID;
CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
ThreadID = CGF.Builder.CreateLoad(CGF.CurFn->arg_begin());
} else {
// Generate "int32 .kmpc_global_thread_num.addr;"
CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc)};
ThreadID = CGF.EmitRuntimeCall(
CreateRuntimeFunction(OMPRTL__kmpc_global_thread_num), Args);
} }
OpenMPThreadIDMap[CGF.CurFn] = ThreadID; } else {
// This is not an outlined function region - need to call __kmpc_int32
// kmpc_global_thread_num(ident_t *loc).
// Generate thread id value and cache this value for use across the
// function.
CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc)};
ThreadID = CGF.EmitRuntimeCall(
CreateRuntimeFunction(OMPRTL__kmpc_global_thread_num), Args);
auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn);
Elem.second.ThreadID = ThreadID;
} }
return ThreadID; return ThreadID;
} }
void CGOpenMPRuntime::FunctionFinished(CodeGenFunction &CGF) { void CGOpenMPRuntime::FunctionFinished(CodeGenFunction &CGF) {
assert(CGF.CurFn && "No function in current CodeGenFunction."); assert(CGF.CurFn && "No function in current CodeGenFunction.");
if (OpenMPThreadIDMap.count(CGF.CurFn)) if (OpenMPLocThreadIDMap.count(CGF.CurFn))
OpenMPThreadIDMap.erase(CGF.CurFn); OpenMPLocThreadIDMap.erase(CGF.CurFn);
if (OpenMPLocMap.count(CGF.CurFn))
OpenMPLocMap.erase(CGF.CurFn);
} }
llvm::Type *CGOpenMPRuntime::getIdentTyPointerTy() { llvm::Type *CGOpenMPRuntime::getIdentTyPointerTy() {

View File

@ -14,49 +14,29 @@
#ifndef LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIME_H #ifndef LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIME_H
#define LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIME_H #define LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIME_H
#include "CodeGenFunction.h" #include "clang/Basic/SourceLocation.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h" namespace llvm {
class ArrayType;
class Constant;
class Function;
class FunctionType;
class StructType;
class Type;
class Value;
} // namespace llvm
namespace clang { namespace clang {
class OMPExecutableDirective;
class VarDecl;
namespace CodeGen { namespace CodeGen {
/// \brief API for captured statement code generation in OpenMP constructs. class CodeGenFunction;
class CGOpenMPRegionInfo : public CodeGenFunction::CGCapturedStmtInfo { class CodeGenModule;
public:
CGOpenMPRegionInfo(const OMPExecutableDirective &D, const CapturedStmt &S,
const VarDecl *ThreadIDVar)
: CGCapturedStmtInfo(S, CR_OpenMP), ThreadIDVar(ThreadIDVar),
Directive(D) {}
virtual ~CGOpenMPRegionInfo() override{};
/// \brief Gets a variable or parameter for storing global thread id
/// inside OpenMP construct.
const VarDecl *getThreadIDVariable() const { return ThreadIDVar; }
static bool classof(const CGCapturedStmtInfo *Info) {
return Info->getKind() == CR_OpenMP;
}
/// \brief Emit the captured statement body.
virtual void EmitBody(CodeGenFunction &CGF, Stmt *S) override;
/// \brief Get the name of the capture helper.
virtual StringRef getHelperName() const override { return ".omp_outlined."; }
private:
/// \brief A variable or parameter storing global thread id for OpenMP
/// constructs.
const VarDecl *ThreadIDVar;
/// \brief OpenMP executable directive associated with the region.
const OMPExecutableDirective &Directive;
};
class CGOpenMPRuntime { class CGOpenMPRuntime {
public: public:
@ -102,7 +82,7 @@ private:
/// \brief Default const ident_t object used for initialization of all other /// \brief Default const ident_t object used for initialization of all other
/// ident_t objects. /// ident_t objects.
llvm::Constant *DefaultOpenMPPSource; llvm::Constant *DefaultOpenMPPSource;
/// \brief Map of flags and corrsponding default locations. /// \brief Map of flags and corresponding default locations.
typedef llvm::DenseMap<unsigned, llvm::Value *> OpenMPDefaultLocMapTy; typedef llvm::DenseMap<unsigned, llvm::Value *> OpenMPDefaultLocMapTy;
OpenMPDefaultLocMapTy OpenMPDefaultLocMap; OpenMPDefaultLocMapTy OpenMPDefaultLocMap;
llvm::Value *GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags); llvm::Value *GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags);
@ -147,19 +127,22 @@ private:
IdentField_PSource IdentField_PSource
}; };
llvm::StructType *IdentTy; llvm::StructType *IdentTy;
/// \brief Map for Sourcelocation and OpenMP runtime library debug locations. /// \brief Map for SourceLocation and OpenMP runtime library debug locations.
typedef llvm::DenseMap<unsigned, llvm::Value *> OpenMPDebugLocMapTy; typedef llvm::DenseMap<unsigned, llvm::Value *> OpenMPDebugLocMapTy;
OpenMPDebugLocMapTy OpenMPDebugLocMap; OpenMPDebugLocMapTy OpenMPDebugLocMap;
/// \brief The type for a microtask which gets passed to __kmpc_fork_call(). /// \brief The type for a microtask which gets passed to __kmpc_fork_call().
/// Original representation is: /// Original representation is:
/// typedef void (kmpc_micro)(kmp_int32 global_tid, kmp_int32 bound_tid,...); /// typedef void (kmpc_micro)(kmp_int32 global_tid, kmp_int32 bound_tid,...);
llvm::FunctionType *Kmpc_MicroTy; llvm::FunctionType *Kmpc_MicroTy;
/// \brief Map of local debug location and functions. /// \brief Stores debug location and ThreadID for the function.
typedef llvm::DenseMap<llvm::Function *, llvm::Value *> OpenMPLocMapTy; struct DebugLocThreadIdTy {
OpenMPLocMapTy OpenMPLocMap; llvm::Value *DebugLoc;
/// \brief Map of local ThreadID and functions. llvm::Value *ThreadID;
typedef llvm::DenseMap<llvm::Function *, llvm::Value *> OpenMPThreadIDMapTy; };
OpenMPThreadIDMapTy OpenMPThreadIDMap; /// \brief Map of local debug location, ThreadId and functions.
typedef llvm::DenseMap<llvm::Function *, DebugLocThreadIdTy>
OpenMPLocThreadIDMapTy;
OpenMPLocThreadIDMapTy OpenMPLocThreadIDMap;
/// \brief Type kmp_critical_name, originally defined as typedef kmp_int32 /// \brief Type kmp_critical_name, originally defined as typedef kmp_int32
/// kmp_critical_name[8]; /// kmp_critical_name[8];
llvm::ArrayType *KmpCriticalNameTy; llvm::ArrayType *KmpCriticalNameTy;
@ -167,8 +150,6 @@ private:
llvm::StringMap<llvm::Value *, llvm::BumpPtrAllocator> CriticalRegionVarNames; llvm::StringMap<llvm::Value *, llvm::BumpPtrAllocator> CriticalRegionVarNames;
/// \brief Emits object of ident_t type with info for source location. /// \brief Emits object of ident_t type with info for source location.
/// \param CGF Reference to current CodeGenFunction.
/// \param Loc Clang source location.
/// \param Flags Flags for OpenMP location. /// \param Flags Flags for OpenMP location.
/// ///
llvm::Value * llvm::Value *
@ -187,8 +168,6 @@ private:
llvm::Constant *CreateRuntimeFunction(OpenMPRTLFunction Function); llvm::Constant *CreateRuntimeFunction(OpenMPRTLFunction Function);
/// \brief Gets thread id value for the current thread. /// \brief Gets thread id value for the current thread.
/// \param CGF Reference to current CodeGenFunction.
/// \param Loc Clang source location.
/// ///
llvm::Value *GetOpenMPThreadID(CodeGenFunction &CGF, SourceLocation Loc); llvm::Value *GetOpenMPThreadID(CodeGenFunction &CGF, SourceLocation Loc);
@ -196,16 +175,25 @@ public:
explicit CGOpenMPRuntime(CodeGenModule &CGM); explicit CGOpenMPRuntime(CodeGenModule &CGM);
virtual ~CGOpenMPRuntime() {} virtual ~CGOpenMPRuntime() {}
/// \brief Emits outlined function for the specified OpenMP directive \a D
/// (required for parallel and task directives). This outlined function has
/// type void(*)(kmp_int32 /*ThreadID*/, kmp_int32 /*BoundID*/, struct
/// context_vars*).
/// \param D OpenMP directive.
/// \param ThreadIDVar Variable for thread id in the current OpenMP region.
///
virtual llvm::Value *
EmitOpenMPOutlinedFunction(const OMPExecutableDirective &D,
const VarDecl *ThreadIDVar);
/// \brief Cleans up references to the objects in finished function. /// \brief Cleans up references to the objects in finished function.
/// \param CGF Reference to finished CodeGenFunction.
/// ///
void FunctionFinished(CodeGenFunction &CGF); void FunctionFinished(CodeGenFunction &CGF);
/// \brief Emits code for parallel call of the \a OutlinedFn with variables /// \brief Emits code for parallel call of the \a OutlinedFn with variables
/// captured in a record which address is stored in \a CapturedStruct. /// captured in a record which address is stored in \a CapturedStruct.
/// \param CGF Reference to current CodeGenFunction. /// \param OutlinedFn Outlined function to be run in parallel threads. Type of
/// \param Loc Clang source location. /// this function is void(*)(kmp_int32, kmp_int32, struct context_vars*).
/// \param OutlinedFn Outlined function to be run in parallel threads.
/// \param CapturedStruct A pointer to the record with the references to /// \param CapturedStruct A pointer to the record with the references to
/// variables used in \a OutlinedFn function. /// variables used in \a OutlinedFn function.
/// ///
@ -216,14 +204,14 @@ public:
/// \brief Returns corresponding lock object for the specified critical region /// \brief Returns corresponding lock object for the specified critical region
/// name. If the lock object does not exist it is created, otherwise the /// name. If the lock object does not exist it is created, otherwise the
/// reference to the existing copy is returned. /// reference to the existing copy is returned.
/// \param CriticalName Name of the critical region.
///
llvm::Value *GetCriticalRegionLock(StringRef CriticalName); llvm::Value *GetCriticalRegionLock(StringRef CriticalName);
/// \brief Emits start of the critical region by calling void /// \brief Emits start of the critical region by calling void
/// __kmpc_critical(ident_t *loc, kmp_int32 global_tid, kmp_critical_name /// __kmpc_critical(ident_t *loc, kmp_int32 global_tid, kmp_critical_name
/// * \a RegionLock) /// * \a RegionLock)
/// \param CGF Reference to current CodeGenFunction.
/// \param RegionLock The lock object for critical region. /// \param RegionLock The lock object for critical region.
/// \param Loc Location of the construct.
virtual void EmitOMPCriticalRegionStart(CodeGenFunction &CGF, virtual void EmitOMPCriticalRegionStart(CodeGenFunction &CGF,
llvm::Value *RegionLock, llvm::Value *RegionLock,
SourceLocation Loc); SourceLocation Loc);
@ -231,16 +219,12 @@ public:
/// \brief Emits end of the critical region by calling void /// \brief Emits end of the critical region by calling void
/// __kmpc_end_critical(ident_t *loc, kmp_int32 global_tid, kmp_critical_name /// __kmpc_end_critical(ident_t *loc, kmp_int32 global_tid, kmp_critical_name
/// * \a RegionLock) /// * \a RegionLock)
/// \param CGF Reference to current CodeGenFunction.
/// \param RegionLock The lock object for critical region. /// \param RegionLock The lock object for critical region.
/// \param Loc Location of the construct.
virtual void EmitOMPCriticalRegionEnd(CodeGenFunction &CGF, virtual void EmitOMPCriticalRegionEnd(CodeGenFunction &CGF,
llvm::Value *RegionLock, llvm::Value *RegionLock,
SourceLocation Loc); SourceLocation Loc);
/// \brief Emits a barrier for OpenMP threads. /// \brief Emits a barrier for OpenMP threads.
/// \param CGF Reference to current CodeGenFunction.
/// \param Loc Clang source location.
/// \param Flags Flags for the barrier. /// \param Flags Flags for the barrier.
/// ///
virtual void EmitOMPBarrierCall(CodeGenFunction &CGF, SourceLocation Loc, virtual void EmitOMPBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,

View File

@ -138,17 +138,10 @@ void CodeGenFunction::EmitOMPFirstprivateClause(
} }
void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) { void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
const CapturedStmt *CS = cast<CapturedStmt>(S.getAssociatedStmt()); auto CS = cast<CapturedStmt>(S.getAssociatedStmt());
llvm::Value *CapturedStruct = GenerateCapturedStmtArgument(*CS); auto CapturedStruct = GenerateCapturedStmtArgument(*CS);
auto OutlinedFn = CGM.getOpenMPRuntime().EmitOpenMPOutlinedFunction(
llvm::Value *OutlinedFn; S, *CS->getCapturedDecl()->param_begin());
{
CodeGenFunction CGF(CGM, true);
CGOpenMPRegionInfo CGInfo(S, *CS, *CS->getCapturedDecl()->param_begin());
CGF.CapturedStmtInfo = &CGInfo;
OutlinedFn = CGF.GenerateCapturedStmtFunction(*CS);
}
CGM.getOpenMPRuntime().EmitOMPParallelCall(*this, S.getLocStart(), OutlinedFn, CGM.getOpenMPRuntime().EmitOMPParallelCall(*this, S.getLocStart(), OutlinedFn,
CapturedStruct); CapturedStruct);
} }

View File

@ -215,6 +215,10 @@ public:
bool isCXXThisExprCaptured() const { return CXXThisFieldDecl != nullptr; } bool isCXXThisExprCaptured() const { return CXXThisFieldDecl != nullptr; }
FieldDecl *getThisFieldDecl() const { return CXXThisFieldDecl; } FieldDecl *getThisFieldDecl() const { return CXXThisFieldDecl; }
static bool classof(const CGCapturedStmtInfo *) {
return true;
}
/// \brief Emit the captured statement body. /// \brief Emit the captured statement body.
virtual void EmitBody(CodeGenFunction &CGF, Stmt *S) { virtual void EmitBody(CodeGenFunction &CGF, Stmt *S) {
RegionCounter Cnt = CGF.getPGORegionCounter(S); RegionCounter Cnt = CGF.getPGORegionCounter(S);

View File

@ -74,7 +74,7 @@ int main() {
// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}], // CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]], // CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]], // CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_ADDR]] // CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
// CHECK: [[T_VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 1 // CHECK: [[T_VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 1
// CHECK: [[T_VAR_REF:%.+]] = load i{{[0-9]+}}** [[T_VAR_PTR_REF]], // CHECK: [[T_VAR_REF:%.+]] = load i{{[0-9]+}}** [[T_VAR_PTR_REF]],
// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}* [[T_VAR_REF]], // CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}* [[T_VAR_REF]],
@ -110,6 +110,8 @@ int main() {
// CHECK: call {{.*}} [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]]) // CHECK: call {{.*}} [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
// CHECK: call {{.*}} [[S_FLOAT_TY_COPY_CONSTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]], [[S_FLOAT_TY]]* {{.*}} [[VAR_REF]], [[ST_TY]]* [[ST_TY_TEMP]]) // CHECK: call {{.*}} [[S_FLOAT_TY_COPY_CONSTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]], [[S_FLOAT_TY]]* {{.*}} [[VAR_REF]], [[ST_TY]]* [[ST_TY_TEMP]])
// CHECK: call {{.*}} [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]]) // CHECK: call {{.*}} [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]])
// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}** [[GTID_ADDR_ADDR]]
// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_REF]]
// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]]) // CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]]) // CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* // CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]*
@ -127,7 +129,7 @@ int main() {
// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}], // CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]], // CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]],
// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]], // CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]],
// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_ADDR]] // CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
// CHECK: [[T_VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 1 // CHECK: [[T_VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 1
// CHECK: [[T_VAR_REF:%.+]] = load i{{[0-9]+}}** [[T_VAR_PTR_REF]], // CHECK: [[T_VAR_REF:%.+]] = load i{{[0-9]+}}** [[T_VAR_PTR_REF]],
// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}* [[T_VAR_REF]], // CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}* [[T_VAR_REF]],
@ -163,6 +165,8 @@ int main() {
// CHECK: call {{.*}} [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]]) // CHECK: call {{.*}} [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
// CHECK: call {{.*}} [[S_INT_TY_COPY_CONSTR]]([[S_INT_TY]]* [[VAR_PRIV]], [[S_INT_TY]]* {{.*}} [[VAR_REF]], [[ST_TY]]* [[ST_TY_TEMP]]) // CHECK: call {{.*}} [[S_INT_TY_COPY_CONSTR]]([[S_INT_TY]]* [[VAR_PRIV]], [[S_INT_TY]]* {{.*}} [[VAR_REF]], [[ST_TY]]* [[ST_TY_TEMP]])
// CHECK: call {{.*}} [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]]) // CHECK: call {{.*}} [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]])
// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}** [[GTID_ADDR_ADDR]]
// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_REF]]
// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]]) // CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK-DAG: call {{.*}} [[S_INT_TY_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]]) // CHECK-DAG: call {{.*}} [[S_INT_TY_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]])
// CHECK-DAG: call {{.*}} [[S_INT_TY_DESTR]]([[S_INT_TY]]* // CHECK-DAG: call {{.*}} [[S_INT_TY_DESTR]]([[S_INT_TY]]*