Vendor import of clang release_70 branch r339999:

https://llvm.org/svn/llvm-project/cfe/branches/release_70@339999
This commit is contained in:
Dimitry Andric 2018-08-18 08:26:59 +00:00
parent 46faa67da1
commit 5a4cb1eb0c
42 changed files with 1075 additions and 492 deletions

View File

@ -186,6 +186,12 @@ Windows Support
Visual Studio's default stdafx.h setup now uses precompiled headers with
clang-cl.
- The alternative entry point names
(``wmain``/``WinMain``/``wWinMain``/``DllMain``) now are properly mangled
as plain C names in C++ contexts when targeting MinGW, without having to
explicit specify ``extern "C"``. (This was already the case for MSVC
targets.)
- ...

View File

@ -2718,7 +2718,7 @@ public:
/// predicate.
void forEachMultiversionedFunctionVersion(
const FunctionDecl *FD,
llvm::function_ref<void(const FunctionDecl *)> Pred) const;
llvm::function_ref<void(FunctionDecl *)> Pred) const;
const CXXConstructorDecl *
getCopyConstructorForExceptionObject(CXXRecordDecl *RD);

View File

@ -922,8 +922,11 @@ public:
/// \endcode
/// In this example directive '#pragma omp for' has 'ordered' clause with
/// parameter 2.
class OMPOrderedClause : public OMPClause {
class OMPOrderedClause final
: public OMPClause,
private llvm::TrailingObjects<OMPOrderedClause, Expr *> {
friend class OMPClauseReader;
friend TrailingObjects;
/// Location of '('.
SourceLocation LParenLoc;
@ -931,6 +934,26 @@ class OMPOrderedClause : public OMPClause {
/// Number of for-loops.
Stmt *NumForLoops = nullptr;
/// Real number of loops.
unsigned NumberOfLoops = 0;
/// Build 'ordered' clause.
///
/// \param Num Expression, possibly associated with this clause.
/// \param NumLoops Number of loops, associated with this clause.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
OMPOrderedClause(Expr *Num, unsigned NumLoops, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation EndLoc)
: OMPClause(OMPC_ordered, StartLoc, EndLoc), LParenLoc(LParenLoc),
NumForLoops(Num), NumberOfLoops(NumLoops) {}
/// Build an empty clause.
explicit OMPOrderedClause(unsigned NumLoops)
: OMPClause(OMPC_ordered, SourceLocation(), SourceLocation()),
NumberOfLoops(NumLoops) {}
/// Set the number of associated for-loops.
void setNumForLoops(Expr *Num) { NumForLoops = Num; }
@ -938,17 +961,17 @@ public:
/// Build 'ordered' clause.
///
/// \param Num Expression, possibly associated with this clause.
/// \param NumLoops Number of loops, associated with this clause.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
OMPOrderedClause(Expr *Num, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation EndLoc)
: OMPClause(OMPC_ordered, StartLoc, EndLoc), LParenLoc(LParenLoc),
NumForLoops(Num) {}
static OMPOrderedClause *Create(const ASTContext &C, Expr *Num,
unsigned NumLoops, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
/// Build an empty clause.
explicit OMPOrderedClause()
: OMPClause(OMPC_ordered, SourceLocation(), SourceLocation()) {}
static OMPOrderedClause* CreateEmpty(const ASTContext &C, unsigned NumLoops);
/// Sets the location of '('.
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
@ -959,6 +982,17 @@ public:
/// Return the number of associated for-loops.
Expr *getNumForLoops() const { return cast_or_null<Expr>(NumForLoops); }
/// Set number of iterations for the specified loop.
void setLoopNumIterations(unsigned NumLoop, Expr *NumIterations);
/// Get number of iterations for all the loops.
ArrayRef<Expr *> getLoopNumIterations() const;
/// Set loop counter for the specified loop.
void setLoopCounter(unsigned NumLoop, Expr *Counter);
/// Get loops counter for the specified loop.
Expr *getLoopCunter(unsigned NumLoop);
const Expr *getLoopCunter(unsigned NumLoop) const;
child_range children() { return child_range(&NumForLoops, &NumForLoops + 1); }
static bool classof(const OMPClause *T) {
@ -3087,24 +3121,32 @@ class OMPDependClause final
/// Colon location.
SourceLocation ColonLoc;
/// Number of loops, associated with the depend clause.
unsigned NumLoops = 0;
/// Build clause with number of variables \a N.
///
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
/// \param N Number of the variables in the clause.
/// \param NumLoops Number of loops that is associated with this depend
/// clause.
OMPDependClause(SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc, unsigned N)
SourceLocation EndLoc, unsigned N, unsigned NumLoops)
: OMPVarListClause<OMPDependClause>(OMPC_depend, StartLoc, LParenLoc,
EndLoc, N) {}
EndLoc, N), NumLoops(NumLoops) {}
/// Build an empty clause.
///
/// \param N Number of variables.
explicit OMPDependClause(unsigned N)
/// \param NumLoops Number of loops that is associated with this depend
/// clause.
explicit OMPDependClause(unsigned N, unsigned NumLoops)
: OMPVarListClause<OMPDependClause>(OMPC_depend, SourceLocation(),
SourceLocation(), SourceLocation(),
N) {}
N),
NumLoops(NumLoops) {}
/// Set dependency kind.
void setDependencyKind(OpenMPDependClauseKind K) { DepKind = K; }
@ -3126,16 +3168,23 @@ public:
/// \param DepLoc Location of the dependency type.
/// \param ColonLoc Colon location.
/// \param VL List of references to the variables.
static OMPDependClause *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc, OpenMPDependClauseKind DepKind,
SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL);
/// \param NumLoops Number of loops that is associated with this depend
/// clause.
static OMPDependClause *Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc,
OpenMPDependClauseKind DepKind,
SourceLocation DepLoc, SourceLocation ColonLoc,
ArrayRef<Expr *> VL, unsigned NumLoops);
/// Creates an empty clause with \a N variables.
///
/// \param C AST context.
/// \param N The number of variables.
static OMPDependClause *CreateEmpty(const ASTContext &C, unsigned N);
/// \param NumLoops Number of loops that is associated with this depend
/// clause.
static OMPDependClause *CreateEmpty(const ASTContext &C, unsigned N,
unsigned NumLoops);
/// Get dependency type.
OpenMPDependClauseKind getDependencyKind() const { return DepKind; }
@ -3146,15 +3195,16 @@ public:
/// Get colon location.
SourceLocation getColonLoc() const { return ColonLoc; }
/// Set the loop counter value for the depend clauses with 'sink|source' kind
/// of dependency. Required for codegen.
void setCounterValue(Expr *V);
/// Get number of loops associated with the clause.
unsigned getNumLoops() const { return NumLoops; }
/// Get the loop counter value.
Expr *getCounterValue();
/// Set the loop data for the depend clauses with 'sink|source' kind of
/// dependency.
void setLoopData(unsigned NumLoop, Expr *Cnt);
/// Get the loop counter value.
const Expr *getCounterValue() const;
/// Get the loop data.
Expr *getLoopData(unsigned NumLoop);
const Expr *getLoopData(unsigned NumLoop) const;
child_range children() {
return child_range(reinterpret_cast<Stmt **>(varlist_begin()),

View File

@ -2938,9 +2938,10 @@ def OMPDeclareSimdDecl : Attr {
}];
}
def OMPDeclareTargetDecl : Attr {
def OMPDeclareTargetDecl : InheritableAttr {
let Spellings = [Pragma<"omp", "declare target">];
let SemaHandler = 0;
let Subjects = SubjectList<[Function, SharedVar]>;
let Documentation = [OMPDeclareTargetDocs];
let Args = [
EnumArgument<"MapType", "MapTypeTy",
@ -2953,6 +2954,15 @@ def OMPDeclareTargetDecl : Attr {
if (getMapType() != MT_To)
OS << ' ' << ConvertMapTypeTyToStr(getMapType());
}
static llvm::Optional<MapTypeTy>
isDeclareTargetDeclaration(const ValueDecl *VD) {
if (!VD->hasAttrs())
return llvm::None;
if (const auto *Attr = VD->getAttr<OMPDeclareTargetDeclAttr>())
return Attr->getMapType();
return llvm::None;
}
}];
}

View File

@ -364,7 +364,6 @@ def NonVirtualDtor : DiagGroup<"non-virtual-dtor">;
def NullPointerArithmetic : DiagGroup<"null-pointer-arithmetic">;
def : DiagGroup<"effc++", [NonVirtualDtor]>;
def OveralignedType : DiagGroup<"over-aligned">;
def AlignedAllocationUnavailable : DiagGroup<"aligned-allocation-unavailable">;
def OldStyleCast : DiagGroup<"old-style-cast">;
def : DiagGroup<"old-style-definition">;
def OutOfLineDeclaration : DiagGroup<"out-of-line-declaration">;

View File

@ -6465,12 +6465,12 @@ def warn_overaligned_type : Warning<
"type %0 requires %1 bytes of alignment and the default allocator only "
"guarantees %2 bytes">,
InGroup<OveralignedType>, DefaultIgnore;
def warn_aligned_allocation_unavailable :Warning<
def err_aligned_allocation_unavailable : Error<
"aligned %select{allocation|deallocation}0 function of type '%1' is only "
"available on %2 %3 or newer">, InGroup<AlignedAllocationUnavailable>, DefaultError;
"available on %2 %3 or newer">;
def note_silence_unligned_allocation_unavailable : Note<
"if you supply your own aligned allocation functions, use "
"-Wno-aligned-allocation-unavailable to silence this diagnostic">;
"-faligned-allocation to silence this diagnostic">;
def err_conditional_void_nonvoid : Error<
"%select{left|right}1 operand to ? is void, but %select{right|left}1 operand "

View File

@ -1488,7 +1488,7 @@ def fobjc_weak : Flag<["-"], "fobjc-weak">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable ARC-style weak references in Objective-C">;
// Objective-C ABI options.
def fobjc_runtime_EQ : Joined<["-"], "fobjc-runtime=">, Group<f_Group>, Flags<[CC1Option]>,
def fobjc_runtime_EQ : Joined<["-"], "fobjc-runtime=">, Group<f_Group>, Flags<[CC1Option, CoreOption]>,
HelpText<"Specify the target Objective-C runtime kind and version">;
def fobjc_abi_version_EQ : Joined<["-"], "fobjc-abi-version=">, Group<f_Group>;
def fobjc_nonfragile_abi_version_EQ : Joined<["-"], "fobjc-nonfragile-abi-version=">, Group<f_Group>;

View File

@ -9798,20 +9798,16 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
return true;
// If the decl is marked as `declare target`, it should be emitted.
for (const auto *Decl : D->redecls()) {
if (!Decl->hasAttrs())
continue;
if (const auto *Attr = Decl->getAttr<OMPDeclareTargetDeclAttr>())
if (Attr->getMapType() != OMPDeclareTargetDeclAttr::MT_Link)
return true;
}
if (const llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
return *Res != OMPDeclareTargetDeclAttr::MT_Link;
return false;
}
void ASTContext::forEachMultiversionedFunctionVersion(
const FunctionDecl *FD,
llvm::function_ref<void(const FunctionDecl *)> Pred) const {
llvm::function_ref<void(FunctionDecl *)> Pred) const {
assert(FD->isMultiVersion() && "Only valid for multiversioned functions");
llvm::SmallDenseSet<const FunctionDecl*, 4> SeenDecls;
FD = FD->getCanonicalDecl();

View File

@ -1091,6 +1091,10 @@ void DeclPrinter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
printTemplateParameters(FD->getTemplateParameterList(I));
}
VisitRedeclarableTemplateDecl(D);
// Declare target attribute is special one, natural spelling for the pragma
// assumes "ending" construct so print it here.
if (D->getTemplatedDecl()->hasAttr<OMPDeclareTargetDeclAttr>())
Out << "#pragma omp end declare target\n";
// Never print "instantiations" for deduction guides (they don't really
// have them).

View File

