Here's a patch to fix non-constant struct initializers. If this seems
a bit too big, I can split it into a few pieces, but I figured I would
post the whole thing since I have it. The only thing that's missing,
as far as I know, is support for initializers with elided braces; I
don't think we really have a good solution for that yet, though.
The patch is pretty straightforward; I don't think I need to say
anything more about it.
-Eli
Index: CodeGen/CGExprAgg.cpp
===================================================================
--- CodeGen/CGExprAgg.cpp (revision 46904)
+++ CodeGen/CGExprAgg.cpp (working copy)
@@ -18,6 +18,7 @@
#include "llvm/Function.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Intrinsics.h"
using namespace clang;
using namespace CodeGen;
@@ -81,6 +82,9 @@
void VisitConditionalOperator(const ConditionalOperator *CO);
void VisitInitListExpr(InitListExpr *E);
+
+ void EmitInitializationToLValue(Expr *E, LValue Address);
+ void EmitNullInitializationToLValue(LValue Address, QualType T);
// case Expr::ChooseExprClass:
};
} // end anonymous namespace.
@@ -223,81 +233,129 @@
CGF.EmitBlock(ContBlock);
}
-void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
-
- unsigned NumInitElements = E->getNumInits();
-
- if (!E->getType()->isArrayType()) {
- CGF.WarnUnsupported(E, "aggregate init-list expression");
+void AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) {
+ // FIXME: Are initializers affected by volatile?
+ if (E->getType()->isComplexType()) {
+ CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false);
return;
}
+ RValue RV = CGF.EmitAnyExpr(E, LV.getAddress(), false);
+ if (CGF.hasAggregateLLVMType(E->getType()))
+ return;
+ CGF.EmitStoreThroughLValue(RV, LV, E->getType());
+}
- std::vector<llvm::Constant*> ArrayElts;
- const llvm::PointerType *APType =
cast<llvm::PointerType>(DestPtr->getType());
- const llvm::ArrayType *AType =
- cast<llvm::ArrayType>(APType->getElementType());
+void AggExprEmitter::EmitNullInitializationToLValue(LValue LV, QualType T) {
+ if (!CGF.hasAggregateLLVMType(T)) {
+ // For non-aggregates, we can store zero
+ const llvm::Type *T =
+ cast<llvm::PointerType>(LV.getAddress()->getType())->getElementType();
+ Builder.CreateStore(llvm::Constant::getNullValue(T), LV.getAddress());
+ } else {
+ // Otherwise, just memset the whole thing to zero. This is legal
+ // because in LLVM, all default initializers are guaranteed to have a
+ // bit pattern of all zeros.
+ // There's a potential optimization opportunity in combining
+ // memsets; that would be easy for arrays, but relatively
+ // difficult for structures with the current code.
+ llvm::Value* memset = CGF.CGM.getIntrinsic(llvm::Intrinsic::memset_i64);
+ uint64_t size = CGF.getContext().getTypeSize(T, SourceLocation());
- // Copy initializer elements.
- bool AllConstElements = true;
- unsigned i = 0;
- for (i = 0; i != NumInitElements; ++i) {
- if (llvm::Constant *C =
- dyn_cast<llvm::Constant>(CGF.EmitScalarExpr(E->getInit(i))))
- ArrayElts.push_back(C);
- else {
- AllConstElements = false;
- break;
- }
+ const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ llvm::Value* DestPtr = Builder.CreateBitCast(LV.getAddress(), BP, "tmp");
+
+ llvm::Value *MemSetOps[4] = {
+ DestPtr, llvm::ConstantInt::get(llvm::Type::Int8Ty, 0),
+ llvm::ConstantInt::get(llvm::Type::Int64Ty, size/8),
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, 0)
+ };
+
+ Builder.CreateCall(memset, MemSetOps, MemSetOps+4);
}
+}
- unsigned NumArrayElements = AType->getNumElements();
- const llvm::Type *ElementType = CGF.ConvertType(E->getInit(0)->getType());
+void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
+ if (E->isConstantExpr(CGF.getContext(), 0)) {
+ // FIXME: call into const expr emitter so that we can emit
+ // a memcpy instead of storing the individual members.
+ // This is purely for perf; both codepaths lead to equivalent
+ // (although not necessarily identical) code.
+ // It's worth noting that LLVM keeps on getting smarter, though,
+ // so it might not be worth bothering.
+ }
- if (AllConstElements) {
- // Initialize remaining array elements.
- for (/*Do not initialize i*/; i < NumArrayElements; ++i)
- ArrayElts.push_back(llvm::Constant::getNullValue(ElementType));
+ if (E->getType()->isArrayType()) {
+ const llvm::PointerType *APType =
cast<llvm::PointerType>(DestPtr->getType());
+ const llvm::ArrayType *AType =
+ cast<llvm::ArrayType>(APType->getElementType());
- // Create global value to hold this array.
- llvm::Constant *V = llvm::ConstantArray::get(AType, ArrayElts);
- V = new llvm::GlobalVariable(V->getType(), true,
- llvm::GlobalValue::InternalLinkage,
- V, ".array",
- &CGF.CGM.getModule());
-
- EmitAggregateCopy(DestPtr, V , E->getType());
+ unsigned NumInitElements = E->getNumInits();
+ unsigned NumArrayElements = AType->getNumElements();
+ QualType ElementType = E->getType()->getAsArrayType()->getElementType();
+ llvm::Value *Idxs[] = {
+ llvm::Constant::getNullValue(llvm::Type::Int32Ty),
+ NULL
+ };
+ llvm::Value *NextVal;
+
+ for (unsigned i = 0; i < NumArrayElements; ++i) {
+ Idxs[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, i);
+ NextVal = Builder.CreateGEP(DestPtr, Idxs, Idxs + 2, ".array");
+ if (i < NumInitElements)
+ EmitInitializationToLValue(E->getInit(i), LValue::MakeAddr(NextVal));
+ else
+ EmitNullInitializationToLValue(LValue::MakeAddr(NextVal),
+ ElementType);
+ }
+
return;
}
- // Emit indiviudal array element stores.
- unsigned index = 0;
- llvm::Value *NextVal = NULL;
- llvm::Value *Idxs[] = {
- llvm::Constant::getNullValue(llvm::Type::Int32Ty),
- NULL
- };
-
- // Emit already seen constants initializers.
- for (i = 0; i < ArrayElts.size(); i++) {
- Idxs[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, index++);
- NextVal = Builder.CreateGEP(DestPtr, Idxs, Idxs + 2, ".array");
- Builder.CreateStore(ArrayElts[i], NextVal);
- }
+ assert(E->getType()->isRecordType() && "Only support structs/unions here!");
- // Emit remaining initializers
- for (/*Do not initizalize i*/; i < NumInitElements; ++i) {
- Idxs[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, index++);
- NextVal = Builder.CreateGEP(DestPtr, Idxs, Idxs + 2, ".array");
- llvm::Value *V = CGF.EmitScalarExpr(E->getInit(i));
- Builder.CreateStore(V, NextVal);
+ // Do struct initialization; this code just sets each individual member
+ // to the approprate value. This makes bitfield support automatic;
+ // the disadvantage is that the generated code is more difficult for
+ // the optimizer, especially with bitfields.
+ unsigned NumInitElements = E->getNumInits();
+ RecordDecl *SD = E->getType()->getAsRecordType()->getDecl();
+ unsigned numMembers = SD->getNumMembers() -
+ SD->hasFlexibleArrayMember();
+ unsigned curInit = 0;
+ bool isUnion = E->getType()->isUnionType();
+ // Here we iterate over the fields; this makes it simpler to both
+ // default-initialize fields and skip over unnamed fields.
+ for (unsigned curFieldNo = 0; curFieldNo < numMembers; ++curFieldNo) {
+ if (curInit >= NumInitElements) {
+ // No more initializers; we're done
+ break;
+ }
+ FieldDecl *curField = SD->getMember(curFieldNo);
+ if (!curField->getIdentifier()) {
+ // Initializers can't initialize unnamed fields, e.g. "int : 20;"
+ continue;
+ }
+ LValue curLocation = CGF.EmitLValueForField(DestPtr, curField, isUnion);
+ if (curInit < NumInitElements) {
+ // Store the initializer into the field
+ // This will probably have to get a bit smarter when we support
+ // designators in initializers
+ Expr* expr = E->getInit(curInit);
+ ++curInit;
+ EmitInitializationToLValue(expr, curLocation);
+ } else {
+ // We're out of initalizers; default-initialize to null
+ EmitNullInitializationToLValue(curLocation, curField->getType());
+ }
+
+ // Unions only initialize one field
+ // (things can get weird with designators, but they aren't
+ // supported yet.)
+ if (E->getType()->isUnionType())
+ break;
}
- // Emit remaining default initializers
- for (/*Do not initialize i*/; i < NumArrayElements; ++i) {
- Idxs[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, index++);
- NextVal = Builder.CreateGEP(DestPtr, Idxs, Idxs + 2, ".array");
- Builder.CreateStore(llvm::Constant::getNullValue(ElementType), NextVal);
- }
+ return;
}
//===----------------------------------------------------------------------===//
_______________________________________________
cfe-dev mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev