diff options
Diffstat (limited to 'lib/CodeGen/CGExprConstant.cpp')
-rw-r--r-- | lib/CodeGen/CGExprConstant.cpp | 174 |
1 files changed, 103 insertions, 71 deletions
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index d1b9e13a6f937..cfd0b859233ab 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -635,6 +635,72 @@ static ConstantAddress tryEmitGlobalCompoundLiteral(CodeGenModule &CGM, return ConstantAddress(GV, Align); } +static llvm::Constant * +EmitArrayConstant(CodeGenModule &CGM, const ConstantArrayType *DestType, + llvm::Type *CommonElementType, unsigned ArrayBound, + SmallVectorImpl<llvm::Constant *> &Elements, + llvm::Constant *Filler) { + // Figure out how long the initial prefix of non-zero elements is. + unsigned NonzeroLength = ArrayBound; + if (Elements.size() < NonzeroLength && Filler->isNullValue()) + NonzeroLength = Elements.size(); + if (NonzeroLength == Elements.size()) { + while (NonzeroLength > 0 && Elements[NonzeroLength - 1]->isNullValue()) + --NonzeroLength; + } + + if (NonzeroLength == 0) { + return llvm::ConstantAggregateZero::get( + CGM.getTypes().ConvertType(QualType(DestType, 0))); + } + + // Add a zeroinitializer array filler if we have lots of trailing zeroes. + unsigned TrailingZeroes = ArrayBound - NonzeroLength; + if (TrailingZeroes >= 8) { + assert(Elements.size() >= NonzeroLength && + "missing initializer for non-zero element"); + + // If all the elements had the same type up to the trailing zeroes, emit a + // struct of two arrays (the nonzero data and the zeroinitializer). + if (CommonElementType && NonzeroLength >= 8) { + llvm::Constant *Initial = llvm::ConstantArray::get( + llvm::ArrayType::get(CommonElementType, NonzeroLength), + makeArrayRef(Elements).take_front(NonzeroLength)); + Elements.resize(2); + Elements[0] = Initial; + } else { + Elements.resize(NonzeroLength + 1); + } + + auto *FillerType = + CommonElementType + ? CommonElementType + : CGM.getTypes().ConvertType(DestType->getElementType()); + FillerType = llvm::ArrayType::get(FillerType, TrailingZeroes); + Elements.back() = llvm::ConstantAggregateZero::get(FillerType); + CommonElementType = nullptr; + } else if (Elements.size() != ArrayBound) { + // Otherwise pad to the right size with the filler if necessary. + Elements.resize(ArrayBound, Filler); + if (Filler->getType() != CommonElementType) + CommonElementType = nullptr; + } + + // If all elements have the same type, just emit an array constant. + if (CommonElementType) + return llvm::ConstantArray::get( + llvm::ArrayType::get(CommonElementType, ArrayBound), Elements); + + // We have mixed types. Use a packed struct. + llvm::SmallVector<llvm::Type *, 16> Types; + Types.reserve(Elements.size()); + for (llvm::Constant *Elt : Elements) + Types.push_back(Elt->getType()); + llvm::StructType *SType = + llvm::StructType::get(CGM.getLLVMContext(), Types, true); + return llvm::ConstantStruct::get(SType, Elements); +} + /// This class only needs to handle two cases: /// 1) Literals (this is used by APValue emission to emit literals). /// 2) Arrays, structs and unions (outside C++11 mode, we don't currently @@ -832,60 +898,47 @@ public: } llvm::Constant *EmitArrayInitialization(InitListExpr *ILE, QualType T) { - llvm::ArrayType *AType = - cast<llvm::ArrayType>(ConvertType(ILE->getType())); - llvm::Type *ElemTy = AType->getElementType(); + auto *CAT = CGM.getContext().getAsConstantArrayType(ILE->getType()); + assert(CAT && "can't emit array init for non-constant-bound array"); unsigned NumInitElements = ILE->getNumInits(); - unsigned NumElements = AType->getNumElements(); + unsigned NumElements = CAT->getSize().getZExtValue(); // Initialising an array requires us to automatically // initialise any elements that have not been initialised explicitly unsigned NumInitableElts = std::min(NumInitElements, NumElements); - QualType EltType = CGM.getContext().getAsArrayType(T)->getElementType(); + QualType EltType = CAT->getElementType(); // Initialize remaining array elements. - llvm::Constant *fillC; - if (Expr *filler = ILE->getArrayFiller()) + llvm::Constant *fillC = nullptr; + if (Expr *filler = ILE->getArrayFiller()) { fillC = Emitter.tryEmitAbstractForMemory(filler, EltType); - else - fillC = Emitter.emitNullForMemory(EltType); - if (!fillC) - return nullptr; - - // Try to use a ConstantAggregateZero if we can. - if (fillC->isNullValue() && !NumInitableElts) - return llvm::ConstantAggregateZero::get(AType); + if (!fillC) + return nullptr; + } // Copy initializer elements. SmallVector<llvm::Constant*, 16> Elts; - Elts.reserve(NumInitableElts + NumElements); + if (fillC && fillC->isNullValue()) + Elts.reserve(NumInitableElts + 1); + else + Elts.reserve(NumElements); - bool RewriteType = false; + llvm::Type *CommonElementType = nullptr; for (unsigned i = 0; i < NumInitableElts; ++i) { Expr *Init = ILE->getInit(i); llvm::Constant *C = Emitter.tryEmitPrivateForMemory(Init, EltType); if (!C) return nullptr; - RewriteType |= (C->getType() != ElemTy); + if (i == 0) + CommonElementType = C->getType(); + else if (C->getType() != CommonElementType) + CommonElementType = nullptr; Elts.push_back(C); } - RewriteType |= (fillC->getType() != ElemTy); - Elts.resize(NumElements, fillC); - - if (RewriteType) { - // FIXME: Try to avoid packing the array - std::vector<llvm::Type*> Types; - Types.reserve(NumInitableElts + NumElements); - for (unsigned i = 0, e = Elts.size(); i < e; ++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); + return EmitArrayConstant(CGM, CAT, CommonElementType, NumElements, Elts, + fillC); } llvm::Constant *EmitRecordInitialization(InitListExpr *ILE, QualType T) { @@ -1881,40 +1934,31 @@ llvm::Constant *ConstantEmitter::tryEmitPrivate(const APValue &Value, case APValue::Union: return ConstStructBuilder::BuildStruct(*this, Value, DestType); case APValue::Array: { - const ArrayType *CAT = CGM.getContext().getAsArrayType(DestType); + const ConstantArrayType *CAT = + CGM.getContext().getAsConstantArrayType(DestType); unsigned NumElements = Value.getArraySize(); unsigned NumInitElts = Value.getArrayInitializedElts(); // Emit array filler, if there is one. llvm::Constant *Filler = nullptr; - if (Value.hasArrayFiller()) + if (Value.hasArrayFiller()) { Filler = tryEmitAbstractForMemory(Value.getArrayFiller(), CAT->getElementType()); - - // Emit initializer elements. - llvm::Type *CommonElementType = - CGM.getTypes().ConvertType(CAT->getElementType()); - - // Try to use a ConstantAggregateZero if we can. - if (Filler && Filler->isNullValue() && !NumInitElts) { - llvm::ArrayType *AType = - llvm::ArrayType::get(CommonElementType, NumElements); - return llvm::ConstantAggregateZero::get(AType); + if (!Filler) + return nullptr; } + // Emit initializer elements. SmallVector<llvm::Constant*, 16> Elts; - Elts.reserve(NumElements); - for (unsigned I = 0; I < NumElements; ++I) { - llvm::Constant *C = Filler; - if (I < NumInitElts) { - C = tryEmitPrivateForMemory(Value.getArrayInitializedElt(I), - CAT->getElementType()); - } else if (!Filler) { - assert(Value.hasArrayFiller() && - "Missing filler for implicit elements of initializer"); - C = tryEmitPrivateForMemory(Value.getArrayFiller(), - CAT->getElementType()); - } + if (Filler && Filler->isNullValue()) + Elts.reserve(NumInitElts + 1); + else + Elts.reserve(NumElements); + + llvm::Type *CommonElementType = nullptr; + for (unsigned I = 0; I < NumInitElts; ++I) { + llvm::Constant *C = tryEmitPrivateForMemory( + Value.getArrayInitializedElt(I), CAT->getElementType()); if (!C) return nullptr; if (I == 0) @@ -1924,20 +1968,8 @@ llvm::Constant *ConstantEmitter::tryEmitPrivate(const APValue &Value, Elts.push_back(C); } - if (!CommonElementType) { - // FIXME: Try to avoid packing the array - std::vector<llvm::Type*> Types; - Types.reserve(NumElements); - for (unsigned i = 0, e = Elts.size(); i < e; ++i) - Types.push_back(Elts[i]->getType()); - llvm::StructType *SType = - llvm::StructType::get(CGM.getLLVMContext(), Types, true); - return llvm::ConstantStruct::get(SType, Elts); - } - - llvm::ArrayType *AType = - llvm::ArrayType::get(CommonElementType, NumElements); - return llvm::ConstantArray::get(AType, Elts); + return EmitArrayConstant(CGM, CAT, CommonElementType, NumElements, Elts, + Filler); } case APValue::MemberPointer: return CGM.getCXXABI().EmitMemberPointer(Value, DestType); |