forked from OSchip/llvm-project
[OPENMP] Codegen for 'firstprivate' clause.
This patch generates some helper variables that used as private copies of the corresponding original variables inside an OpenMP 'parallel' directive. These generated variables are initialized by copy using values of the original variables (with the copy constructor, if any). For arrays, initializator is generated for single element and in the codegen procedure this initial value is automatically propagated between all elements of the private copy. In outlined function, references to original variables are replaced by the references to these private helper variables. At the end of the initialization of the private variables an implicit barier is generated by calling __kmpc_barrier(...) runtime function to be sure that all threads were initialized using original values of the variables. Differential Revision: http://reviews.llvm.org/D5140 llvm-svn: 219297
This commit is contained in:
parent
bdef50e1ad
commit
3854f63aaf
|
@ -2482,6 +2482,12 @@ template <typename Derived>
|
||||||
bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause(
|
bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause(
|
||||||
OMPFirstprivateClause *C) {
|
OMPFirstprivateClause *C) {
|
||||||
TRY_TO(VisitOMPClauseList(C));
|
TRY_TO(VisitOMPClauseList(C));
|
||||||
|
for (auto *E : C->private_copies()) {
|
||||||
|
TRY_TO(TraverseStmt(E));
|
||||||
|
}
|
||||||
|
for (auto *E : C->inits()) {
|
||||||
|
TRY_TO(TraverseStmt(E));
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -986,6 +986,8 @@ public:
|
||||||
/// with the variables 'a' and 'b'.
|
/// with the variables 'a' and 'b'.
|
||||||
///
|
///
|
||||||
class OMPFirstprivateClause : public OMPVarListClause<OMPFirstprivateClause> {
|
class OMPFirstprivateClause : public OMPVarListClause<OMPFirstprivateClause> {
|
||||||
|
friend class OMPClauseReader;
|
||||||
|
|
||||||
/// \brief Build clause with number of variables \a N.
|
/// \brief Build clause with number of variables \a N.
|
||||||
///
|
///
|
||||||
/// \param StartLoc Starting location of the clause.
|
/// \param StartLoc Starting location of the clause.
|
||||||
|
@ -1006,6 +1008,33 @@ class OMPFirstprivateClause : public OMPVarListClause<OMPFirstprivateClause> {
|
||||||
: OMPVarListClause<OMPFirstprivateClause>(
|
: OMPVarListClause<OMPFirstprivateClause>(
|
||||||
OMPC_firstprivate, SourceLocation(), SourceLocation(),
|
OMPC_firstprivate, SourceLocation(), SourceLocation(),
|
||||||
SourceLocation(), N) {}
|
SourceLocation(), N) {}
|
||||||
|
/// \brief Sets the list of references to private copies with initializers for
|
||||||
|
/// new private variables.
|
||||||
|
/// \param VL List of references.
|
||||||
|
void setPrivateCopies(ArrayRef<Expr *> VL);
|
||||||
|
|
||||||
|
/// \brief Gets the list of references to private copies with initializers for
|
||||||
|
/// new private variables.
|
||||||
|
MutableArrayRef<Expr *> getPrivateCopies() {
|
||||||
|
return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
|
||||||
|
}
|
||||||
|
ArrayRef<const Expr *> getPrivateCopies() const {
|
||||||
|
return llvm::makeArrayRef(varlist_end(), varlist_size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Sets the list of references to initializer variables for new
|
||||||
|
/// private variables.
|
||||||
|
/// \param VL List of references.
|
||||||
|
void setInits(ArrayRef<Expr *> VL);
|
||||||
|
|
||||||
|
/// \brief Gets the list of references to initializer variables for new
|
||||||
|
/// private variables.
|
||||||
|
MutableArrayRef<Expr *> getInits() {
|
||||||
|
return MutableArrayRef<Expr *>(getPrivateCopies().end(), varlist_size());
|
||||||
|
}
|
||||||
|
ArrayRef<const Expr *> getInits() const {
|
||||||
|
return llvm::makeArrayRef(getPrivateCopies().end(), varlist_size());
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// \brief Creates clause with a list of variables \a VL.
|
/// \brief Creates clause with a list of variables \a VL.
|
||||||
|
@ -1014,11 +1043,16 @@ public:
|
||||||
/// \param StartLoc Starting location of the clause.
|
/// \param StartLoc Starting location of the clause.
|
||||||
/// \param LParenLoc Location of '('.
|
/// \param LParenLoc Location of '('.
|
||||||
/// \param EndLoc Ending location of the clause.
|
/// \param EndLoc Ending location of the clause.
|
||||||
/// \param VL List of references to the variables.
|
/// \param VL List of references to the original variables.
|
||||||
|
/// \param PrivateVL List of references to private copies with initializers.
|
||||||
|
/// \param InitVL List of references to auto generated variables used for
|
||||||
|
/// initialization of a single array element. Used if firstprivate variable is
|
||||||
|
/// of array type.
|
||||||
///
|
///
|
||||||
static OMPFirstprivateClause *
|
static OMPFirstprivateClause *
|
||||||
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
|
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||||
SourceLocation EndLoc, ArrayRef<Expr *> VL);
|
SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL,
|
||||||
|
ArrayRef<Expr *> InitVL);
|
||||||
/// \brief Creates an empty clause with the place for \a N variables.
|
/// \brief Creates an empty clause with the place for \a N variables.
|
||||||
///
|
///
|
||||||
/// \param C AST context.
|
/// \param C AST context.
|
||||||
|
@ -1026,6 +1060,33 @@ public:
|
||||||
///
|
///
|
||||||
static OMPFirstprivateClause *CreateEmpty(const ASTContext &C, unsigned N);
|
static OMPFirstprivateClause *CreateEmpty(const ASTContext &C, unsigned N);
|
||||||
|
|
||||||
|
typedef MutableArrayRef<Expr *>::iterator private_copies_iterator;
|
||||||
|
typedef ArrayRef<const Expr *>::iterator private_copies_const_iterator;
|
||||||
|
typedef llvm::iterator_range<private_copies_iterator> private_copies_range;
|
||||||
|
typedef llvm::iterator_range<private_copies_const_iterator>
|
||||||
|
private_copies_const_range;
|
||||||
|
|
||||||
|
private_copies_range private_copies() {
|
||||||
|
return private_copies_range(getPrivateCopies().begin(),
|
||||||
|
getPrivateCopies().end());
|
||||||
|
}
|
||||||
|
private_copies_const_range private_copies() const {
|
||||||
|
return private_copies_const_range(getPrivateCopies().begin(),
|
||||||
|
getPrivateCopies().end());
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef MutableArrayRef<Expr *>::iterator inits_iterator;
|
||||||
|
typedef ArrayRef<const Expr *>::iterator inits_const_iterator;
|
||||||
|
typedef llvm::iterator_range<inits_iterator> inits_range;
|
||||||
|
typedef llvm::iterator_range<inits_const_iterator> inits_const_range;
|
||||||
|
|
||||||
|
inits_range inits() {
|
||||||
|
return inits_range(getInits().begin(), getInits().end());
|
||||||
|
}
|
||||||
|
inits_const_range inits() const {
|
||||||
|
return inits_const_range(getInits().begin(), getInits().end());
|
||||||
|
}
|
||||||
|
|
||||||
StmtRange children() {
|
StmtRange children() {
|
||||||
return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
|
return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
|
||||||
reinterpret_cast<Stmt **>(varlist_end()));
|
reinterpret_cast<Stmt **>(varlist_end()));
|
||||||
|
|
|
@ -2504,6 +2504,12 @@ template <typename Derived>
|
||||||
bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause(
|
bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause(
|
||||||
OMPFirstprivateClause *C) {
|
OMPFirstprivateClause *C) {
|
||||||
TRY_TO(VisitOMPClauseList(C));
|
TRY_TO(VisitOMPClauseList(C));
|
||||||
|
for (auto *E : C->private_copies()) {
|
||||||
|
TRY_TO(TraverseStmt(E));
|
||||||
|
}
|
||||||
|
for (auto *E : C->inits()) {
|
||||||
|
TRY_TO(TraverseStmt(E));
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7141,8 +7141,8 @@ def err_omp_expected_var_name : Error<
|
||||||
"expected variable name">;
|
"expected variable name">;
|
||||||
def err_omp_required_method : Error<
|
def err_omp_required_method : Error<
|
||||||
"%0 variable must have an accessible, unambiguous %select{default constructor|copy constructor|copy assignment operator|'%2'|destructor}1">;
|
"%0 variable must have an accessible, unambiguous %select{default constructor|copy constructor|copy assignment operator|'%2'|destructor}1">;
|
||||||
def err_omp_task_predetermined_firstprivate_required_method : Error<
|
def note_omp_task_predetermined_firstprivate_here : Note<
|
||||||
"predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous %select{copy constructor|destructor}0">;
|
"predetermined as a firstprivate in a task construct here">;
|
||||||
def err_omp_clause_ref_type_arg : Error<
|
def err_omp_clause_ref_type_arg : Error<
|
||||||
"arguments of OpenMP clause '%0' cannot be of reference type %1">;
|
"arguments of OpenMP clause '%0' cannot be of reference type %1">;
|
||||||
def err_omp_task_predetermined_firstprivate_ref_type_arg : Error<
|
def err_omp_task_predetermined_firstprivate_ref_type_arg : Error<
|
||||||
|
|
|
@ -1198,19 +1198,31 @@ OMPPrivateClause *OMPPrivateClause::CreateEmpty(const ASTContext &C,
|
||||||
return new (Mem) OMPPrivateClause(N);
|
return new (Mem) OMPPrivateClause(N);
|
||||||
}
|
}
|
||||||
|
|
||||||
OMPFirstprivateClause *OMPFirstprivateClause::Create(const ASTContext &C,
|
void OMPFirstprivateClause::setPrivateCopies(ArrayRef<Expr *> VL) {
|
||||||
SourceLocation StartLoc,
|
assert(VL.size() == varlist_size() &&
|
||||||
SourceLocation LParenLoc,
|
"Number of private copies is not the same as the preallocated buffer");
|
||||||
SourceLocation EndLoc,
|
std::copy(VL.begin(), VL.end(), varlist_end());
|
||||||
ArrayRef<Expr *> VL) {
|
}
|
||||||
|
|
||||||
|
void OMPFirstprivateClause::setInits(ArrayRef<Expr *> VL) {
|
||||||
|
assert(VL.size() == varlist_size() &&
|
||||||
|
"Number of inits is not the same as the preallocated buffer");
|
||||||
|
std::copy(VL.begin(), VL.end(), getPrivateCopies().end());
|
||||||
|
}
|
||||||
|
|
||||||
|
OMPFirstprivateClause *
|
||||||
|
OMPFirstprivateClause::Create(const ASTContext &C, SourceLocation StartLoc,
|
||||||
|
SourceLocation LParenLoc, SourceLocation EndLoc,
|
||||||
|
ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL,
|
||||||
|
ArrayRef<Expr *> InitVL) {
|
||||||
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstprivateClause),
|
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstprivateClause),
|
||||||
llvm::alignOf<Expr *>()) +
|
llvm::alignOf<Expr *>()) +
|
||||||
sizeof(Expr *) * VL.size());
|
3 * sizeof(Expr *) * VL.size());
|
||||||
OMPFirstprivateClause *Clause = new (Mem) OMPFirstprivateClause(StartLoc,
|
OMPFirstprivateClause *Clause =
|
||||||
LParenLoc,
|
new (Mem) OMPFirstprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
|
||||||
EndLoc,
|
|
||||||
VL.size());
|
|
||||||
Clause->setVarRefs(VL);
|
Clause->setVarRefs(VL);
|
||||||
|
Clause->setPrivateCopies(PrivateVL);
|
||||||
|
Clause->setInits(InitVL);
|
||||||
return Clause;
|
return Clause;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1218,7 +1230,7 @@ OMPFirstprivateClause *OMPFirstprivateClause::CreateEmpty(const ASTContext &C,
|
||||||
unsigned N) {
|
unsigned N) {
|
||||||
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstprivateClause),
|
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstprivateClause),
|
||||||
llvm::alignOf<Expr *>()) +
|
llvm::alignOf<Expr *>()) +
|
||||||
sizeof(Expr *) * N);
|
3 * sizeof(Expr *) * N);
|
||||||
return new (Mem) OMPFirstprivateClause(N);
|
return new (Mem) OMPFirstprivateClause(N);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -329,9 +329,15 @@ void OMPClauseProfiler::VisitOMPClauseList(T *Node) {
|
||||||
void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) {
|
void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) {
|
||||||
VisitOMPClauseList(C);
|
VisitOMPClauseList(C);
|
||||||
}
|
}
|
||||||
void OMPClauseProfiler::VisitOMPFirstprivateClause(
|
void
|
||||||
const OMPFirstprivateClause *C) {
|
OMPClauseProfiler::VisitOMPFirstprivateClause(const OMPFirstprivateClause *C) {
|
||||||
VisitOMPClauseList(C);
|
VisitOMPClauseList(C);
|
||||||
|
for (auto *E : C->private_copies()) {
|
||||||
|
Profiler->VisitStmt(E);
|
||||||
|
}
|
||||||
|
for (auto *E : C->inits()) {
|
||||||
|
Profiler->VisitStmt(E);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
OMPClauseProfiler::VisitOMPLastprivateClause(const OMPLastprivateClause *C) {
|
OMPClauseProfiler::VisitOMPLastprivateClause(const OMPLastprivateClause *C) {
|
||||||
|
|
|
@ -1073,7 +1073,7 @@ static bool isCapturedBy(const VarDecl &var, const Expr *e) {
|
||||||
|
|
||||||
/// \brief Determine whether the given initializer is trivial in the sense
|
/// \brief Determine whether the given initializer is trivial in the sense
|
||||||
/// that it requires no code to be generated.
|
/// that it requires no code to be generated.
|
||||||
static bool isTrivialInitializer(const Expr *Init) {
|
bool CodeGenFunction::isTrivialInitializer(const Expr *Init) {
|
||||||
if (!Init)
|
if (!Init)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,29 @@
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
using namespace CodeGen;
|
using namespace CodeGen;
|
||||||
|
|
||||||
|
void CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, Stmt *S) {
|
||||||
|
CodeGenFunction::OuterDeclMapTy OuterDeclMap;
|
||||||
|
CGF.EmitOMPFirstprivateClause(Directive, OuterDeclMap);
|
||||||
|
if (!OuterDeclMap.empty()) {
|
||||||
|
// Emit implicit barrier to synchronize threads and avoid data races.
|
||||||
|
auto Flags = static_cast<CGOpenMPRuntime::OpenMPLocationFlags>(
|
||||||
|
CGOpenMPRuntime::OMP_IDENT_KMPC |
|
||||||
|
CGOpenMPRuntime::OMP_IDENT_BARRIER_IMPL);
|
||||||
|
CGF.CGM.getOpenMPRuntime().EmitOMPBarrierCall(CGF, Directive.getLocStart(),
|
||||||
|
Flags);
|
||||||
|
// Remap captured variables to use their private copies in the outlined
|
||||||
|
// function.
|
||||||
|
for (auto I : OuterDeclMap) {
|
||||||
|
CGF.LocalDeclMap[I.first] = I.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CGCapturedStmtInfo::EmitBody(CGF, S);
|
||||||
|
// Clear mappings of captured private variables.
|
||||||
|
for (auto I : OuterDeclMap) {
|
||||||
|
CGF.LocalDeclMap.erase(I.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)
|
CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)
|
||||||
: CGM(CGM), DefaultOpenMPPSource(nullptr) {
|
: CGM(CGM), DefaultOpenMPPSource(nullptr) {
|
||||||
IdentTy = llvm::StructType::create(
|
IdentTy = llvm::StructType::create(
|
||||||
|
@ -51,11 +74,10 @@ CGOpenMPRuntime::GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags) {
|
||||||
DefaultOpenMPPSource =
|
DefaultOpenMPPSource =
|
||||||
llvm::ConstantExpr::getBitCast(DefaultOpenMPPSource, CGM.Int8PtrTy);
|
llvm::ConstantExpr::getBitCast(DefaultOpenMPPSource, CGM.Int8PtrTy);
|
||||||
}
|
}
|
||||||
llvm::GlobalVariable *DefaultOpenMPLocation = cast<llvm::GlobalVariable>(
|
auto DefaultOpenMPLocation = new llvm::GlobalVariable(
|
||||||
CGM.CreateRuntimeVariable(IdentTy, ".kmpc_default_loc.addr"));
|
CGM.getModule(), IdentTy, /*isConstant*/ true,
|
||||||
|
llvm::GlobalValue::PrivateLinkage, /*Initializer*/ nullptr);
|
||||||
DefaultOpenMPLocation->setUnnamedAddr(true);
|
DefaultOpenMPLocation->setUnnamedAddr(true);
|
||||||
DefaultOpenMPLocation->setConstant(true);
|
|
||||||
DefaultOpenMPLocation->setLinkage(llvm::GlobalValue::PrivateLinkage);
|
|
||||||
|
|
||||||
llvm::Constant *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0, true);
|
llvm::Constant *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0, true);
|
||||||
llvm::Constant *Values[] = {Zero,
|
llvm::Constant *Values[] = {Zero,
|
||||||
|
@ -63,6 +85,7 @@ CGOpenMPRuntime::GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags) {
|
||||||
Zero, Zero, DefaultOpenMPPSource};
|
Zero, Zero, DefaultOpenMPPSource};
|
||||||
llvm::Constant *Init = llvm::ConstantStruct::get(IdentTy, Values);
|
llvm::Constant *Init = llvm::ConstantStruct::get(IdentTy, Values);
|
||||||
DefaultOpenMPLocation->setInitializer(Init);
|
DefaultOpenMPLocation->setInitializer(Init);
|
||||||
|
OpenMPDefaultLocMap[Flags] = DefaultOpenMPLocation;
|
||||||
return DefaultOpenMPLocation;
|
return DefaultOpenMPLocation;
|
||||||
}
|
}
|
||||||
return Entry;
|
return Entry;
|
||||||
|
@ -120,14 +143,14 @@ llvm::Value *CGOpenMPRuntime::EmitOpenMPUpdateLocation(
|
||||||
return LocValue;
|
return LocValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Value *CGOpenMPRuntime::GetOpenMPGlobalThreadNum(CodeGenFunction &CGF,
|
llvm::Value *CGOpenMPRuntime::GetOpenMPThreadID(CodeGenFunction &CGF,
|
||||||
SourceLocation Loc) {
|
SourceLocation Loc) {
|
||||||
assert(CGF.CurFn && "No function in current CodeGenFunction.");
|
assert(CGF.CurFn && "No function in current CodeGenFunction.");
|
||||||
|
|
||||||
llvm::Value *GTid = nullptr;
|
llvm::Value *ThreadID = nullptr;
|
||||||
OpenMPGtidMapTy::iterator I = OpenMPGtidMap.find(CGF.CurFn);
|
OpenMPThreadIDMapTy::iterator I = OpenMPThreadIDMap.find(CGF.CurFn);
|
||||||
if (I != OpenMPGtidMap.end()) {
|
if (I != OpenMPThreadIDMap.end()) {
|
||||||
GTid = I->second;
|
ThreadID = I->second;
|
||||||
} else {
|
} else {
|
||||||
// Check if current function is a function which has first parameter
|
// Check if current function is a function which has first parameter
|
||||||
// with type int32 and name ".global_tid.".
|
// with type int32 and name ".global_tid.".
|
||||||
|
@ -145,24 +168,24 @@ llvm::Value *CGOpenMPRuntime::GetOpenMPGlobalThreadNum(CodeGenFunction &CGF,
|
||||||
CGF.CurFn->arg_begin()->getName() == ".global_tid.") {
|
CGF.CurFn->arg_begin()->getName() == ".global_tid.") {
|
||||||
CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
|
CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
|
||||||
CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
|
CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
|
||||||
GTid = CGF.Builder.CreateLoad(CGF.CurFn->arg_begin());
|
ThreadID = CGF.Builder.CreateLoad(CGF.CurFn->arg_begin());
|
||||||
} else {
|
} else {
|
||||||
// Generate "int32 .kmpc_global_thread_num.addr;"
|
// Generate "int32 .kmpc_global_thread_num.addr;"
|
||||||
CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
|
CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
|
||||||
CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
|
CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
|
||||||
llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc)};
|
llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc)};
|
||||||
GTid = CGF.EmitRuntimeCall(
|
ThreadID = CGF.EmitRuntimeCall(
|
||||||
CreateRuntimeFunction(OMPRTL__kmpc_global_thread_num), Args);
|
CreateRuntimeFunction(OMPRTL__kmpc_global_thread_num), Args);
|
||||||
}
|
}
|
||||||
OpenMPGtidMap[CGF.CurFn] = GTid;
|
OpenMPThreadIDMap[CGF.CurFn] = ThreadID;
|
||||||
}
|
}
|
||||||
return GTid;
|
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 (OpenMPGtidMap.count(CGF.CurFn))
|
if (OpenMPThreadIDMap.count(CGF.CurFn))
|
||||||
OpenMPGtidMap.erase(CGF.CurFn);
|
OpenMPThreadIDMap.erase(CGF.CurFn);
|
||||||
if (OpenMPLocMap.count(CGF.CurFn))
|
if (OpenMPLocMap.count(CGF.CurFn))
|
||||||
OpenMPLocMap.erase(CGF.CurFn);
|
OpenMPLocMap.erase(CGF.CurFn);
|
||||||
}
|
}
|
||||||
|
@ -219,10 +242,33 @@ CGOpenMPRuntime::CreateRuntimeFunction(OpenMPRTLFunction Function) {
|
||||||
RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_critical");
|
RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_critical");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case OMPRTL__kmpc_barrier: {
|
||||||
|
// Build void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid);
|
||||||
|
llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
|
||||||
|
llvm::FunctionType *FnTy =
|
||||||
|
llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
|
||||||
|
RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name*/ "__kmpc_barrier");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return RTLFn;
|
return RTLFn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGOpenMPRuntime::EmitOMPParallelCall(CodeGenFunction &CGF,
|
||||||
|
SourceLocation Loc,
|
||||||
|
llvm::Value *OutlinedFn,
|
||||||
|
llvm::Value *CapturedStruct) {
|
||||||
|
// Build call __kmpc_fork_call(loc, 1, microtask, captured_struct/*context*/)
|
||||||
|
llvm::Value *Args[] = {
|
||||||
|
EmitOpenMPUpdateLocation(CGF, Loc),
|
||||||
|
CGF.Builder.getInt32(1), // Number of arguments after 'microtask' argument
|
||||||
|
// (there is only one additional argument - 'context')
|
||||||
|
CGF.Builder.CreateBitCast(OutlinedFn, getKmpc_MicroPointerTy()),
|
||||||
|
CGF.EmitCastToVoidPtr(CapturedStruct)};
|
||||||
|
auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_fork_call);
|
||||||
|
CGF.EmitRuntimeCall(RTLFn, Args);
|
||||||
|
}
|
||||||
|
|
||||||
llvm::Value *CGOpenMPRuntime::GetCriticalRegionLock(StringRef CriticalName) {
|
llvm::Value *CGOpenMPRuntime::GetCriticalRegionLock(StringRef CriticalName) {
|
||||||
SmallString<256> Buffer;
|
SmallString<256> Buffer;
|
||||||
llvm::raw_svector_ostream Out(Buffer);
|
llvm::raw_svector_ostream Out(Buffer);
|
||||||
|
@ -245,7 +291,7 @@ void CGOpenMPRuntime::EmitOMPCriticalRegionStart(CodeGenFunction &CGF,
|
||||||
SourceLocation Loc) {
|
SourceLocation Loc) {
|
||||||
// Prepare other arguments and build a call to __kmpc_critical
|
// Prepare other arguments and build a call to __kmpc_critical
|
||||||
llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc),
|
llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc),
|
||||||
GetOpenMPGlobalThreadNum(CGF, Loc), RegionLock};
|
GetOpenMPThreadID(CGF, Loc), RegionLock};
|
||||||
auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_critical);
|
auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_critical);
|
||||||
CGF.EmitRuntimeCall(RTLFn, Args);
|
CGF.EmitRuntimeCall(RTLFn, Args);
|
||||||
}
|
}
|
||||||
|
@ -255,8 +301,19 @@ void CGOpenMPRuntime::EmitOMPCriticalRegionEnd(CodeGenFunction &CGF,
|
||||||
SourceLocation Loc) {
|
SourceLocation Loc) {
|
||||||
// Prepare other arguments and build a call to __kmpc_end_critical
|
// Prepare other arguments and build a call to __kmpc_end_critical
|
||||||
llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc),
|
llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc),
|
||||||
GetOpenMPGlobalThreadNum(CGF, Loc), RegionLock};
|
GetOpenMPThreadID(CGF, Loc), RegionLock};
|
||||||
auto RTLFn =
|
auto RTLFn =
|
||||||
CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_end_critical);
|
CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_end_critical);
|
||||||
CGF.EmitRuntimeCall(RTLFn, Args);
|
CGF.EmitRuntimeCall(RTLFn, Args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGOpenMPRuntime::EmitOMPBarrierCall(CodeGenFunction &CGF,
|
||||||
|
SourceLocation Loc,
|
||||||
|
OpenMPLocationFlags Flags) {
|
||||||
|
// Build call __kmpc_barrier(loc, thread_id)
|
||||||
|
llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc, Flags),
|
||||||
|
GetOpenMPThreadID(CGF, Loc)};
|
||||||
|
auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_barrier);
|
||||||
|
CGF.EmitRuntimeCall(RTLFn, Args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,33 +14,49 @@
|
||||||
#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/AST/StmtOpenMP.h"
|
||||||
#include "clang/AST/Type.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/Type.h"
|
||||||
#include "llvm/IR/Value.h"
|
#include "llvm/IR/Value.h"
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
class AllocaInst;
|
|
||||||
class CallInst;
|
|
||||||
class GlobalVariable;
|
|
||||||
class Constant;
|
|
||||||
class Function;
|
|
||||||
class Module;
|
|
||||||
class StructLayout;
|
|
||||||
class ArrayType;
|
|
||||||
class FunctionType;
|
|
||||||
class StructType;
|
|
||||||
class Type;
|
|
||||||
class Value;
|
|
||||||
} // namespace llvm
|
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
|
|
||||||
namespace CodeGen {
|
namespace CodeGen {
|
||||||
|
|
||||||
class CodeGenFunction;
|
/// \brief API for captured statement code generation in OpenMP constructs.
|
||||||
class CodeGenModule;
|
class CGOpenMPRegionInfo : public CodeGenFunction::CGCapturedStmtInfo {
|
||||||
|
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:
|
||||||
|
@ -76,7 +92,9 @@ public:
|
||||||
OMPRTL__kmpc_critical,
|
OMPRTL__kmpc_critical,
|
||||||
// Call to void __kmpc_end_critical(ident_t *loc, kmp_int32 global_tid,
|
// Call to void __kmpc_end_critical(ident_t *loc, kmp_int32 global_tid,
|
||||||
// kmp_critical_name *crit);
|
// kmp_critical_name *crit);
|
||||||
OMPRTL__kmpc_end_critical
|
OMPRTL__kmpc_end_critical,
|
||||||
|
// Call to void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid);
|
||||||
|
OMPRTL__kmpc_barrier
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -139,24 +157,15 @@ private:
|
||||||
/// \brief Map of local debug location and functions.
|
/// \brief Map of local debug location and functions.
|
||||||
typedef llvm::DenseMap<llvm::Function *, llvm::Value *> OpenMPLocMapTy;
|
typedef llvm::DenseMap<llvm::Function *, llvm::Value *> OpenMPLocMapTy;
|
||||||
OpenMPLocMapTy OpenMPLocMap;
|
OpenMPLocMapTy OpenMPLocMap;
|
||||||
/// \brief Map of local gtid and functions.
|
/// \brief Map of local ThreadID and functions.
|
||||||
typedef llvm::DenseMap<llvm::Function *, llvm::Value *> OpenMPGtidMapTy;
|
typedef llvm::DenseMap<llvm::Function *, llvm::Value *> OpenMPThreadIDMapTy;
|
||||||
OpenMPGtidMapTy OpenMPGtidMap;
|
OpenMPThreadIDMapTy OpenMPThreadIDMap;
|
||||||
/// \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;
|
||||||
/// \brief Map of critical regions names and the corresponding lock objects.
|
/// \brief Map of critical regions names and the corresponding lock objects.
|
||||||
llvm::StringMap<llvm::Value *, llvm::BumpPtrAllocator> CriticalRegionVarNames;
|
llvm::StringMap<llvm::Value *, llvm::BumpPtrAllocator> CriticalRegionVarNames;
|
||||||
|
|
||||||
public:
|
|
||||||
explicit CGOpenMPRuntime(CodeGenModule &CGM);
|
|
||||||
virtual ~CGOpenMPRuntime() {}
|
|
||||||
|
|
||||||
/// \brief Cleans up references to the objects in finished function.
|
|
||||||
/// \param CGF Reference to finished CodeGenFunction.
|
|
||||||
///
|
|
||||||
void FunctionFinished(CodeGenFunction &CGF);
|
|
||||||
|
|
||||||
/// \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 CGF Reference to current CodeGenFunction.
|
||||||
/// \param Loc Clang source location.
|
/// \param Loc Clang source location.
|
||||||
|
@ -166,13 +175,6 @@ public:
|
||||||
EmitOpenMPUpdateLocation(CodeGenFunction &CGF, SourceLocation Loc,
|
EmitOpenMPUpdateLocation(CodeGenFunction &CGF, SourceLocation Loc,
|
||||||
OpenMPLocationFlags Flags = OMP_IDENT_KMPC);
|
OpenMPLocationFlags Flags = OMP_IDENT_KMPC);
|
||||||
|
|
||||||
/// \brief Generates global thread number value.
|
|
||||||
/// \param CGF Reference to current CodeGenFunction.
|
|
||||||
/// \param Loc Clang source location.
|
|
||||||
///
|
|
||||||
llvm::Value *GetOpenMPGlobalThreadNum(CodeGenFunction &CGF,
|
|
||||||
SourceLocation Loc);
|
|
||||||
|
|
||||||
/// \brief Returns pointer to ident_t type;
|
/// \brief Returns pointer to ident_t type;
|
||||||
llvm::Type *getIdentTyPointerTy();
|
llvm::Type *getIdentTyPointerTy();
|
||||||
|
|
||||||
|
@ -184,6 +186,33 @@ public:
|
||||||
/// \return Specified function.
|
/// \return Specified function.
|
||||||
llvm::Constant *CreateRuntimeFunction(OpenMPRTLFunction Function);
|
llvm::Constant *CreateRuntimeFunction(OpenMPRTLFunction Function);
|
||||||
|
|
||||||
|
/// \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);
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CGOpenMPRuntime(CodeGenModule &CGM);
|
||||||
|
virtual ~CGOpenMPRuntime() {}
|
||||||
|
|
||||||
|
/// \brief Cleans up references to the objects in finished function.
|
||||||
|
/// \param CGF Reference to finished CodeGenFunction.
|
||||||
|
///
|
||||||
|
void FunctionFinished(CodeGenFunction &CGF);
|
||||||
|
|
||||||
|
/// \brief Emits code for parallel call of the \a OutlinedFn with variables
|
||||||
|
/// captured in a record which address is stored in \a CapturedStruct.
|
||||||
|
/// \param CGF Reference to current CodeGenFunction.
|
||||||
|
/// \param Loc Clang source location.
|
||||||
|
/// \param OutlinedFn Outlined function to be run in parallel threads.
|
||||||
|
/// \param CapturedStruct A pointer to the record with the references to
|
||||||
|
/// variables used in \a OutlinedFn function.
|
||||||
|
///
|
||||||
|
virtual void EmitOMPParallelCall(CodeGenFunction &CGF, SourceLocation Loc,
|
||||||
|
llvm::Value *OutlinedFn,
|
||||||
|
llvm::Value *CapturedStruct);
|
||||||
|
|
||||||
/// \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.
|
||||||
|
@ -208,6 +237,14 @@ public:
|
||||||
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.
|
||||||
|
/// \param CGF Reference to current CodeGenFunction.
|
||||||
|
/// \param Loc Clang source location.
|
||||||
|
/// \param Flags Flags for the barrier.
|
||||||
|
///
|
||||||
|
virtual void EmitOMPBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,
|
||||||
|
OpenMPLocationFlags Flags);
|
||||||
};
|
};
|
||||||
} // namespace CodeGen
|
} // namespace CodeGen
|
||||||
} // namespace clang
|
} // namespace clang
|
||||||
|
|
|
@ -24,6 +24,110 @@ using namespace CodeGen;
|
||||||
// OpenMP Directive Emission
|
// OpenMP Directive Emission
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
void CodeGenFunction::EmitOMPAggregateAssign(LValue OriginalAddr,
|
||||||
|
llvm::Value *PrivateAddr,
|
||||||
|
const Expr *AssignExpr,
|
||||||
|
QualType OriginalType,
|
||||||
|
const VarDecl *VDInit) {
|
||||||
|
EmitBlock(createBasicBlock(".omp.assign.begin."));
|
||||||
|
if (!isa<CXXConstructExpr>(AssignExpr) || isTrivialInitializer(AssignExpr)) {
|
||||||
|
// Perform simple memcpy.
|
||||||
|
EmitAggregateAssign(PrivateAddr, OriginalAddr.getAddress(),
|
||||||
|
AssignExpr->getType());
|
||||||
|
} else {
|
||||||
|
// Perform element-by-element initialization.
|
||||||
|
QualType ElementTy;
|
||||||
|
auto SrcBegin = OriginalAddr.getAddress();
|
||||||
|
auto DestBegin = PrivateAddr;
|
||||||
|
auto ArrayTy = OriginalType->getAsArrayTypeUnsafe();
|
||||||
|
auto SrcNumElements = emitArrayLength(ArrayTy, ElementTy, SrcBegin);
|
||||||
|
auto DestNumElements = emitArrayLength(ArrayTy, ElementTy, DestBegin);
|
||||||
|
auto SrcEnd = Builder.CreateGEP(SrcBegin, SrcNumElements);
|
||||||
|
auto DestEnd = Builder.CreateGEP(DestBegin, DestNumElements);
|
||||||
|
// The basic structure here is a do-while loop, because we don't
|
||||||
|
// need to check for the zero-element case.
|
||||||
|
auto BodyBB = createBasicBlock("omp.arraycpy.body");
|
||||||
|
auto DoneBB = createBasicBlock("omp.arraycpy.done");
|
||||||
|
auto IsEmpty =
|
||||||
|
Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arraycpy.isempty");
|
||||||
|
Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
|
||||||
|
|
||||||
|
// Enter the loop body, making that address the current address.
|
||||||
|
auto EntryBB = Builder.GetInsertBlock();
|
||||||
|
EmitBlock(BodyBB);
|
||||||
|
auto SrcElementPast = Builder.CreatePHI(SrcBegin->getType(), 2,
|
||||||
|
"omp.arraycpy.srcElementPast");
|
||||||
|
SrcElementPast->addIncoming(SrcEnd, EntryBB);
|
||||||
|
auto DestElementPast = Builder.CreatePHI(DestBegin->getType(), 2,
|
||||||
|
"omp.arraycpy.destElementPast");
|
||||||
|
DestElementPast->addIncoming(DestEnd, EntryBB);
|
||||||
|
|
||||||
|
// Shift the address back by one element.
|
||||||
|
auto NegativeOne = llvm::ConstantInt::get(SizeTy, -1, true);
|
||||||
|
auto DestElement = Builder.CreateGEP(DestElementPast, NegativeOne,
|
||||||
|
"omp.arraycpy.dest.element");
|
||||||
|
auto SrcElement = Builder.CreateGEP(SrcElementPast, NegativeOne,
|
||||||
|
"omp.arraycpy.src.element");
|
||||||
|
{
|
||||||
|
// Create RunCleanScope to cleanup possible temps.
|
||||||
|
CodeGenFunction::RunCleanupsScope Init(*this);
|
||||||
|
// Emit initialization for single element.
|
||||||
|
LocalDeclMap[VDInit] = SrcElement;
|
||||||
|
EmitAnyExprToMem(AssignExpr, DestElement,
|
||||||
|
AssignExpr->getType().getQualifiers(),
|
||||||
|
/*IsInitializer*/ false);
|
||||||
|
LocalDeclMap.erase(VDInit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether we've reached the end.
|
||||||
|
auto Done =
|
||||||
|
Builder.CreateICmpEQ(DestElement, DestBegin, "omp.arraycpy.done");
|
||||||
|
Builder.CreateCondBr(Done, DoneBB, BodyBB);
|
||||||
|
DestElementPast->addIncoming(DestElement, Builder.GetInsertBlock());
|
||||||
|
SrcElementPast->addIncoming(SrcElement, Builder.GetInsertBlock());
|
||||||
|
|
||||||
|
// Done.
|
||||||
|
EmitBlock(DoneBB, true);
|
||||||
|
}
|
||||||
|
EmitBlock(createBasicBlock(".omp.assign.end."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeGenFunction::EmitOMPFirstprivateClause(
|
||||||
|
const OMPExecutableDirective &D,
|
||||||
|
CodeGenFunction::OuterDeclMapTy &OuterDeclMap) {
|
||||||
|
auto PrivateFilter = [](const OMPClause *C) -> bool {
|
||||||
|
return C->getClauseKind() == OMPC_firstprivate;
|
||||||
|
};
|
||||||
|
for (OMPExecutableDirective::filtered_clause_iterator<decltype(PrivateFilter)>
|
||||||
|
I(D.clauses(), PrivateFilter); I; ++I) {
|
||||||
|
auto *C = cast<OMPFirstprivateClause>(*I);
|
||||||
|
auto IRef = C->varlist_begin();
|
||||||
|
auto InitsRef = C->inits().begin();
|
||||||
|
for (auto IInit : C->private_copies()) {
|
||||||
|
auto VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
|
||||||
|
if (*InitsRef != nullptr) {
|
||||||
|
// Emit VarDecl with copy init for arrays.
|
||||||
|
auto *FD = CapturedStmtInfo->lookup(
|
||||||
|
cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl()));
|
||||||
|
LValue Base = MakeNaturalAlignAddrLValue(
|
||||||
|
CapturedStmtInfo->getContextValue(),
|
||||||
|
getContext().getTagDeclType(FD->getParent()));
|
||||||
|
auto OriginalAddr = EmitLValueForField(Base, FD);
|
||||||
|
auto VDInit = cast<VarDecl>(cast<DeclRefExpr>(*InitsRef)->getDecl());
|
||||||
|
auto Emission = EmitAutoVarAlloca(*VD);
|
||||||
|
// Emit initialization of aggregate firstprivate vars.
|
||||||
|
EmitOMPAggregateAssign(OriginalAddr, Emission.getAllocatedAddress(),
|
||||||
|
VD->getInit(), (*IRef)->getType(), VDInit);
|
||||||
|
EmitAutoVarCleanups(Emission);
|
||||||
|
} else
|
||||||
|
// Emit VarDecl with copy init.
|
||||||
|
EmitDecl(*VD);
|
||||||
|
OuterDeclMap[cast<DeclRefExpr>(*IRef)->getDecl()] = GetAddrOfLocalVar(VD);
|
||||||
|
++IRef, ++InitsRef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
|
void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
|
||||||
const CapturedStmt *CS = cast<CapturedStmt>(S.getAssociatedStmt());
|
const CapturedStmt *CS = cast<CapturedStmt>(S.getAssociatedStmt());
|
||||||
llvm::Value *CapturedStruct = GenerateCapturedStmtArgument(*CS);
|
llvm::Value *CapturedStruct = GenerateCapturedStmtArgument(*CS);
|
||||||
|
@ -31,22 +135,13 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
|
||||||
llvm::Value *OutlinedFn;
|
llvm::Value *OutlinedFn;
|
||||||
{
|
{
|
||||||
CodeGenFunction CGF(CGM, true);
|
CodeGenFunction CGF(CGM, true);
|
||||||
CGCapturedStmtInfo CGInfo(*CS, CS->getCapturedRegionKind());
|
CGOpenMPRegionInfo CGInfo(S, *CS, *CS->getCapturedDecl()->param_begin());
|
||||||
CGF.CapturedStmtInfo = &CGInfo;
|
CGF.CapturedStmtInfo = &CGInfo;
|
||||||
OutlinedFn = CGF.GenerateCapturedStmtFunction(*CS);
|
OutlinedFn = CGF.GenerateCapturedStmtFunction(*CS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build call __kmpc_fork_call(loc, 1, microtask, captured_struct/*context*/)
|
CGM.getOpenMPRuntime().EmitOMPParallelCall(*this, S.getLocStart(), OutlinedFn,
|
||||||
llvm::Value *Args[] = {
|
CapturedStruct);
|
||||||
CGM.getOpenMPRuntime().EmitOpenMPUpdateLocation(*this, S.getLocStart()),
|
|
||||||
Builder.getInt32(1), // Number of arguments after 'microtask' argument
|
|
||||||
// (there is only one additional argument - 'context')
|
|
||||||
Builder.CreateBitCast(OutlinedFn,
|
|
||||||
CGM.getOpenMPRuntime().getKmpc_MicroPointerTy()),
|
|
||||||
EmitCastToVoidPtr(CapturedStruct)};
|
|
||||||
llvm::Constant *RTLFn = CGM.getOpenMPRuntime().CreateRuntimeFunction(
|
|
||||||
CGOpenMPRuntime::OMPRTL__kmpc_fork_call);
|
|
||||||
EmitRuntimeCall(RTLFn, Args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &S,
|
void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &S,
|
||||||
|
|
|
@ -113,6 +113,7 @@ class CodeGenFunction : public CodeGenTypeCache {
|
||||||
void operator=(const CodeGenFunction &) LLVM_DELETED_FUNCTION;
|
void operator=(const CodeGenFunction &) LLVM_DELETED_FUNCTION;
|
||||||
|
|
||||||
friend class CGCXXABI;
|
friend class CGCXXABI;
|
||||||
|
friend class CGOpenMPRegionInfo;
|
||||||
public:
|
public:
|
||||||
/// A jump destination is an abstract label, branching to which may
|
/// A jump destination is an abstract label, branching to which may
|
||||||
/// require a jump out through normal cleanups.
|
/// require a jump out through normal cleanups.
|
||||||
|
@ -1826,6 +1827,10 @@ public:
|
||||||
typedef void SpecialInitFn(CodeGenFunction &Init, const VarDecl &D,
|
typedef void SpecialInitFn(CodeGenFunction &Init, const VarDecl &D,
|
||||||
llvm::Value *Address);
|
llvm::Value *Address);
|
||||||
|
|
||||||
|
/// \brief Determine whether the given initializer is trivial in the sense
|
||||||
|
/// that it requires no code to be generated.
|
||||||
|
bool isTrivialInitializer(const Expr *Init);
|
||||||
|
|
||||||
/// EmitAutoVarDecl - Emit an auto variable declaration.
|
/// EmitAutoVarDecl - Emit an auto variable declaration.
|
||||||
///
|
///
|
||||||
/// This function can be called with a null (unreachable) insert point.
|
/// This function can be called with a null (unreachable) insert point.
|
||||||
|
@ -1991,8 +1996,16 @@ public:
|
||||||
ArrayRef<const Attr *> Attrs = None);
|
ArrayRef<const Attr *> Attrs = None);
|
||||||
|
|
||||||
llvm::Function *EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K);
|
llvm::Function *EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K);
|
||||||
|
void GenerateCapturedStmtFunctionProlog(const CapturedStmt &S);
|
||||||
|
llvm::Function *GenerateCapturedStmtFunctionEpilog(const CapturedStmt &S);
|
||||||
llvm::Function *GenerateCapturedStmtFunction(const CapturedStmt &S);
|
llvm::Function *GenerateCapturedStmtFunction(const CapturedStmt &S);
|
||||||
llvm::Value *GenerateCapturedStmtArgument(const CapturedStmt &S);
|
llvm::Value *GenerateCapturedStmtArgument(const CapturedStmt &S);
|
||||||
|
typedef llvm::DenseMap<const Decl *, llvm::Value *> OuterDeclMapTy;
|
||||||
|
void EmitOMPAggregateAssign(LValue OriginalAddr, llvm::Value *PrivateAddr,
|
||||||
|
const Expr *AssignExpr, QualType Type,
|
||||||
|
const VarDecl *VDInit);
|
||||||
|
void EmitOMPFirstprivateClause(const OMPExecutableDirective &D,
|
||||||
|
OuterDeclMapTy &OuterDeclMap);
|
||||||
|
|
||||||
void EmitOMPParallelDirective(const OMPParallelDirective &S);
|
void EmitOMPParallelDirective(const OMPParallelDirective &S);
|
||||||
void EmitOMPSimdDirective(const OMPSimdDirective &S);
|
void EmitOMPSimdDirective(const OMPSimdDirective &S);
|
||||||
|
|
|
@ -3902,11 +3902,36 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
|
||||||
return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
|
return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class DiagsUninitializedSeveretyRAII {
|
||||||
|
private:
|
||||||
|
DiagnosticsEngine &Diags;
|
||||||
|
SourceLocation SavedLoc;
|
||||||
|
bool IsIgnored;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DiagsUninitializedSeveretyRAII(DiagnosticsEngine &Diags, SourceLocation Loc,
|
||||||
|
bool IsIgnored)
|
||||||
|
: Diags(Diags), SavedLoc(Loc), IsIgnored(IsIgnored) {
|
||||||
|
if (!IsIgnored) {
|
||||||
|
Diags.setSeverity(/*Diag*/ diag::warn_uninit_self_reference_in_init,
|
||||||
|
/*Map*/ diag::Severity::Ignored, Loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~DiagsUninitializedSeveretyRAII() {
|
||||||
|
if (!IsIgnored)
|
||||||
|
Diags.popMappings(SavedLoc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
|
OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
|
||||||
SourceLocation StartLoc,
|
SourceLocation StartLoc,
|
||||||
SourceLocation LParenLoc,
|
SourceLocation LParenLoc,
|
||||||
SourceLocation EndLoc) {
|
SourceLocation EndLoc) {
|
||||||
SmallVector<Expr *, 8> Vars;
|
SmallVector<Expr *, 8> Vars;
|
||||||
|
SmallVector<Expr *, 8> PrivateCopies;
|
||||||
|
SmallVector<Expr *, 8> Inits;
|
||||||
bool IsImplicitClause =
|
bool IsImplicitClause =
|
||||||
StartLoc.isInvalid() && LParenLoc.isInvalid() && EndLoc.isInvalid();
|
StartLoc.isInvalid() && LParenLoc.isInvalid() && EndLoc.isInvalid();
|
||||||
auto ImplicitClauseLoc = DSAStack->getConstructLoc();
|
auto ImplicitClauseLoc = DSAStack->getConstructLoc();
|
||||||
|
@ -3916,11 +3941,13 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
|
||||||
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
|
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
|
||||||
// It will be analyzed later.
|
// It will be analyzed later.
|
||||||
Vars.push_back(RefExpr);
|
Vars.push_back(RefExpr);
|
||||||
|
PrivateCopies.push_back(nullptr);
|
||||||
|
Inits.push_back(nullptr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceLocation ELoc = IsImplicitClause ? ImplicitClauseLoc
|
SourceLocation ELoc =
|
||||||
: RefExpr->getExprLoc();
|
IsImplicitClause ? ImplicitClauseLoc : RefExpr->getExprLoc();
|
||||||
// OpenMP [2.1, C/C++]
|
// OpenMP [2.1, C/C++]
|
||||||
// A list item is a variable name.
|
// A list item is a variable name.
|
||||||
// OpenMP [2.9.3.3, Restrictions, p.1]
|
// OpenMP [2.9.3.3, Restrictions, p.1]
|
||||||
|
@ -3938,6 +3965,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
|
||||||
if (Type->isDependentType() || Type->isInstantiationDependentType()) {
|
if (Type->isDependentType() || Type->isInstantiationDependentType()) {
|
||||||
// It will be analyzed later.
|
// It will be analyzed later.
|
||||||
Vars.push_back(DE);
|
Vars.push_back(DE);
|
||||||
|
PrivateCopies.push_back(nullptr);
|
||||||
|
Inits.push_back(nullptr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3971,65 +4000,6 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
|
||||||
// clause requires an accessible, unambiguous copy constructor for the
|
// clause requires an accessible, unambiguous copy constructor for the
|
||||||
// class type.
|
// class type.
|
||||||
Type = Context.getBaseElementType(Type);
|
Type = Context.getBaseElementType(Type);
|
||||||
CXXRecordDecl *RD = getLangOpts().CPlusPlus
|
|
||||||
? Type.getNonReferenceType()->getAsCXXRecordDecl()
|
|
||||||
: nullptr;
|
|
||||||
// FIXME This code must be replaced by actual constructing/destructing of
|
|
||||||
// the firstprivate variable.
|
|
||||||
if (RD) {
|
|
||||||
CXXConstructorDecl *CD = LookupCopyingConstructor(RD, 0);
|
|
||||||
PartialDiagnostic PD =
|
|
||||||
PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
|
|
||||||
if (!CD ||
|
|
||||||
CheckConstructorAccess(ELoc, CD,
|
|
||||||
InitializedEntity::InitializeTemporary(Type),
|
|
||||||
CD->getAccess(), PD) == AR_inaccessible ||
|
|
||||||
CD->isDeleted()) {
|
|
||||||
if (IsImplicitClause) {
|
|
||||||
Diag(ImplicitClauseLoc,
|
|
||||||
diag::err_omp_task_predetermined_firstprivate_required_method)
|
|
||||||
<< 0;
|
|
||||||
Diag(RefExpr->getExprLoc(), diag::note_used_here);
|
|
||||||
} else {
|
|
||||||
Diag(ELoc, diag::err_omp_required_method)
|
|
||||||
<< getOpenMPClauseName(OMPC_firstprivate) << 1;
|
|
||||||
}
|
|
||||||
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
|
|
||||||
VarDecl::DeclarationOnly;
|
|
||||||
Diag(VD->getLocation(),
|
|
||||||
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
|
|
||||||
<< VD;
|
|
||||||
Diag(RD->getLocation(), diag::note_previous_decl) << RD;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
MarkFunctionReferenced(ELoc, CD);
|
|
||||||
DiagnoseUseOfDecl(CD, ELoc);
|
|
||||||
|
|
||||||
CXXDestructorDecl *DD = RD->getDestructor();
|
|
||||||
if (DD) {
|
|
||||||
if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
|
|
||||||
DD->isDeleted()) {
|
|
||||||
if (IsImplicitClause) {
|
|
||||||
Diag(ImplicitClauseLoc,
|
|
||||||
diag::err_omp_task_predetermined_firstprivate_required_method)
|
|
||||||
<< 1;
|
|
||||||
Diag(RefExpr->getExprLoc(), diag::note_used_here);
|
|
||||||
} else {
|
|
||||||
Diag(ELoc, diag::err_omp_required_method)
|
|
||||||
<< getOpenMPClauseName(OMPC_firstprivate) << 4;
|
|
||||||
}
|
|
||||||
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
|
|
||||||
VarDecl::DeclarationOnly;
|
|
||||||
Diag(VD->getLocation(),
|
|
||||||
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
|
|
||||||
<< VD;
|
|
||||||
Diag(RD->getLocation(), diag::note_previous_decl) << RD;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
MarkFunctionReferenced(ELoc, DD);
|
|
||||||
DiagnoseUseOfDecl(DD, ELoc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If an implicit firstprivate variable found it was checked already.
|
// If an implicit firstprivate variable found it was checked already.
|
||||||
if (!IsImplicitClause) {
|
if (!IsImplicitClause) {
|
||||||
|
@ -4119,15 +4089,67 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type = Type.getUnqualifiedType();
|
||||||
|
auto VDPrivate = VarDecl::Create(Context, CurContext, DE->getLocStart(),
|
||||||
|
ELoc, VD->getIdentifier(), VD->getType(),
|
||||||
|
VD->getTypeSourceInfo(), /*S*/ SC_Auto);
|
||||||
|
// Generate helper private variable and initialize it with the value of the
|
||||||
|
// original variable. The address of the original variable is replaced by
|
||||||
|
// the address of the new private variable in the CodeGen. This new variable
|
||||||
|
// is not added to IdResolver, so the code in the OpenMP region uses
|
||||||
|
// original variable for proper diagnostics and variable capturing.
|
||||||
|
Expr *VDInitRefExpr = nullptr;
|
||||||
|
// For arrays generate initializer for single element and replace it by the
|
||||||
|
// original array element in CodeGen.
|
||||||
|
if (DE->getType()->isArrayType()) {
|
||||||
|
auto VDInit = VarDecl::Create(Context, CurContext, DE->getLocStart(),
|
||||||
|
ELoc, VD->getIdentifier(), Type,
|
||||||
|
VD->getTypeSourceInfo(), /*S*/ SC_Auto);
|
||||||
|
CurContext->addHiddenDecl(VDInit);
|
||||||
|
VDInitRefExpr = DeclRefExpr::Create(
|
||||||
|
Context, /*QualifierLoc*/ NestedNameSpecifierLoc(),
|
||||||
|
/*TemplateKWLoc*/ SourceLocation(), VDInit,
|
||||||
|
/*isEnclosingLocal*/ false, ELoc, Type,
|
||||||
|
/*VK*/ VK_LValue);
|
||||||
|
VDInit->setIsUsed();
|
||||||
|
auto Init = DefaultLvalueConversion(VDInitRefExpr).get();
|
||||||
|
InitializedEntity Entity = InitializedEntity::InitializeVariable(VDInit);
|
||||||
|
InitializationKind Kind = InitializationKind::CreateCopy(ELoc, ELoc);
|
||||||
|
|
||||||
|
InitializationSequence InitSeq(*this, Entity, Kind, Init);
|
||||||
|
ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Init);
|
||||||
|
if (Result.isInvalid())
|
||||||
|
VDPrivate->setInvalidDecl();
|
||||||
|
else
|
||||||
|
VDPrivate->setInit(Result.getAs<Expr>());
|
||||||
|
} else {
|
||||||
|
AddInitializerToDecl(VDPrivate, DefaultLvalueConversion(DE).get(),
|
||||||
|
/*DirectInit*/ false, /*TypeMayContainAuto*/ false);
|
||||||
|
}
|
||||||
|
if (VDPrivate->isInvalidDecl()) {
|
||||||
|
if (IsImplicitClause) {
|
||||||
|
Diag(DE->getExprLoc(),
|
||||||
|
diag::note_omp_task_predetermined_firstprivate_here);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
CurContext->addDecl(VDPrivate);
|
||||||
|
auto VDPrivateRefExpr = DeclRefExpr::Create(
|
||||||
|
Context, /*QualifierLoc*/ NestedNameSpecifierLoc(),
|
||||||
|
/*TemplateKWLoc*/ SourceLocation(), VDPrivate,
|
||||||
|
/*isEnclosingLocal*/ false, DE->getLocStart(), DE->getType(),
|
||||||
|
/*VK*/ VK_LValue);
|
||||||
DSAStack->addDSA(VD, DE, OMPC_firstprivate);
|
DSAStack->addDSA(VD, DE, OMPC_firstprivate);
|
||||||
Vars.push_back(DE);
|
Vars.push_back(DE);
|
||||||
|
PrivateCopies.push_back(VDPrivateRefExpr);
|
||||||
|
Inits.push_back(VDInitRefExpr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Vars.empty())
|
if (Vars.empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
|
return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
|
||||||
Vars);
|
Vars, PrivateCopies, Inits);
|
||||||
}
|
}
|
||||||
|
|
||||||
OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
|
OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
|
||||||
|
|
|
@ -1854,6 +1854,14 @@ void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
|
||||||
for (unsigned i = 0; i != NumVars; ++i)
|
for (unsigned i = 0; i != NumVars; ++i)
|
||||||
Vars.push_back(Reader->Reader.ReadSubExpr());
|
Vars.push_back(Reader->Reader.ReadSubExpr());
|
||||||
C->setVarRefs(Vars);
|
C->setVarRefs(Vars);
|
||||||
|
Vars.clear();
|
||||||
|
for (unsigned i = 0; i != NumVars; ++i)
|
||||||
|
Vars.push_back(Reader->Reader.ReadSubExpr());
|
||||||
|
C->setPrivateCopies(Vars);
|
||||||
|
Vars.clear();
|
||||||
|
for (unsigned i = 0; i != NumVars; ++i)
|
||||||
|
Vars.push_back(Reader->Reader.ReadSubExpr());
|
||||||
|
C->setInits(Vars);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OMPClauseReader::VisitOMPLastprivateClause(OMPLastprivateClause *C) {
|
void OMPClauseReader::VisitOMPLastprivateClause(OMPLastprivateClause *C) {
|
||||||
|
|
|
@ -1761,8 +1761,15 @@ void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) {
|
||||||
void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
|
void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
|
||||||
Record.push_back(C->varlist_size());
|
Record.push_back(C->varlist_size());
|
||||||
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
|
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
|
||||||
for (auto *VE : C->varlists())
|
for (auto *VE : C->varlists()) {
|
||||||
Writer->Writer.AddStmt(VE);
|
Writer->Writer.AddStmt(VE);
|
||||||
|
}
|
||||||
|
for (auto *VE : C->private_copies()) {
|
||||||
|
Writer->Writer.AddStmt(VE);
|
||||||
|
}
|
||||||
|
for (auto *VE : C->inits()) {
|
||||||
|
Writer->Writer.AddStmt(VE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OMPClauseWriter::VisitOMPLastprivateClause(OMPLastprivateClause *C) {
|
void OMPClauseWriter::VisitOMPLastprivateClause(OMPLastprivateClause *C) {
|
||||||
|
|
|
@ -14,7 +14,7 @@ class S2 {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S2() : a(0) {}
|
S2() : a(0) {}
|
||||||
S2(S2 &s2) : a(s2.a) {}
|
S2(const S2 &s2) : a(s2.a) {}
|
||||||
static float S2s;
|
static float S2s;
|
||||||
static const float S2sc;
|
static const float S2sc;
|
||||||
};
|
};
|
||||||
|
@ -26,23 +26,23 @@ class S3 {
|
||||||
S3 &operator=(const S3 &s3);
|
S3 &operator=(const S3 &s3);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S3() : a(0) {}
|
S3() : a(0) {} // expected-note {{candidate constructor not viable: requires 0 arguments, but 1 was provided}}
|
||||||
S3(S3 &s3) : a(s3.a) {}
|
S3(S3 &s3) : a(s3.a) {} // expected-note {{candidate constructor not viable: 1st argument ('const S3') would lose const qualifier}}
|
||||||
};
|
};
|
||||||
const S3 c;
|
const S3 c;
|
||||||
const S3 ca[5];
|
const S3 ca[5];
|
||||||
extern const int f;
|
extern const int f;
|
||||||
class S4 { // expected-note 2 {{'S4' declared here}}
|
class S4 {
|
||||||
int a;
|
int a;
|
||||||
S4();
|
S4();
|
||||||
S4(const S4 &s4);
|
S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S4(int v) : a(v) {}
|
S4(int v) : a(v) {}
|
||||||
};
|
};
|
||||||
class S5 { // expected-note 4 {{'S5' declared here}}
|
class S5 {
|
||||||
int a;
|
int a;
|
||||||
S5(const S5 &s5) : a(s5.a) {}
|
S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S5() : a(0) {}
|
S5() : a(0) {}
|
||||||
|
@ -62,8 +62,8 @@ S3 h;
|
||||||
|
|
||||||
template <class I, class C>
|
template <class I, class C>
|
||||||
int foomain(int argc, char **argv) {
|
int foomain(int argc, char **argv) {
|
||||||
I e(4); // expected-note {{'e' defined here}}
|
I e(4);
|
||||||
C g(5); // expected-note 2 {{'g' defined here}}
|
C g(5);
|
||||||
int i;
|
int i;
|
||||||
int &j = i; // expected-note {{'j' defined here}}
|
int &j = i; // expected-note {{'j' defined here}}
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
|
@ -107,7 +107,7 @@ int foomain(int argc, char **argv) {
|
||||||
for (int k = 0; k < argc; ++k)
|
for (int k = 0; k < argc; ++k)
|
||||||
++k;
|
++k;
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp for firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp for firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
|
||||||
for (int k = 0; k < argc; ++k)
|
for (int k = 0; k < argc; ++k)
|
||||||
++k;
|
++k;
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
|
@ -138,7 +138,7 @@ int foomain(int argc, char **argv) {
|
||||||
for (int k = 0; k < argc; ++k)
|
for (int k = 0; k < argc; ++k)
|
||||||
++k;
|
++k;
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp for lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp for lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel private(i) // expected-note {{defined as private}}
|
#pragma omp parallel private(i) // expected-note {{defined as private}}
|
||||||
|
@ -155,8 +155,8 @@ int foomain(int argc, char **argv) {
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
const int d = 5;
|
const int d = 5;
|
||||||
const int da[5] = {0};
|
const int da[5] = {0};
|
||||||
S4 e(4); // expected-note {{'e' defined here}}
|
S4 e(4);
|
||||||
S5 g(5); // expected-note 2 {{'g' defined here}}
|
S5 g(5);
|
||||||
S3 m;
|
S3 m;
|
||||||
S6 n(2);
|
S6 n(2);
|
||||||
int i;
|
int i;
|
||||||
|
@ -194,7 +194,7 @@ int main(int argc, char **argv) {
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp for firstprivate(a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}}
|
#pragma omp for firstprivate(a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}} expected-error {{no matching constructor for initialization of 'const S3'}}
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
|
@ -235,7 +235,7 @@ int main(int argc, char **argv) {
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp for firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp for firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
|
@ -263,7 +263,7 @@ int main(int argc, char **argv) {
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp for lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp for lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
|
@ -291,3 +291,4 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
return foomain<S4, S5>(argc, argv); // expected-note {{in instantiation of function template specialization 'foomain<S4, S5>' requested here}}
|
return foomain<S4, S5>(argc, argv); // expected-note {{in instantiation of function template specialization 'foomain<S4, S5>' requested here}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ class S2 {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S2() : a(0) {}
|
S2() : a(0) {}
|
||||||
S2(S2 &s2) : a(s2.a) {}
|
S2(const S2 &s2) : a(s2.a) {}
|
||||||
static float S2s;
|
static float S2s;
|
||||||
static const float S2sc;
|
static const float S2sc;
|
||||||
};
|
};
|
||||||
|
@ -27,22 +27,22 @@ class S3 {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S3() : a(0) {}
|
S3() : a(0) {}
|
||||||
S3(S3 &s3) : a(s3.a) {}
|
S3(const S3 &s3) : a(s3.a) {}
|
||||||
};
|
};
|
||||||
const S3 c;
|
const S3 c;
|
||||||
const S3 ca[5];
|
const S3 ca[5];
|
||||||
extern const int f;
|
extern const int f;
|
||||||
class S4 { // expected-note 2 {{'S4' declared here}}
|
class S4 {
|
||||||
int a;
|
int a;
|
||||||
S4();
|
S4();
|
||||||
S4(const S4 &s4);
|
S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S4(int v) : a(v) {}
|
S4(int v) : a(v) {}
|
||||||
};
|
};
|
||||||
class S5 { // expected-note 4 {{'S5' declared here}}
|
class S5 {
|
||||||
int a;
|
int a;
|
||||||
S5(const S5 &s5) : a(s5.a) {}
|
S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S5() : a(0) {}
|
S5() : a(0) {}
|
||||||
|
@ -62,8 +62,8 @@ S3 h;
|
||||||
|
|
||||||
template <class I, class C>
|
template <class I, class C>
|
||||||
int foomain(int argc, char **argv) {
|
int foomain(int argc, char **argv) {
|
||||||
I e(4); // expected-note {{'e' defined here}}
|
I e(4);
|
||||||
C g(5); // expected-note 2 {{'g' defined here}}
|
C g(5);
|
||||||
int i;
|
int i;
|
||||||
int &j = i; // expected-note {{'j' defined here}}
|
int &j = i; // expected-note {{'j' defined here}}
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
|
@ -99,7 +99,7 @@ int foomain(int argc, char **argv) {
|
||||||
for (int k = 0; k < argc; ++k)
|
for (int k = 0; k < argc; ++k)
|
||||||
++k;
|
++k;
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp for simd firstprivate(a, b) // expected-error {{firstprivate variable with incomplete type 'S1'}}
|
#pragma omp for simd firstprivate(a, b) // expected-error {{a firstprivate variable with incomplete type 'S1'}}
|
||||||
for (int k = 0; k < argc; ++k)
|
for (int k = 0; k < argc; ++k)
|
||||||
++k;
|
++k;
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
|
@ -107,7 +107,7 @@ int foomain(int argc, char **argv) {
|
||||||
for (int k = 0; k < argc; ++k)
|
for (int k = 0; k < argc; ++k)
|
||||||
++k;
|
++k;
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp for simd firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp for simd firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
|
||||||
for (int k = 0; k < argc; ++k)
|
for (int k = 0; k < argc; ++k)
|
||||||
++k;
|
++k;
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
|
@ -138,7 +138,7 @@ int foomain(int argc, char **argv) {
|
||||||
for (int k = 0; k < argc; ++k)
|
for (int k = 0; k < argc; ++k)
|
||||||
++k;
|
++k;
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp for simd lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp for simd lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel private(i) // expected-note {{defined as private}}
|
#pragma omp parallel private(i) // expected-note {{defined as private}}
|
||||||
|
@ -155,8 +155,8 @@ int foomain(int argc, char **argv) {
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
const int d = 5;
|
const int d = 5;
|
||||||
const int da[5] = {0};
|
const int da[5] = {0};
|
||||||
S4 e(4); // expected-note {{'e' defined here}}
|
S4 e(4);
|
||||||
S5 g(5); // expected-note 2 {{'g' defined here}}
|
S5 g(5);
|
||||||
S3 m;
|
S3 m;
|
||||||
S6 n(2);
|
S6 n(2);
|
||||||
int i;
|
int i;
|
||||||
|
@ -235,7 +235,7 @@ int main(int argc, char **argv) {
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp for simd firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp for simd firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
|
@ -263,7 +263,7 @@ int main(int argc, char **argv) {
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp for simd lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp for simd lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
|
|
|
@ -39,7 +39,7 @@ int main (int argc, char **argv) {
|
||||||
// CHECK: [[ARGC_REF:%.+]] = getelementptr inbounds %struct.anon* [[AGG_CAPTURED]], i32 0, i32 0
|
// CHECK: [[ARGC_REF:%.+]] = getelementptr inbounds %struct.anon* [[AGG_CAPTURED]], i32 0, i32 0
|
||||||
// CHECK-NEXT: store i32* {{%[a-z0-9.]+}}, i32** [[ARGC_REF]]
|
// CHECK-NEXT: store i32* {{%[a-z0-9.]+}}, i32** [[ARGC_REF]]
|
||||||
// CHECK-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon* [[AGG_CAPTURED]] to i8*
|
// CHECK-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon* [[AGG_CAPTURED]] to i8*
|
||||||
// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @__captured_stmt to void (i32*, i32*, ...)*), i8* [[BITCAST]])
|
// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @.omp_outlined. to void (i32*, i32*, ...)*), i8* [[BITCAST]])
|
||||||
// CHECK-NEXT: [[ARGV:%.+]] = load i8*** {{%[a-z0-9.]+}}
|
// CHECK-NEXT: [[ARGV:%.+]] = load i8*** {{%[a-z0-9.]+}}
|
||||||
// CHECK-NEXT: [[RET:%.+]] = call {{[a-z]*[ ]?i32}} [[TMAIN:@.+tmain.+]](i8** [[ARGV]])
|
// CHECK-NEXT: [[RET:%.+]] = call {{[a-z]*[ ]?i32}} [[TMAIN:@.+tmain.+]](i8** [[ARGV]])
|
||||||
// CHECK-NEXT: ret i32 [[RET]]
|
// CHECK-NEXT: ret i32 [[RET]]
|
||||||
|
@ -55,13 +55,13 @@ int main (int argc, char **argv) {
|
||||||
// CHECK-DEBUG-NEXT: [[KMPC_LOC_PSOURCE_REF:%.+]] = getelementptr inbounds %ident_t* [[LOC_2_ADDR]], i32 0, i32 4
|
// CHECK-DEBUG-NEXT: [[KMPC_LOC_PSOURCE_REF:%.+]] = getelementptr inbounds %ident_t* [[LOC_2_ADDR]], i32 0, i32 4
|
||||||
// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.+}} x i8]* [[LOC1]], i32 0, i32 0), i8** [[KMPC_LOC_PSOURCE_REF]]
|
// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.+}} x i8]* [[LOC1]], i32 0, i32 0), i8** [[KMPC_LOC_PSOURCE_REF]]
|
||||||
// CHECK-DEBUG-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon* [[AGG_CAPTURED]] to i8*
|
// CHECK-DEBUG-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon* [[AGG_CAPTURED]] to i8*
|
||||||
// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @__captured_stmt to void (i32*, i32*, ...)*), i8* [[BITCAST]])
|
// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @.omp_outlined. to void (i32*, i32*, ...)*), i8* [[BITCAST]])
|
||||||
// CHECK-DEBUG-NEXT: [[ARGV:%.+]] = load i8*** {{%[a-z0-9.]+}}
|
// CHECK-DEBUG-NEXT: [[ARGV:%.+]] = load i8*** {{%[a-z0-9.]+}}
|
||||||
// CHECK-DEBUG-NEXT: [[RET:%.+]] = call i32 [[TMAIN:@.+tmain.+]](i8** [[ARGV]])
|
// CHECK-DEBUG-NEXT: [[RET:%.+]] = call i32 [[TMAIN:@.+tmain.+]](i8** [[ARGV]])
|
||||||
// CHECK-DEBUG-NEXT: ret i32 [[RET]]
|
// CHECK-DEBUG-NEXT: ret i32 [[RET]]
|
||||||
// CHECK-DEBUG-NEXT: }
|
// CHECK-DEBUG-NEXT: }
|
||||||
|
|
||||||
// CHECK-LABEL: define internal void @__captured_stmt(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
|
// CHECK-LABEL: define internal void @.omp_outlined.(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
|
||||||
// CHECK: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon*
|
// CHECK: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon*
|
||||||
// CHECK: store %struct.anon* %__context, %struct.anon** [[CONTEXT_ADDR]]
|
// CHECK: store %struct.anon* %__context, %struct.anon** [[CONTEXT_ADDR]]
|
||||||
// CHECK: [[CONTEXT_PTR:%.+]] = load %struct.anon** [[CONTEXT_ADDR]]
|
// CHECK: [[CONTEXT_PTR:%.+]] = load %struct.anon** [[CONTEXT_ADDR]]
|
||||||
|
@ -73,7 +73,7 @@ int main (int argc, char **argv) {
|
||||||
// CHECK: call void @{{.+terminate.*}}(
|
// CHECK: call void @{{.+terminate.*}}(
|
||||||
// CHECK-NEXT: unreachable
|
// CHECK-NEXT: unreachable
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
// CHECK-DEBUG-LABEL: define internal void @__captured_stmt(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
|
// CHECK-DEBUG-LABEL: define internal void @.omp_outlined.(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
|
||||||
// CHECK-DEBUG: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon*
|
// CHECK-DEBUG: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon*
|
||||||
// CHECK-DEBUG: store %struct.anon* %__context, %struct.anon** [[CONTEXT_ADDR]]
|
// CHECK-DEBUG: store %struct.anon* %__context, %struct.anon** [[CONTEXT_ADDR]]
|
||||||
// CHECK-DEBUG: [[CONTEXT_PTR:%.+]] = load %struct.anon** [[CONTEXT_ADDR]]
|
// CHECK-DEBUG: [[CONTEXT_PTR:%.+]] = load %struct.anon** [[CONTEXT_ADDR]]
|
||||||
|
@ -96,7 +96,7 @@ int main (int argc, char **argv) {
|
||||||
// CHECK: [[ARGC_REF:%.+]] = getelementptr inbounds %struct.anon.0* [[AGG_CAPTURED]], i32 0, i32 0
|
// CHECK: [[ARGC_REF:%.+]] = getelementptr inbounds %struct.anon.0* [[AGG_CAPTURED]], i32 0, i32 0
|
||||||
// CHECK-NEXT: store i8*** {{%[a-z0-9.]+}}, i8**** [[ARGC_REF]]
|
// CHECK-NEXT: store i8*** {{%[a-z0-9.]+}}, i8**** [[ARGC_REF]]
|
||||||
// CHECK-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon.0* [[AGG_CAPTURED]] to i8*
|
// CHECK-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon.0* [[AGG_CAPTURED]] to i8*
|
||||||
// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @__captured_stmt1 to void (i32*, i32*, ...)*), i8* [[BITCAST]])
|
// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @.omp_outlined.1 to void (i32*, i32*, ...)*), i8* [[BITCAST]])
|
||||||
// CHECK-NEXT: ret i32 0
|
// CHECK-NEXT: ret i32 0
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
// CHECK-DEBUG: define linkonce_odr i32 [[TMAIN]](i8** %argc)
|
// CHECK-DEBUG: define linkonce_odr i32 [[TMAIN]](i8** %argc)
|
||||||
|
@ -110,11 +110,11 @@ int main (int argc, char **argv) {
|
||||||
// CHECK-DEBUG-NEXT: [[KMPC_LOC_PSOURCE_REF:%.+]] = getelementptr inbounds %ident_t* [[LOC_2_ADDR]], i32 0, i32 4
|
// CHECK-DEBUG-NEXT: [[KMPC_LOC_PSOURCE_REF:%.+]] = getelementptr inbounds %ident_t* [[LOC_2_ADDR]], i32 0, i32 4
|
||||||
// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.+}} x i8]* [[LOC2]], i32 0, i32 0), i8** [[KMPC_LOC_PSOURCE_REF]]
|
// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.+}} x i8]* [[LOC2]], i32 0, i32 0), i8** [[KMPC_LOC_PSOURCE_REF]]
|
||||||
// CHECK-DEBUG-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon.0* [[AGG_CAPTURED]] to i8*
|
// CHECK-DEBUG-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon.0* [[AGG_CAPTURED]] to i8*
|
||||||
// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @__captured_stmt1 to void (i32*, i32*, ...)*), i8* [[BITCAST]])
|
// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @.omp_outlined.1 to void (i32*, i32*, ...)*), i8* [[BITCAST]])
|
||||||
// CHECK-DEBUG-NEXT: ret i32 0
|
// CHECK-DEBUG-NEXT: ret i32 0
|
||||||
// CHECK-DEBUG-NEXT: }
|
// CHECK-DEBUG-NEXT: }
|
||||||
|
|
||||||
// CHECK-LABEL: define internal void @__captured_stmt1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
|
// CHECK-LABEL: define internal void @.omp_outlined.1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
|
||||||
// CHECK: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon.0*
|
// CHECK: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon.0*
|
||||||
// CHECK: store %struct.anon.0* %__context, %struct.anon.0** [[CONTEXT_ADDR]]
|
// CHECK: store %struct.anon.0* %__context, %struct.anon.0** [[CONTEXT_ADDR]]
|
||||||
// CHECK: [[CONTEXT_PTR:%.+]] = load %struct.anon.0** [[CONTEXT_ADDR]]
|
// CHECK: [[CONTEXT_PTR:%.+]] = load %struct.anon.0** [[CONTEXT_ADDR]]
|
||||||
|
@ -126,7 +126,7 @@ int main (int argc, char **argv) {
|
||||||
// CHECK: call void @{{.+terminate.*}}(
|
// CHECK: call void @{{.+terminate.*}}(
|
||||||
// CHECK-NEXT: unreachable
|
// CHECK-NEXT: unreachable
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
// CHECK-DEBUG-LABEL: define internal void @__captured_stmt1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
|
// CHECK-DEBUG-LABEL: define internal void @.omp_outlined.1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
|
||||||
// CHECK-DEBUG: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon.0*
|
// CHECK-DEBUG: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon.0*
|
||||||
// CHECK-DEBUG: store %struct.anon.0* %__context, %struct.anon.0** [[CONTEXT_ADDR]]
|
// CHECK-DEBUG: store %struct.anon.0* %__context, %struct.anon.0** [[CONTEXT_ADDR]]
|
||||||
// CHECK-DEBUG: [[CONTEXT_PTR:%.+]] = load %struct.anon.0** [[CONTEXT_ADDR]]
|
// CHECK-DEBUG: [[CONTEXT_PTR:%.+]] = load %struct.anon.0** [[CONTEXT_ADDR]]
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -emit-llvm %s -o - | FileCheck %s
|
||||||
|
// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-unknown-unknown -emit-pch -o %t %s
|
||||||
|
// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
|
||||||
|
// expected-no-diagnostics
|
||||||
|
#ifndef HEADER
|
||||||
|
#define HEADER
|
||||||
|
|
||||||
|
struct St {
|
||||||
|
int a, b;
|
||||||
|
St() : a(0), b(0) {}
|
||||||
|
St(const St &st) : a(st.a + st.b), b(0) {}
|
||||||
|
~St() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct S {
|
||||||
|
T f;
|
||||||
|
S(T a) : f(a) {}
|
||||||
|
S() : f() {}
|
||||||
|
S(const S &s, St t = St()) : f(s.f + t.a) {}
|
||||||
|
operator T() { return T(); }
|
||||||
|
~S() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// CHECK-DAG: [[S_FLOAT_TY:%.+]] = type { float }
|
||||||
|
// CHECK-DAG: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} }
|
||||||
|
// CHECK-DAG: [[ST_TY:%.+]] = type { i{{[0-9]+}}, i{{[0-9]+}} }
|
||||||
|
// CHECK-DAG: [[CAP_MAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]* }
|
||||||
|
// CHECK-DAG: [[CAP_TMAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]* }
|
||||||
|
// CHECK-DAG: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8*
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T tmain() {
|
||||||
|
S<T> test;
|
||||||
|
T t_var = T();
|
||||||
|
T vec[] = {1, 2};
|
||||||
|
S<T> s_arr[] = {1, 2};
|
||||||
|
S<T> var(3);
|
||||||
|
#pragma omp parallel firstprivate(t_var, vec, s_arr, var)
|
||||||
|
{
|
||||||
|
vec[0] = t_var;
|
||||||
|
s_arr[0] = var;
|
||||||
|
}
|
||||||
|
return T();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
S<float> test;
|
||||||
|
int t_var = 0;
|
||||||
|
int vec[] = {1, 2};
|
||||||
|
S<float> s_arr[] = {1, 2};
|
||||||
|
S<float> var(3);
|
||||||
|
#pragma omp parallel firstprivate(t_var, vec, s_arr, var)
|
||||||
|
{
|
||||||
|
vec[0] = t_var;
|
||||||
|
s_arr[0] = var;
|
||||||
|
}
|
||||||
|
return tmain<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: define i{{[0-9]+}} @main()
|
||||||
|
// CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]],
|
||||||
|
// CHECK: call void [[S_FLOAT_TY_DEF_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]])
|
||||||
|
// CHECK: %{{.+}} = bitcast [[CAP_MAIN_TY]]*
|
||||||
|
// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...)* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_MAIN_TY]]*)* [[MAIN_MICROTASK:@.+]] to void
|
||||||
|
// CHECK: = call i{{.+}} [[TMAIN_INT:@.+]]()
|
||||||
|
// CHECK: call void [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]*
|
||||||
|
// CHECK: ret
|
||||||
|
//
|
||||||
|
// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_MAIN_TY]]* %{{.+}})
|
||||||
|
// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
|
||||||
|
// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
|
||||||
|
// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
|
||||||
|
// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
|
||||||
|
// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_ADDR]]
|
||||||
|
// 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_VAL:%.+]] = load i{{[0-9]+}}* [[T_VAR_REF]],
|
||||||
|
// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_PRIV]],
|
||||||
|
// CHECK: [[VEC_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0
|
||||||
|
// CHECK: [[VEC_REF:%.+]] = load [2 x i{{[0-9]+}}]** [[VEC_PTR_REF:%.+]],
|
||||||
|
// CHECK: br label %[[VEC_PRIV_INIT:.+]]
|
||||||
|
// CHECK: [[VEC_PRIV_INIT]]
|
||||||
|
// CHECK: [[VEC_DEST:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8*
|
||||||
|
// CHECK: [[VEC_SRC:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_REF]] to i8*
|
||||||
|
// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VEC_DEST]], i8* [[VEC_SRC]],
|
||||||
|
// CHECK: br label %[[VEC_PRIV_INIT_END:.+]]
|
||||||
|
// CHECK: [[VEC_PRIV_INIT_END]]
|
||||||
|
// CHECK: [[S_ARR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 2
|
||||||
|
// CHECK: [[S_ARR_REF:%.+]] = load [2 x [[S_FLOAT_TY]]]** [[S_ARR_REF_PTR]],
|
||||||
|
// CHECK: br label %[[S_ARR_PRIV_INIT:.+]]
|
||||||
|
// CHECK: [[S_ARR_PRIV_INIT]]
|
||||||
|
// CHECK: [[S_ARR_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]]* [[S_ARR_REF]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
|
||||||
|
// CHECK: [[S_ARR_PRIV_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]]* [[S_ARR_PRIV]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
|
||||||
|
// CHECK: [[S_ARR_END:%.+]] = getelementptr [[S_FLOAT_TY]]* [[S_ARR_BEGIN]], i{{[0-9]+}} 2
|
||||||
|
// CHECK: [[S_ARR_PRIV_END:%.+]] = getelementptr [[S_FLOAT_TY]]* [[S_ARR_PRIV_BEGIN]], i{{[0-9]+}} 2
|
||||||
|
// CHECK: [[IS_EMPTY:%.+]] = icmp eq [[S_FLOAT_TY]]* [[S_ARR_PRIV_BEGIN]], [[S_ARR_PRIV_END]]
|
||||||
|
// CHECK: br i1 [[IS_EMPTY]], label %[[S_ARR_BODY_DONE:.+]], label %[[S_ARR_BODY:.+]]
|
||||||
|
// CHECK: [[S_ARR_BODY]]
|
||||||
|
// CHECK: call void [[ST_TY_DEFAULT_CONSTR:@.+]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
|
||||||
|
// CHECK: call void [[S_FLOAT_TY_COPY_CONSTR:@.+]]([[S_FLOAT_TY]]* {{.+}}, [[S_FLOAT_TY]]* {{.+}}, [[ST_TY]]* [[ST_TY_TEMP]])
|
||||||
|
// CHECK: call void [[ST_TY_DESTR:@.+]]([[ST_TY]]* [[ST_TY_TEMP]])
|
||||||
|
// CHECK: br i1 {{.+}}, label %{{.+}}, label %[[S_ARR_BODY]]
|
||||||
|
// CHECK: br label %[[S_ARR_PRIV_INIT_END:.+]]
|
||||||
|
// CHECK: [[S_ARR_PRIV_INIT_END]]
|
||||||
|
// CHECK: [[VAR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 3
|
||||||
|
// CHECK: [[VAR_REF:%.+]] = load [[S_FLOAT_TY]]** [[VAR_REF_PTR]],
|
||||||
|
// CHECK: call void [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
|
||||||
|
// CHECK: call void [[S_FLOAT_TY_COPY_CONSTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]], [[S_FLOAT_TY]]* {{.*}} [[VAR_REF]], [[ST_TY]]* [[ST_TY_TEMP]])
|
||||||
|
// CHECK: call void [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]])
|
||||||
|
// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
|
||||||
|
// CHECK-DAG: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
|
||||||
|
// CHECK-DAG: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]*
|
||||||
|
// CHECK: ret void
|
||||||
|
|
||||||
|
// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
|
||||||
|
// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]],
|
||||||
|
// CHECK: call void [[S_INT_TY_DEF_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]])
|
||||||
|
// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...)* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_TMAIN_TY]]*)* [[TMAIN_MICROTASK:@.+]] to void
|
||||||
|
// CHECK: call void [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]*
|
||||||
|
// CHECK: ret
|
||||||
|
//
|
||||||
|
// CHECK: define internal void [[TMAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_TMAIN_TY]]* %{{.+}})
|
||||||
|
// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
|
||||||
|
// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
|
||||||
|
// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]],
|
||||||
|
// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]],
|
||||||
|
// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_ADDR]]
|
||||||
|
// 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_VAL:%.+]] = load i{{[0-9]+}}* [[T_VAR_REF]],
|
||||||
|
// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_PRIV]],
|
||||||
|
// CHECK: [[VEC_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0
|
||||||
|
// CHECK: [[VEC_REF:%.+]] = load [2 x i{{[0-9]+}}]** [[VEC_PTR_REF:%.+]],
|
||||||
|
// CHECK: br label %[[VEC_PRIV_INIT:.+]]
|
||||||
|
// CHECK: [[VEC_PRIV_INIT]]
|
||||||
|
// CHECK: [[VEC_DEST:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8*
|
||||||
|
// CHECK: [[VEC_SRC:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_REF]] to i8*
|
||||||
|
// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VEC_DEST]], i8* [[VEC_SRC]],
|
||||||
|
// CHECK: br label %[[VEC_PRIV_INIT_END:.+]]
|
||||||
|
// CHECK: [[VEC_PRIV_INIT_END]]
|
||||||
|
// CHECK: [[S_ARR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 2
|
||||||
|
// CHECK: [[S_ARR_REF:%.+]] = load [2 x [[S_INT_TY]]]** [[S_ARR_REF_PTR]],
|
||||||
|
// CHECK: br label %[[S_ARR_PRIV_INIT:.+]]
|
||||||
|
// CHECK: [[S_ARR_PRIV_INIT]]
|
||||||
|
// CHECK: [[S_ARR_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_INT_TY]]]* [[S_ARR_REF]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
|
||||||
|
// CHECK: [[S_ARR_PRIV_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_INT_TY]]]* [[S_ARR_PRIV]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
|
||||||
|
// CHECK: [[S_ARR_END:%.+]] = getelementptr [[S_INT_TY]]* [[S_ARR_BEGIN]], i{{[0-9]+}} 2
|
||||||
|
// CHECK: [[S_ARR_PRIV_END:%.+]] = getelementptr [[S_INT_TY]]* [[S_ARR_PRIV_BEGIN]], i{{[0-9]+}} 2
|
||||||
|
// CHECK: [[IS_EMPTY:%.+]] = icmp eq [[S_INT_TY]]* [[S_ARR_PRIV_BEGIN]], [[S_ARR_PRIV_END]]
|
||||||
|
// CHECK: br i1 [[IS_EMPTY]], label %[[S_ARR_BODY_DONE:.+]], label %[[S_ARR_BODY:.+]]
|
||||||
|
// CHECK: [[S_ARR_BODY]]
|
||||||
|
// CHECK: call void [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
|
||||||
|
// CHECK: call void [[S_INT_TY_COPY_CONSTR:@.+]]([[S_INT_TY]]* {{.+}}, [[S_INT_TY]]* {{.+}}, [[ST_TY]]* [[ST_TY_TEMP]])
|
||||||
|
// CHECK: call void [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]])
|
||||||
|
// CHECK: br i1 {{.+}}, label %{{.+}}, label %[[S_ARR_BODY]]
|
||||||
|
// CHECK: br label %[[S_ARR_PRIV_INIT_END:.+]]
|
||||||
|
// CHECK: [[S_ARR_PRIV_INIT_END]]
|
||||||
|
// CHECK: [[VAR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 3
|
||||||
|
// CHECK: [[VAR_REF:%.+]] = load [[S_INT_TY]]** [[VAR_REF_PTR]],
|
||||||
|
// CHECK: call void [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
|
||||||
|
// CHECK: call void [[S_INT_TY_COPY_CONSTR]]([[S_INT_TY]]* [[VAR_PRIV]], [[S_INT_TY]]* {{.*}} [[VAR_REF]], [[ST_TY]]* [[ST_TY_TEMP]])
|
||||||
|
// CHECK: call void [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]])
|
||||||
|
// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
|
||||||
|
// CHECK-DAG: call void [[S_INT_TY_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]])
|
||||||
|
// CHECK-DAG: call void [[S_INT_TY_DESTR]]([[S_INT_TY]]*
|
||||||
|
// CHECK: ret void
|
||||||
|
#endif
|
||||||
|
|
|
@ -13,7 +13,7 @@ class S2 {
|
||||||
mutable int a;
|
mutable int a;
|
||||||
public:
|
public:
|
||||||
S2():a(0) { }
|
S2():a(0) { }
|
||||||
S2(S2 &s2):a(s2.a) { }
|
S2(const S2 &s2):a(s2.a) { }
|
||||||
static float S2s;
|
static float S2s;
|
||||||
static const float S2sc;
|
static const float S2sc;
|
||||||
};
|
};
|
||||||
|
@ -24,22 +24,22 @@ class S3 {
|
||||||
int a;
|
int a;
|
||||||
public:
|
public:
|
||||||
S3():a(0) { }
|
S3():a(0) { }
|
||||||
S3(S3 &s3):a(s3.a) { }
|
S3(const S3 &s3):a(s3.a) { }
|
||||||
};
|
};
|
||||||
const S3 c;
|
const S3 c;
|
||||||
const S3 ca[5];
|
const S3 ca[5];
|
||||||
extern const int f;
|
extern const int f;
|
||||||
class S4 { // expected-note {{'S4' declared here}}
|
class S4 {
|
||||||
int a;
|
int a;
|
||||||
S4();
|
S4();
|
||||||
S4(const S4 &s4);
|
S4(const S4 &s4); // expected-note {{implicitly declared private here}}
|
||||||
public:
|
public:
|
||||||
S4(int v):a(v) { }
|
S4(int v):a(v) { }
|
||||||
};
|
};
|
||||||
class S5 { // expected-note {{'S5' declared here}}
|
class S5 {
|
||||||
int a;
|
int a;
|
||||||
S5():a(0) {}
|
S5():a(0) {}
|
||||||
S5(const S5 &s5):a(s5.a) { }
|
S5(const S5 &s5):a(s5.a) { } // expected-note {{implicitly declared private here}}
|
||||||
public:
|
public:
|
||||||
S5(int v):a(v) { }
|
S5(int v):a(v) { }
|
||||||
};
|
};
|
||||||
|
@ -50,8 +50,8 @@ S3 h;
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
const int d = 5;
|
const int d = 5;
|
||||||
const int da[5] = { 0 };
|
const int da[5] = { 0 };
|
||||||
S4 e(4); // expected-note {{'e' defined here}}
|
S4 e(4);
|
||||||
S5 g(5); // expected-note {{'g' defined here}}
|
S5 g(5);
|
||||||
int i;
|
int i;
|
||||||
int &j = i; // expected-note {{'j' defined here}}
|
int &j = i; // expected-note {{'j' defined here}}
|
||||||
#pragma omp parallel firstprivate // expected-error {{expected '(' after 'firstprivate'}}
|
#pragma omp parallel firstprivate // expected-error {{expected '(' after 'firstprivate'}}
|
||||||
|
@ -69,7 +69,7 @@ int main(int argc, char **argv) {
|
||||||
#pragma omp parallel firstprivate(da)
|
#pragma omp parallel firstprivate(da)
|
||||||
#pragma omp parallel firstprivate(S2::S2s)
|
#pragma omp parallel firstprivate(S2::S2s)
|
||||||
#pragma omp parallel firstprivate(S2::S2sc)
|
#pragma omp parallel firstprivate(S2::S2sc)
|
||||||
#pragma omp parallel firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp parallel firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
|
||||||
#pragma omp parallel firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
|
#pragma omp parallel firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
|
||||||
#pragma omp parallel private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}}
|
#pragma omp parallel private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}}
|
||||||
foo();
|
foo();
|
||||||
|
|
|
@ -14,7 +14,7 @@ class S2 {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S2() : a(0) {}
|
S2() : a(0) {}
|
||||||
S2(S2 &s2) : a(s2.a) {}
|
S2(const S2 &s2) : a(s2.a) {}
|
||||||
static float S2s;
|
static float S2s;
|
||||||
static const float S2sc;
|
static const float S2sc;
|
||||||
};
|
};
|
||||||
|
@ -27,22 +27,22 @@ class S3 {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S3() : a(0) {}
|
S3() : a(0) {}
|
||||||
S3(S3 &s3) : a(s3.a) {}
|
S3(const S3 &s3) : a(s3.a) {}
|
||||||
};
|
};
|
||||||
const S3 c;
|
const S3 c;
|
||||||
const S3 ca[5];
|
const S3 ca[5];
|
||||||
extern const int f;
|
extern const int f;
|
||||||
class S4 { // expected-note 2 {{'S4' declared here}}
|
class S4 {
|
||||||
int a;
|
int a;
|
||||||
S4();
|
S4();
|
||||||
S4(const S4 &s4);
|
S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S4(int v) : a(v) {}
|
S4(int v) : a(v) {}
|
||||||
};
|
};
|
||||||
class S5 { // expected-note 4 {{'S5' declared here}}
|
class S5 {
|
||||||
int a;
|
int a;
|
||||||
S5(const S5 &s5) : a(s5.a) {}
|
S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S5() : a(0) {}
|
S5() : a(0) {}
|
||||||
|
@ -62,8 +62,8 @@ S3 h;
|
||||||
|
|
||||||
template <class I, class C>
|
template <class I, class C>
|
||||||
int foomain(int argc, char **argv) {
|
int foomain(int argc, char **argv) {
|
||||||
I e(4); // expected-note {{'e' defined here}}
|
I e(4);
|
||||||
C g(5); // expected-note 2 {{'g' defined here}}
|
C g(5);
|
||||||
int i;
|
int i;
|
||||||
int &j = i; // expected-note {{'j' defined here}}
|
int &j = i; // expected-note {{'j' defined here}}
|
||||||
#pragma omp parallel for firstprivate // expected-error {{expected '(' after 'firstprivate'}}
|
#pragma omp parallel for firstprivate // expected-error {{expected '(' after 'firstprivate'}}
|
||||||
|
@ -96,7 +96,7 @@ int foomain(int argc, char **argv) {
|
||||||
#pragma omp parallel for firstprivate(argv[1]) // expected-error {{expected variable name}}
|
#pragma omp parallel for firstprivate(argv[1]) // expected-error {{expected variable name}}
|
||||||
for (int k = 0; k < argc; ++k)
|
for (int k = 0; k < argc; ++k)
|
||||||
++k;
|
++k;
|
||||||
#pragma omp parallel for firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp parallel for firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
|
||||||
for (int k = 0; k < argc; ++k)
|
for (int k = 0; k < argc; ++k)
|
||||||
++k;
|
++k;
|
||||||
#pragma omp parallel for firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
|
#pragma omp parallel for firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
|
||||||
|
@ -123,7 +123,7 @@ int foomain(int argc, char **argv) {
|
||||||
#pragma omp parallel for firstprivate(i)
|
#pragma omp parallel for firstprivate(i)
|
||||||
for (int k = 0; k < argc; ++k)
|
for (int k = 0; k < argc; ++k)
|
||||||
++k;
|
++k;
|
||||||
#pragma omp parallel for lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp parallel for lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel private(i)
|
#pragma omp parallel private(i)
|
||||||
|
@ -140,8 +140,8 @@ int foomain(int argc, char **argv) {
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
const int d = 5;
|
const int d = 5;
|
||||||
const int da[5] = {0};
|
const int da[5] = {0};
|
||||||
S4 e(4); // expected-note {{'e' defined here}}
|
S4 e(4);
|
||||||
S5 g(5); // expected-note 2 {{'g' defined here}}
|
S5 g(5);
|
||||||
S3 m;
|
S3 m;
|
||||||
S6 n(2);
|
S6 n(2);
|
||||||
int i;
|
int i;
|
||||||
|
@ -201,7 +201,7 @@ int main(int argc, char **argv) {
|
||||||
#pragma omp parallel for safelen(5) // expected-error {{unexpected OpenMP clause 'safelen' in directive '#pragma omp parallel for'}}
|
#pragma omp parallel for safelen(5) // expected-error {{unexpected OpenMP clause 'safelen' in directive '#pragma omp parallel for'}}
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel for firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp parallel for firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel for firstprivate(m) // OK
|
#pragma omp parallel for firstprivate(m) // OK
|
||||||
|
@ -223,7 +223,7 @@ int main(int argc, char **argv) {
|
||||||
#pragma omp parallel for firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}}
|
#pragma omp parallel for firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}}
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel for lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp parallel for lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel for lastprivate(n) firstprivate(n) // OK
|
#pragma omp parallel for lastprivate(n) firstprivate(n) // OK
|
||||||
|
|
|
@ -14,7 +14,7 @@ class S2 {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S2() : a(0) {}
|
S2() : a(0) {}
|
||||||
S2(S2 &s2) : a(s2.a) {}
|
S2(const S2 &s2) : a(s2.a) {}
|
||||||
static float S2s;
|
static float S2s;
|
||||||
static const float S2sc;
|
static const float S2sc;
|
||||||
};
|
};
|
||||||
|
@ -27,22 +27,22 @@ class S3 {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S3() : a(0) {}
|
S3() : a(0) {}
|
||||||
S3(S3 &s3) : a(s3.a) {}
|
S3(const S3 &s3) : a(s3.a) {}
|
||||||
};
|
};
|
||||||
const S3 c;
|
const S3 c;
|
||||||
const S3 ca[5];
|
const S3 ca[5];
|
||||||
extern const int f;
|
extern const int f;
|
||||||
class S4 { // expected-note 2 {{'S4' declared here}}
|
class S4 {
|
||||||
int a;
|
int a;
|
||||||
S4();
|
S4();
|
||||||
S4(const S4 &s4);
|
S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S4(int v) : a(v) {}
|
S4(int v) : a(v) {}
|
||||||
};
|
};
|
||||||
class S5 { // expected-note 4 {{'S5' declared here}}
|
class S5 {
|
||||||
int a;
|
int a;
|
||||||
S5(const S5 &s5) : a(s5.a) {}
|
S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S5() : a(0) {}
|
S5() : a(0) {}
|
||||||
|
@ -62,8 +62,8 @@ S3 h;
|
||||||
|
|
||||||
template <class I, class C>
|
template <class I, class C>
|
||||||
int foomain(int argc, char **argv) {
|
int foomain(int argc, char **argv) {
|
||||||
I e(4); // expected-note {{'e' defined here}}
|
I e(4);
|
||||||
C g(5); // expected-note 2 {{'g' defined here}}
|
C g(5);
|
||||||
int i;
|
int i;
|
||||||
int &j = i; // expected-note {{'j' defined here}}
|
int &j = i; // expected-note {{'j' defined here}}
|
||||||
#pragma omp parallel for simd firstprivate // expected-error {{expected '(' after 'firstprivate'}}
|
#pragma omp parallel for simd firstprivate // expected-error {{expected '(' after 'firstprivate'}}
|
||||||
|
@ -96,7 +96,7 @@ int foomain(int argc, char **argv) {
|
||||||
#pragma omp parallel for simd firstprivate(argv[1]) // expected-error {{expected variable name}}
|
#pragma omp parallel for simd firstprivate(argv[1]) // expected-error {{expected variable name}}
|
||||||
for (int k = 0; k < argc; ++k)
|
for (int k = 0; k < argc; ++k)
|
||||||
++k;
|
++k;
|
||||||
#pragma omp parallel for simd firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp parallel for simd firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
|
||||||
for (int k = 0; k < argc; ++k)
|
for (int k = 0; k < argc; ++k)
|
||||||
++k;
|
++k;
|
||||||
#pragma omp parallel for simd firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
|
#pragma omp parallel for simd firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
|
||||||
|
@ -122,7 +122,7 @@ int foomain(int argc, char **argv) {
|
||||||
#pragma omp parallel for simd firstprivate(i)
|
#pragma omp parallel for simd firstprivate(i)
|
||||||
for (int k = 0; k < argc; ++k)
|
for (int k = 0; k < argc; ++k)
|
||||||
++k;
|
++k;
|
||||||
#pragma omp parallel for simd lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp parallel for simd lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel private(i)
|
#pragma omp parallel private(i)
|
||||||
|
@ -139,8 +139,8 @@ int foomain(int argc, char **argv) {
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
const int d = 5;
|
const int d = 5;
|
||||||
const int da[5] = {0};
|
const int da[5] = {0};
|
||||||
S4 e(4); // expected-note {{'e' defined here}}
|
S4 e(4);
|
||||||
S5 g(5); // expected-note 2 {{'g' defined here}}
|
S5 g(5);
|
||||||
S3 m;
|
S3 m;
|
||||||
S6 n(2);
|
S6 n(2);
|
||||||
int i;
|
int i;
|
||||||
|
@ -200,7 +200,7 @@ int main(int argc, char **argv) {
|
||||||
#pragma omp parallel for simd safelen(5)
|
#pragma omp parallel for simd safelen(5)
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel for simd firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp parallel for simd firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel for simd firstprivate(m) // OK
|
#pragma omp parallel for simd firstprivate(m) // OK
|
||||||
|
@ -221,7 +221,7 @@ int main(int argc, char **argv) {
|
||||||
#pragma omp parallel for simd firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}}
|
#pragma omp parallel for simd firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}}
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel for simd lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp parallel for simd lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel for simd lastprivate(n) firstprivate(n) // OK
|
#pragma omp parallel for simd lastprivate(n) firstprivate(n) // OK
|
||||||
|
|
|
@ -14,7 +14,7 @@ class S2 {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S2() : a(0) {}
|
S2() : a(0) {}
|
||||||
S2(S2 &s2) : a(s2.a) {}
|
S2(const S2 &s2) : a(s2.a) {}
|
||||||
static float S2s;
|
static float S2s;
|
||||||
static const float S2sc;
|
static const float S2sc;
|
||||||
};
|
};
|
||||||
|
@ -27,22 +27,22 @@ class S3 {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S3() : a(0) {}
|
S3() : a(0) {}
|
||||||
S3(S3 &s3) : a(s3.a) {}
|
S3(const S3 &s3) : a(s3.a) {}
|
||||||
};
|
};
|
||||||
const S3 c;
|
const S3 c;
|
||||||
const S3 ca[5];
|
const S3 ca[5];
|
||||||
extern const int f;
|
extern const int f;
|
||||||
class S4 { // expected-note 2 {{'S4' declared here}}
|
class S4 {
|
||||||
int a;
|
int a;
|
||||||
S4();
|
S4();
|
||||||
S4(const S4 &s4);
|
S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S4(int v) : a(v) {}
|
S4(int v) : a(v) {}
|
||||||
};
|
};
|
||||||
class S5 { // expected-note 4 {{'S5' declared here}}
|
class S5 {
|
||||||
int a;
|
int a;
|
||||||
S5(const S5 &s5) : a(s5.a) {}
|
S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S5() : a(0) {}
|
S5() : a(0) {}
|
||||||
|
@ -62,8 +62,8 @@ S3 h;
|
||||||
|
|
||||||
template <class I, class C>
|
template <class I, class C>
|
||||||
int foomain(int argc, char **argv) {
|
int foomain(int argc, char **argv) {
|
||||||
I e(4); // expected-note {{'e' defined here}}
|
I e(4);
|
||||||
C g(5); // expected-note 2 {{'g' defined here}}
|
C g(5);
|
||||||
int i;
|
int i;
|
||||||
int &j = i; // expected-note {{'j' defined here}}
|
int &j = i; // expected-note {{'j' defined here}}
|
||||||
#pragma omp parallel sections firstprivate // expected-error {{expected '(' after 'firstprivate'}}
|
#pragma omp parallel sections firstprivate // expected-error {{expected '(' after 'firstprivate'}}
|
||||||
|
@ -106,7 +106,7 @@ int foomain(int argc, char **argv) {
|
||||||
{
|
{
|
||||||
foo();
|
foo();
|
||||||
}
|
}
|
||||||
#pragma omp parallel sections firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp parallel sections firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
|
||||||
{
|
{
|
||||||
foo();
|
foo();
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,7 @@ int foomain(int argc, char **argv) {
|
||||||
{
|
{
|
||||||
foo();
|
foo();
|
||||||
}
|
}
|
||||||
#pragma omp parallel sections lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp parallel sections lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
|
||||||
{
|
{
|
||||||
foo();
|
foo();
|
||||||
}
|
}
|
||||||
|
@ -158,8 +158,8 @@ int foomain(int argc, char **argv) {
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
const int d = 5;
|
const int d = 5;
|
||||||
const int da[5] = {0};
|
const int da[5] = {0};
|
||||||
S4 e(4); // expected-note {{'e' defined here}}
|
S4 e(4);
|
||||||
S5 g(5); // expected-note 2 {{'g' defined here}}
|
S5 g(5);
|
||||||
S3 m;
|
S3 m;
|
||||||
S6 n(2);
|
S6 n(2);
|
||||||
int i;
|
int i;
|
||||||
|
@ -237,7 +237,7 @@ int main(int argc, char **argv) {
|
||||||
{
|
{
|
||||||
foo();
|
foo();
|
||||||
}
|
}
|
||||||
#pragma omp parallel sections firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp parallel sections firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
|
||||||
{
|
{
|
||||||
foo();
|
foo();
|
||||||
}
|
}
|
||||||
|
@ -262,7 +262,7 @@ int main(int argc, char **argv) {
|
||||||
{
|
{
|
||||||
foo();
|
foo();
|
||||||
}
|
}
|
||||||
#pragma omp parallel sections lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp parallel sections lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
|
||||||
{
|
{
|
||||||
foo();
|
foo();
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ class S2 {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S2() : a(0) {}
|
S2() : a(0) {}
|
||||||
S2(S2 &s2) : a(s2.a) {}
|
S2(const S2 &s2) : a(s2.a) {}
|
||||||
static float S2s;
|
static float S2s;
|
||||||
static const float S2sc;
|
static const float S2sc;
|
||||||
};
|
};
|
||||||
|
@ -27,22 +27,22 @@ class S3 {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S3() : a(0) {}
|
S3() : a(0) {}
|
||||||
S3(S3 &s3) : a(s3.a) {}
|
S3(const S3 &s3) : a(s3.a) {}
|
||||||
};
|
};
|
||||||
const S3 c;
|
const S3 c;
|
||||||
const S3 ca[5];
|
const S3 ca[5];
|
||||||
extern const int f;
|
extern const int f;
|
||||||
class S4 { // expected-note 2 {{'S4' declared here}}
|
class S4 {
|
||||||
int a;
|
int a;
|
||||||
S4();
|
S4();
|
||||||
S4(const S4 &s4);
|
S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S4(int v) : a(v) {}
|
S4(int v) : a(v) {}
|
||||||
};
|
};
|
||||||
class S5 { // expected-note 4 {{'S5' declared here}}
|
class S5 {
|
||||||
int a;
|
int a;
|
||||||
S5(const S5 &s5) : a(s5.a) {}
|
S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S5() : a(0) {}
|
S5() : a(0) {}
|
||||||
|
@ -62,8 +62,8 @@ S3 h;
|
||||||
|
|
||||||
template <class I, class C>
|
template <class I, class C>
|
||||||
int foomain(int argc, char **argv) {
|
int foomain(int argc, char **argv) {
|
||||||
I e(4); // expected-note {{'e' defined here}}
|
I e(4);
|
||||||
C g(5); // expected-note 2 {{'g' defined here}}
|
C g(5);
|
||||||
int i;
|
int i;
|
||||||
int &j = i; // expected-note {{'j' defined here}}
|
int &j = i; // expected-note {{'j' defined here}}
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
|
@ -117,7 +117,7 @@ int foomain(int argc, char **argv) {
|
||||||
foo();
|
foo();
|
||||||
}
|
}
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp sections firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp sections firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
|
||||||
{
|
{
|
||||||
foo();
|
foo();
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ int foomain(int argc, char **argv) {
|
||||||
foo();
|
foo();
|
||||||
}
|
}
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp sections lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp sections lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
|
||||||
{
|
{
|
||||||
foo();
|
foo();
|
||||||
}
|
}
|
||||||
|
@ -173,8 +173,8 @@ int foomain(int argc, char **argv) {
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
const int d = 5;
|
const int d = 5;
|
||||||
const int da[5] = {0};
|
const int da[5] = {0};
|
||||||
S4 e(4); // expected-note {{'e' defined here}}
|
S4 e(4);
|
||||||
S5 g(5); // expected-note 2 {{'g' defined here}}
|
S5 g(5);
|
||||||
S3 m;
|
S3 m;
|
||||||
S6 n(2);
|
S6 n(2);
|
||||||
int i;
|
int i;
|
||||||
|
@ -271,7 +271,7 @@ int main(int argc, char **argv) {
|
||||||
foo();
|
foo();
|
||||||
}
|
}
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp sections firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp sections firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
|
||||||
{
|
{
|
||||||
foo();
|
foo();
|
||||||
}
|
}
|
||||||
|
@ -301,7 +301,7 @@ int main(int argc, char **argv) {
|
||||||
foo();
|
foo();
|
||||||
}
|
}
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp sections lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp sections lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
|
||||||
{
|
{
|
||||||
foo();
|
foo();
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ class S2 {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S2() : a(0) {}
|
S2() : a(0) {}
|
||||||
S2(S2 &s2) : a(s2.a) {}
|
S2(const S2 &s2) : a(s2.a) {}
|
||||||
static float S2s;
|
static float S2s;
|
||||||
static const float S2sc;
|
static const float S2sc;
|
||||||
};
|
};
|
||||||
|
@ -27,22 +27,22 @@ class S3 {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S3() : a(0) {}
|
S3() : a(0) {}
|
||||||
S3(S3 &s3) : a(s3.a) {}
|
S3(const S3 &s3) : a(s3.a) {}
|
||||||
};
|
};
|
||||||
const S3 c;
|
const S3 c;
|
||||||
const S3 ca[5];
|
const S3 ca[5];
|
||||||
extern const int f;
|
extern const int f;
|
||||||
class S4 { // expected-note 2 {{'S4' declared here}}
|
class S4 {
|
||||||
int a;
|
int a;
|
||||||
S4();
|
S4();
|
||||||
S4(const S4 &s4);
|
S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S4(int v) : a(v) {}
|
S4(int v) : a(v) {}
|
||||||
};
|
};
|
||||||
class S5 { // expected-note 4 {{'S5' declared here}}
|
class S5 {
|
||||||
int a;
|
int a;
|
||||||
S5(const S5 &s5) : a(s5.a) {}
|
S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S5() : a(0) {}
|
S5() : a(0) {}
|
||||||
|
@ -62,8 +62,8 @@ S3 h;
|
||||||
|
|
||||||
template <class I, class C>
|
template <class I, class C>
|
||||||
int foomain(int argc, char **argv) {
|
int foomain(int argc, char **argv) {
|
||||||
I e(4); // expected-note {{'e' defined here}}
|
I e(4);
|
||||||
C g(5); // expected-note 2 {{'g' defined here}}
|
C g(5);
|
||||||
int i;
|
int i;
|
||||||
int &j = i; // expected-note {{'j' defined here}}
|
int &j = i; // expected-note {{'j' defined here}}
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
|
@ -97,7 +97,7 @@ int foomain(int argc, char **argv) {
|
||||||
#pragma omp single firstprivate(argv[1]) // expected-error {{expected variable name}}
|
#pragma omp single firstprivate(argv[1]) // expected-error {{expected variable name}}
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp single firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp single firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp single firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
|
#pragma omp single firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
|
||||||
|
@ -121,7 +121,7 @@ int foomain(int argc, char **argv) {
|
||||||
#pragma omp single firstprivate(i)
|
#pragma omp single firstprivate(i)
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp single firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp single firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel private(i) // expected-note {{defined as private}}
|
#pragma omp parallel private(i) // expected-note {{defined as private}}
|
||||||
#pragma omp single firstprivate(i) // expected-error {{firstprivate variable must be shared}}
|
#pragma omp single firstprivate(i) // expected-error {{firstprivate variable must be shared}}
|
||||||
|
@ -135,8 +135,8 @@ int foomain(int argc, char **argv) {
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
const int d = 5;
|
const int d = 5;
|
||||||
const int da[5] = {0};
|
const int da[5] = {0};
|
||||||
S4 e(4); // expected-note {{'e' defined here}}
|
S4 e(4);
|
||||||
S5 g(5); // expected-note 2 {{'g' defined here}}
|
S5 g(5);
|
||||||
S3 m;
|
S3 m;
|
||||||
S6 n(2);
|
S6 n(2);
|
||||||
int i;
|
int i;
|
||||||
|
@ -197,7 +197,7 @@ int main(int argc, char **argv) {
|
||||||
#pragma omp single safelen(5) // expected-error {{unexpected OpenMP clause 'safelen' in directive '#pragma omp single'}}
|
#pragma omp single safelen(5) // expected-error {{unexpected OpenMP clause 'safelen' in directive '#pragma omp single'}}
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp single firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp single firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp single firstprivate(m) // OK
|
#pragma omp single firstprivate(m) // OK
|
||||||
|
@ -215,7 +215,7 @@ int main(int argc, char **argv) {
|
||||||
#pragma omp single firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}}
|
#pragma omp single firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}}
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp single firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp single firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
|
||||||
foo();
|
foo();
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp single firstprivate(n) // OK
|
#pragma omp single firstprivate(n) // OK
|
||||||
|
|
|
@ -14,7 +14,7 @@ class S2 {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S2() : a(0) {}
|
S2() : a(0) {}
|
||||||
S2(S2 &s2) : a(s2.a) {}
|
S2(const S2 &s2) : a(s2.a) {}
|
||||||
static float S2s;
|
static float S2s;
|
||||||
static const float S2sc;
|
static const float S2sc;
|
||||||
};
|
};
|
||||||
|
@ -26,23 +26,23 @@ class S3 {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S3() : a(0) {}
|
S3() : a(0) {}
|
||||||
S3(S3 &s3) : a(s3.a) {}
|
S3(const S3 &s3) : a(s3.a) {}
|
||||||
};
|
};
|
||||||
const S3 c;
|
const S3 c;
|
||||||
const S3 ca[5];
|
const S3 ca[5];
|
||||||
extern const int f;
|
extern const int f;
|
||||||
class S4 { // expected-note {{'S4' declared here}}
|
class S4 {
|
||||||
int a;
|
int a;
|
||||||
S4();
|
S4();
|
||||||
S4(const S4 &s4);
|
S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S4(int v) : a(v) {}
|
S4(int v) : a(v) {}
|
||||||
};
|
};
|
||||||
class S5 { // expected-note {{'S5' declared here}}
|
class S5 {
|
||||||
int a;
|
int a;
|
||||||
S5() : a(0) {}
|
S5() : a(0) {}
|
||||||
S5(const S5 &s5) : a(s5.a) {}
|
S5(const S5 &s5) : a(s5.a) {} // expected-note 2 {{implicitly declared private here}}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
S5(int v) : a(v) {}
|
S5(int v) : a(v) {}
|
||||||
|
@ -54,8 +54,8 @@ S3 h;
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
const int d = 5;
|
const int d = 5;
|
||||||
const int da[5] = {0};
|
const int da[5] = {0};
|
||||||
S4 e(4); // expected-note {{'e' defined here}}
|
S4 e(4);
|
||||||
S5 g(5); // expected-note {{'g' defined here}}
|
S5 g(5);
|
||||||
int i;
|
int i;
|
||||||
int &j = i; // expected-note {{'j' defined here}}
|
int &j = i; // expected-note {{'j' defined here}}
|
||||||
#pragma omp task firstprivate // expected-error {{expected '(' after 'firstprivate'}}
|
#pragma omp task firstprivate // expected-error {{expected '(' after 'firstprivate'}}
|
||||||
|
@ -73,7 +73,7 @@ int main(int argc, char **argv) {
|
||||||
#pragma omp task firstprivate(da)
|
#pragma omp task firstprivate(da)
|
||||||
#pragma omp task firstprivate(S2::S2s)
|
#pragma omp task firstprivate(S2::S2s)
|
||||||
#pragma omp task firstprivate(S2::S2sc)
|
#pragma omp task firstprivate(S2::S2sc)
|
||||||
#pragma omp task firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
|
#pragma omp task firstprivate(e, g) // expected-error 2 {{calling a private constructor of class 'S4'}} expected-error 2 {{calling a private constructor of class 'S5'}}
|
||||||
#pragma omp task firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
|
#pragma omp task firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
|
||||||
#pragma omp task private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}}
|
#pragma omp task private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}}
|
||||||
foo();
|
foo();
|
||||||
|
|
|
@ -5,8 +5,8 @@ void foo() {
|
||||||
|
|
||||||
#pragma omp task // expected-error {{unexpected OpenMP directive '#pragma omp task'}}
|
#pragma omp task // expected-error {{unexpected OpenMP directive '#pragma omp task'}}
|
||||||
|
|
||||||
class S { // expected-note 6 {{'S' declared here}}
|
class S {
|
||||||
S(const S &s) { a = s.a + 12; }
|
S(const S &s) { a = s.a + 12; } // expected-note 6 {{implicitly declared private here}}
|
||||||
int a;
|
int a;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -17,23 +17,35 @@ public:
|
||||||
S operator+(const S &) { return *this; }
|
S operator+(const S &) { return *this; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class S1 {
|
||||||
|
int a;
|
||||||
|
|
||||||
|
public:
|
||||||
|
S1() : a(0) {}
|
||||||
|
S1 &operator++() { return *this; }
|
||||||
|
S1(const S1 &) = delete; // expected-note 2 {{'S1' has been explicitly marked deleted here}}
|
||||||
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
int foo() {
|
int foo() {
|
||||||
T a; // expected-note 3 {{'a' defined here}}
|
T a;
|
||||||
T &b = a; // expected-note 4 {{'b' defined here}}
|
T &b = a; // expected-note 4 {{'b' defined here}}
|
||||||
int r;
|
int r;
|
||||||
|
S1 s1;
|
||||||
|
// expected-error@+1 2 {{call to deleted constructor of 'S1'}}
|
||||||
|
#pragma omp task
|
||||||
|
// expected-note@+1 2 {{predetermined as a firstprivate in a task construct here}}
|
||||||
|
++s1;
|
||||||
#pragma omp task default(none)
|
#pragma omp task default(none)
|
||||||
#pragma omp task default(shared)
|
#pragma omp task default(shared)
|
||||||
++a;
|
++a;
|
||||||
// expected-error@+2 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}}
|
|
||||||
#pragma omp task default(none)
|
#pragma omp task default(none)
|
||||||
#pragma omp task
|
#pragma omp task
|
||||||
// expected-note@+1 {{used here}}
|
// expected-error@+1 {{calling a private constructor of class 'S'}}
|
||||||
++a;
|
++a;
|
||||||
#pragma omp task
|
#pragma omp task
|
||||||
// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}}
|
|
||||||
#pragma omp task
|
#pragma omp task
|
||||||
// expected-note@+1 {{used here}}
|
// expected-error@+1 {{calling a private constructor of class 'S'}}
|
||||||
++a;
|
++a;
|
||||||
#pragma omp task default(shared)
|
#pragma omp task default(shared)
|
||||||
#pragma omp task
|
#pragma omp task
|
||||||
|
@ -46,11 +58,11 @@ int foo() {
|
||||||
#pragma omp task
|
#pragma omp task
|
||||||
// expected-note@+1 2 {{used here}}
|
// expected-note@+1 2 {{used here}}
|
||||||
++b;
|
++b;
|
||||||
// expected-error@+3 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'int &'}}
|
// expected-error@+2 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'int &'}}
|
||||||
// expected-error@+2 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'S &'}}
|
// expected-error@+1 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'S &'}}
|
||||||
// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}}
|
|
||||||
#pragma omp task
|
#pragma omp task
|
||||||
// expected-note@+1 3 {{used here}}
|
// expected-error@+2 {{calling a private constructor of class 'S'}}
|
||||||
|
// expected-note@+1 2 {{used here}}
|
||||||
#pragma omp parallel shared(a, b)
|
#pragma omp parallel shared(a, b)
|
||||||
++a, ++b;
|
++a, ++b;
|
||||||
// expected-note@+1 3 {{defined as reduction}}
|
// expected-note@+1 3 {{defined as reduction}}
|
||||||
|
@ -109,7 +121,7 @@ int foo() {
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
int a;
|
int a;
|
||||||
int &b = a; // expected-note 2 {{'b' defined here}}
|
int &b = a; // expected-note 2 {{'b' defined here}}
|
||||||
S sa; // expected-note 3 {{'sa' defined here}}
|
S sa;
|
||||||
S &sb = sa; // expected-note 2 {{'sb' defined here}}
|
S &sb = sa; // expected-note 2 {{'sb' defined here}}
|
||||||
int r;
|
int r;
|
||||||
#pragma omp task { // expected-warning {{extra tokens at the end of '#pragma omp task' are ignored}}
|
#pragma omp task { // expected-warning {{extra tokens at the end of '#pragma omp task' are ignored}}
|
||||||
|
@ -193,14 +205,12 @@ L2:
|
||||||
#pragma omp task default(shared)
|
#pragma omp task default(shared)
|
||||||
++sa;
|
++sa;
|
||||||
#pragma omp task default(none)
|
#pragma omp task default(none)
|
||||||
// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}}
|
|
||||||
#pragma omp task
|
#pragma omp task
|
||||||
// expected-note@+1 {{used here}}
|
// expected-error@+1 {{calling a private constructor of class 'S'}}
|
||||||
++sa;
|
++sa;
|
||||||
#pragma omp task
|
#pragma omp task
|
||||||
// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}}
|
|
||||||
#pragma omp task
|
#pragma omp task
|
||||||
// expected-note@+1 {{used here}}
|
// expected-error@+1 {{calling a private constructor of class 'S'}}
|
||||||
++sa;
|
++sa;
|
||||||
#pragma omp task default(shared)
|
#pragma omp task default(shared)
|
||||||
#pragma omp task
|
#pragma omp task
|
||||||
|
@ -212,10 +222,10 @@ L2:
|
||||||
#pragma omp task
|
#pragma omp task
|
||||||
// expected-note@+1 {{used here}}
|
// expected-note@+1 {{used here}}
|
||||||
++sb;
|
++sb;
|
||||||
// expected-error@+2 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'S &'}}
|
// expected-error@+1 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'S &'}}
|
||||||
// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}}
|
|
||||||
#pragma omp task
|
#pragma omp task
|
||||||
// expected-note@+1 2 {{used here}}
|
// expected-error@+2 {{calling a private constructor of class 'S'}}
|
||||||
|
// expected-note@+1 {{used here}}
|
||||||
#pragma omp parallel shared(sa, sb)
|
#pragma omp parallel shared(sa, sb)
|
||||||
++sa, ++sb;
|
++sa, ++sb;
|
||||||
// expected-note@+1 2 {{defined as reduction}}
|
// expected-note@+1 2 {{defined as reduction}}
|
||||||
|
|
Loading…
Reference in New Issue