Skip to content
6 changes: 3 additions & 3 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -5896,7 +5896,7 @@ def note_deleted_special_member_class_subobject : Note<
def note_deleted_default_ctor_uninit_field : Note<
"%select{default constructor of|constructor inherited by}0 "
"%1 is implicitly deleted because field %2 of "
"%select{reference|const-qualified}4 type %3 would not be initialized">;
"%select{reference|const-qualified|reducer}4 type %3 would not be initialized">;
def note_deleted_default_ctor_all_const : Note<
"%select{default constructor of|constructor inherited by}0 "
"%1 is implicitly deleted because all "
Expand Down Expand Up @@ -10895,8 +10895,8 @@ def incomplete_hyperobject : Error<
def nested_hyperobject : Error<
"type %0, which contains a hyperobject, may not be a hyperobject">;

def reducer_callbacks_not_allowed: Warning<
"reducer callbacks not implemented for structure members">,
def reducer_registration_not_implemented: Warning<
"reducer registration not implemented for structure members">,
InGroup<CilkIgnored>;

def err_invalid_reducer_callback : Error<
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1083,6 +1083,15 @@ void CXXRecordDecl::addedMember(Decl *D) {
data().DefaultedCopyConstructorIsDeleted = true;
}

if (T->isHyperobjectType()) {
// Do not allow braced list initialization, which would
// suppress hyperobject registration.
data().Aggregate = false;
data().HasIrrelevantDestructor = false;
data().HasTrivialSpecialMembers &= ~SMF_All;
data().HasTrivialSpecialMembersForCall &= ~SMF_All;
}

if (!Field->hasInClassInitializer() && !Field->isMutable()) {
if (CXXRecordDecl *FieldType = T->getAsCXXRecordDecl()) {
if (FieldType->hasDefinition() && !FieldType->allowConstDefaultInit())
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/CodeGen/CGClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,10 @@ void CodeGenFunction::EmitInitializerForField(FieldDecl *Field, LValue LHS,
}
}

ReducerCallbacks RCB = {0, 0};
if (getReducer(Field, RCB))
EmitReducerInit(Field, RCB, LHS.getPointer(*this));

// Ensure that we destroy this object if an exception is thrown
// later in the constructor.
QualType::DestructionKind dtorKind = FieldType.isDestructedType();
Expand Down Expand Up @@ -1639,6 +1643,11 @@ namespace {
LValue LV = CGF.EmitLValueForField(ThisLV, field);
assert(LV.isSimple());

if (field->getType()->isHyperobjectType()) {
llvm::Function *F =
CGF.CGM.getIntrinsic(llvm::Intrinsic::reducer_unregister);
CGF.Builder.CreateCall(F, {LV.getPointer(CGF)});
}
CGF.emitDestroy(LV.getAddress(CGF), field->getType(), destroyer,
flags.isForNormalCleanup() && useEHCleanupForArray);
}
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/CodeGen/CGDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1877,7 +1877,8 @@ void CodeGenFunction::emitZeroOrPatternForAutoVarInit(QualType type,
}
}

