summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen/CGExprConstant.cpp
diff options
context:
space:
mode:
authorYunzhong Gao <Yunzhong_Gao@playstation.sony.com>2015-06-10 00:27:52 +0000
committerYunzhong Gao <Yunzhong_Gao@playstation.sony.com>2015-06-10 00:27:52 +0000
commitcb77930d6b20e53c735233eecf4572a1c30eb0c0 (patch)
tree74f8f3c0612aee5391a6cb5bbb5eb01c0a6d5be8 /clang/lib/CodeGen/CGExprConstant.cpp
parent7912d9b8999266e55ff40e15d37fa458e66f436c (diff)
downloadbcm5719-llvm-cb77930d6b20e53c735233eecf4572a1c30eb0c0.tar.gz
bcm5719-llvm-cb77930d6b20e53c735233eecf4572a1c30eb0c0.zip
Implementing C99 partial re-initialization behavior (DR-253)
Based on previous discussion on the mailing list, clang currently lacks support for C99 partial re-initialization behavior: Reference: http://lists.cs.uiuc.edu/pipermail/cfe-dev/2013-April/029188.html Reference: http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_253.htm This patch attempts to fix this problem. Given the following code snippet, struct P1 { char x[6]; }; struct LP1 { struct P1 p1; }; struct LP1 l = { .p1 = { "foo" }, .p1.x[2] = 'x' }; // this example is adapted from the example for "struct fred x[]" in DR-253; // currently clang produces in l: { "\0\0x" }, // whereas gcc 4.8 produces { "fox" }; // with this fix, clang will also produce: { "fox" }; Differential Review: http://reviews.llvm.org/D5789 llvm-svn: 239446
Diffstat (limited to 'clang/lib/CodeGen/CGExprConstant.cpp')
-rw-r--r--clang/lib/CodeGen/CGExprConstant.cpp156
1 files changed, 156 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index b90b3ab61d8..acfb9b6dbb2 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -33,6 +33,7 @@ using namespace CodeGen;
//===----------------------------------------------------------------------===//
namespace {
+class ConstExprEmitter;
class ConstStructBuilder {
CodeGenModule &CGM;
CodeGenFunction *CGF;
@@ -42,6 +43,10 @@ class ConstStructBuilder {
CharUnits LLVMStructAlignment;
SmallVector<llvm::Constant *, 32> Elements;
public:
+ static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CFG,
+ ConstExprEmitter *Emitter,
+ llvm::ConstantStruct *Base,
+ InitListExpr *Updater);
static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF,
InitListExpr *ILE);
static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF,
@@ -68,6 +73,8 @@ private:
void ConvertStructToPacked();
bool Build(InitListExpr *ILE);
+ bool Build(ConstExprEmitter *Emitter, llvm::ConstantStruct *Base,
+ InitListExpr *Updater);
void Build(const APValue &Val, const RecordDecl *RD, bool IsPrimaryBase,
const CXXRecordDecl *VTableClass, CharUnits BaseOffset);
llvm::Constant *Finalize(QualType Ty);
@@ -547,6 +554,17 @@ llvm::Constant *ConstStructBuilder::Finalize(QualType Ty) {
llvm::Constant *ConstStructBuilder::BuildStruct(CodeGenModule &CGM,
CodeGenFunction *CGF,
+ ConstExprEmitter *Emitter,
+ llvm::ConstantStruct *Base,
+ InitListExpr *Updater) {
+ ConstStructBuilder Builder(CGM, CGF);
+ if (!Builder.Build(Emitter, Base, Updater))
+ return nullptr;
+ return Builder.Finalize(Updater->getType());
+}
+
+llvm::Constant *ConstStructBuilder::BuildStruct(CodeGenModule &CGM,
+ CodeGenFunction *CGF,
InitListExpr *ILE) {
ConstStructBuilder Builder(CGM, CGF);
@@ -818,6 +836,82 @@ public:
return nullptr;
}
+ llvm::Constant *EmitDesignatedInitUpdater(llvm::Constant *Base,
+ InitListExpr *Updater) {
+ QualType ExprType = Updater->getType();
+
+ if (ExprType->isArrayType()) {
+ llvm::ArrayType *AType = cast<llvm::ArrayType>(ConvertType(ExprType));
+ llvm::Type *ElemType = AType->getElementType();
+
+ unsigned NumInitElements = Updater->getNumInits();
+ unsigned NumElements = AType->getNumElements();
+
+ std::vector<llvm::Constant *> Elts;
+ Elts.reserve(NumElements);
+
+ if (llvm::ConstantDataArray *DataArray =
+ dyn_cast<llvm::ConstantDataArray>(Base))
+ for (unsigned i = 0; i != NumElements; ++i)
+ Elts.push_back(DataArray->getElementAsConstant(i));
+ else if (llvm::ConstantArray *Array =
+ dyn_cast<llvm::ConstantArray>(Base))
+ for (unsigned i = 0; i != NumElements; ++i)
+ Elts.push_back(Array->getOperand(i));
+ else
+ return nullptr; // FIXME: other array types not implemented
+
+ llvm::Constant *fillC = nullptr;
+ if (Expr *filler = Updater->getArrayFiller())
+ if (!isa<NoInitExpr>(filler))
+ fillC = CGM.EmitConstantExpr(filler, filler->getType(), CGF);
+ bool RewriteType = (fillC && fillC->getType() != ElemType);
+
+ for (unsigned i = 0; i != NumElements; ++i) {
+ Expr *Init = nullptr;
+ if (i < NumInitElements)
+ Init = Updater->getInit(i);
+
+ if (!Init && fillC)
+ Elts[i] = fillC;
+ else if (!Init || isa<NoInitExpr>(Init))
+ ; // Do nothing.
+ else if (InitListExpr *ChildILE = dyn_cast<InitListExpr>(Init))
+ Elts[i] = EmitDesignatedInitUpdater(Elts[i], ChildILE);
+ else
+ Elts[i] = CGM.EmitConstantExpr(Init, Init->getType(), CGF);
+
+ if (!Elts[i])
+ return nullptr;
+ RewriteType |= (Elts[i]->getType() != ElemType);
+ }
+
+ if (RewriteType) {
+ std::vector<llvm::Type *> Types;
+ Types.reserve(NumElements);
+ for (unsigned i = 0; i != NumElements; ++i)
+ Types.push_back(Elts[i]->getType());
+ llvm::StructType *SType = llvm::StructType::get(AType->getContext(),
+ Types, true);
+ return llvm::ConstantStruct::get(SType, Elts);
+ }
+
+ return llvm::ConstantArray::get(AType, Elts);
+ }
+
+ if (ExprType->isRecordType())
+ return ConstStructBuilder::BuildStruct(CGM, CGF, this,
+ dyn_cast<llvm::ConstantStruct>(Base), Updater);
+
+ return nullptr;
+ }
+
+ llvm::Constant *VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E) {
+ return EmitDesignatedInitUpdater(
+ CGM.EmitConstantExpr(E->getBase(), E->getType(), CGF),
+ E->getUpdater());
+ }
+
llvm::Constant *VisitCXXConstructExpr(CXXConstructExpr *E) {
if (!E->getConstructor()->isTrivial())
return nullptr;
@@ -1003,6 +1097,68 @@ public:
} // end anonymous namespace.
+bool ConstStructBuilder::Build(ConstExprEmitter *Emitter,
+ llvm::ConstantStruct *Base,
+ InitListExpr *Updater) {
+ assert(Base && "base expression should not be empty");
+
+ QualType ExprType = Updater->getType();
+ RecordDecl *RD = ExprType->getAs<RecordType>()->getDecl();
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ const llvm::StructLayout *BaseLayout = CGM.getDataLayout().getStructLayout(
+ Base->getType());
+ unsigned FieldNo = -1;
+ unsigned ElementNo = 0;
+
+ for (FieldDecl *Field : RD->fields()) {
+ ++FieldNo;
+
+ if (RD->isUnion() && Updater->getInitializedFieldInUnion() != Field)
+ continue;
+
+ // Skip anonymous bitfields.
+ if (Field->isUnnamedBitfield())
+ continue;
+
+ llvm::Constant *EltInit = Base->getOperand(ElementNo);
+
+ // Bail out if the type of the ConstantStruct does not have the same layout
+ // as the type of the InitListExpr.
+ if (CGM.getTypes().ConvertType(Field->getType()) != EltInit->getType() ||
+ Layout.getFieldOffset(ElementNo) !=
+ BaseLayout->getElementOffsetInBits(ElementNo))
+ return false;
+
+ // Get the initializer. If we encounter an empty field or a NoInitExpr,
+ // we use values from the base expression.
+ Expr *Init = nullptr;
+ if (ElementNo < Updater->getNumInits())
+ Init = Updater->getInit(ElementNo);
+
+ if (!Init || isa<NoInitExpr>(Init))
+ ; // Do nothing.
+ else if (InitListExpr *ChildILE = dyn_cast<InitListExpr>(Init))
+ EltInit = Emitter->EmitDesignatedInitUpdater(EltInit, ChildILE);
+ else
+ EltInit = CGM.EmitConstantExpr(Init, Field->getType(), CGF);
+
+ ++ElementNo;
+
+ if (!EltInit)
+ return false;
+
+ if (!Field->isBitField())
+ AppendField(Field, Layout.getFieldOffset(FieldNo), EltInit);
+ else if (llvm::ConstantInt *CI = dyn_cast<llvm::ConstantInt>(EltInit))
+ AppendBitField(Field, Layout.getFieldOffset(FieldNo), CI);
+ else
+ // Initializing a bitfield with a non-trivial constant?
+ return false;
+ }
+
+ return true;
+}
+
llvm::Constant *CodeGenModule::EmitConstantInit(const VarDecl &D,
CodeGenFunction *CGF) {
// Make a quick check if variable can be default NULL initialized
OpenPOWER on IntegriCloud