Use empty list initializers to construct all zero-initialized variables.
Bug: http://b/24008889
In the past, we always tried to construct appropriate full
zero-initializers for uninitialized variables that contained any RS
object types (like rs_allocation) or any RS matrix types. For some
structures containing rs_matrix* types, we would insert an initializer
that uses just a single raw 0. While this is almost correct, it leads to
an invalid AST (that Clang is still happy to do the right thing with, for
now). Instead, we can rely on a supported extension that allows
zero-initialization with empty initializer lists (like in C++11, but for
older versions of C too). Switching to the empty list allows us to
remove a particularly tricky (and incomplete) section of code.
Change-Id: Id2e4ff88289af8b1e95cc9660b97c5c5e64f79ff
diff --git a/rs_cc_options.cpp b/rs_cc_options.cpp
index 889a050..8c8ae58 100644
--- a/rs_cc_options.cpp
+++ b/rs_cc_options.cpp
@@ -129,6 +129,10 @@
DiagOpts.IgnoreWarnings = Args.hasArg(OPT_w);
DiagOpts.Warnings = Args.getAllArgValues(OPT_W);
+ // Always turn off warnings for empty initializers, since we really want to
+ // employ/encourage this extension for zero-initialization of structures.
+ DiagOpts.Warnings.push_back("no-gnu-empty-initializer");
+
for (llvm::opt::ArgList::const_iterator it = Args.begin(), ie = Args.end();
it != ie; ++it) {
const llvm::opt::Arg *A = *it;
diff --git a/slang_rs_object_ref_count.cpp b/slang_rs_object_ref_count.cpp
index eaaf1e0..99cab02 100644
--- a/slang_rs_object_ref_count.cpp
+++ b/slang_rs_object_ref_count.cpp
@@ -1307,9 +1307,7 @@
}
clang::Expr *ZeroInitializer =
- CreateZeroInitializerForRSSpecificType(*DT,
- VD->getASTContext(),
- VD->getLocation());
+ CreateEmptyInitListExpr(VD->getASTContext(), VD->getLocation());
if (ZeroInitializer) {
ZeroInitializer->setType(T->getCanonicalTypeInternal());
@@ -1319,112 +1317,15 @@
return DataTypeIsRSObject;
}
-clang::Expr *RSObjectRefCount::CreateZeroInitializerForRSSpecificType(
- DataType DT,
+clang::Expr *RSObjectRefCount::CreateEmptyInitListExpr(
clang::ASTContext &C,
const clang::SourceLocation &Loc) {
- clang::Expr *Res = nullptr;
- switch (DT) {
- case DataTypeIsStruct:
- case DataTypeRSElement:
- case DataTypeRSType:
- case DataTypeRSAllocation:
- case DataTypeRSSampler:
- case DataTypeRSScript:
- case DataTypeRSMesh:
- case DataTypeRSPath:
- case DataTypeRSProgramFragment:
- case DataTypeRSProgramVertex:
- case DataTypeRSProgramRaster:
- case DataTypeRSProgramStore:
- case DataTypeRSFont: {
- // (ImplicitCastExpr 'nullptr_t'
- // (IntegerLiteral 0)))
- llvm::APInt Zero(C.getTypeSize(C.IntTy), 0);
- clang::Expr *Int0 = clang::IntegerLiteral::Create(C, Zero, C.IntTy, Loc);
- clang::Expr *CastToNull =
- clang::ImplicitCastExpr::Create(C,
- C.NullPtrTy,
- clang::CK_IntegralToPointer,
- Int0,
- nullptr,
- clang::VK_RValue);
- llvm::SmallVector<clang::Expr*, 1>InitList;
- InitList.push_back(CastToNull);
-
- Res = new(C) clang::InitListExpr(C, Loc, InitList, Loc);
- break;
- }
- case DataTypeRSMatrix2x2:
- case DataTypeRSMatrix3x3:
- case DataTypeRSMatrix4x4: {
- // RS matrix is not completely an RS object. They hold data by themselves.
- // (InitListExpr rs_matrix2x2
- // (InitListExpr float[4]
- // (FloatingLiteral 0)
- // (FloatingLiteral 0)
- // (FloatingLiteral 0)
- // (FloatingLiteral 0)))
- clang::QualType FloatTy = C.FloatTy;
- // Constructor sets value to 0.0f by default
- llvm::APFloat Val(C.getFloatTypeSemantics(FloatTy));
- clang::FloatingLiteral *Float0Val =
- clang::FloatingLiteral::Create(C,
- Val,
- /* isExact = */true,
- FloatTy,
- Loc);
-
- unsigned N = 0;
- if (DT == DataTypeRSMatrix2x2) {
- N = 2;
- } else if (DT == DataTypeRSMatrix3x3) {
- N = 3;
- } else if (DT == DataTypeRSMatrix4x4) {
- N = 4;
- }
- unsigned N_2 = N * N;
-
- // Assume we are going to be allocating 16 elements, since 4x4 is max.
- llvm::SmallVector<clang::Expr*, 16> InitVals;
- for (unsigned i = 0; i < N_2; i++)
- InitVals.push_back(Float0Val);
- clang::Expr *InitExpr =
- new(C) clang::InitListExpr(C, Loc, InitVals, Loc);
- InitExpr->setType(C.getConstantArrayType(FloatTy,
- llvm::APInt(32, N_2),
- clang::ArrayType::Normal,
- /* EltTypeQuals = */0));
- llvm::SmallVector<clang::Expr*, 1> InitExprVec;
- InitExprVec.push_back(InitExpr);
-
- Res = new(C) clang::InitListExpr(C, Loc, InitExprVec, Loc);
- break;
- }
- case DataTypeUnknown:
- case DataTypeFloat16:
- case DataTypeFloat32:
- case DataTypeFloat64:
- case DataTypeSigned8:
- case DataTypeSigned16:
- case DataTypeSigned32:
- case DataTypeSigned64:
- case DataTypeUnsigned8:
- case DataTypeUnsigned16:
- case DataTypeUnsigned32:
- case DataTypeUnsigned64:
- case DataTypeBoolean:
- case DataTypeUnsigned565:
- case DataTypeUnsigned5551:
- case DataTypeUnsigned4444:
- case DataTypeMax: {
- slangAssert(false && "Not RS object type!");
- }
- // No default case will enable compiler detecting the missing cases
- }
-
- return Res;
+ // We can cheaply construct a zero initializer by just creating an empty
+ // initializer list. Clang supports this extension to C(99), and will create
+ // any necessary constructs to zero out the entire variable.
+ llvm::SmallVector<clang::Expr*, 1> EmptyInitList;
+ return new(C) clang::InitListExpr(C, Loc, EmptyInitList, Loc);
}
clang::CompoundStmt* RSObjectRefCount::CreateRetStmtWithTempVar(
@@ -1459,9 +1360,8 @@
clang::SC_None // Storage class
);
const clang::Type *T = RetTy.getTypePtr();
- DataType DT = RSExportPrimitiveType::GetRSSpecificType(T);
clang::Expr *ZeroInitializer =
- RSObjectRefCount::CreateZeroInitializerForRSSpecificType(DT, C, Loc);
+ RSObjectRefCount::CreateEmptyInitListExpr(C, Loc);
ZeroInitializer->setType(T->getCanonicalTypeInternal());
RSRetValDecl->setInit(ZeroInitializer);
clang::Decl* Decls[] = { RSRetValDecl };
diff --git a/slang_rs_object_ref_count.h b/slang_rs_object_ref_count.h
index 88a7a49..5de60d1 100644
--- a/slang_rs_object_ref_count.h
+++ b/slang_rs_object_ref_count.h
@@ -131,10 +131,13 @@
DataType *DT,
clang::Expr **InitExpr);
- // Return a zero-initializer expr of the type DT. This processes both
- // RS matrix type and RS object type.
- static clang::Expr *CreateZeroInitializerForRSSpecificType(
- DataType DT,
+ // Return an empty list initializer expression at the appropriate location.
+ // This construct can then be used to cheaply construct a zero-initializer
+ // for any RenderScript objects (like rs_allocation) or rs_matrix* types
+ // (possibly even embedded within other types). These types are expected to
+ // be zero-initialized always, and so we can use this helper to ensure that
+ // they at least have an empty initializer.
+ static clang::Expr *CreateEmptyInitListExpr(
clang::ASTContext &C,
const clang::SourceLocation &Loc);
diff --git a/tests/P_struct_matrix/stderr.txt.expect b/tests/P_struct_matrix/stderr.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_struct_matrix/stderr.txt.expect
diff --git a/tests/P_struct_matrix/stdout.txt.expect b/tests/P_struct_matrix/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_struct_matrix/stdout.txt.expect
diff --git a/tests/P_struct_matrix/struct_matrix.rs b/tests/P_struct_matrix/struct_matrix.rs
new file mode 100644
index 0000000..353238b
--- /dev/null
+++ b/tests/P_struct_matrix/struct_matrix.rs
@@ -0,0 +1,31 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+struct hasMatrix {
+ int j;
+ rs_matrix3x3 m;
+ int i;
+} ghm;
+
+extern foo(struct hasMatrix*);
+
+void singleStmt() {
+ struct hasMatrix h = ghm;
+}
+
+struct new_matrix {
+ float f[2];
+};
+
+struct new_struct {
+ struct new_matrix m;
+ rs_matrix3x3 t;
+ int i;
+} newm;
+
+void newstmt() {
+ struct new_struct h = {1.f, 2.f, 3};
+ struct new_struct h_uninit;
+ struct new_struct empty_init = {};
+}
+