bool CodeGenFunction::getReducer(const VarDecl *D, ReducerCallbacks &CB) {
bool CodeGenFunction::getReducer(const DeclaratorDecl *D,
ReducerCallbacks &CB) {
if (const HyperobjectType *H = D->getType()->getAs<HyperobjectType>()) {
if (H->hasCallbacks()) {
CB.Identity = H->getIdentity();
Expand All @@ -1902,7 +1903,7 @@ void CodeGenFunction::destroyHyperobject(CodeGenFunction &CGF, Address Addr,
}
}

void CodeGenFunction::EmitReducerInit(const VarDecl *D,
void CodeGenFunction::EmitReducerInit(const DeclaratorDecl *D,
const ReducerCallbacks &C,
llvm::Value *Addr) {
RValue Identity = EmitAnyExpr(C.Identity);
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -3778,8 +3778,8 @@ class CodeGenFunction : public CodeGenTypeCache {
Expr *Reduce;
};

bool getReducer(const VarDecl *D, ReducerCallbacks &CB);
void EmitReducerInit(const VarDecl *D, const ReducerCallbacks &CB,
bool getReducer(const DeclaratorDecl *D, ReducerCallbacks &CB);
void EmitReducerInit(const DeclaratorDecl *D, const ReducerCallbacks &CB,
llvm::Value *Addr);

/// Emits the alloca and debug information for the size expressions for each
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19234,11 +19234,12 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
continue;
}

if (!FDTy->isDependentType()) {
// In C++ a constructor and destructor will be synthesized
// to register hyperobjects.
if (!CXXRecord && !FDTy->isDependentType()) {
if (const HyperobjectType *HT = FDTy->getAs<HyperobjectType>()) {
if (HT->hasCallbacks())
Diag(FD->getLocation(), diag::reducer_callbacks_not_allowed)
<< FD->getDeclName();
Diag(FD->getLocation(), diag::reducer_registration_not_implemented)
<< FD->getDeclName();
}
}

Expand Down
10 changes: 8 additions & 2 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5096,7 +5096,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
"Unhandled implicit init kind!");

QualType FieldBaseElementType =
SemaRef.Context.getBaseElementType(Field->getType());
SemaRef.Context.getBaseElementType(Field->getType().stripHyperobject());

if (FieldBaseElementType->isRecordType()) {
InitializedEntity InitEntity =
Expand Down Expand Up @@ -5863,7 +5863,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,

QualType FieldType = Context.getBaseElementType(Field->getType());

const RecordType* RT = FieldType->getAs<RecordType>();
const RecordType* RT = FieldType.stripHyperobject()->getAs<RecordType>();
if (!RT)
continue;

Expand Down Expand Up @@ -9595,6 +9595,12 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
<< !!ICI << MD->getParent() << FD << FieldType << /*Reference*/0;
return true;
}
if (FieldType->isHyperobjectType() && !FD->hasInClassInitializer()) {
if (Diagnose)
S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field)
<< !!ICI << MD->getParent() << FD << FieldType << /*Reducer*/2;
return true;
}
// C++11 [class.ctor]p5 (modified by DR2394): any non-variant non-static
// data member of const-qualified type (or array thereof) with no
// brace-or-equal-initializer is not const-default-constructible.
Expand Down
11 changes: 1 addition & 10 deletions clang/test/Cilk/222.cpp
Original file line number Diff line number Diff line change
@@ -1,26 +1,17 @@
// RUN: %clang_cc1 %s -x c++ -fopencilk -emit-llvm -verify -mllvm -use-opencilk-runtime-bc=false -mllvm -debug-abi-calls -o /dev/null
// expected-no-diagnostics
#define DEPTH 3
template<int N> struct R {
static void identity(void *);
static void reduce(void *, void *);
int get(int depth) { return depth <= 0 ? i : field.get(depth - 1); }
public:
R<N - 1> field;
// expected-note@-1{{in instantiation}}
// expected-note@-2{{in instantiation}}
// expected-note@-3{{in instantiation}}
int _Hyperobject(identity, reduce) i;
// expected-warning@-1{{reducer callbacks not implemented for structure members}}
// expected-warning@-2{{reducer callbacks not implemented for structure members}}
// expected-warning@-3{{reducer callbacks not implemented for structure members}}
};

template<> struct R<0> { int field; int get(int) { return field; } };

extern R<DEPTH> r;

int f() { return r.get(DEPTH / 2); }
// expected-note@-1{{in instantiation}}
// expected-note@-2{{in instantiation}}
// expected-note@-3{{in instantiation}}

23 changes: 23 additions & 0 deletions clang/test/Cilk/hyper-destruct2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// RUN: %clang_cc1 %s -x c++ -fopencilk -verify -disable-llvm-passes -S -emit-llvm -o - | FileCheck %s
// expected-no-diagnostics
template <typename T>
struct Inner
{
static void identity(void *);
static void reduce(void *, void *);
Inner();
~Inner() noexcept { }
};

struct Outer {
Inner<char> _Hyperobject(&Inner<char>::identity, &Inner<char>::reduce) member;
Outer();
~Outer();
};

// Make sure the appropriate variant of ~Inner() is emitted.
// CHECK: {{^}}define{{.*}} void @_ZN5OuterD2Ev
// CHECK: call void @_ZN5InnerIcED2Ev
// CHECK: {{^}}define linkonce_odr void @_ZN5InnerIcED2Ev

Outer::~Outer() { }
4 changes: 2 additions & 2 deletions clang/test/Cilk/hyper-errors.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 %s -fopencilk -verify -fsyntax-only -Werror=incompatible-function-pointer-types -Werror=int-conversion
// RUN: %clang_cc1 %s -x c++ -fopencilk -verify -fsyntax-only
struct C { int _Hyperobject c; };
// expected-warning@-1{{reducer registration not implemented for structure members}}
struct C _Hyperobject c; // expected-error{{type 'struct C', which contains a hyperobject, may not be a hyperobject}}
long _Hyperobject d; // expected-note{{previous definition}}
void f() {
Expand All @@ -17,7 +17,7 @@ extern void reduce(void *, void *), identity(void *);

struct D {
int _Hyperobject(identity, reduce) field;
// expected-warning@-1{{reducer callbacks not implemented for structure members}}
// expected-warning@-1{{reducer registration not implemented for structure members}}
};

int _Hyperobject(reduce, identity) h;
Expand Down
38 changes: 38 additions & 0 deletions clang/test/Cilk/hyper-errors.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// RUN: %clang_cc1 %s -x c++ -fopencilk -verify -fsyntax-only
struct C { int _Hyperobject c = 0; };
struct C _Hyperobject c; // expected-error{{type 'struct C', which contains a hyperobject, may not be a hyperobject}}
long _Hyperobject d; // expected-note{{previous definition}}
void f() {
extern int _Hyperobject d;
// expected-error@-1{{redeclaration of 'd' with a different type: 'int _Hyperobject' vs 'long _Hyperobject'}}
}
char _Hyperobject e; // expected-note{{previous definition}}
typedef long _Hyperobject long_h;
void g() {
extern long_h e; // expected-error{{redeclaration of 'e'}}
}

extern void reduce(void *, void *), identity(void *);

struct D {
int _Hyperobject(identity, reduce) field;
};

int _Hyperobject(reduce, identity) h;
// expected-error@-1{{incompatible function pointer types passing 'void (*)(void *, void *)' to parameter of type 'void (*)(void *)'}}
// expected-error@-2{{incompatible function pointer types passing 'void (*)(void *)' to parameter of type 'void (*)(void *, void *)'}}

int _Hyperobject(x) i; // expected-error{{use of undeclared identifier 'x'}}
int _Hyperobject(0) j; // expected-error{{hyperobject must have 0 or 2 callbacks}}
int _Hyperobject(0,0,0,0) k; // expected-error{{hyperobject must have 0 or 2 callbacks}}
int _Hyperobject(0, 1) x; // expected-error{{incompatible integer to pointer conversion passing 'int' to parameter of type 'void (*)(void *, void *)'}}

void function() {
int _Hyperobject(typo1, reduce) var1 = 0;
// expected-error@-1{{use of undeclared identifier 'typo1'}}
int _Hyperobject(typo2, typo3) var2 = 0;
// expected-error@-1{{use of undeclared identifier 'typo2'}}
// expected-error@-2{{use of undeclared identifier 'typo3'}}
int _Hyperobject(0, typo4) var3 = 0;
// expected-error@-1{{use of undeclared identifier 'typo4'}}
}
22 changes: 22 additions & 0 deletions clang/test/Cilk/hyper-init-error.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// RUN: %clang_cc1 %s -fopencilk -verify -fsyntax-only
extern void id(void *), reduce(void *, void *);
struct uninit_hyperobject {
// expected-note@-1{{implicit copy}}
// expected-note@-2{{implicit move}}
// expected-note@-3{{implicit default}}
int _Hyperobject(id, reduce) field;
// expected-note@-1{{would not be initialized}}
};

// braced initializer lists do not work
uninit_hyperobject h1 = {-1};
// expected-error@-1{{no matching constructor for initialization}}

uninit_hyperobject h2;
// expected-error@-1{{implicitly-deleted default constructor}}

struct init_hyperobject {
int _Hyperobject(id, reduce) field = 0;
};

init_hyperobject h3;
68 changes: 68 additions & 0 deletions clang/test/Cilk/hyper-member.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// RUN: %clang_cc1 %s -x c++ -triple aarch64-freebsd -fopencilk -S -emit-llvm -disable-llvm-passes -o - | FileCheck %s
struct ctor_dtor { ctor_dtor(); ~ctor_dtor(); long data; };
struct ctor_only { ctor_only(); long data; };
struct dtor_only { ~dtor_only(); long data; };
struct neither { long data; };
extern void identity(void *), reduce(void *, void *);
struct with_ctor_dtor {
with_ctor_dtor();
~with_ctor_dtor();
ctor_dtor _Hyperobject(identity, reduce) field;
};

// Hyperobject field is constructed then registered.
// CHECK-LABEL: _ZN14with_ctor_dtorC2Ev
// CHECK: call void @_ZN9ctor_dtorC1Ev
// CHECK: call void @llvm.reducer.register
with_ctor_dtor::with_ctor_dtor() { }

// Hyperobject field is destructed then unregistered.
// CHECK-LABEL: _ZN14with_ctor_dtorD2Ev
// CHECK: call void @llvm.reducer.unregister
// CHECK: call void @_ZN9ctor_dtorD1Ev
with_ctor_dtor::~with_ctor_dtor() { }

template<class Field> struct wrapper {
wrapper();
~wrapper();
Field field;
};

// CHECK-LABEL: define dso_local void @_ZN7wrapperIH9ctor_dtorEC2Ev
// CHECK: call void @_ZN9ctor_dtorC1Ev
// CHECK: call void @llvm.reducer.register
template<> wrapper<ctor_dtor _Hyperobject(identity, reduce)>::wrapper() { }
// CHECK-LABEL: define dso_local void @_ZN7wrapperIH9ctor_dtorED2Ev
// CHECK: call void @llvm.reducer.unregister
// CHECK: call void @_ZN9ctor_dtorD1Ev
template<> wrapper<ctor_dtor _Hyperobject(identity, reduce)>::~wrapper() { }

// CHECK-LABEL: define dso_local void @_ZN7wrapperIH9ctor_onlyEC2Ev
// CHECK: call void @_ZN9ctor_onlyC1Ev
// CHECK: call void @llvm.reducer.register
template<> wrapper<ctor_only _Hyperobject(identity, reduce)>::wrapper() { }

// CHECK-LABEL: define dso_local void @_ZN7wrapperIH9ctor_onlyED2Ev
// CHECK: call void @llvm.reducer.unregister
// CHECK-NOT: call void @_ZN9ctor_onlyD1Ev
template<> wrapper<ctor_only _Hyperobject(identity, reduce)>::~wrapper() { }

// CHECK-LABEL: define dso_local void @_ZN7wrapperIH9dtor_onlyEC2Ev
// CHECK-NOT: call void @_ZN9dtor_onlyC1Ev
// CHECK: call void @llvm.reducer.register
template<> wrapper<dtor_only _Hyperobject(identity, reduce)>::wrapper() { }

// CHECK-LABEL: define dso_local void @_ZN7wrapperIH9dtor_onlyED2Ev
// CHECK: call void @llvm.reducer.unregister
// CHECK: call void @_ZN9dtor_onlyD1Ev
template<> wrapper<dtor_only _Hyperobject(identity, reduce)>::~wrapper() { }

// CHECK-LABEL: define dso_local void @_ZN7wrapperIH7neitherEC2Ev
// CHECK-NOT: call void @_ZN7neitherC1Ev
// CHECK: call void @llvm.reducer.register
template<> wrapper<neither _Hyperobject(identity, reduce)>::wrapper() { }

// CHECK-LABEL: define dso_local void @_ZN7wrapperIH7neitherED2Ev
// CHECK: call void @llvm.reducer.unregister
// CHECK-NOT: call void @_ZN7neitherD1Ev
template<> wrapper<neither _Hyperobject(identity, reduce)>::~wrapper() { }
21 changes: 21 additions & 0 deletions clang/test/Cilk/hyper-register.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// RUN: %clang_cc1 %s -x c++ -fopencilk -S -emit-llvm -disable-llvm-passes -triple aarch64-freebsd14.1 -o - | FileCheck %s

struct S {
static void identity(void *);
static void reduce(void *, void *);
int _Hyperobject(identity, reduce) member = 0;
S();
~S();
};

// CHECK-LABEL: _ZN1SC2Ev
// CHECK: call void @llvm.reducer.register
S::S() {}

// CHECK-LABEL: _ZN1SD2Ev
// CHECK: call void @llvm.reducer.unregister
S::~S() {}

void f() {
struct S s;
}
1 change: 1 addition & 0 deletions clang/test/Cilk/hyper-struct-assign.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 %s -fopencilk -verify -fsyntax-only

struct S { long _Hyperobject field; };
// expected-warning@-1{{reducer registration not implemented for structure members}}
extern struct S x, y;

struct S simple_assign(long val)
Expand Down
3 changes: 2 additions & 1 deletion clang/test/Cilk/hyper-template-errors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ struct reducer
// expected-error@-1{{type 'long _Hyperobject', which contains a hyperobject, may not be a hyperobject}}
// expected-error@-2{{type 'reducer<char>', which contains a hyperobject, may not be a hyperobject}}
// expected-error@-3{{type 'wrap<int _Hyperobject>', which contains a hyperobject, may not be a hyperobject}}
int _Hyperobject value2;
int _Hyperobject value2 = 0;
reducer();
};

reducer<long _Hyperobject> r_hl; // expected-note{{in instantiation}}
Expand Down
6 changes: 2 additions & 4 deletions clang/test/Cilk/hyper-template2.cpp
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
// RUN: %clang_cc1 %s -x c++ -fopencilk -verify -S -emit-llvm -disable-llvm-passes -o - | FileCheck %s
// RUN: %clang_cc1 %s -x c++ -fopencilk -S -emit-llvm -disable-llvm-passes -o - | FileCheck %s
template<typename VIEW>
struct reducer
{
static void identity(void *);
static void reduce(void *, void *);
char pad;
// Registration of structure members is not implemented.
VIEW _Hyperobject(identity, reduce) value;
// expected-warning@-1{{reducer callbacks not implemented}}
reducer();
~reducer();
};

// CHECK: call {{.+}} @_ZN7reducerIsEC1Ev
// CHECK: @_ZN7reducerIsED1Ev
reducer<short> r; // expected-note{{in instantiation}}
reducer<short> r;

// CHECK-LABEL: _Z1fv
// CHECK: call ptr @llvm.hyper.lookup
Expand Down
Loading
Loading