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 ArrayElts; - const llvm::PointerType *APType = cast(DestPtr->getType()); - const llvm::ArrayType *AType = - cast(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(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(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(DestPtr->getType()); + const llvm::ArrayType *AType = + cast(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; } //===----------------------------------------------------------------------===//