@ -445,7 +445,7 @@ void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) {
mangleFunctionEncoding(FD, Context.shouldMangleDeclName(FD));
else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
mangleVariableEncoding(VD);
else
else if (!isa<ObjCInterfaceDecl>(D))
llvm_unreachable("Tried to mangle unexpected NamedDecl!");
}
@ -1884,13 +1884,13 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers,
llvm_unreachable("placeholder types shouldn't get to name mangling");
case BuiltinType::ObjCId:
mangleArtificalTagType(TTK_Struct, "objc_object");
mangleArtificalTagType(TTK_Struct, ".objc_object");
break;
case BuiltinType::ObjCClass:
mangleArtificalTagType(TTK_Struct, "objc_class");
mangleArtificalTagType(TTK_Struct, ".objc_class");
break;
case BuiltinType::ObjCSel:
mangleArtificalTagType(TTK_Struct, "objc_selector");
mangleArtificalTagType(TTK_Struct, ".objc_selector");
break;
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
@ -2570,9 +2570,10 @@ void MicrosoftCXXNameMangler::mangleType(const DependentAddressSpaceType *T,
void MicrosoftCXXNameMangler::mangleType(const ObjCInterfaceType *T, Qualifiers,
SourceRange) {
// ObjC interfaces have structs underlying them.
// ObjC interfaces are mangled as if they were structs with a name that is
// not a valid C/C++ identifier
mangleTagTypeKind(TTK_Struct);
mangleName(T->getDecl());
mangle(T->getDecl(), ".objc_cls_");
}
void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T, Qualifiers,
@ -2590,11 +2591,11 @@ void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T, Qualifiers,
Out << "?$";
if (T->isObjCId())
mangleSourceName("objc_object");
mangleSourceName(".objc_object");
else if (T->isObjCClass())
mangleSourceName("objc_class");
mangleSourceName(".objc_class");
else
mangleSourceName(T->getInterface()->getName());
mangleSourceName((".objc_cls_" + T->getInterface()->getName()).str());
for (const auto &Q : T->quals())
mangleObjCProtocol(Q);

View File

@ -181,6 +181,57 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C)
return nullptr;
}
OMPOrderedClause *OMPOrderedClause::Create(const ASTContext &C, Expr *Num,
unsigned NumLoops,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(2 * NumLoops));
auto *Clause =
new (Mem) OMPOrderedClause(Num, NumLoops, StartLoc, LParenLoc, EndLoc);
for (unsigned I = 0; I < NumLoops; ++I) {
Clause->setLoopNumIterations(I, nullptr);
Clause->setLoopCounter(I, nullptr);
}
return Clause;
}
OMPOrderedClause *OMPOrderedClause::CreateEmpty(const ASTContext &C,
unsigned NumLoops) {
void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(2 * NumLoops));
auto *Clause = new (Mem) OMPOrderedClause(NumLoops);
for (unsigned I = 0; I < NumLoops; ++I) {
Clause->setLoopNumIterations(I, nullptr);
Clause->setLoopCounter(I, nullptr);
}
return Clause;
}
void OMPOrderedClause::setLoopNumIterations(unsigned NumLoop,
Expr *NumIterations) {
assert(NumLoop < NumberOfLoops && "out of loops number.");
getTrailingObjects<Expr *>()[NumLoop] = NumIterations;
}
ArrayRef<Expr *> OMPOrderedClause::getLoopNumIterations() const {
return llvm::makeArrayRef(getTrailingObjects<Expr *>(), NumberOfLoops);
}
void OMPOrderedClause::setLoopCounter(unsigned NumLoop, Expr *Counter) {
assert(NumLoop < NumberOfLoops && "out of loops number.");
getTrailingObjects<Expr *>()[NumberOfLoops + NumLoop] = Counter;
}
Expr *OMPOrderedClause::getLoopCunter(unsigned NumLoop) {
assert(NumLoop < NumberOfLoops && "out of loops number.");
return getTrailingObjects<Expr *>()[NumberOfLoops + NumLoop];
}
const Expr *OMPOrderedClause::getLoopCunter(unsigned NumLoop) const {
assert(NumLoop < NumberOfLoops && "out of loops number.");
return getTrailingObjects<Expr *>()[NumberOfLoops + NumLoop];
}
void OMPPrivateClause::setPrivateCopies(ArrayRef<Expr *> VL) {
assert(VL.size() == varlist_size() &&
"Number of private copies is not the same as the preallocated buffer");
@ -653,44 +704,58 @@ OMPFlushClause *OMPFlushClause::CreateEmpty(const ASTContext &C, unsigned N) {
return new (Mem) OMPFlushClause(N);
}
OMPDependClause *OMPDependClause::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc, OpenMPDependClauseKind DepKind,
SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL) {
void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size() + 1));
OMPDependClause *Clause =
new (Mem) OMPDependClause(StartLoc, LParenLoc, EndLoc, VL.size());
OMPDependClause *
OMPDependClause::Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation EndLoc,
OpenMPDependClauseKind DepKind, SourceLocation DepLoc,
SourceLocation ColonLoc, ArrayRef<Expr *> VL,
unsigned NumLoops) {
void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size() + NumLoops));
OMPDependClause *Clause = new (Mem)
OMPDependClause(StartLoc, LParenLoc, EndLoc, VL.size(), NumLoops);
Clause->setVarRefs(VL);
Clause->setDependencyKind(DepKind);
Clause->setDependencyLoc(DepLoc);
Clause->setColonLoc(ColonLoc);
Clause->setCounterValue(nullptr);
for (unsigned I = 0 ; I < NumLoops; ++I)
Clause->setLoopData(I, nullptr);
return Clause;
}
OMPDependClause *OMPDependClause::CreateEmpty(const ASTContext &C, unsigned N) {
void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N + 1));
return new (Mem) OMPDependClause(N);
OMPDependClause *OMPDependClause::CreateEmpty(const ASTContext &C, unsigned N,
unsigned NumLoops) {
void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N + NumLoops));
return new (Mem) OMPDependClause(N, NumLoops);
}
void OMPDependClause::setCounterValue(Expr *V) {
assert(getDependencyKind() == OMPC_DEPEND_sink ||
getDependencyKind() == OMPC_DEPEND_source || V == nullptr);
*getVarRefs().end() = V;
void OMPDependClause::setLoopData(unsigned NumLoop, Expr *Cnt) {
assert((getDependencyKind() == OMPC_DEPEND_sink ||
getDependencyKind() == OMPC_DEPEND_source) &&
NumLoop < NumLoops &&
"Expected sink or source depend + loop index must be less number of "
"loops.");
auto It = std::next(getVarRefs().end(), NumLoop);
*It = Cnt;
}
const Expr *OMPDependClause::getCounterValue() const {
auto *V = *getVarRefs().end();
assert(getDependencyKind() == OMPC_DEPEND_sink ||
getDependencyKind() == OMPC_DEPEND_source || V == nullptr);
return V;
Expr *OMPDependClause::getLoopData(unsigned NumLoop) {
assert((getDependencyKind() == OMPC_DEPEND_sink ||
getDependencyKind() == OMPC_DEPEND_source) &&
NumLoop < NumLoops &&
"Expected sink or source depend + loop index must be less number of "
"loops.");
auto It = std::next(getVarRefs().end(), NumLoop);
return *It;
}
Expr *OMPDependClause::getCounterValue() {
auto *V = *getVarRefs().end();
assert(getDependencyKind() == OMPC_DEPEND_sink ||
getDependencyKind() == OMPC_DEPEND_source || V == nullptr);
return V;
const Expr *OMPDependClause::getLoopData(unsigned NumLoop) const {
assert((getDependencyKind() == OMPC_DEPEND_sink ||
getDependencyKind() == OMPC_DEPEND_source) &&
NumLoop < NumLoops &&
"Expected sink or source depend + loop index must be less number of "
"loops.");
auto It = std::next(getVarRefs().end(), NumLoop);
return *It;
}
unsigned OMPClauseMappableExprCommon::getComponentsTotalNumber(

View File

@ -1829,7 +1829,7 @@ void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF,
SmallString<128> Name;
{
llvm::raw_svector_ostream OS(Name);
const FunctionDecl *ParentSEHFn = ParentCGF.CurSEHParent;
const NamedDecl *ParentSEHFn = ParentCGF.CurSEHParent;
assert(ParentSEHFn && "No CurSEHParent!");
MangleContext &Mangler = CGM.getCXXABI().getMangleContext();
if (IsFilter)
@ -1972,6 +1972,11 @@ llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() {
return Builder.CreateZExt(&*AI, Int32Ty);
}
void CodeGenFunction::pushSEHCleanup(CleanupKind Kind,
llvm::Function *FinallyFunc) {
EHStack.pushCleanup<PerformSEHFinally>(Kind, FinallyFunc);
}
void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true);
if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {

View File

@ -18,6 +18,7 @@
#include "CGCleanup.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "CGCXXABI.h"
#include "clang/CodeGen/ConstantInitBuilder.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
@ -178,6 +179,9 @@ protected:
/// runtime provides some LLVM passes that can use this to do things like
/// automatic IMP caching and speculative inlining.
unsigned msgSendMDKind;
/// Does the current target use SEH-based exceptions? False implies
/// Itanium-style DWARF unwinding.
bool usesSEHExceptions;
/// Helper to check if we are targeting a specific runtime version or later.
bool isRuntime(ObjCRuntime::Kind kind, unsigned major, unsigned minor=0) {
@ -217,6 +221,7 @@ protected:
llvm::Constant *value = llvm::ConstantDataArray::getString(VMContext,Str);
auto *GV = new llvm::GlobalVariable(TheModule, value->getType(), true,
llvm::GlobalValue::LinkOnceODRLinkage, value, name);
GV->setComdat(TheModule.getOrInsertComdat(name));
if (Private)
GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
ConstStr = GV;
@ -510,8 +515,8 @@ protected:
/// Returns a selector with the specified type encoding. An empty string is
/// used to return an untyped selector (with the types field set to NULL).
virtual llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
const std::string &TypeEncoding);
virtual llvm::Value *GetTypedSelector(CodeGenFunction &CGF, Selector Sel,
const std::string &TypeEncoding);
/// Returns the name of ivar offset variables. In the GNUstep v1 ABI, this
/// contains the class and ivar names, in the v2 ABI this contains the type
@ -810,8 +815,12 @@ class CGObjCGNUstep : public CGObjCGNU {
// Slot_t objc_slot_lookup_super(struct objc_super*, SEL);
SlotLookupSuperFn.init(&CGM, "objc_slot_lookup_super", SlotTy,
PtrToObjCSuperTy, SelectorTy);
// If we're in ObjC++ mode, then we want to make
if (CGM.getLangOpts().CPlusPlus) {
// If we're in ObjC++ mode, then we want to make
if (usesSEHExceptions) {
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// void objc_exception_rethrow(void)
ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy);
} else if (CGM.getLangOpts().CPlusPlus) {
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// void *__cxa_begin_catch(void *e)
EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy);
@ -888,22 +897,25 @@ class CGObjCGNUstep : public CGObjCGNU {
/// This is the ABI that provides a clean break with the legacy GCC ABI and
/// cleans up a number of things that were added to work around 1980s linkers.
class CGObjCGNUstep2 : public CGObjCGNUstep {
/// The section for selectors.
static constexpr const char *const SelSection = "__objc_selectors";
/// The section for classes.
static constexpr const char *const ClsSection = "__objc_classes";
/// The section for references to classes.
static constexpr const char *const ClsRefSection = "__objc_class_refs";
/// The section for categories.
static constexpr const char *const CatSection = "__objc_cats";
/// The section for protocols.
static constexpr const char *const ProtocolSection = "__objc_protocols";
/// The section for protocol references.
static constexpr const char *const ProtocolRefSection = "__objc_protocol_refs";
/// The section for class aliases
static constexpr const char *const ClassAliasSection = "__objc_class_aliases";
/// The section for constexpr constant strings
static constexpr const char *const ConstantStringSection = "__objc_constant_string";
enum SectionKind
{
SelectorSection = 0,
ClassSection,
ClassReferenceSection,
CategorySection,
ProtocolSection,
ProtocolReferenceSection,
ClassAliasSection,
ConstantStringSection
};
static const char *const SectionsBaseNames[8];
template<SectionKind K>
std::string sectionName() {
std::string name(SectionsBaseNames[K]);
if (CGM.getTriple().isOSBinFormatCOFF())
name += "$m";
return name;
}
/// The GCC ABI superclass message lookup function. Takes a pointer to a
/// structure describing the receiver and the class, and a selector as
/// arguments. Returns the IMP for the corresponding method.
@ -1069,7 +1081,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
isNamed ? StringRef(StringName) : ".objc_string",
Align, false, isNamed ? llvm::GlobalValue::LinkOnceODRLinkage
: llvm::GlobalValue::PrivateLinkage);
ObjCStrGV->setSection(ConstantStringSection);
ObjCStrGV->setSection(sectionName<ConstantStringSection>());
if (isNamed) {
ObjCStrGV->setComdat(TheModule.getOrInsertComdat(StringName));
ObjCStrGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
@ -1247,9 +1259,10 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
assert(!TheModule.getGlobalVariable(RefName));
// Emit a reference symbol.
auto GV = new llvm::GlobalVariable(TheModule, ProtocolPtrTy,
false, llvm::GlobalValue::ExternalLinkage,
false, llvm::GlobalValue::LinkOnceODRLinkage,
llvm::ConstantExpr::getBitCast(Protocol, ProtocolPtrTy), RefName);
GV->setSection(ProtocolRefSection);
GV->setComdat(TheModule.getOrInsertComdat(RefName));
GV->setSection(sectionName<ProtocolReferenceSection>());
GV->setAlignment(CGM.getPointerAlign().getQuantity());
Ref = GV;
}
@ -1282,9 +1295,22 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
EmittedProtocol = true;
auto SymName = SymbolForProtocol(ProtocolName);
auto *OldGV = TheModule.getGlobalVariable(SymName);
// Use the protocol definition, if there is one.
if (const ObjCProtocolDecl *Def = PD->getDefinition())
PD = Def;
else {
// If there is no definition, then create an external linkage symbol and
// hope that someone else fills it in for us (and fail to link if they
// don't).
assert(!OldGV);
Protocol = new llvm::GlobalVariable(TheModule, ProtocolTy,
/*isConstant*/false,
llvm::GlobalValue::ExternalLinkage, nullptr, SymName);
return Protocol;
}
SmallVector<llvm::Constant*, 16> Protocols;
for (const auto *PI : PD->protocols())
@ -1301,8 +1327,6 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
EmitProtocolMethodList(PD->class_methods(), ClassMethodList,
OptionalClassMethodList);
auto SymName = SymbolForProtocol(ProtocolName);
auto *OldGV = TheModule.getGlobalVariable(SymName);
// The isa pointer must be set to a magic number so the runtime knows it's
// the correct layout.
ConstantInitBuilder builder(CGM);
@ -1326,7 +1350,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
auto *GV = ProtocolBuilder.finishAndCreateGlobal(SymName,
CGM.getPointerAlign(), false, llvm::GlobalValue::ExternalLinkage);
GV->setSection(ProtocolSection);
GV->setSection(sectionName<ProtocolSection>());
GV->setComdat(TheModule.getOrInsertComdat(SymName));
if (OldGV) {
OldGV->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(GV,
@ -1342,8 +1366,8 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
return Val;
return llvm::ConstantExpr::getBitCast(Val, Ty);
}
llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
const std::string &TypeEncoding) override {
llvm::Value *GetTypedSelector(CodeGenFunction &CGF, Selector Sel,
const std::string &TypeEncoding) override {
return GetConstantSelector(Sel, TypeEncoding);
}
llvm::Constant *GetTypeString(llvm::StringRef TypeEncoding) {
@ -1359,6 +1383,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
TypeEncoding);
auto *GV = new llvm::GlobalVariable(TheModule, Init->getType(),
true, llvm::GlobalValue::LinkOnceODRLinkage, Init, TypesVarName);
GV->setComdat(TheModule.getOrInsertComdat(TypesVarName));
GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
TypesGlobal = GV;
}
@ -1387,12 +1412,41 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
CGM.getPointerAlign(), false, llvm::GlobalValue::LinkOnceODRLinkage);
GV->setComdat(TheModule.getOrInsertComdat(SelVarName));
GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
GV->setSection(SelSection);
GV->setSection(sectionName<SelectorSection>());
auto *SelVal = EnforceType(GV, SelectorTy);
return SelVal;
}
llvm::StructType *emptyStruct = nullptr;
/// Return pointers to the start and end of a section. On ELF platforms, we
/// use the __start_ and __stop_ symbols that GNU-compatible linkers will set
/// to the start and end of section names, as long as those section names are
/// valid identifiers and the symbols are referenced but not defined. On
/// Windows, we use the fact that MSVC-compatible linkers will lexically sort
/// by subsections and place everything that we want to reference in a middle
/// subsection and then insert zero-sized symbols in subsections a and z.
std::pair<llvm::Constant*,llvm::Constant*>
GetSectionBounds(StringRef Section) {
if (CGM.getTriple().isOSBinFormatCOFF()) {
if (emptyStruct == nullptr) {
emptyStruct = llvm::StructType::create(VMContext, ".objc_section_sentinel");
emptyStruct->setBody({}, /*isPacked*/true);
}
auto ZeroInit = llvm::Constant::getNullValue(emptyStruct);
auto Sym = [&](StringRef Prefix, StringRef SecSuffix) {
auto *Sym = new llvm::GlobalVariable(TheModule, emptyStruct,
/*isConstant*/false,
llvm::GlobalValue::LinkOnceODRLinkage, ZeroInit, Prefix +
Section);
Sym->setVisibility(llvm::GlobalValue::HiddenVisibility);
Sym->setSection((Section + SecSuffix).str());
Sym->setComdat(TheModule.getOrInsertComdat((Prefix +
Section).str()));
Sym->setAlignment(1);
return Sym;
};
return { Sym("__start_", "$a"), Sym("__stop", "$z") };
}
auto *Start = new llvm::GlobalVariable(TheModule, PtrTy,
/*isConstant*/false,
llvm::GlobalValue::ExternalLinkage, nullptr, StringRef("__start_") +
@ -1405,6 +1459,9 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
Stop->setVisibility(llvm::GlobalValue::HiddenVisibility);
return { Start, Stop };
}
CatchTypeInfo getCatchAllTypeInfo() override {
return CGM.getCXXABI().getCatchAllTypeInfo();
}
llvm::Function *ModuleInitFunction() override {
llvm::Function *LoadFunction = llvm::Function::Create(
llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false),
@ -1420,19 +1477,11 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
ConstantInitBuilder builder(CGM);
auto InitStructBuilder = builder.beginStruct();
InitStructBuilder.addInt(Int64Ty, 0);
auto addSection = [&](const char *section) {
auto bounds = GetSectionBounds(section);
for (auto *s : SectionsBaseNames) {
auto bounds = GetSectionBounds(s);
InitStructBuilder.add(bounds.first);
InitStructBuilder.add(bounds.second);
};
addSection(SelSection);
addSection(ClsSection);
addSection(ClsRefSection);
addSection(CatSection);
addSection(ProtocolSection);
addSection(ProtocolRefSection);
addSection(ClassAliasSection);
addSection(ConstantStringSection);
auto *InitStruct = InitStructBuilder.finishAndCreateGlobal(".objc_init",
CGM.getPointerAlign(), false, llvm::GlobalValue::LinkOnceODRLinkage);
InitStruct->setVisibility(llvm::GlobalValue::HiddenVisibility);
@ -1451,18 +1500,23 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
// Check that this hasn't been renamed. This shouldn't happen, because
// this function should be called precisely once.
assert(InitVar->getName() == ".objc_ctor");
InitVar->setSection(".ctors");
// In Windows, initialisers are sorted by the suffix. XCL is for library
// initialisers, which run before user initialisers. We are running
// Objective-C loads at the end of library load. This means +load methods
// will run before any other static constructors, but that static
// constructors can see a fully initialised Objective-C state.
if (CGM.getTriple().isOSBinFormatCOFF())
InitVar->setSection(".CRT$XCLz");
else
InitVar->setSection(".ctors");
InitVar->setVisibility(llvm::GlobalValue::HiddenVisibility);
InitVar->setComdat(TheModule.getOrInsertComdat(".objc_ctor"));
CGM.addCompilerUsedGlobal(InitVar);
CGM.addUsedGlobal(InitVar);
for (auto *C : Categories) {
auto *Cat = cast<llvm::GlobalVariable>(C->stripPointerCasts());
Cat->setSection(CatSection);
Cat->setSection(sectionName<CategorySection>());
CGM.addUsedGlobal(Cat);
}
// Add a null value fore each special section so that we can always
// guarantee that the _start and _stop symbols will exist and be
// meaningful.
auto createNullGlobal = [&](StringRef Name, ArrayRef<llvm::Constant*> Init,
StringRef Section) {
auto nullBuilder = builder.beginStruct();
@ -1476,38 +1530,48 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
CGM.addUsedGlobal(GV);
return GV;
};
createNullGlobal(".objc_null_selector", {NULLPtr, NULLPtr}, SelSection);
if (Categories.empty())
createNullGlobal(".objc_null_category", {NULLPtr, NULLPtr,
NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr}, CatSection);
if (!EmittedClass) {
createNullGlobal(".objc_null_cls_init_ref", NULLPtr, ClsSection);
createNullGlobal(".objc_null_class_ref", { NULLPtr, NULLPtr },
ClsRefSection);
}
if (!EmittedProtocol)
createNullGlobal(".objc_null_protocol", {NULLPtr, NULLPtr, NULLPtr,
NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr,
NULLPtr}, ProtocolSection);
if (!EmittedProtocolRef)
createNullGlobal(".objc_null_protocol_ref", {NULLPtr}, ProtocolRefSection);
if (!ClassAliases.empty())
for (auto clsAlias : ClassAliases)
createNullGlobal(std::string(".objc_class_alias") +
clsAlias.second, { MakeConstantString(clsAlias.second),
GetClassVar(clsAlias.first) }, ClassAliasSection);
else
createNullGlobal(".objc_null_class_alias", { NULLPtr, NULLPtr },
ClassAliasSection);
if (ConstantStrings.empty()) {
auto i32Zero = llvm::ConstantInt::get(Int32Ty, 0);
createNullGlobal(".objc_null_constant_string", { NULLPtr, i32Zero,
i32Zero, i32Zero, i32Zero, NULLPtr }, ConstantStringSection);
for (auto clsAlias : ClassAliases)
createNullGlobal(std::string(".objc_class_alias") +
clsAlias.second, { MakeConstantString(clsAlias.second),
GetClassVar(clsAlias.first) }, sectionName<ClassAliasSection>());
// On ELF platforms, add a null value for each special section so that we
// can always guarantee that the _start and _stop symbols will exist and be
// meaningful. This is not required on COFF platforms, where our start and
// stop symbols will create the section.
if (!CGM.getTriple().isOSBinFormatCOFF()) {
createNullGlobal(".objc_null_selector", {NULLPtr, NULLPtr},
sectionName<SelectorSection>());
if (Categories.empty())
createNullGlobal(".objc_null_category", {NULLPtr, NULLPtr,
NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr},
sectionName<CategorySection>());
if (!EmittedClass) {
createNullGlobal(".objc_null_cls_init_ref", NULLPtr,
sectionName<ClassReferenceSection>());
createNullGlobal(".objc_null_class_ref", { NULLPtr, NULLPtr },
sectionName<ClassReferenceSection>());
}
if (!EmittedProtocol)
createNullGlobal(".objc_null_protocol", {NULLPtr, NULLPtr, NULLPtr,
NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr,
NULLPtr}, sectionName<ProtocolSection>());
if (!EmittedProtocolRef)
createNullGlobal(".objc_null_protocol_ref", {NULLPtr},
sectionName<ProtocolReferenceSection>());
if (ClassAliases.empty())
createNullGlobal(".objc_null_class_alias", { NULLPtr, NULLPtr },
sectionName<ClassAliasSection>());
if (ConstantStrings.empty()) {
auto i32Zero = llvm::ConstantInt::get(Int32Ty, 0);
createNullGlobal(".objc_null_constant_string", { NULLPtr, i32Zero,
i32Zero, i32Zero, i32Zero, NULLPtr },
sectionName<ConstantStringSection>());
}
}
ConstantStrings.clear();
Categories.clear();
Classes.clear();
return nullptr;//CGObjCGNU::ModuleInitFunction();
return nullptr;
}
/// In the v2 ABI, ivar offset variables use the type encoding in their name
/// to trigger linker failures if the types don't match.
@ -1774,7 +1838,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
}
auto *classRefSymbol = GetClassVar(className);
classRefSymbol->setSection(ClsRefSection);
classRefSymbol->setSection(sectionName<ClassReferenceSection>());
classRefSymbol->setInitializer(llvm::ConstantExpr::getBitCast(classStruct, IdTy));
@ -1805,7 +1869,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
auto classInitRef = new llvm::GlobalVariable(TheModule,
classStruct->getType(), false, llvm::GlobalValue::ExternalLinkage,
classStruct, "._OBJC_INIT_CLASS_" + className);
classInitRef->setSection(ClsSection);
classInitRef->setSection(sectionName<ClassSection>());
CGM.addUsedGlobal(classInitRef);
EmittedClass = true;
@ -1829,6 +1893,18 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
};
const char *const CGObjCGNUstep2::SectionsBaseNames[8] =
{
"__objc_selectors",
"__objc_classes",
"__objc_class_refs",
"__objc_cats",
"__objc_protocols",
"__objc_protocol_refs",
"__objc_class_aliases",
"__objc_constant_string"
};
/// Support for the ObjFW runtime.
class CGObjCObjFW: public CGObjCGNU {
protected:
@ -1931,6 +2007,8 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
ProtocolVersion(protocolClassVersion), ClassABIVersion(classABI) {
msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend");
usesSEHExceptions =
cgm.getContext().getTargetInfo().getTriple().isWindowsMSVCEnvironment();
CodeGenTypes &Types = CGM.getTypes();
IntTy = cast<llvm::IntegerType>(
@ -2121,8 +2199,8 @@ llvm::Value *CGObjCGNU::EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
return Value;
}
llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF, Selector Sel,
const std::string &TypeEncoding) {
llvm::Value *CGObjCGNU::GetTypedSelector(CodeGenFunction &CGF, Selector Sel,
const std::string &TypeEncoding) {
SmallVectorImpl<TypedSelector> &Types = SelectorTable[Sel];
llvm::GlobalAlias *SelValue = nullptr;
@ -2155,13 +2233,13 @@ Address CGObjCGNU::GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) {
}
llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF, Selector Sel) {
return GetSelector(CGF, Sel, std::string());
return GetTypedSelector(CGF, Sel, std::string());
}
llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF,
const ObjCMethodDecl *Method) {
std::string SelTypes = CGM.getContext().getObjCEncodingForMethodDecl(Method);
return GetSelector(CGF, Method->getSelector(), SelTypes);
return GetTypedSelector(CGF, Method->getSelector(), SelTypes);
}
llvm::Constant *CGObjCGNU::GetEHType(QualType T) {
@ -2186,6 +2264,9 @@ llvm::Constant *CGObjCGNU::GetEHType(QualType T) {
}
llvm::Constant *CGObjCGNUstep::GetEHType(QualType T) {
if (usesSEHExceptions)
return CGM.getCXXABI().getAddrOfRTTIDescriptor(T);
if (!CGM.getLangOpts().CPlusPlus)
return CGObjCGNU::GetEHType(T);
@ -3726,6 +3807,7 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
const ObjCAtThrowStmt &S,
bool ClearInsertionPoint) {
llvm::Value *ExceptionAsObject;
bool isRethrow = false;
if (const Expr *ThrowExpr = S.getThrowExpr()) {
llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr);
@ -3734,11 +3816,24 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) &&
"Unexpected rethrow outside @catch block.");
ExceptionAsObject = CGF.ObjCEHValueStack.back();
isRethrow = true;
}
if (isRethrow && usesSEHExceptions) {
// For SEH, ExceptionAsObject may be undef, because the catch handler is
// not passed it for catchalls and so it is not visible to the catch
// funclet. The real thrown object will still be live on the stack at this
// point and will be rethrown. If we are explicitly rethrowing the object
// that was passed into the `@catch` block, then this code path is not
// reached and we will instead call `objc_exception_throw` with an explicit
// argument.
CGF.EmitRuntimeCallOrInvoke(ExceptionReThrowFn).setDoesNotReturn();
}
else {
ExceptionAsObject = CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy);
llvm::CallSite Throw =
CGF.EmitRuntimeCallOrInvoke(ExceptionThrowFn, ExceptionAsObject);
Throw.setDoesNotReturn();
}
ExceptionAsObject = CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy);
llvm::CallSite Throw =
CGF.EmitRuntimeCallOrInvoke(ExceptionThrowFn, ExceptionAsObject);
Throw.setDoesNotReturn();
CGF.Builder.CreateUnreachable();
if (ClearInsertionPoint)
CGF.Builder.ClearInsertionPoint();

View File

@ -15,6 +15,7 @@
#include "CGObjCRuntime.h"
#include "CGCleanup.h"
#include "CGCXXABI.h"
#include "CGRecordLayout.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
@ -22,6 +23,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "llvm/IR/CallSite.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
using namespace CodeGen;
@ -120,6 +122,8 @@ namespace {
const Stmt *Body;
llvm::BasicBlock *Block;
llvm::Constant *TypeInfo;
/// Flags used to differentiate cleanups and catchalls in Windows SEH
unsigned Flags;
};
struct CallObjCEndCatch final : EHScopeStack::Cleanup {
@ -148,13 +152,17 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
if (S.getNumCatchStmts())
Cont = CGF.getJumpDestInCurrentScope("eh.cont");
bool useFunclets = EHPersonality::get(CGF).usesFuncletPads();
CodeGenFunction::FinallyInfo FinallyInfo;
if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt())
FinallyInfo.enter(CGF, Finally->getFinallyBody(),
beginCatchFn, endCatchFn, exceptionRethrowFn);
if (!useFunclets)
if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt())
FinallyInfo.enter(CGF, Finally->getFinallyBody(),
beginCatchFn, endCatchFn, exceptionRethrowFn);
SmallVector<CatchHandler, 8> Handlers;
// Enter the catch, if there is one.
if (S.getNumCatchStmts()) {
for (unsigned I = 0, N = S.getNumCatchStmts(); I != N; ++I) {
@ -166,10 +174,13 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
Handler.Variable = CatchDecl;
Handler.Body = CatchStmt->getCatchBody();
Handler.Block = CGF.createBasicBlock("catch");
Handler.Flags = 0;
// @catch(...) always matches.
if (!CatchDecl) {
Handler.TypeInfo = nullptr; // catch-all
auto catchAll = getCatchAllTypeInfo();
Handler.TypeInfo = catchAll.RTTI;
Handler.Flags = catchAll.Flags;
// Don't consider any other catches.
break;
}
@ -179,9 +190,31 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
EHCatchScope *Catch = CGF.EHStack.pushCatch(Handlers.size());
for (unsigned I = 0, E = Handlers.size(); I != E; ++I)
Catch->setHandler(I, Handlers[I].TypeInfo, Handlers[I].Block);
Catch->setHandler(I, { Handlers[I].TypeInfo, Handlers[I].Flags }, Handlers[I].Block);
}
if (useFunclets)
if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt()) {
CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true);
if (!CGF.CurSEHParent)
CGF.CurSEHParent = cast<NamedDecl>(CGF.CurFuncDecl);
// Outline the finally block.
const Stmt *FinallyBlock = Finally->getFinallyBody();
HelperCGF.startOutlinedSEHHelper(CGF, /*isFilter*/false, FinallyBlock);
// Emit the original filter expression, convert to i32, and return.
HelperCGF.EmitStmt(FinallyBlock);
HelperCGF.FinishFunction(FinallyBlock->getLocEnd());
llvm::Function *FinallyFunc = HelperCGF.CurFn;
// Push a cleanup for __finally blocks.
CGF.pushSEHCleanup(NormalAndEHCleanup, FinallyFunc);
}
// Emit the try body.
CGF.EmitStmt(S.getTryBody());
@ -197,6 +230,13 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
CatchHandler &Handler = Handlers[I];
CGF.EmitBlock(Handler.Block);
llvm::CatchPadInst *CPI = nullptr;
SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(CGF.CurrentFuncletPad);
if (useFunclets)
if ((CPI = dyn_cast_or_null<llvm::CatchPadInst>(Handler.Block->getFirstNonPHI()))) {
CGF.CurrentFuncletPad = CPI;
CPI->setOperand(2, CGF.getExceptionSlot().getPointer());
}
llvm::Value *RawExn = CGF.getExceptionFromSlot();
// Enter the catch.
@ -223,6 +263,8 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
CGF.EmitAutoVarDecl(*CatchParam);
EmitInitOfCatchParam(CGF, CastExn, CatchParam);
}
if (CPI)
CGF.EHStack.pushCleanup<CatchRetScope>(NormalCleanup, CPI);
CGF.ObjCEHValueStack.push_back(Exn);
CGF.EmitStmt(Handler.Body);
@ -232,13 +274,13 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
cleanups.ForceCleanup();
CGF.EmitBranchThroughCleanup(Cont);
}
}
// Go back to the try-statement fallthrough.
CGF.Builder.restoreIP(SavedIP);
// Pop out of the finally.
if (S.getFinallyStmt())
if (!useFunclets && S.getFinallyStmt())
FinallyInfo.exit(CGF);
if (Cont.isValid())
@ -277,7 +319,7 @@ namespace {
: SyncExitFn(SyncExitFn), SyncArg(SyncArg) {}
void Emit(CodeGenFunction &CGF, Flags flags) override {
CGF.Builder.CreateCall(SyncExitFn, SyncArg)->setDoesNotThrow();
CGF.EmitNounwindRuntimeCall(SyncExitFn, SyncArg);
}
};
}

View File

@ -17,6 +17,7 @@
#define LLVM_CLANG_LIB_CODEGEN_CGOBJCRUNTIME_H
#include "CGBuilder.h"
#include "CGCall.h"
#include "CGCleanup.h"
#include "CGValue.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/IdentifierTable.h" // Selector
@ -141,6 +142,8 @@ public:
/// error to Sema.
virtual llvm::Constant *GetEHType(QualType T) = 0;
virtual CatchTypeInfo getCatchAllTypeInfo() { return { nullptr, 0 }; }
/// Generate a constant string object.
virtual ConstantAddress GenerateConstantString(const StringLiteral *) = 0;

View File

@ -897,25 +897,6 @@ static void EmitOMPAggregateInit(CodeGenFunction &CGF, Address DestAddr,
CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
}
static llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy>
isDeclareTargetDeclaration(const ValueDecl *VD) {
for (const Decl *D : VD->redecls()) {
if (!D->hasAttrs())
continue;
if (const auto *Attr = D->getAttr<OMPDeclareTargetDeclAttr>())
return Attr->getMapType();
}
if (const auto *V = dyn_cast<VarDecl>(VD)) {
if (const VarDecl *TD = V->getTemplateInstantiationPattern())
return isDeclareTargetDeclaration(TD);
} else if (const auto *FD = dyn_cast<FunctionDecl>(VD)) {
if (const auto *TD = FD->getTemplateInstantiationPattern())
return isDeclareTargetDeclaration(TD);
}
return llvm::None;
}
LValue ReductionCodeGen::emitSharedLValue(CodeGenFunction &CGF, const Expr *E) {
return CGF.EmitOMPSharedLValue(E);
}
@ -2417,7 +2398,7 @@ Address CGOpenMPRuntime::getAddrOfDeclareTargetLink(const VarDecl *VD) {
if (CGM.getLangOpts().OpenMPSimd)
return Address::invalid();
llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
isDeclareTargetDeclaration(VD);
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
if (Res && *Res == OMPDeclareTargetDeclAttr::MT_Link) {
SmallString<64> PtrName;
{
@ -2639,7 +2620,7 @@ bool CGOpenMPRuntime::emitDeclareTargetVarDefinition(const VarDecl *VD,
llvm::GlobalVariable *Addr,
bool PerformInit) {
Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
isDeclareTargetDeclaration(VD);
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
if (!Res || *Res == OMPDeclareTargetDeclAttr::MT_Link)
return false;
VD = VD->getDefinition(CGM.getContext());
@ -6945,7 +6926,7 @@ private:
if (const auto *VD =
dyn_cast_or_null<VarDecl>(I->getAssociatedDeclaration())) {
if (llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
isDeclareTargetDeclaration(VD))
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
if (*Res == OMPDeclareTargetDeclAttr::MT_Link) {
IsLink = true;
BP = CGF.CGM.getOpenMPRuntime().getAddrOfDeclareTargetLink(VD);
@ -7436,7 +7417,7 @@ public:
if (!VD)
continue;
llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
isDeclareTargetDeclaration(VD);
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
if (!Res || *Res != OMPDeclareTargetDeclAttr::MT_Link)
continue;
StructRangeInfoTy PartialStruct;
@ -8066,7 +8047,7 @@ bool CGOpenMPRuntime::emitTargetFunctions(GlobalDecl GD) {
scanForTargetRegionsFunctions(FD->getBody(), CGM.getMangledName(GD));
// Do not to emit function if it is not marked as declare target.
return !isDeclareTargetDeclaration(FD) &&
return !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(FD) &&
AlreadyEmittedTargetFunctions.count(FD->getCanonicalDecl()) == 0;
}
@ -8093,14 +8074,15 @@ bool CGOpenMPRuntime::emitTargetGlobalVariable(GlobalDecl GD) {
// Do not to emit variable if it is not marked as declare target.
llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
isDeclareTargetDeclaration(cast<VarDecl>(GD.getDecl()));
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(
cast<VarDecl>(GD.getDecl()));
return !Res || *Res == OMPDeclareTargetDeclAttr::MT_Link;
}
void CGOpenMPRuntime::registerTargetGlobalVariable(const VarDecl *VD,
llvm::Constant *Addr) {
if (llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
isDeclareTargetDeclaration(VD)) {
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) {
OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryKind Flags;
StringRef VarName;
CharUnits VarSize;
@ -8173,7 +8155,7 @@ bool CGOpenMPRuntime::markAsGlobalTarget(GlobalDecl GD) {
const FunctionDecl *FD = D->getCanonicalDecl();
// Do not to emit function if it is marked as declare target as it was already
// emitted.
if (isDeclareTargetDeclaration(D)) {
if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(D)) {
if (D->hasBody() && AlreadyEmittedTargetFunctions.count(FD) == 0) {
if (auto *F = dyn_cast_or_null<llvm::Function>(
CGM.GetGlobalValue(CGM.getMangledName(GD))))
@ -8782,7 +8764,8 @@ public:
} // namespace
void CGOpenMPRuntime::emitDoacrossInit(CodeGenFunction &CGF,
const OMPLoopDirective &D) {
const OMPLoopDirective &D,
ArrayRef<Expr *> NumIterations) {
if (!CGF.HaveInsertPoint())
return;
@ -8805,32 +8788,45 @@ void CGOpenMPRuntime::emitDoacrossInit(CodeGenFunction &CGF,
} else {
RD = cast<RecordDecl>(KmpDimTy->getAsTagDecl());
}
llvm::APInt Size(/*numBits=*/32, NumIterations.size());
QualType ArrayTy =
C.getConstantArrayType(KmpDimTy, Size, ArrayType::Normal, 0);
Address DimsAddr = CGF.CreateMemTemp(KmpDimTy, "dims");
CGF.EmitNullInitialization(DimsAddr, KmpDimTy);
Address DimsAddr = CGF.CreateMemTemp(ArrayTy, "dims");
CGF.EmitNullInitialization(DimsAddr, ArrayTy);
enum { LowerFD = 0, UpperFD, StrideFD };
// Fill dims with data.
LValue DimsLVal = CGF.MakeAddrLValue(DimsAddr, KmpDimTy);
// dims.upper = num_iterations;
LValue UpperLVal =
CGF.EmitLValueForField(DimsLVal, *std::next(RD->field_begin(), UpperFD));
llvm::Value *NumIterVal = CGF.EmitScalarConversion(
CGF.EmitScalarExpr(D.getNumIterations()), D.getNumIterations()->getType(),
Int64Ty, D.getNumIterations()->getExprLoc());
CGF.EmitStoreOfScalar(NumIterVal, UpperLVal);
// dims.stride = 1;
LValue StrideLVal =
CGF.EmitLValueForField(DimsLVal, *std::next(RD->field_begin(), StrideFD));
CGF.EmitStoreOfScalar(llvm::ConstantInt::getSigned(CGM.Int64Ty, /*V=*/1),
StrideLVal);
for (unsigned I = 0, E = NumIterations.size(); I < E; ++I) {
LValue DimsLVal =
CGF.MakeAddrLValue(CGF.Builder.CreateConstArrayGEP(
DimsAddr, I, C.getTypeSizeInChars(KmpDimTy)),
KmpDimTy);
// dims.upper = num_iterations;
LValue UpperLVal = CGF.EmitLValueForField(
DimsLVal, *std::next(RD->field_begin(), UpperFD));
llvm::Value *NumIterVal =
CGF.EmitScalarConversion(CGF.EmitScalarExpr(NumIterations[I]),
D.getNumIterations()->getType(), Int64Ty,
D.getNumIterations()->getExprLoc());
CGF.EmitStoreOfScalar(NumIterVal, UpperLVal);
// dims.stride = 1;
LValue StrideLVal = CGF.EmitLValueForField(
DimsLVal, *std::next(RD->field_begin(), StrideFD));
CGF.EmitStoreOfScalar(llvm::ConstantInt::getSigned(CGM.Int64Ty, /*V=*/1),
StrideLVal);
}
// Build call void __kmpc_doacross_init(ident_t *loc, kmp_int32 gtid,
// kmp_int32 num_dims, struct kmp_dim * dims);
llvm::Value *Args[] = {emitUpdateLocation(CGF, D.getLocStart()),
getThreadID(CGF, D.getLocStart()),
llvm::ConstantInt::getSigned(CGM.Int32Ty, 1),
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
DimsAddr.getPointer(), CGM.VoidPtrTy)};
llvm::Value *Args[] = {
emitUpdateLocation(CGF, D.getLocStart()),
getThreadID(CGF, D.getLocStart()),
llvm::ConstantInt::getSigned(CGM.Int32Ty, NumIterations.size()),
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
CGF.Builder
.CreateConstArrayGEP(DimsAddr, 0, C.getTypeSizeInChars(KmpDimTy))
.getPointer(),
CGM.VoidPtrTy)};
llvm::Value *RTLFn = createRuntimeFunction(OMPRTL__kmpc_doacross_init);
CGF.EmitRuntimeCall(RTLFn, Args);
@ -8845,16 +8841,29 @@ void CGOpenMPRuntime::emitDoacrossOrdered(CodeGenFunction &CGF,
const OMPDependClause *C) {
QualType Int64Ty =
CGM.getContext().getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1);
const Expr *CounterVal = C->getCounterValue();
assert(CounterVal);
llvm::Value *CntVal = CGF.EmitScalarConversion(CGF.EmitScalarExpr(CounterVal),
CounterVal->getType(), Int64Ty,
CounterVal->getExprLoc());
Address CntAddr = CGF.CreateMemTemp(Int64Ty, ".cnt.addr");
CGF.EmitStoreOfScalar(CntVal, CntAddr, /*Volatile=*/false, Int64Ty);
llvm::Value *Args[] = {emitUpdateLocation(CGF, C->getLocStart()),
getThreadID(CGF, C->getLocStart()),
CntAddr.getPointer()};
llvm::APInt Size(/*numBits=*/32, C->getNumLoops());
QualType ArrayTy = CGM.getContext().getConstantArrayType(
Int64Ty, Size, ArrayType::Normal, 0);
Address CntAddr = CGF.CreateMemTemp(ArrayTy, ".cnt.addr");
for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I) {
const Expr *CounterVal = C->getLoopData(I);
assert(CounterVal);
llvm::Value *CntVal = CGF.EmitScalarConversion(
CGF.EmitScalarExpr(CounterVal), CounterVal->getType(), Int64Ty,
CounterVal->getExprLoc());
CGF.EmitStoreOfScalar(
CntVal,
CGF.Builder.CreateConstArrayGEP(
CntAddr, I, CGM.getContext().getTypeSizeInChars(Int64Ty)),
/*Volatile=*/false, Int64Ty);
}
llvm::Value *Args[] = {
emitUpdateLocation(CGF, C->getLocStart()),
getThreadID(CGF, C->getLocStart()),
CGF.Builder
.CreateConstArrayGEP(CntAddr, 0,
CGM.getContext().getTypeSizeInChars(Int64Ty))
.getPointer()};
llvm::Value *RTLFn;
if (C->getDependencyKind() == OMPC_DEPEND_source) {
RTLFn = createRuntimeFunction(OMPRTL__kmpc_doacross_post);
@ -9169,7 +9178,8 @@ void CGOpenMPSIMDRuntime::emitTargetDataStandAloneCall(
}
void CGOpenMPSIMDRuntime::emitDoacrossInit(CodeGenFunction &CGF,
const OMPLoopDirective &D) {
const OMPLoopDirective &D,
ArrayRef<Expr *> NumIterations) {
llvm_unreachable("Not supported in SIMD-only mode");
}

View File

@ -1465,8 +1465,8 @@ public:
/// Emit initialization for doacross loop nesting support.
/// \param D Loop-based construct used in doacross nesting construct.
virtual void emitDoacrossInit(CodeGenFunction &CGF,
const OMPLoopDirective &D);
virtual void emitDoacrossInit(CodeGenFunction &CGF, const OMPLoopDirective &D,
ArrayRef<Expr *> NumIterations);
/// Emit code for doacross ordered directive with 'depend' clause.
/// \param C 'depend' clause with 'sink|source' dependency kind.
@ -2051,8 +2051,8 @@ public:
/// Emit initialization for doacross loop nesting support.
/// \param D Loop-based construct used in doacross nesting construct.
void emitDoacrossInit(CodeGenFunction &CGF,
const OMPLoopDirective &D) override;
void emitDoacrossInit(CodeGenFunction &CGF, const OMPLoopDirective &D,
ArrayRef<Expr *> NumIterations) override;
/// Emit code for doacross ordered directive with 'depend' clause.
/// \param C 'depend' clause with 'sink|source' dependency kind.

View File

@ -191,20 +191,10 @@ class CheckVarsEscapingDeclContext final
bool AllEscaped = false;
bool IsForCombinedParallelRegion = false;
static llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy>
isDeclareTargetDeclaration(const ValueDecl *VD) {
for (const Decl *D : VD->redecls()) {
if (!D->hasAttrs())
continue;
if (const auto *Attr = D->getAttr<OMPDeclareTargetDeclAttr>())
return Attr->getMapType();
}
return llvm::None;
}
void markAsEscaped(const ValueDecl *VD) {
// Do not globalize declare target variables.
if (!isa<VarDecl>(VD) || isDeclareTargetDeclaration(VD))
if (!isa<VarDecl>(VD) ||
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
return;
VD = cast<ValueDecl>(VD->getCanonicalDecl());
// Variables captured by value must be globalized.

View File

@ -1509,6 +1509,23 @@ void CodeGenFunction::EmitOMPPrivateLoopCounters(
}
++I;
}
// Privatize extra loop counters used in loops for ordered(n) clauses.
for (const auto *C : S.getClausesOfKind<OMPOrderedClause>()) {
if (!C->getNumForLoops())
continue;
for (unsigned I = S.getCollapsedNumber(),
E = C->getLoopNumIterations().size();
I < E; ++I) {
const auto *DRE = cast<DeclRefExpr>(C->getLoopCunter(I));
const auto *VD = cast<VarDecl>(DRE->getDecl());
// Override only those variables that are really emitted already.
if (LocalDeclMap.count(VD)) {
(void)LoopScope.addPrivate(VD, [this, DRE, VD]() {
return CreateMemTemp(DRE->getType(), VD->getName());
});
}
}
}
}
static void emitPreCond(CodeGenFunction &CGF, const OMPLoopDirective &S,
@ -2244,7 +2261,7 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(
bool Ordered = false;
if (const auto *OrderedClause = S.getSingleClause<OMPOrderedClause>()) {
if (OrderedClause->getNumForLoops())
RT.emitDoacrossInit(*this, S);
RT.emitDoacrossInit(*this, S, OrderedClause->getLoopNumIterations());
else
Ordered = true;
}
@ -4943,6 +4960,20 @@ void CodeGenFunction::EmitSimpleOMPExecutableDirective(
CGF.EmitVarDecl(*VD);
}
}
for (const auto *C : D.getClausesOfKind<OMPOrderedClause>()) {
if (!C->getNumForLoops())
continue;
for (unsigned I = LD->getCollapsedNumber(),
E = C->getLoopNumIterations().size();
I < E; ++I) {
if (const auto *VD = dyn_cast<OMPCapturedExprDecl>(
cast<DeclRefExpr>(C->getLoopCunter(I))->getDecl())) {
// Emit only those that were not explicitly referenced in clauses.
if (!CGF.LocalDeclMap.count(VD))
CGF.EmitVarDecl(*VD);
}
}
}
}
CGF.EmitStmt(D.getInnermostCapturedStmt()->getCapturedStmt());
}

View File

@ -470,7 +470,7 @@ public:
/// potentially set the return value.
bool SawAsmBlock = false;
const FunctionDecl *CurSEHParent = nullptr;
const NamedDecl *CurSEHParent = nullptr;
/// True if the current function is an outlined SEH helper. This can be a
/// finally block or filter expression.
@ -2878,6 +2878,8 @@ public:
void EnterSEHTryStmt(const SEHTryStmt &S);
void ExitSEHTryStmt(const SEHTryStmt &S);
void pushSEHCleanup(CleanupKind kind,
llvm::Function *FinallyFunc);
void startOutlinedSEHHelper(CodeGenFunction &ParentCGF, bool IsFilter,
const Stmt *OutlinedStmt);

View File

@ -4912,7 +4912,8 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args,
}
if ((runtime.getKind() == ObjCRuntime::GNUstep) &&
(runtime.getVersion() >= VersionTuple(2, 0)))
if (!getToolChain().getTriple().isOSBinFormatELF()) {
if (!getToolChain().getTriple().isOSBinFormatELF() &&
!getToolChain().getTriple().isOSBinFormatCOFF()) {
getToolChain().getDriver().Diag(
diag::err_drv_gnustep_objc_runtime_incompatible_binary)
<< runtime.getVersion().getMajor();

View File

@ -2035,7 +2035,11 @@ bool Darwin::isAlignedAllocationUnavailable() const {
void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
Action::OffloadKind DeviceOffloadKind) const {
if (isAlignedAllocationUnavailable())
// Pass "-faligned-alloc-unavailable" only when the user hasn't manually
// enabled or disabled aligned allocations.
if (!DriverArgs.hasArgNoClaim(options::OPT_faligned_allocation,
options::OPT_fno_aligned_allocation) &&
isAlignedAllocationUnavailable())
CC1Args.push_back("-faligned-alloc-unavailable");
}

View File

@ -553,7 +553,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_guaranteed_copy_elision", "201606L");
Builder.defineMacro("__cpp_nontype_template_parameter_auto", "201606L");
}
if (LangOpts.AlignedAllocation)
if (LangOpts.AlignedAllocation && !LangOpts.AlignedAllocationUnavailable)
Builder.defineMacro("__cpp_aligned_new", "201606L");
if (LangOpts.RelaxedTemplateTemplateArgs)
Builder.defineMacro("__cpp_template_template_args", "201611L");

View File

@ -1747,9 +1747,9 @@ static void diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD,
StringRef OSName = AvailabilityAttr::getPlatformNameSourceSpelling(
S.getASTContext().getTargetInfo().getPlatformName());
S.Diag(Loc, diag::warn_aligned_allocation_unavailable)
<< IsDelete << FD.getType().getAsString() << OSName
<< alignedAllocMinVersion(T.getOS()).getAsString();
S.Diag(Loc, diag::err_aligned_allocation_unavailable)
<< IsDelete << FD.getType().getAsString() << OSName
<< alignedAllocMinVersion(T.getOS()).getAsString();
S.Diag(Loc, diag::note_silence_unligned_allocation_unavailable);
}
}

View File

@ -73,6 +73,8 @@ public:
};
using OperatorOffsetTy =
llvm::SmallVector<std::pair<Expr *, OverloadedOperatorKind>, 4>;
using DoacrossDependMapTy =
llvm::DenseMap<OMPDependClause *, OperatorOffsetTy>;
private:
struct DSAInfo {
@ -97,8 +99,6 @@ private:
llvm::DenseMap<const ValueDecl *, MappedExprComponentTy>;
using CriticalsWithHintsTy =
llvm::StringMap<std::pair<const OMPCriticalDirective *, llvm::APSInt>>;
using DoacrossDependMapTy =
llvm::DenseMap<OMPDependClause *, OperatorOffsetTy>;
struct ReductionData {
using BOKPtrType = llvm::PointerEmbeddedInt<BinaryOperatorKind, 16>;
SourceRange ReductionRange;
@ -137,7 +137,7 @@ private:
/// first argument (Expr *) contains optional argument of the
/// 'ordered' clause, the second one is true if the regions has 'ordered'
/// clause, false otherwise.
llvm::PointerIntPair<const Expr *, 1, bool> OrderedRegion;
llvm::Optional<std::pair<const Expr *, OMPOrderedClause *>> OrderedRegion;
bool NowaitRegion = false;
bool CancelRegion = false;
unsigned AssociatedLoops = 1;
@ -398,23 +398,42 @@ public:
}
/// Marks current region as ordered (it has an 'ordered' clause).
void setOrderedRegion(bool IsOrdered, const Expr *Param) {
void setOrderedRegion(bool IsOrdered, const Expr *Param,
OMPOrderedClause *Clause) {
assert(!isStackEmpty());
Stack.back().first.back().OrderedRegion.setInt(IsOrdered);
Stack.back().first.back().OrderedRegion.setPointer(Param);
if (IsOrdered)
Stack.back().first.back().OrderedRegion.emplace(Param, Clause);
else
Stack.back().first.back().OrderedRegion.reset();
}
/// Returns true, if region is ordered (has associated 'ordered' clause),
/// false - otherwise.
bool isOrderedRegion() const {
if (isStackEmpty())
return false;
return Stack.back().first.rbegin()->OrderedRegion.hasValue();
}
/// Returns optional parameter for the ordered region.
std::pair<const Expr *, OMPOrderedClause *> getOrderedRegionParam() const {
if (isStackEmpty() ||
!Stack.back().first.rbegin()->OrderedRegion.hasValue())
return std::make_pair(nullptr, nullptr);
return Stack.back().first.rbegin()->OrderedRegion.getValue();
}
/// Returns true, if parent region is ordered (has associated
/// 'ordered' clause), false - otherwise.
bool isParentOrderedRegion() const {
if (isStackEmpty() || Stack.back().first.size() == 1)
return false;
return std::next(Stack.back().first.rbegin())->OrderedRegion.getInt();
return std::next(Stack.back().first.rbegin())->OrderedRegion.hasValue();
}
/// Returns optional parameter for the ordered region.
const Expr *getParentOrderedRegionParam() const {
if (isStackEmpty() || Stack.back().first.size() == 1)
return nullptr;
return std::next(Stack.back().first.rbegin())->OrderedRegion.getPointer();
std::pair<const Expr *, OMPOrderedClause *>
getParentOrderedRegionParam() const {
if (isStackEmpty() || Stack.back().first.size() == 1 ||
!std::next(Stack.back().first.rbegin())->OrderedRegion.hasValue())
return std::make_pair(nullptr, nullptr);
return std::next(Stack.back().first.rbegin())->OrderedRegion.getValue();
}
/// Marks current region as nowait (it has a 'nowait' clause).
void setNowaitRegion(bool IsNowait = true) {
@ -1239,17 +1258,6 @@ void Sema::popOpenMPFunctionRegion(const FunctionScopeInfo *OldFSI) {
DSAStack->popFunction(OldFSI);
}
static llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy>
isDeclareTargetDeclaration(const ValueDecl *VD) {
for (const Decl *D : VD->redecls()) {
if (!D->hasAttrs())
continue;
if (const auto *Attr = D->getAttr<OMPDeclareTargetDeclAttr>())
return Attr->getMapType();
}
return llvm::None;
}
bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
@ -1429,7 +1437,7 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D) const {
// If the declaration is enclosed in a 'declare target' directive,
// then it should not be captured.
//
if (isDeclareTargetDeclaration(VD))
if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
return nullptr;
return VD;
}
@ -1968,7 +1976,7 @@ public:
// Skip internally declared static variables.
llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
isDeclareTargetDeclaration(VD);
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
if (VD->hasGlobalStorage() && !CS->capturesVariable(VD) &&
(!Res || *Res != OMPDeclareTargetDeclAttr::MT_Link))
return;
@ -3736,6 +3744,13 @@ public:
Expr *buildCounterInit() const;
/// Build step of the counter be used for codegen.
Expr *buildCounterStep() const;
/// Build loop data with counter value for depend clauses in ordered
/// directives.
Expr *
buildOrderedLoopData(Scope *S, Expr *Counter,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures,
SourceLocation Loc, Expr *Inc = nullptr,
OverloadedOperatorKind OOK = OO_Amp);
/// Return true if any expression is dependent.
bool dependent() const;
@ -3900,7 +3915,12 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) {
SemaRef.Diag(S->getLocStart(),
diag::ext_omp_loop_not_canonical_init)
<< S->getSourceRange();
return setLCDeclAndLB(Var, nullptr, Var->getInit());
return setLCDeclAndLB(
Var,
buildDeclRefExpr(SemaRef, Var,
Var->getType().getNonReferenceType(),
DS->getLocStart()),
Var->getInit());
}
}
}
@ -4262,7 +4282,8 @@ Expr *OpenMPIterationSpaceChecker::buildPreCond(
/// Build reference expression to the counter be used for codegen.
DeclRefExpr *OpenMPIterationSpaceChecker::buildCounterVar(
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures, DSAStackTy &DSA) const {
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures,
DSAStackTy &DSA) const {
auto *VD = dyn_cast<VarDecl>(LCDecl);
if (!VD) {
VD = SemaRef.isOpenMPCapturedDecl(LCDecl);
@ -4302,6 +4323,63 @@ Expr *OpenMPIterationSpaceChecker::buildCounterInit() const { return LB; }
/// Build step of the counter be used for codegen.
Expr *OpenMPIterationSpaceChecker::buildCounterStep() const { return Step; }
Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData(
Scope *S, Expr *Counter,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures, SourceLocation Loc,
Expr *Inc, OverloadedOperatorKind OOK) {
Expr *Cnt = SemaRef.DefaultLvalueConversion(Counter).get();
if (!Cnt)
return nullptr;
if (Inc) {
assert((OOK == OO_Plus || OOK == OO_Minus) &&
"Expected only + or - operations for depend clauses.");
BinaryOperatorKind BOK = (OOK == OO_Plus) ? BO_Add : BO_Sub;
Cnt = SemaRef.BuildBinOp(S, Loc, BOK, Cnt, Inc).get();
if (!Cnt)
return nullptr;
}
ExprResult Diff;
QualType VarType = LCDecl->getType().getNonReferenceType();
if (VarType->isIntegerType() || VarType->isPointerType() ||
SemaRef.getLangOpts().CPlusPlus) {
// Upper - Lower
Expr *Upper =
TestIsLessOp ? Cnt : tryBuildCapture(SemaRef, UB, Captures).get();
Expr *Lower =
TestIsLessOp ? tryBuildCapture(SemaRef, LB, Captures).get() : Cnt;
if (!Upper || !Lower)
return nullptr;
Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower);
if (!Diff.isUsable() && VarType->getAsCXXRecordDecl()) {
// BuildBinOp already emitted error, this one is to point user to upper
// and lower bound, and to tell what is passed to 'operator-'.
SemaRef.Diag(Upper->getLocStart(), diag::err_omp_loop_diff_cxx)
<< Upper->getSourceRange() << Lower->getSourceRange();
return nullptr;
}
}
if (!Diff.isUsable())
return nullptr;
// Parentheses (for dumping/debugging purposes only).
Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
if (!Diff.isUsable())
return nullptr;
ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures);
if (!NewStep.isUsable())
return nullptr;
// (Upper - Lower) / Step
Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get());
if (!Diff.isUsable())
return nullptr;
return Diff.get();
}
/// Iteration space of a single for loop.
struct LoopIterationSpace final {
/// Condition of the loop.
@ -4361,7 +4439,8 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
static bool checkOpenMPIterationSpace(
OpenMPDirectiveKind DKind, Stmt *S, Sema &SemaRef, DSAStackTy &DSA,
unsigned CurrentNestedLoopCount, unsigned NestedLoopCount,
Expr *CollapseLoopCountExpr, Expr *OrderedLoopCountExpr,
unsigned TotalNestedLoopCount, Expr *CollapseLoopCountExpr,
Expr *OrderedLoopCountExpr,
Sema::VarsWithInheritedDSAType &VarsWithImplicitDSA,
LoopIterationSpace &ResultIterSpace,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) {
@ -4371,9 +4450,9 @@ static bool checkOpenMPIterationSpace(
if (!For) {
SemaRef.Diag(S->getLocStart(), diag::err_omp_not_for)
<< (CollapseLoopCountExpr != nullptr || OrderedLoopCountExpr != nullptr)
<< getOpenMPDirectiveName(DKind) << NestedLoopCount
<< getOpenMPDirectiveName(DKind) << TotalNestedLoopCount
<< (CurrentNestedLoopCount > 0) << CurrentNestedLoopCount;
if (NestedLoopCount > 1) {
if (TotalNestedLoopCount > 1) {
if (CollapseLoopCountExpr && OrderedLoopCountExpr)
SemaRef.Diag(DSA.getConstructLoc(),
diag::note_omp_collapse_ordered_expr)
@ -4506,6 +4585,41 @@ static bool checkOpenMPIterationSpace(
ResultIterSpace.PrivateCounterVar == nullptr ||
ResultIterSpace.CounterInit == nullptr ||
ResultIterSpace.CounterStep == nullptr);
if (!HasErrors && DSA.isOrderedRegion()) {
if (DSA.getOrderedRegionParam().second->getNumForLoops()) {
if (CurrentNestedLoopCount <
DSA.getOrderedRegionParam().second->getLoopNumIterations().size()) {
DSA.getOrderedRegionParam().second->setLoopNumIterations(
CurrentNestedLoopCount, ResultIterSpace.NumIterations);
DSA.getOrderedRegionParam().second->setLoopCounter(
CurrentNestedLoopCount, ResultIterSpace.CounterVar);
}
}
for (auto &Pair : DSA.getDoacrossDependClauses()) {
if (CurrentNestedLoopCount >= Pair.first->getNumLoops()) {
// Erroneous case - clause has some problems.
continue;
}
if (Pair.first->getDependencyKind() == OMPC_DEPEND_sink &&
Pair.second.size() <= CurrentNestedLoopCount) {
// Erroneous case - clause has some problems.
Pair.first->setLoopData(CurrentNestedLoopCount, nullptr);
continue;
}
Expr *CntValue;
if (Pair.first->getDependencyKind() == OMPC_DEPEND_source)
CntValue = ISC.buildOrderedLoopData(
DSA.getCurScope(), ResultIterSpace.CounterVar, Captures,
Pair.first->getDependencyLoc());
else
CntValue = ISC.buildOrderedLoopData(
DSA.getCurScope(), ResultIterSpace.CounterVar, Captures,
Pair.first->getDependencyLoc(),
Pair.second[CurrentNestedLoopCount].first,
Pair.second[CurrentNestedLoopCount].second);
Pair.first->setLoopData(CurrentNestedLoopCount, CntValue);
}
}
return HasErrors;
}
@ -4691,6 +4805,7 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
if (CollapseLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext()))
NestedLoopCount = Result.getLimitedValue();
}
unsigned OrderedLoopCount = 1;
if (OrderedLoopCountExpr) {
// Found 'ordered' clause - calculate collapse number.
llvm::APSInt Result;
@ -4703,20 +4818,21 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
diag::note_collapse_loop_count)
<< CollapseLoopCountExpr->getSourceRange();
}
NestedLoopCount = Result.getLimitedValue();
OrderedLoopCount = Result.getLimitedValue();
}
}
// This is helper routine for loop directives (e.g., 'for', 'simd',
// 'for simd', etc.).
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
SmallVector<LoopIterationSpace, 4> IterSpaces;
IterSpaces.resize(NestedLoopCount);
IterSpaces.resize(std::max(OrderedLoopCount, NestedLoopCount));
Stmt *CurStmt = AStmt->IgnoreContainers(/* IgnoreCaptured */ true);
for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) {
if (checkOpenMPIterationSpace(DKind, CurStmt, SemaRef, DSA, Cnt,
NestedLoopCount, CollapseLoopCountExpr,
OrderedLoopCountExpr, VarsWithImplicitDSA,
IterSpaces[Cnt], Captures))
if (checkOpenMPIterationSpace(
DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount,
std::max(OrderedLoopCount, NestedLoopCount), CollapseLoopCountExpr,
OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces[Cnt],
Captures))
return 0;
// Move on to the next nested for loop, or to the loop body.
// OpenMP [2.8.1, simd construct, Restrictions]
@ -4725,6 +4841,27 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
// any two loops.
CurStmt = cast<ForStmt>(CurStmt)->getBody()->IgnoreContainers();
}
for (unsigned Cnt = NestedLoopCount; Cnt < OrderedLoopCount; ++Cnt) {
if (checkOpenMPIterationSpace(
DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount,
std::max(OrderedLoopCount, NestedLoopCount), CollapseLoopCountExpr,
OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces[Cnt],
Captures))
return 0;
if (Cnt > 0 && IterSpaces[Cnt].CounterVar) {
// Handle initialization of captured loop iterator variables.
auto *DRE = cast<DeclRefExpr>(IterSpaces[Cnt].CounterVar);
if (isa<OMPCapturedExprDecl>(DRE->getDecl())) {
Captures[DRE] = DRE;
}
}
// Move on to the next nested for loop, or to the loop body.
// OpenMP [2.8.1, simd construct, Restrictions]
// All loops associated with the construct must be perfectly nested; that
// is, there must be no intervening code nor any OpenMP directive between
// any two loops.
CurStmt = cast<ForStmt>(CurStmt)->getBody()->IgnoreContainers();
}
Built.clear(/* size */ NestedLoopCount);
@ -5104,7 +5241,6 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
Built.Inits.resize(NestedLoopCount);
Built.Updates.resize(NestedLoopCount);
Built.Finals.resize(NestedLoopCount);
SmallVector<Expr *, 4> LoopMultipliers;
{
ExprResult Div;
// Go from inner nested loop to outer.
@ -5174,7 +5310,6 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
HasErrors = true;
break;
}
LoopMultipliers.push_back(Div.get());
}
if (!Update.isUsable() || !Final.isUsable()) {
HasErrors = true;
@ -5222,55 +5357,6 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
Built.DistCombinedFields.NLB = CombNextLB.get();
Built.DistCombinedFields.NUB = CombNextUB.get();
Expr *CounterVal = SemaRef.DefaultLvalueConversion(IV.get()).get();
// Fill data for doacross depend clauses.
for (const auto &Pair : DSA.getDoacrossDependClauses()) {
if (Pair.first->getDependencyKind() == OMPC_DEPEND_source) {
Pair.first->setCounterValue(CounterVal);
} else {
if (NestedLoopCount != Pair.second.size() ||
NestedLoopCount != LoopMultipliers.size() + 1) {
// Erroneous case - clause has some problems.
Pair.first->setCounterValue(CounterVal);
continue;
}
assert(Pair.first->getDependencyKind() == OMPC_DEPEND_sink);
auto I = Pair.second.rbegin();
auto IS = IterSpaces.rbegin();
auto ILM = LoopMultipliers.rbegin();
Expr *UpCounterVal = CounterVal;
Expr *Multiplier = nullptr;
for (int Cnt = NestedLoopCount - 1; Cnt >= 0; --Cnt) {
if (I->first) {
assert(IS->CounterStep);
Expr *NormalizedOffset =
SemaRef
.BuildBinOp(CurScope, I->first->getExprLoc(), BO_Div,
I->first, IS->CounterStep)
.get();
if (Multiplier) {
NormalizedOffset =
SemaRef
.BuildBinOp(CurScope, I->first->getExprLoc(), BO_Mul,
NormalizedOffset, Multiplier)
.get();
}
assert(I->second == OO_Plus || I->second == OO_Minus);
BinaryOperatorKind BOK = (I->second == OO_Plus) ? BO_Add : BO_Sub;
UpCounterVal = SemaRef
.BuildBinOp(CurScope, I->first->getExprLoc(), BOK,
UpCounterVal, NormalizedOffset)
.get();
}
Multiplier = *ILM;
++I;
++IS;
++ILM;
}
Pair.first->setCounterValue(UpCounterVal);
}
}
return NestedLoopCount;
}
@ -5838,12 +5924,12 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses,
Diag(DependFound->getLocStart(), diag::err_omp_depend_clause_thread_simd)
<< getOpenMPClauseName(TC ? TC->getClauseKind() : SC->getClauseKind());
ErrorFound = true;
} else if (DependFound && !DSAStack->getParentOrderedRegionParam()) {
} else if (DependFound && !DSAStack->getParentOrderedRegionParam().first) {
Diag(DependFound->getLocStart(),
diag::err_omp_ordered_directive_without_param);
ErrorFound = true;
} else if (TC || Clauses.empty()) {
if (const Expr *Param = DSAStack->getParentOrderedRegionParam()) {
if (const Expr *Param = DSAStack->getParentOrderedRegionParam().first) {
SourceLocation ErrLoc = TC ? TC->getLocStart() : StartLoc;
Diag(ErrLoc, diag::err_omp_ordered_directive_with_param)
<< (TC != nullptr);
@ -8619,9 +8705,11 @@ OMPClause *Sema::ActOnOpenMPOrderedClause(SourceLocation StartLoc,
} else {
NumForLoops = nullptr;
}
DSAStack->setOrderedRegion(/*IsOrdered=*/true, NumForLoops);
return new (Context)
OMPOrderedClause(NumForLoops, StartLoc, LParenLoc, EndLoc);
auto *Clause = OMPOrderedClause::Create(
Context, NumForLoops, NumForLoops ? DSAStack->getAssociatedLoops() : 0,
StartLoc, LParenLoc, EndLoc);
DSAStack->setOrderedRegion(/*IsOrdered=*/true, NumForLoops, Clause);
return Clause;
}
OMPClause *Sema::ActOnOpenMPSimpleClause(
@ -11477,8 +11565,9 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
DSAStackTy::OperatorOffsetTy OpsOffs;
llvm::APSInt DepCounter(/*BitWidth=*/32);
llvm::APSInt TotalDepCount(/*BitWidth=*/32);
if (DepKind == OMPC_DEPEND_sink) {
if (const Expr *OrderedCountExpr = DSAStack->getParentOrderedRegionParam()) {
if (DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) {
if (const Expr *OrderedCountExpr =
DSAStack->getParentOrderedRegionParam().first) {
TotalDepCount = OrderedCountExpr->EvaluateKnownConstInt(Context);
TotalDepCount.setIsUnsigned(/*Val=*/true);
}
@ -11494,7 +11583,7 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
SourceLocation ELoc = RefExpr->getExprLoc();
Expr *SimpleExpr = RefExpr->IgnoreParenCasts();
if (DepKind == OMPC_DEPEND_sink) {
if (DSAStack->getParentOrderedRegionParam() &&
if (DSAStack->getParentOrderedRegionParam().first &&
DepCounter >= TotalDepCount) {
Diag(ELoc, diag::err_omp_depend_sink_unexpected_expr);
continue;
@ -11560,7 +11649,7 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
continue;
}
if (!CurContext->isDependentContext() &&
DSAStack->getParentOrderedRegionParam() &&
DSAStack->getParentOrderedRegionParam().first &&
DepCounter != DSAStack->isParentLoopControlVariable(D).first) {
const ValueDecl *VD =
DSAStack->getParentLoopControlVariable(DepCounter.getZExtValue());
@ -11598,7 +11687,7 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
if (!CurContext->isDependentContext() && DepKind == OMPC_DEPEND_sink &&
TotalDepCount > VarList.size() &&
DSAStack->getParentOrderedRegionParam() &&
DSAStack->getParentOrderedRegionParam().first &&
DSAStack->getParentLoopControlVariable(VarList.size() + 1)) {
Diag(EndLoc, diag::err_omp_depend_sink_expected_loop_iteration)
<< 1 << DSAStack->getParentLoopControlVariable(VarList.size() + 1);
@ -11608,7 +11697,8 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
return nullptr;
auto *C = OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc,
DepKind, DepLoc, ColonLoc, Vars);
DepKind, DepLoc, ColonLoc, Vars,
TotalDepCount.getZExtValue());
if ((DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) &&
DSAStack->isParentOrderedRegion())
DSAStack->addDoacrossDependClause(C, OpsOffs);
@ -13042,6 +13132,8 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
return;
}
}
if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
D = FTD->getTemplatedDecl();
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->hasAttr<OMPDeclareTargetDeclAttr>() &&
(FD->getAttr<OMPDeclareTargetDeclAttr>()->getMapType() ==
@ -13052,16 +13144,6 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
return;
}
}
if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D)) {
if (FTD->hasAttr<OMPDeclareTargetDeclAttr>() &&
(FTD->getAttr<OMPDeclareTargetDeclAttr>()->getMapType() ==
OMPDeclareTargetDeclAttr::MT_Link)) {
assert(IdLoc.isValid() && "Source location is expected");
Diag(IdLoc, diag::err_omp_function_in_link_clause);
Diag(FTD->getLocation(), diag::note_defined_here) << FTD;
return;
}
}
if (!E) {
// Checking declaration inside declare target region.
if (!D->hasAttr<OMPDeclareTargetDeclAttr>() &&

View File

@ -5192,10 +5192,20 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) {
bool DefinitionRequired = Function->getTemplateSpecializationKind() ==
TSK_ExplicitInstantiationDefinition;
InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true,
DefinitionRequired, true);
if (Function->isDefined())
Function->setInstantiationIsPending(false);
if (Function->isMultiVersion()) {
getASTContext().forEachMultiversionedFunctionVersion(
Function, [this, Inst, DefinitionRequired](FunctionDecl *CurFD) {
InstantiateFunctionDefinition(/*FIXME:*/ Inst.second, CurFD, true,
DefinitionRequired, true);
if (CurFD->isDefined())
CurFD->setInstantiationIsPending(false);
});
} else {
InstantiateFunctionDefinition(/*FIXME:*/ Inst.second, Function, true,
DefinitionRequired, true);
if (Function->isDefined())
Function->setInstantiationIsPending(false);
}
continue;
}

View File

@ -1856,7 +1856,7 @@ OMPClause *OMPClauseReader::readClause() {
C = new (Context) OMPScheduleClause();
break;
case OMPC_ordered:
C = new (Context) OMPOrderedClause();
C = OMPOrderedClause::CreateEmpty(Context, Reader->Record.readInt());
break;
case OMPC_nowait:
C = new (Context) OMPNowaitClause();
@ -1927,9 +1927,12 @@ OMPClause *OMPClauseReader::readClause() {
case OMPC_flush:
C = OMPFlushClause::CreateEmpty(Context, Reader->Record.readInt());
break;
case OMPC_depend:
C = OMPDependClause::CreateEmpty(Context, Reader->Record.readInt());
case OMPC_depend: {
unsigned NumVars = Reader->Record.readInt();
unsigned NumLoops = Reader->Record.readInt();
C = OMPDependClause::CreateEmpty(Context, NumVars, NumLoops);
break;
}
case OMPC_device:
C = new (Context) OMPDeviceClause();
break;
@ -2087,6 +2090,10 @@ void OMPClauseReader::VisitOMPScheduleClause(OMPScheduleClause *C) {
void OMPClauseReader::VisitOMPOrderedClause(OMPOrderedClause *C) {
C->setNumForLoops(Reader->Record.readSubExpr());
for (unsigned I = 0, E = C->NumberOfLoops; I < E; ++I)
C->setLoopNumIterations(I, Reader->Record.readSubExpr());
for (unsigned I = 0, E = C->NumberOfLoops; I < E; ++I)
C->setLoopCounter(I, Reader->Record.readSubExpr());
C->setLParenLoc(Reader->ReadSourceLocation());
}
@ -2395,10 +2402,11 @@ void OMPClauseReader::VisitOMPDependClause(OMPDependClause *C) {
unsigned NumVars = C->varlist_size();
SmallVector<Expr *, 16> Vars;
Vars.reserve(NumVars);
for (unsigned i = 0; i != NumVars; ++i)
for (unsigned I = 0; I != NumVars; ++I)
Vars.push_back(Reader->Record.readSubExpr());
C->setVarRefs(Vars);
C->setCounterValue(Reader->Record.readSubExpr());
for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I)
C->setLoopData(I, Reader->Record.readSubExpr());
}
void OMPClauseReader::VisitOMPDeviceClause(OMPDeviceClause *C) {

View File

@ -1898,7 +1898,12 @@ void OMPClauseWriter::VisitOMPScheduleClause(OMPScheduleClause *C) {
}
void OMPClauseWriter::VisitOMPOrderedClause(OMPOrderedClause *C) {
Record.push_back(C->getLoopNumIterations().size());
Record.AddStmt(C->getNumForLoops());
for (Expr *NumIter : C->getLoopNumIterations())
Record.AddStmt(NumIter);
for (unsigned I = 0, E = C->getLoopNumIterations().size(); I <E; ++I)
Record.AddStmt(C->getLoopCunter(I));
Record.AddSourceLocation(C->getLParenLoc());
}
@ -2102,13 +2107,15 @@ void OMPClauseWriter::VisitOMPFlushClause(OMPFlushClause *C) {
void OMPClauseWriter::VisitOMPDependClause(OMPDependClause *C) {
Record.push_back(C->varlist_size());
Record.push_back(C->getNumLoops());
Record.AddSourceLocation(C->getLParenLoc());
Record.push_back(C->getDependencyKind());
Record.AddSourceLocation(C->getDependencyLoc());
Record.AddSourceLocation(C->getColonLoc());
for (auto *VE : C->varlists())
Record.AddStmt(VE);
Record.AddStmt(C->getCounterValue());
for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I)
Record.AddStmt(C->getLoopData(I));
}
void OMPClauseWriter::VisitOMPDeviceClause(OMPDeviceClause *C) {

View File

@ -111,13 +111,12 @@ int templ_use() {
// CHECK: call i32 @_ZN5templIiE3fooEi.ifunc
// CHECK: call i32 @_ZN5templIdE3fooEi.ifunc
// CHECK: define i32 (%struct.templ*, i32)* @_ZN5templIiE3fooEi.resolver() comdat
// CHECK: ret i32 (%struct.templ*, i32)* @_ZN5templIiE3fooEi.arch_sandybridge
// CHECK: ret i32 (%struct.templ*, i32)* @_ZN5templIiE3fooEi.arch_ivybridge
// CHECK: ret i32 (%struct.templ*, i32)* @_ZN5templIiE3fooEi.sse4.2
// CHECK: ret i32 (%struct.templ*, i32)* @_ZN5templIiE3fooEi
//
// CHECK: define i32 (%struct.templ.0*, i32)* @_ZN5templIdE3fooEi.resolver() comdat
// CHECK: ret i32 (%struct.templ.0*, i32)* @_ZN5templIdE3fooEi.arch_sandybridge
// CHECK: ret i32 (%struct.templ.0*, i32)* @_ZN5templIdE3fooEi.arch_ivybridge
@ -135,3 +134,12 @@ int templ_use() {
// CHECK: define linkonce_odr i32 @_ZN1S3fooEi(%struct.S* %this, i32)
// CHECK: ret i32 2
// CHECK: define linkonce_odr i32 @_ZN5templIiE3fooEi.sse4.2
// CHECK: declare i32 @_ZN5templIiE3fooEi.arch_sandybridge
// CHECK: define linkonce_odr i32 @_ZN5templIiE3fooEi.arch_ivybridge
// CHECK: define linkonce_odr i32 @_ZN5templIiE3fooEi
// CHECK: define linkonce_odr i32 @_ZN5templIdE3fooEi.sse4.2
// CHECK: declare i32 @_ZN5templIdE3fooEi.arch_sandybridge
// CHECK: define linkonce_odr i32 @_ZN5templIdE3fooEi.arch_ivybridge
// CHECK: define linkonce_odr i32 @_ZN5templIdE3fooEi

View File

@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-unknown-freebsd -S -emit-llvm -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck %s -check-prefix=CHECK-NEW
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -S -emit-llvm -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck %s -check-prefix=CHECK-WIN
// RUN: %clang_cc1 -triple x86_64-unknown-freebsd -S -emit-llvm -fobjc-runtime=gnustep-1.8 -o - %s | FileCheck %s -check-prefix=CHECK-OLD
// Almost minimal Objective-C file, check that it emits calls to the correct
@ -49,9 +50,9 @@
// CHECK-NEW: @.objc_null_class_alias = linkonce_odr hidden global { i8*, i8* } zeroinitializer, section "__objc_class_aliases", comdat, align 8
// CHECK-NEW: @.objc_null_constant_string = linkonce_odr hidden global { i8*, i32, i32, i32, i32, i8* } zeroinitializer, section "__objc_constant_string", comdat, align 8
// Make sure that the null symbols are not going to be removed, even by linking.
// CHECK-NEW: @llvm.used = appending global [7 x i8*] [i8* bitcast ({ { i8*, i8*, i8*, i64, i64, i64, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i64, i8* }*, i8*, i8*, i64, i64, i64, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i64, i8* }** @._OBJC_INIT_CLASS_X to i8*), i8* bitcast ({ i8*, i8* }* @.objc_null_selector to i8*), i8* bitcast ({ i8*, i8*, i8*, i8*, i8*, i8*, i8* }* @.objc_null_category to i8*), i8* bitcast ({ i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8* }* @.objc_null_protocol to i8*), i8* bitcast ({ i8* }* @.objc_null_protocol_ref to i8*), i8* bitcast ({ i8*, i8* }* @.objc_null_class_alias to i8*), i8* bitcast ({ i8*, i32, i32, i32, i32, i8* }* @.objc_null_constant_string to i8*)], section "llvm.metadata"
// CHECK-NEW: @llvm.used = appending global [8 x i8*] [i8* bitcast ({ { i8*, i8*, i8*, i64, i64, i64, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i64, i8* }*, i8*, i8*, i64, i64, i64, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i64, i8* }** @._OBJC_INIT_CLASS_X to i8*), i8* bitcast (void ()** @.objc_ctor to i8*), i8* bitcast ({ i8*, i8* }* @.objc_null_selector to i8*), i8* bitcast ({ i8*, i8*, i8*, i8*, i8*, i8*, i8* }* @.objc_null_category to i8*), i8* bitcast ({ i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8* }* @.objc_null_protocol to i8*), i8* bitcast ({ i8* }* @.objc_null_protocol_ref to i8*), i8* bitcast ({ i8*, i8* }* @.objc_null_class_alias to i8*), i8* bitcast ({ i8*, i32, i32, i32, i32, i8* }* @.objc_null_constant_string to i8*)], section "llvm.metadata"
// Make sure that the load function and the reference to it are marked as used.
// CHECK-NEW: @llvm.compiler.used = appending global [2 x i8*] [i8* bitcast (void ()* @.objcv2_load_function to i8*), i8* bitcast (void ()** @.objc_ctor to i8*)], section "llvm.metadata"
// CHECK-NEW: @llvm.compiler.used = appending global [1 x i8*] [i8* bitcast (void ()* @.objcv2_load_function to i8*)], section "llvm.metadata"
// Check that we emit the load function in a comdat and that it does the right thing.
// CHECK-NEW: define linkonce_odr hidden void @.objcv2_load_function() comdat {
@ -67,3 +68,37 @@
// CHECK-OLD-NEXT: entry:
// CHECK-OLD-NEXT: call void ({ i64, i64, i8*, { i64, { i8*, i8* }*, i16, i16, [4 x i8*] }* }*, ...) @__objc_exec_class({ i64, i64, i8*, { i64, { i8*, i8* }*, i16, i16, [4 x i8*] }* }* @4)
// Make sure all of our section boundary variables are emitted correctly.
// CHECK-WIN-DAG: @__start___objc_selectors = linkonce_odr hidden global %.objc_section_sentinel zeroinitializer, section "__objc_selectors$a", comdat, align 1
// CHECK-WIN-DAG: @__stop__objc_selectors = linkonce_odr hidden global %.objc_section_sentinel zeroinitializer, section "__objc_selectors$z", comdat, align 1
// CHECK-WIN-DAG: @__start___objc_classes = linkonce_odr hidden global %.objc_section_sentinel zeroinitializer, section "__objc_classes$a", comdat, align 1
// CHECK-WIN-DAG: @__stop__objc_classes = linkonce_odr hidden global %.objc_section_sentinel zeroinitializer, section "__objc_classes$z", comdat, align 1
// CHECK-WIN-DAG: @__start___objc_class_refs = linkonce_odr hidden global %.objc_section_sentinel zeroinitializer, section "__objc_class_refs$a", comdat, align 1
// CHECK-WIN-DAG: @__stop__objc_class_refs = linkonce_odr hidden global %.objc_section_sentinel zeroinitializer, section "__objc_class_refs$z", comdat, align 1
// CHECK-WIN-DAG: @__start___objc_cats = linkonce_odr hidden global %.objc_section_sentinel zeroinitializer, section "__objc_cats$a", comdat, align 1
// CHECK-WIN-DAG: @__stop__objc_cats = linkonce_odr hidden global %.objc_section_sentinel zeroinitializer, section "__objc_cats$z", comdat, align 1
// CHECK-WIN-DAG: @__start___objc_protocols = linkonce_odr hidden global %.objc_section_sentinel zeroinitializer, section "__objc_protocols$a", comdat, align 1
// CHECK-WIN-DAG: @__stop__objc_protocols = linkonce_odr hidden global %.objc_section_sentinel zeroinitializer, section "__objc_protocols$z", comdat, align 1
// CHECK-WIN-DAG: @__start___objc_protocol_refs = linkonce_odr hidden global %.objc_section_sentinel zeroinitializer, section "__objc_protocol_refs$a", comdat, align 1
// CHECK-WIN-DAG: @__stop__objc_protocol_refs = linkonce_odr hidden global %.objc_section_sentinel zeroinitializer, section "__objc_protocol_refs$z", comdat, align 1
// CHECK-WIN-DAG: @__start___objc_class_aliases = linkonce_odr hidden global %.objc_section_sentinel zeroinitializer, section "__objc_class_aliases$a", comdat, align 1
// CHECK-WIN-DAG: @__stop__objc_class_aliases = linkonce_odr hidden global %.objc_section_sentinel zeroinitializer, section "__objc_class_aliases$z", comdat, align 1
// CHECK-WIN-DAG: @__start___objc_constant_string = linkonce_odr hidden global %.objc_section_sentinel zeroinitializer, section "__objc_constant_string$a", comdat, align 1
// CHECK-WIN-DAG: @__stop__objc_constant_string = linkonce_odr hidden global %.objc_section_sentinel zeroinitializer, section "__objc_constant_string$z", comdat, align 1
// CHECK-WIN: @.objc_init = linkonce_odr hidden global { i64, %.objc_section_sentinel*, %.objc_section_sentinel*, %.objc_section_sentinel*, %.objc_section_sentinel*, %.objc_section_sentinel*, %.objc_section_sentinel*, %.objc_section_sentinel*, %.objc_section_sentinel*, %.objc_section_sentinel*, %.objc_section_sentinel*, %.objc_section_sentinel*, %.objc_section_sentinel*, %.objc_section_sentinel*, %.objc_section_sentinel*, %.objc_section_sentinel*, %.objc_section_sentinel* } { i64 0, %.objc_section_sentinel* @__start___objc_selectors, %.objc_section_sentinel* @__stop__objc_selectors, %.objc_section_sentinel* @__start___objc_classes, %.objc_section_sentinel* @__stop__objc_classes, %.objc_section_sentinel* @__start___objc_class_refs, %.objc_section_sentinel* @__stop__objc_class_refs, %.objc_section_sentinel* @__start___objc_cats, %.objc_section_sentinel* @__stop__objc_cats, %.objc_section_sentinel* @__start___objc_protocols, %.objc_section_sentinel* @__stop__objc_protocols, %.objc_section_sentinel* @__start___objc_protocol_refs, %.objc_section_sentinel* @__stop__objc_protocol_refs, %.objc_section_sentinel* @__start___objc_class_aliases, %.objc_section_sentinel* @__stop__objc_class_aliases, %.objc_section_sentinel* @__start___objc_constant_string, %.objc_section_sentinel* @__stop__objc_constant_string }, comdat, align 8
// Make sure our init variable is in the correct section for late library init.
// CHECK-WIN: @.objc_ctor = linkonce hidden constant void ()* @.objcv2_load_function, section ".CRT$XCLz", comdat
// We shouldn't have emitted any null placeholders on Windows.
// CHECK-WIN: @llvm.used = appending global [2 x i8*] [i8* bitcast ({ { i8*, i8*, i8*, i32, i32, i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i32, i8* }*, i8*, i8*, i32, i32, i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i32, i8* }** @._OBJC_INIT_CLASS_X to i8*), i8* bitcast (void ()** @.objc_ctor to i8*)], section "llvm.metadata"
// CHECK-WIN: @llvm.compiler.used = appending global [1 x i8*] [i8* bitcast (void ()* @.objcv2_load_function to i8*)], section "llvm.metadata"
// Check our load function is in a comdat.
// CHECK-WIN: define linkonce_odr hidden void @.objcv2_load_function() comdat {
// Make sure we have dllimport on the load function
// CHECK-WIN: declare dllimport void @__objc_load

View File

@ -22,11 +22,11 @@
// Check that we're emitting the protocol and a correctly initialised
// indirection variable.
// CHECK: @._OBJC_PROTOCOL_X = global
// CHECK: @._OBJC_PROTOCOL_X = global
// CHECK-SAME: , section "__objc_protocols", comdat, align 8
// CHECK: @._OBJC_REF_PROTOCOL_X = global
// CHECK: @._OBJC_REF_PROTOCOL_X = linkonce_odr global
// CHECK-SAME: @._OBJC_PROTOCOL_X
// CHECK-SAME: , section "__objc_protocol_refs", align 8
// CHECK-SAME: , section "__objc_protocol_refs", comdat, align 8
// Check that we load from the indirection variable on protocol references.

View File

@ -10,7 +10,7 @@ void g() {
}
}
// CHECK: call i8* @"?f@@YAPAUobjc_object@@XZ"() [ "funclet"(token %1) ]
// CHECK: call i8* @"?f@@YAPAU.objc_object@@XZ"() [ "funclet"(token %1) ]
// CHECK-NEXT: call void asm sideeffect "movl{{.*}}%ebp, %ebp{{.*}}", ""() [ "funclet"(token %1) ]
// The corresponding f() call was invoked from the entry basic block.

View File

@ -9,7 +9,7 @@ struct A {
// Verify that we destruct things from left to right in the MS C++ ABI: a, b, c, d.
//
// CHECK-LABEL: define dso_local void @"?test_arc_order@@YAXUA@@PAUobjc_object@@01@Z"
// CHECK-LABEL: define dso_local void @"?test_arc_order@@YAXUA@@PAU.objc_object@@01@Z"
// CHECK: (<{ %struct.A, i8*, %struct.A, i8* }>* inalloca)
void test_arc_order(A a, id __attribute__((ns_consumed)) b , A c, id __attribute__((ns_consumed)) d) {
// CHECK: call x86_thiscallcc void @"??1A@@QAE@XZ"(%struct.A* %{{.*}})

View File

@ -6,61 +6,61 @@
@class I;
void f(id<P>, id, id<P>, id) {}
// CHECK-LABEL: "?f@@YAXPAU?$objc_object@U?$Protocol@UP@@@__ObjC@@@@PAUobjc_object@@01@Z"
// CHECK-LABEL: "?f@@YAXPAU?$.objc_object@U?$Protocol@UP@@@__ObjC@@@@PAU.objc_object@@01@Z"
void f(id, id<P>, id<P>, id) {}
// CHECK-LABEL: "?f@@YAXPAUobjc_object@@PAU?$objc_object@U?$Protocol@UP@@@__ObjC@@@@10@Z"
// CHECK-LABEL: "?f@@YAXPAU.objc_object@@PAU?$.objc_object@U?$Protocol@UP@@@__ObjC@@@@10@Z"
void f(id<P>, id<P>) {}
// CHECK-LABEL: "?f@@YAXPAU?$objc_object@U?$Protocol@UP@@@__ObjC@@@@0@Z"
// CHECK-LABEL: "?f@@YAXPAU?$.objc_object@U?$Protocol@UP@@@__ObjC@@@@0@Z"
void f(id<P>) {}
// CHECK-LABEL: "?f@@YAXPAU?$objc_object@U?$Protocol@UP@@@__ObjC@@@@@Z"
// CHECK-LABEL: "?f@@YAXPAU?$.objc_object@U?$Protocol@UP@@@__ObjC@@@@@Z"
void f(id<P, Q>) {}
// CHECK-LABEL: "?f@@YAXPAU?$objc_object@U?$Protocol@UP@@@__ObjC@@U?$Protocol@UQ@@@2@@@@Z"
// CHECK-LABEL: "?f@@YAXPAU?$.objc_object@U?$Protocol@UP@@@__ObjC@@U?$Protocol@UQ@@@2@@@@Z"
void f(Class<P>) {}
// CHECK-LABEL: "?f@@YAXPAU?$objc_class@U?$Protocol@UP@@@__ObjC@@@@@Z"
// CHECK-LABEL: "?f@@YAXPAU?$.objc_class@U?$Protocol@UP@@@__ObjC@@@@@Z"
void f(Class<P, Q>) {}
// CHECK-LABEL: "?f@@YAXPAU?$objc_class@U?$Protocol@UP@@@__ObjC@@U?$Protocol@UQ@@@2@@@@Z"
// CHECK-LABEL: "?f@@YAXPAU?$.objc_class@U?$Protocol@UP@@@__ObjC@@U?$Protocol@UQ@@@2@@@@Z"
void f(I<P> *) {}
// CHECK-LABEL: "?f@@YAXPAU?$I@U?$Protocol@UP@@@__ObjC@@@@@Z"
// CHECK-LABEL: "?f@@YAXPAU?$.objc_cls_I@U?$Protocol@UP@@@__ObjC@@@@@Z"
void f(I<P, Q> *) {}
// CHECK-LABEL: "?f@@YAXPAU?$I@U?$Protocol@UP@@@__ObjC@@U?$Protocol@UQ@@@2@@@@Z"
// CHECK-LABEL: "?f@@YAXPAU?$.objc_cls_I@U?$Protocol@UP@@@__ObjC@@U?$Protocol@UQ@@@2@@@@Z"
template <typename>
struct S {};
void f(S<__unsafe_unretained id>) {}
// CHECK-LABEL: "?f@@YAXU?$S@PAUobjc_object@@@@@Z"
// CHECK-LABEL: "?f@@YAXU?$S@PAU.objc_object@@@@@Z"
void f(S<__autoreleasing id>) {}
// CHECK-LABEL: "?f@@YAXU?$S@U?$Autoreleasing@PAUobjc_object@@@__ObjC@@@@@Z"
// CHECK-LABEL: "?f@@YAXU?$S@U?$Autoreleasing@PAU.objc_object@@@__ObjC@@@@@Z"
void f(S<__strong id>) {}
// CHECK-LABEL: "?f@@YAXU?$S@U?$Strong@PAUobjc_object@@@__ObjC@@@@@Z"
// CHECK-LABEL: "?f@@YAXU?$S@U?$Strong@PAU.objc_object@@@__ObjC@@@@@Z"
void f(S<__weak id>) {}
// CHECK-LABEL: "?f@@YAXU?$S@U?$Weak@PAUobjc_object@@@__ObjC@@@@@Z"
// CHECK-LABEL: "?f@@YAXU?$S@U?$Weak@PAU.objc_object@@@__ObjC@@@@@Z"
void w(__weak id) {}
// CHECK-LABEL: "?w@@YAXPAUobjc_object@@@Z"
// CHECK-LABEL: "?w@@YAXPAU.objc_object@@@Z"
void s(__strong id) {}
// CHECK-LABEL: "?s@@YAXPAUobjc_object@@@Z"
// CHECK-LABEL: "?s@@YAXPAU.objc_object@@@Z"
void a(__autoreleasing id) {}
// CHECK-LABEL: "?a@@YAXPAUobjc_object@@@Z"
// CHECK-LABEL: "?a@@YAXPAU.objc_object@@@Z"
void u(__unsafe_unretained id) {}
// CHECK-LABEL: "?u@@YAXPAUobjc_object@@@Z"
// CHECK-LABEL: "?u@@YAXPAU.objc_object@@@Z"
S<__autoreleasing id> g() { return S<__autoreleasing id>(); }
// CHECK-LABEL: "?g@@YA?AU?$S@U?$Autoreleasing@PAUobjc_object@@@__ObjC@@@@XZ"
// CHECK-LABEL: "?g@@YA?AU?$S@U?$Autoreleasing@PAU.objc_object@@@__ObjC@@@@XZ"
__autoreleasing id h() { return nullptr; }
// CHECK-LABEL: "?h@@YAPAUobjc_object@@XZ"
// CHECK-LABEL: "?h@@YAPAU.objc_object@@XZ"

View File

@ -3,166 +3,166 @@
@class I;
id kid;
// CHECK: @"?kid@@3PAUobjc_object@@A" = dso_local global
// CHECK: @"?kid@@3PAU.objc_object@@A" = dso_local global
Class klass;
// CHECK: @"?klass@@3PAUobjc_class@@A" = dso_local global
// CHECK: @"?klass@@3PAU.objc_class@@A" = dso_local global
I *kI;
// CHECK: @"?kI@@3PAUI@@A" = dso_local global
// CHECK: @"?kI@@3PAU.objc_cls_I@@A" = dso_local global
void f(I *) {}
// CHECK-LABEL: "?f@@YAXPAUI@@@Z"
// CHECK-LABEL: "?f@@YAXPAU.objc_cls_I@@@Z"
void f(const I *) {}
// CHECK-LABEL: "?f@@YAXPBUI@@@Z"
// CHECK-LABEL: "?f@@YAXPBU.objc_cls_I@@@Z"
void f(I &) {}
// CHECK-LABEL: "?f@@YAXAAUI@@@Z"
// CHECK-LABEL: "?f@@YAXAAU.objc_cls_I@@@Z"
void f(const I &) {}
// CHECK-LABEL: "?f@@YAXABUI@@@Z"
// CHECK-LABEL: "?f@@YAXABU.objc_cls_I@@@Z"
void f(const I &&) {}
// CHECK-LABEL: "?f@@YAX$$QBUI@@@Z"
// CHECK-LABEL: "?f@@YAX$$QBU.objc_cls_I@@@Z"
void g(id) {}
// CHECK-LABEL: "?g@@YAXPAUobjc_object@@@Z"
// CHECK-LABEL: "?g@@YAXPAU.objc_object@@@Z"
void g(id &) {}
// CHECK-LABEL: "?g@@YAXAAPAUobjc_object@@@Z"
// CHECK-LABEL: "?g@@YAXAAPAU.objc_object@@@Z"
void g(const id &) {}
// CHECK-LABEL: "?g@@YAXABQAUobjc_object@@@Z"
// CHECK-LABEL: "?g@@YAXABQAU.objc_object@@@Z"
void g(id &&) {}
// CHECK-LABEL: "?g@@YAX$$QAPAUobjc_object@@@Z"
// CHECK-LABEL: "?g@@YAX$$QAPAU.objc_object@@@Z"
void h(Class) {}
// CHECK-LABEL: "?h@@YAXPAUobjc_class@@@Z"
// CHECK-LABEL: "?h@@YAXPAU.objc_class@@@Z"
void h(Class &) {}
// CHECK-LABEL: "?h@@YAXAAPAUobjc_class@@@Z"
// CHECK-LABEL: "?h@@YAXAAPAU.objc_class@@@Z"
void h(const Class &) {}
// CHECK-LABEL: "?h@@YAXABQAUobjc_class@@@Z"
// CHECK-LABEL: "?h@@YAXABQAU.objc_class@@@Z"
void h(Class &&) {}
// CHECK-LABEL: "?h@@YAX$$QAPAUobjc_class@@@Z"
// CHECK-LABEL: "?h@@YAX$$QAPAU.objc_class@@@Z"
I *i() { return nullptr; }
// CHECK-LABEL: "?i@@YAPAUI@@XZ"
// CHECK-LABEL: "?i@@YAPAU.objc_cls_I@@XZ"
const I *j() { return nullptr; }
// CHECK-LABEL: "?j@@YAPBUI@@XZ"
// CHECK-LABEL: "?j@@YAPBU.objc_cls_I@@XZ"
I &k() { return *kI; }
// CHECK-LABEL: "?k@@YAAAUI@@XZ"
// CHECK-LABEL: "?k@@YAAAU.objc_cls_I@@XZ"
const I &l() { return *kI; }
// CHECK-LABEL: "?l@@YAABUI@@XZ"
// CHECK-LABEL: "?l@@YAABU.objc_cls_I@@XZ"
void m(const id) {}
// CHECK-LABEL: "?m@@YAXQAUobjc_object@@@Z"
// CHECK-LABEL: "?m@@YAXQAU.objc_object@@@Z"
void m(const I *) {}
// CHECK-LABEL: "?m@@YAXPBUI@@@Z"
// CHECK-LABEL: "?m@@YAXPBU.objc_cls_I@@@Z"
void n(SEL) {}
// CHECK-LABEL: "?n@@YAXPAUobjc_selector@@@Z"
// CHECK-LABEL: "?n@@YAXPAU.objc_selector@@@Z"
void n(SEL *) {}
// CHECK-LABEL: "?n@@YAXPAPAUobjc_selector@@@Z"
// CHECK-LABEL: "?n@@YAXPAPAU.objc_selector@@@Z"
void n(const SEL *) {}
// CHECK-LABEL: "?n@@YAXPBQAUobjc_selector@@@Z"
// CHECK-LABEL: "?n@@YAXPBQAU.objc_selector@@@Z"
void n(SEL &) {}
// CHECK-LABEL: "?n@@YAXAAPAUobjc_selector@@@Z"
// CHECK-LABEL: "?n@@YAXAAPAU.objc_selector@@@Z"
void n(const SEL &) {}
// CHECK-LABEL: "?n@@YAXABQAUobjc_selector@@@Z"
// CHECK-LABEL: "?n@@YAXABQAU.objc_selector@@@Z"
void n(SEL &&) {}
// CHECK-LABEL: "?n@@YAX$$QAPAUobjc_selector@@@Z"
// CHECK-LABEL: "?n@@YAX$$QAPAU.objc_selector@@@Z"
struct __declspec(dllexport) s {
struct s &operator=(const struct s &) = delete;
void m(I *) {}
// CHECK-LABEL: "?m@s@@QAAXPAUI@@@Z"
// CHECK-LABEL: "?m@s@@QAAXPAU.objc_cls_I@@@Z"
void m(const I *) {}
// CHECK-LABEL: "?m@s@@QAAXPBUI@@@Z"
// CHECK-LABEL: "?m@s@@QAAXPBU.objc_cls_I@@@Z"
void m(I &) {}
// CHECK-LABEL: "?m@s@@QAAXAAUI@@@Z"
// CHECK-LABEL: "?m@s@@QAAXAAU.objc_cls_I@@@Z"
void m(const I &) {}
// CHECK-LABEL: "?m@s@@QAAXABUI@@@Z"
// CHECK-LABEL: "?m@s@@QAAXABU.objc_cls_I@@@Z"
void m(I &&) {}
// CHECK-LABEL: "?m@s@@QAAX$$QAUI@@@Z"
// CHECK-LABEL: "?m@s@@QAAX$$QAU.objc_cls_I@@@Z"
void m(const I &&) {}
// CHECK-LABEL: "?m@s@@QAAX$$QBUI@@@Z"
// CHECK-LABEL: "?m@s@@QAAX$$QBU.objc_cls_I@@@Z"
void m(id) {}
// CHECK-LABEL: "?m@s@@QAAXPAUobjc_object@@@Z"
// CHECK-LABEL: "?m@s@@QAAXPAU.objc_object@@@Z"
void m(id &) {}
// CHECK-LABEL: "?m@s@@QAAXAAPAUobjc_object@@@Z"
// CHECK-LABEL: "?m@s@@QAAXAAPAU.objc_object@@@Z"
void m(id &&) {}
// CHECK-LABEL: "?m@s@@QAAX$$QAPAUobjc_object@@@Z"
// CHECK-LABEL: "?m@s@@QAAX$$QAPAU.objc_object@@@Z"
void m(const id &) {}
// CHECK-LABEL: "?m@s@@QAAXABQAUobjc_object@@@Z"
// CHECK-LABEL: "?m@s@@QAAXABQAU.objc_object@@@Z"
void m(const id &&) {}
// CHECK-LABEL: "?m@s@@QAAX$$QBQAUobjc_object@@@Z"
// CHECK-LABEL: "?m@s@@QAAX$$QBQAU.objc_object@@@Z"
void m(Class *) {}
// CHECK-LABEL: "?m@s@@QAAXPAPAUobjc_class@@@Z"
// CHECK-LABEL: "?m@s@@QAAXPAPAU.objc_class@@@Z"
void m(const Class *) {}
// CHECK-LABEL: "?m@s@@QAAXPBQAUobjc_class@@@Z"
// CHECK-LABEL: "?m@s@@QAAXPBQAU.objc_class@@@Z"
void m(Class) {}
// CHECK-LABEL: "?m@s@@QAAXPAUobjc_class@@@Z"
// CHECK-LABEL: "?m@s@@QAAXPAU.objc_class@@@Z"
void m(Class &) {}
// CHECK-LABEL: "?m@s@@QAAXAAPAUobjc_class@@@Z"
// CHECK-LABEL: "?m@s@@QAAXAAPAU.objc_class@@@Z"
void m(const Class &) {}
// CHECK-LABEL: "?m@s@@QAAXABQAUobjc_class@@@Z"
// CHECK-LABEL: "?m@s@@QAAXABQAU.objc_class@@@Z"
void m(Class &&) {}
// CHECK-LABEL: "?m@s@@QAAX$$QAPAUobjc_class@@@Z"
// CHECK-LABEL: "?m@s@@QAAX$$QAPAU.objc_class@@@Z"
void m(const Class &&) {}
// CHECK-LABEL: "?m@s@@QAAX$$QBQAUobjc_class@@@Z"
// CHECK-LABEL: "?m@s@@QAAX$$QBQAU.objc_class@@@Z"
void m(SEL) {}
// CHECK-LABEL: "?m@s@@QAAXPAUobjc_selector@@@Z"
// CHECK-LABEL: "?m@s@@QAAXPAU.objc_selector@@@Z"
void m(SEL *) {}
// CHECK-LABEL: "?m@s@@QAAXPAPAUobjc_selector@@@Z"
// CHECK-LABEL: "?m@s@@QAAXPAPAU.objc_selector@@@Z"
void m(const SEL *) {}
// CHECK-LABEL: "?m@s@@QAAXPBQAUobjc_selector@@@Z"
// CHECK-LABEL: "?m@s@@QAAXPBQAU.objc_selector@@@Z"
void m(SEL &) {}
// CHECK-LABEL: "?m@s@@QAAXAAPAUobjc_selector@@@Z"
// CHECK-LABEL: "?m@s@@QAAXAAPAU.objc_selector@@@Z"
void m(const SEL &) {}
// CHECK-LABEL: "?m@s@@QAAXABQAUobjc_selector@@@Z"
// CHECK-LABEL: "?m@s@@QAAXABQAU.objc_selector@@@Z"
void m(SEL &&) {}
// CHECK-LABEL: "?m@s@@QAAX$$QAPAUobjc_selector@@@Z"
// CHECK-LABEL: "?m@s@@QAAX$$QAPAU.objc_selector@@@Z"
void m(const SEL &&) {}
// CHECK-LABEL: "?m@s@@QAAX$$QBQAUobjc_selector@@@Z"
// CHECK-LABEL: "?m@s@@QAAX$$QBQAU.objc_selector@@@Z"
};
template <typename T>
@ -179,14 +179,14 @@ struct t {
};
template struct t<id>;
// CHECK-LABEL: "??0?$t@PAUobjc_object@@@@QAA@XZ"
// CHECK-LABEL: "??0?$t@PAU.objc_object@@@@QAA@XZ"
template struct t<remove_pointer<id>::type>;
// CHECK-LABEL: "??0?$t@Uobjc_object@@@@QAA@XZ"
// CHECK-LABEL: "??0?$t@U.objc_object@@@@QAA@XZ"
template struct t<SEL>;
// CHECK-LABEL: "??0?$t@PAUobjc_selector@@@@QAA@XZ"
// CHECK-LABEL: "??0?$t@PAU.objc_selector@@@@QAA@XZ"
template struct t<remove_pointer<SEL>::type>;
// CHECK-LABEL: "??0?$t@Uobjc_selector@@@@QAA@XZ"
// CHECK-LABEL: "??0?$t@U.objc_selector@@@@QAA@XZ"

View File

@ -51,4 +51,13 @@
// RUN: -c -### %s 2>&1 \
// RUN: | FileCheck %s -check-prefix=AVAILABLE
//
// Check that passing -faligned-allocation or -fno-aligned-allocation stops the
// driver from passing -faligned-alloc-unavailable to cc1.
//
// RUN: %clang -target x86_64-apple-macosx10.12 -faligned-allocation -c -### %s 2>&1 \
// RUN: | FileCheck %s -check-prefix=AVAILABLE
//
// RUN: %clang -target x86_64-apple-macosx10.12 -fno-aligned-allocation -c -### %s 2>&1 \
// RUN: | FileCheck %s -check-prefix=AVAILABLE
// AVAILABLE-NOT: "-faligned-alloc-unavailable"

View File

@ -0,0 +1,23 @@
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -fexceptions -std=c++17 -verify %s \
// RUN: -DEXPECT_DEFINED
//
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -fexceptions -std=c++17 -verify %s \
// RUN: -faligned-alloc-unavailable
//
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -fexceptions -std=c++17 -verify %s \
// RUN: -faligned-allocation -faligned-alloc-unavailable
// Test that __cpp_aligned_new is not defined when CC1 is passed
// -faligned-alloc-unavailable by the Darwin driver, even when aligned
// allocation is actually enabled.
// expected-no-diagnostics
#ifdef EXPECT_DEFINED
# ifndef __cpp_aligned_new
# error "__cpp_aligned_new" should be defined
# endif
#else
# ifdef __cpp_aligned_new
# error "__cpp_aligned_new" should not be defined
# endif
#endif

View File

@ -150,11 +150,35 @@ struct SSSTt {
// CHECK: #pragma omp end declare target
// CHECK: int b;
#pragma omp declare target
template <typename T>
T baz() { return T(); }
#pragma omp end declare target
template <>
int baz() { return 1; }
// CHECK: #pragma omp declare target
// CHECK: template <typename T> T baz() {
// CHECK: return T();
// CHECK: }
// CHECK: #pragma omp end declare target
// CHECK: #pragma omp declare target
// CHECK: template<> float baz<float>() {
// CHECK: return float();
// CHECK: }
// CHECK: template<> int baz<int>() {
// CHECK: return 1;
// CHECK: }
// CHECK: #pragma omp end declare target
int main (int argc, char **argv) {
foo();
foo_c();
foo_cpp();
test1();
baz<float>();
baz<int>();
return (0);
}

View File

@ -19,17 +19,19 @@ void foo();
// CHECK-LABEL: @main()
int main() {
int i;
// CHECK: [[DIMS:%.+]] = alloca [[KMP_DIM]],
// CHECK: [[DIMS:%.+]] = alloca [1 x [[KMP_DIM]]],
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT:%.+]])
// CHECK: icmp
// CHECK-NEXT: br i1 %
// CHECK: [[CAST:%.+]] = bitcast [[KMP_DIM]]* [[DIMS]] to i8*
// CHECK: [[CAST:%.+]] = bitcast [1 x [[KMP_DIM]]]* [[DIMS]] to i8*
// CHECK: call void @llvm.memset.p0i8.i64(i8* align 8 [[CAST]], i8 0, i64 24, i1 false)
// CHECK: getelementptr inbounds [[KMP_DIM]], [[KMP_DIM]]* [[DIMS]], i32 0, i32 1
// CHECK: [[DIM:%.+]] = getelementptr inbounds [1 x [[KMP_DIM]]], [1 x [[KMP_DIM]]]* [[DIMS]], i64 0, i64 0
// CHECK: getelementptr inbounds [[KMP_DIM]], [[KMP_DIM]]* [[DIM]], i32 0, i32 1
// CHECK: store i64 %{{.+}}, i64* %
// CHECK: getelementptr inbounds [[KMP_DIM]], [[KMP_DIM]]* [[DIMS]], i32 0, i32 2
// CHECK: getelementptr inbounds [[KMP_DIM]], [[KMP_DIM]]* [[DIM]], i32 0, i32 2
// CHECK: store i64 1, i64* %
// CHECK: [[CAST:%.+]] = bitcast [[KMP_DIM]]* [[DIMS]] to i8*
// CHECK: [[DIM:%.+]] = getelementptr inbounds [1 x [[KMP_DIM]]], [1 x [[KMP_DIM]]]* [[DIMS]], i64 0, i64 0
// CHECK: [[CAST:%.+]] = bitcast [[KMP_DIM]]* [[DIM]] to i8*
// CHECK: call void @__kmpc_doacross_init([[IDENT]], i32 [[GTID]], i32 1, i8* [[CAST]])
// CHECK: call void @__kmpc_for_static_init_4(
#pragma omp for ordered(1)
@ -37,18 +39,26 @@ int main() {
a[i] = b[i] + 1;
foo();
// CHECK: call void [[FOO:.+]](
// CHECK: load i32, i32* [[CNT:%.+]],
// CHECK: load i32, i32* [[I:%.+]],
// CHECK-NEXT: sub nsw i32 %{{.+}}, 0
// CHECK-NEXT: sdiv i32 %{{.+}}, 1
// CHECK-NEXT: sext i32 %{{.+}} to i64
// CHECK-NEXT: store i64 %{{.+}}, i64* [[TMP:%.+]],
// CHECK-NEXT: [[TMP:%.+]] = getelementptr inbounds [1 x i64], [1 x i64]* [[CNT:%.+]], i64 0, i64 0
// CHECK-NEXT: store i64 %{{.+}}, i64* [[TMP]],
// CHECK-NEXT: [[TMP:%.+]] = getelementptr inbounds [1 x i64], [1 x i64]* [[CNT]], i64 0, i64 0
// CHECK-NEXT: call void @__kmpc_doacross_post([[IDENT]], i32 [[GTID]], i64* [[TMP]])
#pragma omp ordered depend(source)
c[i] = c[i] + 1;
foo();
// CHECK: call void [[FOO]]
// CHECK: load i32, i32* [[CNT]],
// CHECK: load i32, i32* [[I]],
// CHECK-NEXT: sub nsw i32 %{{.+}}, 2
// CHECK-NEXT: sub nsw i32 %{{.+}}, 0
// CHECK-NEXT: sdiv i32 %{{.+}}, 1
// CHECK-NEXT: sext i32 %{{.+}} to i64
// CHECK-NEXT: store i64 %{{.+}}, i64* [[TMP:%.+]],
// CHECK-NEXT: [[TMP:%.+]] = getelementptr inbounds [1 x i64], [1 x i64]* [[CNT:%.+]], i64 0, i64 0
// CHECK-NEXT: store i64 %{{.+}}, i64* [[TMP]],
// CHECK-NEXT: [[TMP:%.+]] = getelementptr inbounds [1 x i64], [1 x i64]* [[CNT]], i64 0, i64 0
// CHECK-NEXT: call void @__kmpc_doacross_wait([[IDENT]], i32 [[GTID]], i64* [[TMP]])
#pragma omp ordered depend(sink : i - 2)
d[i] = a[i - 2];

View File

@ -19,17 +19,19 @@ void foo();
// CHECK-LABEL: @main()
int main() {
int i;
// CHECK: [[DIMS:%.+]] = alloca [[KMP_DIM]],
// CHECK: [[DIMS:%.+]] = alloca [1 x [[KMP_DIM]]],
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT:%.+]])
// CHECK: icmp
// CHECK-NEXT: br i1 %
// CHECK: [[CAST:%.+]] = bitcast [[KMP_DIM]]* [[DIMS]] to i8*
// CHECK: [[CAST:%.+]] = bitcast [1 x [[KMP_DIM]]]* [[DIMS]] to i8*
// CHECK: call void @llvm.memset.p0i8.i64(i8* align 8 [[CAST]], i8 0, i64 24, i1 false)
// CHECK: getelementptr inbounds [[KMP_DIM]], [[KMP_DIM]]* [[DIMS]], i32 0, i32 1
// CHECK: [[DIM:%.+]] = getelementptr inbounds [1 x [[KMP_DIM]]], [1 x [[KMP_DIM]]]* [[DIMS]], i64 0, i64 0
// CHECK: getelementptr inbounds [[KMP_DIM]], [[KMP_DIM]]* [[DIM]], i32 0, i32 1
// CHECK: store i64 %{{.+}}, i64* %
// CHECK: getelementptr inbounds [[KMP_DIM]], [[KMP_DIM]]* [[DIMS]], i32 0, i32 2
// CHECK: getelementptr inbounds [[KMP_DIM]], [[KMP_DIM]]* [[DIM]], i32 0, i32 2
// CHECK: store i64 1, i64* %
// CHECK: [[CAST:%.+]] = bitcast [[KMP_DIM]]* [[DIMS]] to i8*
// CHECK: [[DIM:%.+]] = getelementptr inbounds [1 x [[KMP_DIM]]], [1 x [[KMP_DIM]]]* [[DIMS]], i64 0, i64 0
// CHECK: [[CAST:%.+]] = bitcast [[KMP_DIM]]* [[DIM]] to i8*
// CHECK: call void @__kmpc_doacross_init([[IDENT]], i32 [[GTID]], i32 1, i8* [[CAST]])
// CHECK: call void @__kmpc_for_static_init_4(
#pragma omp for ordered(1)
@ -37,18 +39,26 @@ int main() {
a[i] = b[i] + 1;
foo();
// CHECK: invoke void [[FOO:.+]](
// CHECK: load i32, i32* [[CNT:%.+]],
// CHECK: load i32, i32* [[I:%.+]],
// CHECK-NEXT: sub nsw i32 %{{.+}}, 0
// CHECK-NEXT: sdiv i32 %{{.+}}, 1
// CHECK-NEXT: sext i32 %{{.+}} to i64
// CHECK-NEXT: store i64 %{{.+}}, i64* [[TMP:%.+]],
// CHECK-NEXT: [[TMP:%.+]] = getelementptr inbounds [1 x i64], [1 x i64]* [[CNT:%.+]], i64 0, i64 0
// CHECK-NEXT: store i64 %{{.+}}, i64* [[TMP]],
// CHECK-NEXT: [[TMP:%.+]] = getelementptr inbounds [1 x i64], [1 x i64]* [[CNT]], i64 0, i64 0
// CHECK-NEXT: call void @__kmpc_doacross_post([[IDENT]], i32 [[GTID]], i64* [[TMP]])
#pragma omp ordered depend(source)
c[i] = c[i] + 1;
foo();
// CHECK: invoke void [[FOO]]
// CHECK: load i32, i32* [[CNT]],
// CHECK: load i32, i32* [[I]],
// CHECK-NEXT: sub nsw i32 %{{.+}}, 2
// CHECK-NEXT: sub nsw i32 %{{.+}}, 0
// CHECK-NEXT: sdiv i32 %{{.+}}, 1
// CHECK-NEXT: sext i32 %{{.+}} to i64
// CHECK-NEXT: store i64 %{{.+}}, i64* [[TMP:%.+]],
// CHECK-NEXT: [[TMP:%.+]] = getelementptr inbounds [1 x i64], [1 x i64]* [[CNT:%.+]], i64 0, i64 0
// CHECK-NEXT: store i64 %{{.+}}, i64* [[TMP]],
// CHECK-NEXT: [[TMP:%.+]] = getelementptr inbounds [1 x i64], [1 x i64]* [[CNT]], i64 0, i64 0
// CHECK-NEXT: call void @__kmpc_doacross_wait([[IDENT]], i32 [[GTID]], i64* [[TMP]])
#pragma omp ordered depend(sink : i - 2)
d[i] = a[i - 2];
@ -75,41 +85,84 @@ struct TestStruct {
T bar(T, T, T);
void baz(T, T);
TestStruct() {
// CHECK: [[CNT:%.+]] = alloca i64,
// CHECK: [[DIMS:%.+]] = alloca [[KMP_DIM]],
// CHECK: [[DIMS:%.+]] = alloca [2 x [[KMP_DIM]]],
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT:%.+]])
// CHECK: icmp
// CHECK-NEXT: br i1 %
// CHECK: [[CAST:%.+]] = bitcast [[KMP_DIM]]* [[DIMS]] to i8*
// CHECK: call void @llvm.memset.p0i8.i64(i8* align 8 [[CAST]], i8 0, i64 24, i1 false)
// CHECK: getelementptr inbounds [[KMP_DIM]], [[KMP_DIM]]* [[DIMS]], i32 0, i32 1
// CHECK: store i64 %{{.+}}, i64* %
// CHECK: getelementptr inbounds [[KMP_DIM]], [[KMP_DIM]]* [[DIMS]], i32 0, i32 2
// CHECK: [[CAST:%.+]] = bitcast [2 x [[KMP_DIM]]]* [[DIMS]] to i8*
// CHECK: call void @llvm.memset.p0i8.i64(i8* align 8 [[CAST]], i8 0, i64 48, i1 false)
// CHECK: [[DIM:%.+]] = getelementptr inbounds [2 x [[KMP_DIM]]], [2 x [[KMP_DIM]]]* [[DIMS]], i64 0, i64 0
// CHECK: getelementptr inbounds [[KMP_DIM]], [[KMP_DIM]]* [[DIM]], i32 0, i32 1
// CHECK: store i64 10, i64* %
// CHECK: getelementptr inbounds [[KMP_DIM]], [[KMP_DIM]]* [[DIM]], i32 0, i32 2
// CHECK: store i64 1, i64* %
// CHECK: [[CAST:%.+]] = bitcast [[KMP_DIM]]* [[DIMS]] to i8*
// CHECK: call void @__kmpc_doacross_init([[IDENT]], i32 [[GTID]], i32 1, i8* [[CAST]])
// CHECK: call void @__kmpc_for_static_init_8(
// CHECK: [[DIM:%.+]] = getelementptr inbounds [2 x [[KMP_DIM]]], [2 x [[KMP_DIM]]]* [[DIMS]], i64 0, i64 1
// CHECK: getelementptr inbounds [[KMP_DIM]], [[KMP_DIM]]* [[DIM]], i32 0, i32 1
// CHECK: store i64 %{{.+}}, i64* %
// CHECK: getelementptr inbounds [[KMP_DIM]], [[KMP_DIM]]* [[DIM]], i32 0, i32 2
// CHECK: store i64 1, i64* %
// CHECK: [[DIM:%.+]] = getelementptr inbounds [2 x [[KMP_DIM]]], [2 x [[KMP_DIM]]]* [[DIMS]], i64 0, i64 0
// CHECK: [[CAST:%.+]] = bitcast [[KMP_DIM]]* [[DIM]] to i8*
// CHECK: call void @__kmpc_doacross_init([[IDENT]], i32 [[GTID]], i32 2, i8* [[CAST]])
// CHECK: call void @__kmpc_for_static_init_4(
#pragma omp for ordered(2)
for (T j = 0; j < M; j++)
for (i = 0; i < n; i += 2) {
a[i][j] = foo(i, j);
// CHECK: invoke {{.+TestStruct.+foo}}
// CHECK: load i64, i64* [[CNT]],
// CHECK-NEXT: sub nsw i64 %{{.+}}, 1
// CHECK-NEXT: store i64 %{{.+}}, i64* [[TMP:%.+]],
// CHECK-NEXT: call void @__kmpc_doacross_wait([[IDENT]], i32 [[GTID]], i64* [[TMP]])
// CHECK-NEXT: load i64, i64* [[CNT]],
// CHECK-NEXT: load i32, i32* %
// CHECK-NEXT: mul nsw i32 1, %
// CHECK: load i32*, i32** %
// CHECK: load i32, i32* %
// CHECK: load i32, i32* %
// CHECK: load i32, i32* [[J:%.+]],
// CHECK-NEXT: sub nsw i32 %{{.+}}, 0
// CHECK-NEXT: sdiv i32 %{{.+}}, 1
// CHECK-NEXT: sext i32 %{{.+}} to i64
// CHECK-NEXT: sub nsw i64 %
// CHECK-NEXT: [[TMP:%.+]] = getelementptr inbounds [2 x i64], [2 x i64]* [[CNT:%.+]], i64 0, i64 0
// CHECK-NEXT: store i64 %{{.+}}, i64* [[TMP:%.+]],
// CHECK-NEXT: [[I:%.+]] = load i32*, i32** [[I_REF:%.+]],
// CHECK-NEXT: load i32, i32* [[I]],
// CHECK-NEXT: sub nsw i32 %{{.+}}, 2
// CHECK-NEXT: sub nsw i32 %{{.+}}, 0
// CHECK-NEXT: sdiv i32 %{{.+}}, 2
// CHECK-NEXT: sext i32 %{{.+}} to i64
// CHECK-NEXT: [[TMP:%.+]] = getelementptr inbounds [2 x i64], [2 x i64]* [[CNT]], i64 0, i64 1
// CHECK-NEXT: store i64 %{{.+}}, i64* [[TMP]],
// CHECK-NEXT: [[TMP:%.+]] = getelementptr inbounds [2 x i64], [2 x i64]* [[CNT]], i64 0, i64 0
// CHECK-NEXT: call void @__kmpc_doacross_wait([[IDENT]], i32 [[GTID]], i64* [[TMP]])
// CHECK-NEXT: load i32, i32* [[J:%.+]],
// CHECK-NEXT: sub nsw i32 %{{.+}}, 1
// CHECK-NEXT: sub nsw i32 %{{.+}}, 0
// CHECK-NEXT: sdiv i32 %{{.+}}, 1
// CHECK-NEXT: sext i32 %{{.+}} to i64
// CHECK-NEXT: [[TMP:%.+]] = getelementptr inbounds [2 x i64], [2 x i64]* [[CNT:%.+]], i64 0, i64 0
// CHECK-NEXT: store i64 %{{.+}}, i64* [[TMP:%.+]],
// CHECK-NEXT: [[I:%.+]] = load i32*, i32** [[I_REF]],
// CHECK-NEXT: load i32, i32* [[I]],
// CHECK-NEXT: sub nsw i32 %{{.+}}, 0
// CHECK-NEXT: sdiv i32 %{{.+}}, 2
// CHECK-NEXT: sext i32 %{{.+}} to i64
// CHECK-NEXT: [[TMP:%.+]] = getelementptr inbounds [2 x i64], [2 x i64]* [[CNT]], i64 0, i64 1
// CHECK-NEXT: store i64 %{{.+}}, i64* [[TMP]],
// CHECK-NEXT: [[TMP:%.+]] = getelementptr inbounds [2 x i64], [2 x i64]* [[CNT]], i64 0, i64 0
// CHECK-NEXT: call void @__kmpc_doacross_wait([[IDENT]], i32 [[GTID]], i64* [[TMP]])
#pragma omp ordered depend(sink : j, i - 2) depend(sink : j - 1, i)
b[i][j] = bar(a[i][j], b[i - 1][j], b[i][j - 1]);
// CHECK: invoke {{.+TestStruct.+bar}}
// CHECK: load i64, i64* [[CNT]],
// CHECK: load i32*, i32** %
// CHECK: load i32, i32* %
// CHECK: load i32, i32* %
// CHECK: load i32, i32* [[J]],
// CHECK-NEXT: sub nsw i32 %{{.+}}, 0
// CHECK-NEXT: sdiv i32 %{{.+}}, 1
// CHECK-NEXT: sext i32 %{{.+}} to i64
// CHECK-NEXT: [[TMP:%.+]] = getelementptr inbounds [2 x i64], [2 x i64]* [[CNT:%.+]], i64 0, i64 0
// CHECK-NEXT: store i64 %{{.+}}, i64* [[TMP:%.+]],
// CHECK-NEXT: [[I:%.+]] = load i32*, i32** [[I_REF]],
// CHECK-NEXT: load i32, i32* [[I]],
// CHECK-NEXT: sub nsw i32 %{{.+}}, 0
// CHECK-NEXT: sdiv i32 %{{.+}}, 2
// CHECK-NEXT: sext i32 %{{.+}} to i64
// CHECK-NEXT: [[TMP:%.+]] = getelementptr inbounds [2 x i64], [2 x i64]* [[CNT]], i64 0, i64 1
// CHECK-NEXT: store i64 %{{.+}}, i64* [[TMP]],
// CHECK-NEXT: [[TMP:%.+]] = getelementptr inbounds [2 x i64], [2 x i64]* [[CNT]], i64 0, i64 0
// CHECK-NEXT: call void @__kmpc_doacross_post([[IDENT]], i32 [[GTID]], i64* [[TMP]])
#pragma omp ordered depend(source)
baz(a[i][j], b[i][j]);

View File

@ -48,7 +48,7 @@ class S8 : public S7<S1> {
public:
S8(int v) : S7<S1>(v){
#pragma omp parallel for simd private(a) private(this->a) private(S7<S1>::a)
#pragma omp parallel for simd private(a) private(this->a) private(S7 <S1>::a)
for (int k = 0; k < a.a; ++k)
++this->a.a;
}

View File

@ -1,10 +1,10 @@
// RUN: clang-diff -ast-dump-json %s -- \
// RUN: | '%python' -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \
// RUN: | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \
// RUN: | FileCheck %s
// CHECK: "begin": 301,
// CHECK: "begin": 311,
// CHECK: "type": "FieldDecl",
// CHECK: "end": 321,
// CHECK: "end": 319,
// CHECK: "type": "CXXRecordDecl",
class A {
int x;