#include "CGCXXABI.h"
#include "CGObjCRuntime.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "ConstantEmitter.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/StmtVisitor.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
using namespace clang;
using namespace CodeGen;
namespace {
class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
CodeGenFunction &CGF;
CGBuilderTy &Builder;
AggValueSlot Dest;
bool IsResultUnused;
AggValueSlot EnsureSlot(QualType T) {
if (!Dest.isIgnored()) return Dest;
return CGF.CreateAggTemp(T, "agg.tmp.ensured");
}
void EnsureDest(QualType T) {
if (!Dest.isIgnored()) return;
Dest = CGF.CreateAggTemp(T, "agg.tmp.ensured");
}
void withReturnValueSlot(const Expr *E,
llvm::function_ref<RValue(ReturnValueSlot)> Fn);
public:
AggExprEmitter(CodeGenFunction &cgf, AggValueSlot Dest, bool IsResultUnused)
: CGF(cgf), Builder(CGF.Builder), Dest(Dest),
IsResultUnused(IsResultUnused) { }
void EmitAggLoadOfLValue(const Expr *E);
enum ExprValueKind {
EVK_RValue,
EVK_NonRValue
};
void EmitFinalDestCopy(QualType type, const LValue &src,
ExprValueKind SrcValueKind = EVK_NonRValue);
void EmitFinalDestCopy(QualType type, RValue src);
void EmitCopy(QualType type, const AggValueSlot &dest,
const AggValueSlot &src);
void EmitMoveFromReturnSlot(const Expr *E, RValue Src);
void EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
QualType ArrayQTy, InitListExpr *E);
AggValueSlot::NeedsGCBarriers_t needsGC(QualType T) {
if (CGF.getLangOpts().getGC() && TypeRequiresGCollection(T))
return AggValueSlot::NeedsGCBarriers;
return AggValueSlot::DoesNotNeedGCBarriers;
}
bool TypeRequiresGCollection(QualType T);
void Visit(Expr *E) {
ApplyDebugLocation DL(CGF, E);
StmtVisitor<AggExprEmitter>::Visit(E);
}
void VisitStmt(Stmt *S) {
CGF.ErrorUnsupported(S, "aggregate expression");
}
void VisitParenExpr(ParenExpr *PE) { Visit(PE->getSubExpr()); }
void VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
Visit(GE->getResultExpr());
}
void VisitCoawaitExpr(CoawaitExpr *E) {
CGF.EmitCoawaitExpr(*E, Dest, IsResultUnused);
}
void VisitCoyieldExpr(CoyieldExpr *E) {
CGF.EmitCoyieldExpr(*E, Dest, IsResultUnused);
}
void VisitUnaryCoawait(UnaryOperator *E) { Visit(E->getSubExpr()); }
void VisitUnaryExtension(UnaryOperator *E) { Visit(E->getSubExpr()); }
void VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E) {
return Visit(E->getReplacement());
}
void VisitConstantExpr(ConstantExpr *E) {
EnsureDest(E->getType());
if (llvm::Value *Result = ConstantEmitter(CGF).tryEmitConstantExpr(E)) {
CGF.EmitAggregateStore(Result, Dest.getAddress(),
E->getType().isVolatileQualified());
return;
}
return Visit(E->getSubExpr());
}
void VisitDeclRefExpr(DeclRefExpr *E) { EmitAggLoadOfLValue(E); }
void VisitMemberExpr(MemberExpr *ME) { EmitAggLoadOfLValue(ME); }
void VisitUnaryDeref(UnaryOperator *E) { EmitAggLoadOfLValue(E); }
void VisitStringLiteral(StringLiteral *E) { EmitAggLoadOfLValue(E); }
void VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
void VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
EmitAggLoadOfLValue(E);
}
void VisitPredefinedExpr(const PredefinedExpr *E) {
EmitAggLoadOfLValue(E);
}
void VisitCastExpr(CastExpr *E);
void VisitCallExpr(const CallExpr *E);
void VisitStmtExpr(const StmtExpr *E);
void VisitBinaryOperator(const BinaryOperator *BO);
void VisitPointerToDataMemberBinaryOperator(const BinaryOperator *BO);
void VisitBinAssign(const BinaryOperator *E);
void VisitBinComma(const BinaryOperator *E);
void VisitBinCmp(const BinaryOperator *E);
void VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *E) {
Visit(E->getSemanticForm());
}
void VisitObjCMessageExpr(ObjCMessageExpr *E);
void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
EmitAggLoadOfLValue(E);
}
void VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E);
void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO);
void VisitChooseExpr(const ChooseExpr *CE);
void VisitInitListExpr(InitListExpr *E);
void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E,
llvm::Value *outerBegin = nullptr);
void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
void VisitNoInitExpr(NoInitExpr *E) { } void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
CodeGenFunction::CXXDefaultArgExprScope Scope(CGF, DAE);
Visit(DAE->getExpr());
}
void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) {
CodeGenFunction::CXXDefaultInitExprScope Scope(CGF, DIE);
Visit(DIE->getExpr());
}
void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E);
void VisitCXXConstructExpr(const CXXConstructExpr *E);
void VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
void VisitLambdaExpr(LambdaExpr *E);
void VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E);
void VisitExprWithCleanups(ExprWithCleanups *E);
void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
void VisitCXXTypeidExpr(CXXTypeidExpr *E) { EmitAggLoadOfLValue(E); }
void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E);
void VisitOpaqueValueExpr(OpaqueValueExpr *E);
void VisitPseudoObjectExpr(PseudoObjectExpr *E) {
if (E->isGLValue()) {
LValue LV = CGF.EmitPseudoObjectLValue(E);
return EmitFinalDestCopy(E->getType(), LV);
}
CGF.EmitPseudoObjectRValue(E, EnsureSlot(E->getType()));
}
void VisitVAArgExpr(VAArgExpr *E);
void EmitInitializationToLValue(Expr *E, LValue Address);
void EmitNullInitializationToLValue(LValue Address);
void VisitCXXThrowExpr(const CXXThrowExpr *E) { CGF.EmitCXXThrowExpr(E); }
void VisitAtomicExpr(AtomicExpr *E) {
RValue Res = CGF.EmitAtomicExpr(E);
EmitFinalDestCopy(E->getType(), Res);
}
};
}
void AggExprEmitter::EmitAggLoadOfLValue(const Expr *E) {
LValue LV = CGF.EmitLValue(E);
if (LV.getType()->isAtomicType() || CGF.LValueIsSuitableForInlineAtomic(LV)) {
CGF.EmitAtomicLoad(LV, E->getExprLoc(), Dest);
return;
}
EmitFinalDestCopy(E->getType(), LV);
}
bool AggExprEmitter::TypeRequiresGCollection(QualType T) {
const RecordType *RecordTy = T->getAs<RecordType>();
if (!RecordTy) return false;
RecordDecl *Record = RecordTy->getDecl();
if (isa<CXXRecordDecl>(Record) &&
(cast<CXXRecordDecl>(Record)->hasNonTrivialCopyConstructor() ||
!cast<CXXRecordDecl>(Record)->hasTrivialDestructor()))
return false;
return Record->hasObjectMember();
}
void AggExprEmitter::withReturnValueSlot(
const Expr *E, llvm::function_ref<RValue(ReturnValueSlot)> EmitCall) {
QualType RetTy = E->getType();
bool RequiresDestruction =
!Dest.isExternallyDestructed() &&
RetTy.isDestructedType() == QualType::DK_nontrivial_c_struct;
bool UseTemp = Dest.isPotentiallyAliased() || Dest.requiresGCollection() ||
(RequiresDestruction && !Dest.getAddress().isValid());
Address RetAddr = Address::invalid();
Address RetAllocaAddr = Address::invalid();
EHScopeStack::stable_iterator LifetimeEndBlock;
llvm::Value *LifetimeSizePtr = nullptr;
llvm::IntrinsicInst *LifetimeStartInst = nullptr;
if (!UseTemp) {
RetAddr = Dest.getAddress();
} else {
RetAddr = CGF.CreateMemTemp(RetTy, "tmp", &RetAllocaAddr);
llvm::TypeSize Size =
CGF.CGM.getDataLayout().getTypeAllocSize(CGF.ConvertTypeForMem(RetTy));
LifetimeSizePtr = CGF.EmitLifetimeStart(Size, RetAllocaAddr.getPointer());
if (LifetimeSizePtr) {
LifetimeStartInst =
cast<llvm::IntrinsicInst>(std::prev(Builder.GetInsertPoint()));
assert(LifetimeStartInst->getIntrinsicID() ==
llvm::Intrinsic::lifetime_start &&
"Last insertion wasn't a lifetime.start?");
CGF.pushFullExprCleanup<CodeGenFunction::CallLifetimeEnd>(
NormalEHLifetimeMarker, RetAllocaAddr, LifetimeSizePtr);
LifetimeEndBlock = CGF.EHStack.stable_begin();
}
}
RValue Src =
EmitCall(ReturnValueSlot(RetAddr, Dest.isVolatile(), IsResultUnused,
Dest.isExternallyDestructed()));
if (!UseTemp)
return;
assert(Dest.isIgnored() || Dest.getPointer() != Src.getAggregatePointer());
EmitFinalDestCopy(E->getType(), Src);
if (!RequiresDestruction && LifetimeStartInst) {
CGF.DeactivateCleanupBlock(LifetimeEndBlock, LifetimeStartInst);
CGF.EmitLifetimeEnd(LifetimeSizePtr, RetAllocaAddr.getPointer());
}
}
void AggExprEmitter::EmitFinalDestCopy(QualType type, RValue src) {
assert(src.isAggregate() && "value must be aggregate value!");
LValue srcLV = CGF.MakeAddrLValue(src.getAggregateAddress(), type);
EmitFinalDestCopy(type, srcLV, EVK_RValue);
}
void AggExprEmitter::EmitFinalDestCopy(QualType type, const LValue &src,
ExprValueKind SrcValueKind) {
if (Dest.isIgnored())
return;
LValue DstLV = CGF.MakeAddrLValue(
Dest.getAddress(), Dest.isVolatile() ? type.withVolatile() : type);
if (SrcValueKind == EVK_RValue) {
if (type.isNonTrivialToPrimitiveDestructiveMove() == QualType::PCK_Struct) {
if (Dest.isPotentiallyAliased())
CGF.callCStructMoveAssignmentOperator(DstLV, src);
else
CGF.callCStructMoveConstructor(DstLV, src);
return;
}
} else {
if (type.isNonTrivialToPrimitiveCopy() == QualType::PCK_Struct) {
if (Dest.isPotentiallyAliased())
CGF.callCStructCopyAssignmentOperator(DstLV, src);
else
CGF.callCStructCopyConstructor(DstLV, src);
return;
}
}
AggValueSlot srcAgg = AggValueSlot::forLValue(
src, CGF, AggValueSlot::IsDestructed, needsGC(type),
AggValueSlot::IsAliased, AggValueSlot::MayOverlap);
EmitCopy(type, Dest, srcAgg);
}
void AggExprEmitter::EmitCopy(QualType type, const AggValueSlot &dest,
const AggValueSlot &src) {
if (dest.requiresGCollection()) {
CharUnits sz = dest.getPreferredSize(CGF.getContext(), type);
llvm::Value *size = llvm::ConstantInt::get(CGF.SizeTy, sz.getQuantity());
CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF,
dest.getAddress(),
src.getAddress(),
size);
return;
}
LValue DestLV = CGF.MakeAddrLValue(dest.getAddress(), type);
LValue SrcLV = CGF.MakeAddrLValue(src.getAddress(), type);
CGF.EmitAggregateCopy(DestLV, SrcLV, type, dest.mayOverlap(),
dest.isVolatile() || src.isVolatile());
}
void
AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
ASTContext &Ctx = CGF.getContext();
LValue Array = CGF.EmitLValue(E->getSubExpr());
assert(Array.isSimple() && "initializer_list array not a simple lvalue");
Address ArrayPtr = Array.getAddress(CGF);
const ConstantArrayType *ArrayType =
Ctx.getAsConstantArrayType(E->getSubExpr()->getType());
assert(ArrayType && "std::initializer_list constructed from non-array");
RecordDecl *Record = E->getType()->castAs<RecordType>()->getDecl();
RecordDecl::field_iterator Field = Record->field_begin();
if (Field == Record->field_end()) {
CGF.ErrorUnsupported(E, "weird std::initializer_list");
return;
}
if (!Field->getType()->isPointerType() ||
!Ctx.hasSameType(Field->getType()->getPointeeType(),
ArrayType->getElementType())) {
CGF.ErrorUnsupported(E, "weird std::initializer_list");
return;
}
AggValueSlot Dest = EnsureSlot(E->getType());
LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType());
LValue Start = CGF.EmitLValueForFieldInitialization(DestLV, *Field);
llvm::Value *Zero = llvm::ConstantInt::get(CGF.PtrDiffTy, 0);
llvm::Value *IdxStart[] = { Zero, Zero };
llvm::Value *ArrayStart = Builder.CreateInBoundsGEP(
ArrayPtr.getElementType(), ArrayPtr.getPointer(), IdxStart, "arraystart");
CGF.EmitStoreThroughLValue(RValue::get(ArrayStart), Start);
++Field;
if (Field == Record->field_end()) {
CGF.ErrorUnsupported(E, "weird std::initializer_list");
return;
}
llvm::Value *Size = Builder.getInt(ArrayType->getSize());
LValue EndOrLength = CGF.EmitLValueForFieldInitialization(DestLV, *Field);
if (Field->getType()->isPointerType() &&
Ctx.hasSameType(Field->getType()->getPointeeType(),
ArrayType->getElementType())) {
llvm::Value *IdxEnd[] = { Zero, Size };
llvm::Value *ArrayEnd = Builder.CreateInBoundsGEP(
ArrayPtr.getElementType(), ArrayPtr.getPointer(), IdxEnd, "arrayend");
CGF.EmitStoreThroughLValue(RValue::get(ArrayEnd), EndOrLength);
} else if (Ctx.hasSameType(Field->getType(), Ctx.getSizeType())) {
CGF.EmitStoreThroughLValue(RValue::get(Size), EndOrLength);
} else {
CGF.ErrorUnsupported(E, "weird std::initializer_list");
return;
}
}
static bool isTrivialFiller(Expr *E) {
if (!E)
return true;
if (isa<ImplicitValueInitExpr>(E))
return true;
if (auto *ILE = dyn_cast<InitListExpr>(E)) {
if (ILE->getNumInits())
return false;
return isTrivialFiller(ILE->getArrayFiller());
}
if (auto *Cons = dyn_cast_or_null<CXXConstructExpr>(E))
return Cons->getConstructor()->isDefaultConstructor() &&
Cons->getConstructor()->isTrivial();
return false;
}
void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
QualType ArrayQTy, InitListExpr *E) {
uint64_t NumInitElements = E->getNumInits();
uint64_t NumArrayElements = AType->getNumElements();
assert(NumInitElements <= NumArrayElements);
QualType elementType =
CGF.getContext().getAsArrayType(ArrayQTy)->getElementType();
llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0);
llvm::Value *indices[] = { zero, zero };
llvm::Value *begin = Builder.CreateInBoundsGEP(
DestPtr.getElementType(), DestPtr.getPointer(), indices,
"arrayinit.begin");
CharUnits elementSize = CGF.getContext().getTypeSizeInChars(elementType);
CharUnits elementAlign =
DestPtr.getAlignment().alignmentOfArrayElement(elementSize);
llvm::Type *llvmElementType = CGF.ConvertTypeForMem(elementType);
if (NumInitElements * elementSize.getQuantity() > 16 &&
elementType.isTriviallyCopyableType(CGF.getContext())) {
CodeGen::CodeGenModule &CGM = CGF.CGM;
ConstantEmitter Emitter(CGF);
LangAS AS = ArrayQTy.getAddressSpace();
if (llvm::Constant *C = Emitter.tryEmitForInitializer(E, AS, ArrayQTy)) {
auto GV = new llvm::GlobalVariable(
CGM.getModule(), C->getType(),
CGM.isTypeConstant(ArrayQTy, true),
llvm::GlobalValue::PrivateLinkage, C, "constinit",
nullptr, llvm::GlobalVariable::NotThreadLocal,
CGM.getContext().getTargetAddressSpace(AS));
Emitter.finalize(GV);
CharUnits Align = CGM.getContext().getTypeAlignInChars(ArrayQTy);
GV->setAlignment(Align.getAsAlign());
Address GVAddr(GV, GV->getValueType(), Align);
EmitFinalDestCopy(ArrayQTy, CGF.MakeAddrLValue(GVAddr, ArrayQTy));
return;
}
}
QualType::DestructionKind dtorKind = elementType.isDestructedType();
Address endOfInit = Address::invalid();
EHScopeStack::stable_iterator cleanup;
llvm::Instruction *cleanupDominator = nullptr;
if (CGF.needsEHCleanup(dtorKind)) {
endOfInit = CGF.CreateTempAlloca(begin->getType(), CGF.getPointerAlign(),
"arrayinit.endOfInit");
cleanupDominator = Builder.CreateStore(begin, endOfInit);
CGF.pushIrregularPartialArrayCleanup(begin, endOfInit, elementType,
elementAlign,
CGF.getDestroyer(dtorKind));
cleanup = CGF.EHStack.stable_begin();
} else {
dtorKind = QualType::DK_none;
}
llvm::Value *one = llvm::ConstantInt::get(CGF.SizeTy, 1);
llvm::Value *element = begin;
for (uint64_t i = 0; i != NumInitElements; ++i) {
if (i > 0) {
element = Builder.CreateInBoundsGEP(
llvmElementType, element, one, "arrayinit.element");
if (endOfInit.isValid()) Builder.CreateStore(element, endOfInit);
}
LValue elementLV = CGF.MakeAddrLValue(
Address(element, llvmElementType, elementAlign), elementType);
EmitInitializationToLValue(E->getInit(i), elementLV);
}
Expr *filler = E->getArrayFiller();
bool hasTrivialFiller = isTrivialFiller(filler);
if (NumInitElements != NumArrayElements &&
!(Dest.isZeroed() && hasTrivialFiller &&
CGF.getTypes().isZeroInitializable(elementType))) {
if (NumInitElements) {
element = Builder.CreateInBoundsGEP(
llvmElementType, element, one, "arrayinit.start");
if (endOfInit.isValid()) Builder.CreateStore(element, endOfInit);
}
llvm::Value *end = Builder.CreateInBoundsGEP(
llvmElementType, begin,
llvm::ConstantInt::get(CGF.SizeTy, NumArrayElements), "arrayinit.end");
llvm::BasicBlock *entryBB = Builder.GetInsertBlock();
llvm::BasicBlock *bodyBB = CGF.createBasicBlock("arrayinit.body");
CGF.EmitBlock(bodyBB);
llvm::PHINode *currentElement =
Builder.CreatePHI(element->getType(), 2, "arrayinit.cur");
currentElement->addIncoming(element, entryBB);
{
CodeGenFunction::RunCleanupsScope CleanupsScope(CGF);
LValue elementLV = CGF.MakeAddrLValue(
Address(currentElement, llvmElementType, elementAlign), elementType);
if (filler)
EmitInitializationToLValue(filler, elementLV);
else
EmitNullInitializationToLValue(elementLV);
}
llvm::Value *nextElement = Builder.CreateInBoundsGEP(
llvmElementType, currentElement, one, "arrayinit.next");
if (endOfInit.isValid()) Builder.CreateStore(nextElement, endOfInit);
llvm::Value *done = Builder.CreateICmpEQ(nextElement, end,
"arrayinit.done");
llvm::BasicBlock *endBB = CGF.createBasicBlock("arrayinit.end");
Builder.CreateCondBr(done, endBB, bodyBB);
currentElement->addIncoming(nextElement, Builder.GetInsertBlock());
CGF.EmitBlock(endBB);
}
if (dtorKind) CGF.DeactivateCleanupBlock(cleanup, cleanupDominator);
}
void AggExprEmitter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E){
Visit(E->getSubExpr());
}
void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
if (e->isUnique())
Visit(e->getSourceExpr());
else
EmitFinalDestCopy(e->getType(), CGF.getOrCreateOpaqueLValueMapping(e));
}
void
AggExprEmitter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
if (Dest.isPotentiallyAliased() &&
E->getType().isPODType(CGF.getContext())) {
EmitAggLoadOfLValue(E);
return;
}
AggValueSlot Slot = EnsureSlot(E->getType());
bool Destruct =
!CGF.getLangOpts().CPlusPlus && !Slot.isExternallyDestructed();
if (Destruct)
Slot.setExternallyDestructed();
CGF.EmitAggExpr(E->getInitializer(), Slot);
if (Destruct)
if (QualType::DestructionKind DtorKind = E->getType().isDestructedType())
CGF.pushLifetimeExtendedDestroy(
CGF.getCleanupKind(DtorKind), Slot.getAddress(), E->getType(),
CGF.getDestroyer(DtorKind), DtorKind & EHCleanup);
}
static Expr *findPeephole(Expr *op, CastKind kind, const ASTContext &ctx) {
op = op->IgnoreParenNoopCasts(ctx);
if (auto castE = dyn_cast<CastExpr>(op)) {
if (castE->getCastKind() == kind)
return castE->getSubExpr();
}
return nullptr;
}
void AggExprEmitter::VisitCastExpr(CastExpr *E) {
if (const auto *ECE = dyn_cast<ExplicitCastExpr>(E))
CGF.CGM.EmitExplicitCastExprType(ECE, &CGF);
switch (E->getCastKind()) {
case CK_Dynamic: {
assert(isa<CXXDynamicCastExpr>(E) && "CK_Dynamic without a dynamic_cast?");
LValue LV = CGF.EmitCheckedLValue(E->getSubExpr(),
CodeGenFunction::TCK_Load);
if (LV.isSimple())
CGF.EmitDynamicCast(LV.getAddress(CGF), cast<CXXDynamicCastExpr>(E));
else
CGF.CGM.ErrorUnsupported(E, "non-simple lvalue dynamic_cast");
if (!Dest.isIgnored())
CGF.CGM.ErrorUnsupported(E, "lvalue dynamic_cast with a destination");
break;
}
case CK_ToUnion: {
if (Dest.isIgnored()) {
CGF.EmitAnyExpr(E->getSubExpr(), AggValueSlot::ignored(),
true);
break;
}
QualType Ty = E->getSubExpr()->getType();
Address CastPtr =
Builder.CreateElementBitCast(Dest.getAddress(), CGF.ConvertType(Ty));
EmitInitializationToLValue(E->getSubExpr(),
CGF.MakeAddrLValue(CastPtr, Ty));
break;
}
case CK_LValueToRValueBitCast: {
if (Dest.isIgnored()) {
CGF.EmitAnyExpr(E->getSubExpr(), AggValueSlot::ignored(),
true);
break;
}
LValue SourceLV = CGF.EmitLValue(E->getSubExpr());
Address SourceAddress =
Builder.CreateElementBitCast(SourceLV.getAddress(CGF), CGF.Int8Ty);
Address DestAddress =
Builder.CreateElementBitCast(Dest.getAddress(), CGF.Int8Ty);
llvm::Value *SizeVal = llvm::ConstantInt::get(
CGF.SizeTy,
CGF.getContext().getTypeSizeInChars(E->getType()).getQuantity());
Builder.CreateMemCpy(DestAddress, SourceAddress, SizeVal);
break;
}
case CK_DerivedToBase:
case CK_BaseToDerived:
case CK_UncheckedDerivedToBase: {
llvm_unreachable("cannot perform hierarchy conversion in EmitAggExpr: "
"should have been unpacked before we got here");
}
case CK_NonAtomicToAtomic:
case CK_AtomicToNonAtomic: {
bool isToAtomic = (E->getCastKind() == CK_NonAtomicToAtomic);
QualType atomicType = E->getSubExpr()->getType();
QualType valueType = E->getType();
if (isToAtomic) std::swap(atomicType, valueType);
assert(atomicType->isAtomicType());
assert(CGF.getContext().hasSameUnqualifiedType(valueType,
atomicType->castAs<AtomicType>()->getValueType()));
if (Dest.isIgnored() || !CGF.CGM.isPaddedAtomicType(atomicType)) {
return Visit(E->getSubExpr());
}
CastKind peepholeTarget =
(isToAtomic ? CK_AtomicToNonAtomic : CK_NonAtomicToAtomic);
if (Expr *op =
findPeephole(E->getSubExpr(), peepholeTarget, CGF.getContext())) {
assert(CGF.getContext().hasSameUnqualifiedType(op->getType(),
E->getType()) &&
"peephole significantly changed types?");
return Visit(op);
}
if (isToAtomic) {
AggValueSlot valueDest = Dest;
if (!valueDest.isIgnored() && CGF.CGM.isPaddedAtomicType(atomicType)) {
if (!Dest.isZeroed())
CGF.EmitNullInitialization(Dest.getAddress(), atomicType);
Address valueAddr =
CGF.Builder.CreateStructGEP(valueDest.getAddress(), 0);
valueDest = AggValueSlot::forAddr(valueAddr,
valueDest.getQualifiers(),
valueDest.isExternallyDestructed(),
valueDest.requiresGCollection(),
valueDest.isPotentiallyAliased(),
AggValueSlot::DoesNotOverlap,
AggValueSlot::IsZeroed);
}
CGF.EmitAggExpr(E->getSubExpr(), valueDest);
return;
}
AggValueSlot atomicSlot =
CGF.CreateAggTemp(atomicType, "atomic-to-nonatomic.temp");
CGF.EmitAggExpr(E->getSubExpr(), atomicSlot);
Address valueAddr = Builder.CreateStructGEP(atomicSlot.getAddress(), 0);
RValue rvalue = RValue::getAggregate(valueAddr, atomicSlot.isVolatile());
return EmitFinalDestCopy(valueType, rvalue);
}
case CK_AddressSpaceConversion:
return Visit(E->getSubExpr());
case CK_LValueToRValue:
if (E->getSubExpr()->getType().isVolatileQualified()) {
bool Destruct =
!Dest.isExternallyDestructed() &&
E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct;
if (Destruct)
Dest.setExternallyDestructed();
EnsureDest(E->getType());
Visit(E->getSubExpr());
if (Destruct)
CGF.pushDestroy(QualType::DK_nontrivial_c_struct, Dest.getAddress(),
E->getType());
return;
}
LLVM_FALLTHROUGH;
case CK_NoOp:
case CK_UserDefinedConversion:
case CK_ConstructorConversion:
assert(CGF.getContext().hasSameUnqualifiedType(E->getSubExpr()->getType(),
E->getType()) &&
"Implicit cast types must be compatible");
Visit(E->getSubExpr());
break;
case CK_LValueBitCast:
llvm_unreachable("should not be emitting lvalue bitcast as rvalue");
case CK_Dependent:
case CK_BitCast:
case CK_ArrayToPointerDecay:
case CK_FunctionToPointerDecay:
case CK_NullToPointer:
case CK_NullToMemberPointer:
case CK_BaseToDerivedMemberPointer:
case CK_DerivedToBaseMemberPointer:
case CK_MemberPointerToBoolean:
case CK_ReinterpretMemberPointer:
case CK_IntegralToPointer:
case CK_PointerToIntegral:
case CK_PointerToBoolean:
case CK_ToVoid:
case CK_VectorSplat:
case CK_IntegralCast:
case CK_BooleanToSignedIntegral:
case CK_IntegralToBoolean:
case CK_IntegralToFloating:
case CK_FloatingToIntegral:
case CK_FloatingToBoolean:
case CK_FloatingCast:
case CK_CPointerToObjCPointerCast:
case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
case CK_ObjCObjectLValueCast:
case CK_FloatingRealToComplex:
case CK_FloatingComplexToReal:
case CK_FloatingComplexToBoolean:
case CK_FloatingComplexCast:
case CK_FloatingComplexToIntegralComplex:
case CK_IntegralRealToComplex:
case CK_IntegralComplexToReal:
case CK_IntegralComplexToBoolean:
case CK_IntegralComplexCast:
case CK_IntegralComplexToFloatingComplex:
case CK_ARCProduceObject:
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
case CK_CopyAndAutoreleaseBlockObject:
case CK_BuiltinFnToFnPtr:
case CK_ZeroToOCLOpaqueType:
case CK_MatrixCast:
case CK_IntToOCLSampler:
case CK_FloatingToFixedPoint:
case CK_FixedPointToFloating:
case CK_FixedPointCast:
case CK_FixedPointToBoolean:
case CK_FixedPointToIntegral:
case CK_IntegralToFixedPoint:
llvm_unreachable("cast kind invalid for aggregate types");
}
}
void AggExprEmitter::VisitCallExpr(const CallExpr *E) {
if (E->getCallReturnType(CGF.getContext())->isReferenceType()) {
EmitAggLoadOfLValue(E);
return;
}
withReturnValueSlot(E, [&](ReturnValueSlot Slot) {
return CGF.EmitCallExpr(E, Slot);
});
}
void AggExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
withReturnValueSlot(E, [&](ReturnValueSlot Slot) {
return CGF.EmitObjCMessageExpr(E, Slot);
});
}
void AggExprEmitter::VisitBinComma(const BinaryOperator *E) {
CGF.EmitIgnoredExpr(E->getLHS());
Visit(E->getRHS());
}
void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) {
CodeGenFunction::StmtExprEvaluation eval(CGF);
CGF.EmitCompoundStmt(*E->getSubStmt(), true, Dest);
}
enum CompareKind {
CK_Less,
CK_Greater,
CK_Equal,
};
static llvm::Value *EmitCompare(CGBuilderTy &Builder, CodeGenFunction &CGF,
const BinaryOperator *E, llvm::Value *LHS,
llvm::Value *RHS, CompareKind Kind,
const char *NameSuffix = "") {
QualType ArgTy = E->getLHS()->getType();
if (const ComplexType *CT = ArgTy->getAs<ComplexType>())
ArgTy = CT->getElementType();
if (const auto *MPT = ArgTy->getAs<MemberPointerType>()) {
assert(Kind == CK_Equal &&
"member pointers may only be compared for equality");
return CGF.CGM.getCXXABI().EmitMemberPointerComparison(
CGF, LHS, RHS, MPT, false);
}
struct CmpInstInfo {
const char *Name;
llvm::CmpInst::Predicate FCmp;
llvm::CmpInst::Predicate SCmp;
llvm::CmpInst::Predicate UCmp;
};
CmpInstInfo InstInfo = [&]() -> CmpInstInfo {
using FI = llvm::FCmpInst;
using II = llvm::ICmpInst;
switch (Kind) {
case CK_Less:
return {"cmp.lt", FI::FCMP_OLT, II::ICMP_SLT, II::ICMP_ULT};
case CK_Greater:
return {"cmp.gt", FI::FCMP_OGT, II::ICMP_SGT, II::ICMP_UGT};
case CK_Equal:
return {"cmp.eq", FI::FCMP_OEQ, II::ICMP_EQ, II::ICMP_EQ};
}
llvm_unreachable("Unrecognised CompareKind enum");
}();
if (ArgTy->hasFloatingRepresentation())
return Builder.CreateFCmp(InstInfo.FCmp, LHS, RHS,
llvm::Twine(InstInfo.Name) + NameSuffix);
if (ArgTy->isIntegralOrEnumerationType() || ArgTy->isPointerType()) {
auto Inst =
ArgTy->hasSignedIntegerRepresentation() ? InstInfo.SCmp : InstInfo.UCmp;
return Builder.CreateICmp(Inst, LHS, RHS,
llvm::Twine(InstInfo.Name) + NameSuffix);
}
llvm_unreachable("unsupported aggregate binary expression should have "
"already been handled");
}
void AggExprEmitter::VisitBinCmp(const BinaryOperator *E) {
using llvm::BasicBlock;
using llvm::PHINode;
using llvm::Value;
assert(CGF.getContext().hasSameType(E->getLHS()->getType(),
E->getRHS()->getType()));
const ComparisonCategoryInfo &CmpInfo =
CGF.getContext().CompCategories.getInfoForType(E->getType());
assert(CmpInfo.Record->isTriviallyCopyable() &&
"cannot copy non-trivially copyable aggregate");
QualType ArgTy = E->getLHS()->getType();
if (!ArgTy->isIntegralOrEnumerationType() && !ArgTy->isRealFloatingType() &&
!ArgTy->isNullPtrType() && !ArgTy->isPointerType() &&
!ArgTy->isMemberPointerType() && !ArgTy->isAnyComplexType()) {
return CGF.ErrorUnsupported(E, "aggregate three-way comparison");
}
bool IsComplex = ArgTy->isAnyComplexType();
auto EmitOperand = [&](Expr *E) -> std::pair<Value *, Value *> {
RValue RV = CGF.EmitAnyExpr(E);
if (RV.isScalar())
return {RV.getScalarVal(), nullptr};
if (RV.isAggregate())
return {RV.getAggregatePointer(), nullptr};
assert(RV.isComplex());
return RV.getComplexVal();
};
auto LHSValues = EmitOperand(E->getLHS()),
RHSValues = EmitOperand(E->getRHS());
auto EmitCmp = [&](CompareKind K) {
Value *Cmp = EmitCompare(Builder, CGF, E, LHSValues.first, RHSValues.first,
K, IsComplex ? ".r" : "");
if (!IsComplex)
return Cmp;
assert(K == CompareKind::CK_Equal);
Value *CmpImag = EmitCompare(Builder, CGF, E, LHSValues.second,
RHSValues.second, K, ".i");
return Builder.CreateAnd(Cmp, CmpImag, "and.eq");
};
auto EmitCmpRes = [&](const ComparisonCategoryInfo::ValueInfo *VInfo) {
return Builder.getInt(VInfo->getIntValue());
};
Value *Select;
if (ArgTy->isNullPtrType()) {
Select = EmitCmpRes(CmpInfo.getEqualOrEquiv());
} else if (!CmpInfo.isPartial()) {
Value *SelectOne =
Builder.CreateSelect(EmitCmp(CK_Less), EmitCmpRes(CmpInfo.getLess()),
EmitCmpRes(CmpInfo.getGreater()), "sel.lt");
Select = Builder.CreateSelect(EmitCmp(CK_Equal),
EmitCmpRes(CmpInfo.getEqualOrEquiv()),
SelectOne, "sel.eq");
} else {
Value *SelectEq = Builder.CreateSelect(
EmitCmp(CK_Equal), EmitCmpRes(CmpInfo.getEqualOrEquiv()),
EmitCmpRes(CmpInfo.getUnordered()), "sel.eq");
Value *SelectGT = Builder.CreateSelect(EmitCmp(CK_Greater),
EmitCmpRes(CmpInfo.getGreater()),
SelectEq, "sel.gt");
Select = Builder.CreateSelect(
EmitCmp(CK_Less), EmitCmpRes(CmpInfo.getLess()), SelectGT, "sel.lt");
}
EnsureDest(E->getType());
LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType());
LValue FieldLV = CGF.EmitLValueForFieldInitialization(
DestLV, *CmpInfo.Record->field_begin());
CGF.EmitStoreThroughLValue(RValue::get(Select), FieldLV, true);
}
void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) {
if (E->getOpcode() == BO_PtrMemD || E->getOpcode() == BO_PtrMemI)
VisitPointerToDataMemberBinaryOperator(E);
else
CGF.ErrorUnsupported(E, "aggregate binary expression");
}
void AggExprEmitter::VisitPointerToDataMemberBinaryOperator(
const BinaryOperator *E) {
LValue LV = CGF.EmitPointerToDataMemberBinaryExpr(E);
EmitFinalDestCopy(E->getType(), LV);
}
static bool isBlockVarRef(const Expr *E) {
E = E->IgnoreParens();
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
const VarDecl *var = dyn_cast<VarDecl>(DRE->getDecl());
return (var && var->hasAttr<BlocksAttr>());
}
if (const BinaryOperator *op = dyn_cast<BinaryOperator>(E)) {
if (op->isAssignmentOp() || op->isPtrMemOp())
return isBlockVarRef(op->getLHS());
if (op->getOpcode() == BO_Comma)
return isBlockVarRef(op->getRHS());
return false;
} else if (const AbstractConditionalOperator *op
= dyn_cast<AbstractConditionalOperator>(E)) {
return isBlockVarRef(op->getTrueExpr())
|| isBlockVarRef(op->getFalseExpr());
} else if (const OpaqueValueExpr *op
= dyn_cast<OpaqueValueExpr>(E)) {
if (const Expr *src = op->getSourceExpr())
return isBlockVarRef(src);
} else if (const CastExpr *cast = dyn_cast<CastExpr>(E)) {
if (cast->getCastKind() == CK_LValueToRValue)
return false;
return isBlockVarRef(cast->getSubExpr());
} else if (const UnaryOperator *uop = dyn_cast<UnaryOperator>(E)) {
return isBlockVarRef(uop->getSubExpr());
} else if (const MemberExpr *mem = dyn_cast<MemberExpr>(E)) {
return isBlockVarRef(mem->getBase());
} else if (const ArraySubscriptExpr *sub = dyn_cast<ArraySubscriptExpr>(E)) {
return isBlockVarRef(sub->getBase());
}
return false;
}
void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
assert(CGF.getContext().hasSameUnqualifiedType(E->getLHS()->getType(),
E->getRHS()->getType())
&& "Invalid assignment");
if (isBlockVarRef(E->getLHS()) &&
E->getRHS()->HasSideEffects(CGF.getContext())) {
EnsureDest(E->getRHS()->getType());
Visit(E->getRHS());
LValue LHS = CGF.EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
if (LHS.getType()->isAtomicType() ||
CGF.LValueIsSuitableForInlineAtomic(LHS)) {
CGF.EmitAtomicStore(Dest.asRValue(), LHS, false);
return;
}
EmitCopy(E->getLHS()->getType(),
AggValueSlot::forLValue(LHS, CGF, AggValueSlot::IsDestructed,
needsGC(E->getLHS()->getType()),
AggValueSlot::IsAliased,
AggValueSlot::MayOverlap),
Dest);
return;
}
LValue LHS = CGF.EmitLValue(E->getLHS());
if (LHS.getType()->isAtomicType() ||
CGF.LValueIsSuitableForInlineAtomic(LHS)) {
EnsureDest(E->getRHS()->getType());
Visit(E->getRHS());
CGF.EmitAtomicStore(Dest.asRValue(), LHS, false);
return;
}
AggValueSlot LHSSlot = AggValueSlot::forLValue(
LHS, CGF, AggValueSlot::IsDestructed, needsGC(E->getLHS()->getType()),
AggValueSlot::IsAliased, AggValueSlot::MayOverlap);
if (!LHSSlot.isVolatile() &&
CGF.hasVolatileMember(E->getLHS()->getType()))
LHSSlot.setVolatile(true);
CGF.EmitAggExpr(E->getRHS(), LHSSlot);
EmitFinalDestCopy(E->getType(), LHS);
if (!Dest.isIgnored() && !Dest.isExternallyDestructed() &&
E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct)
CGF.pushDestroy(QualType::DK_nontrivial_c_struct, Dest.getAddress(),
E->getType());
}
void AggExprEmitter::
VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true");
llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false");
llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
CodeGenFunction::OpaqueValueMapping binding(CGF, E);
CodeGenFunction::ConditionalEvaluation eval(CGF);
CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock,
CGF.getProfileCount(E));
bool isExternallyDestructed = Dest.isExternallyDestructed();
bool destructNonTrivialCStruct =
!isExternallyDestructed &&
E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct;
isExternallyDestructed |= destructNonTrivialCStruct;
Dest.setExternallyDestructed(isExternallyDestructed);
eval.begin(CGF);
CGF.EmitBlock(LHSBlock);
CGF.incrementProfileCounter(E);
Visit(E->getTrueExpr());
eval.end(CGF);
assert(CGF.HaveInsertPoint() && "expression evaluation ended with no IP!");
CGF.Builder.CreateBr(ContBlock);
Dest.setExternallyDestructed(isExternallyDestructed);
eval.begin(CGF);
CGF.EmitBlock(RHSBlock);
Visit(E->getFalseExpr());
eval.end(CGF);
if (destructNonTrivialCStruct)
CGF.pushDestroy(QualType::DK_nontrivial_c_struct, Dest.getAddress(),
E->getType());
CGF.EmitBlock(ContBlock);
}
void AggExprEmitter::VisitChooseExpr(const ChooseExpr *CE) {
Visit(CE->getChosenSubExpr());
}
void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
Address ArgValue = Address::invalid();
Address ArgPtr = CGF.EmitVAArg(VE, ArgValue);
if (!ArgPtr.isValid()) {
CGF.ErrorUnsupported(VE, "aggregate va_arg expression");
return;
}
EmitFinalDestCopy(VE->getType(), CGF.MakeAddrLValue(ArgPtr, VE->getType()));
}
void AggExprEmitter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
bool wasExternallyDestructed = Dest.isExternallyDestructed();
EnsureDest(E->getType());
Dest.setExternallyDestructed();
Visit(E->getSubExpr());
if (!wasExternallyDestructed)
CGF.EmitCXXTemporary(E->getTemporary(), E->getType(), Dest.getAddress());
}
void
AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) {
AggValueSlot Slot = EnsureSlot(E->getType());
CGF.EmitCXXConstructExpr(E, Slot);
}
void AggExprEmitter::VisitCXXInheritedCtorInitExpr(
const CXXInheritedCtorInitExpr *E) {
AggValueSlot Slot = EnsureSlot(E->getType());
CGF.EmitInheritedCXXConstructorCall(
E->getConstructor(), E->constructsVBase(), Slot.getAddress(),
E->inheritedFromVBase(), E);
}
void
AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) {
AggValueSlot Slot = EnsureSlot(E->getType());
LValue SlotLV = CGF.MakeAddrLValue(Slot.getAddress(), E->getType());
SmallVector<EHScopeStack::stable_iterator, 16> Cleanups;
llvm::Instruction *CleanupDominator = nullptr;
CXXRecordDecl::field_iterator CurField = E->getLambdaClass()->field_begin();
for (LambdaExpr::const_capture_init_iterator i = E->capture_init_begin(),
e = E->capture_init_end();
i != e; ++i, ++CurField) {
LValue LV = CGF.EmitLValueForFieldInitialization(SlotLV, *CurField);
if (CurField->hasCapturedVLAType()) {
CGF.EmitLambdaVLACapture(CurField->getCapturedVLAType(), LV);
continue;
}
EmitInitializationToLValue(*i, LV);
if (QualType::DestructionKind DtorKind =
CurField->getType().isDestructedType()) {
assert(LV.isSimple());
if (CGF.needsEHCleanup(DtorKind)) {
if (!CleanupDominator)
CleanupDominator = CGF.Builder.CreateAlignedLoad(
CGF.Int8Ty,
llvm::Constant::getNullValue(CGF.Int8PtrTy),
CharUnits::One());
CGF.pushDestroy(EHCleanup, LV.getAddress(CGF), CurField->getType(),
CGF.getDestroyer(DtorKind), false);
Cleanups.push_back(CGF.EHStack.stable_begin());
}
}
}
for (unsigned i = Cleanups.size(); i != 0; --i)
CGF.DeactivateCleanupBlock(Cleanups[i-1], CleanupDominator);
if (CleanupDominator)
CleanupDominator->eraseFromParent();
}
void AggExprEmitter::VisitExprWithCleanups(ExprWithCleanups *E) {
CodeGenFunction::RunCleanupsScope cleanups(CGF);
Visit(E->getSubExpr());
}
void AggExprEmitter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
QualType T = E->getType();
AggValueSlot Slot = EnsureSlot(T);
EmitNullInitializationToLValue(CGF.MakeAddrLValue(Slot.getAddress(), T));
}
void AggExprEmitter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
QualType T = E->getType();
AggValueSlot Slot = EnsureSlot(T);
EmitNullInitializationToLValue(CGF.MakeAddrLValue(Slot.getAddress(), T));
}
static bool castPreservesZero(const CastExpr *CE) {
switch (CE->getCastKind()) {
case CK_NoOp:
case CK_UserDefinedConversion:
case CK_ConstructorConversion:
case CK_BitCast:
case CK_ToUnion:
case CK_ToVoid:
case CK_BooleanToSignedIntegral:
case CK_FloatingCast:
case CK_FloatingComplexCast:
case CK_FloatingComplexToBoolean:
case CK_FloatingComplexToIntegralComplex:
case CK_FloatingComplexToReal:
case CK_FloatingRealToComplex:
case CK_FloatingToBoolean:
case CK_FloatingToIntegral:
case CK_IntegralCast:
case CK_IntegralComplexCast:
case CK_IntegralComplexToBoolean:
case CK_IntegralComplexToFloatingComplex:
case CK_IntegralComplexToReal:
case CK_IntegralRealToComplex:
case CK_IntegralToBoolean:
case CK_IntegralToFloating:
case CK_IntegralToPointer:
case CK_PointerToIntegral:
case CK_VectorSplat:
case CK_MatrixCast:
case CK_NonAtomicToAtomic:
case CK_AtomicToNonAtomic:
return true;
case CK_BaseToDerivedMemberPointer:
case CK_DerivedToBaseMemberPointer:
case CK_MemberPointerToBoolean:
case CK_NullToMemberPointer:
case CK_ReinterpretMemberPointer:
return false;
case CK_AnyPointerToBlockPointerCast:
case CK_BlockPointerToObjCPointerCast:
case CK_CPointerToObjCPointerCast:
case CK_ObjCObjectLValueCast:
case CK_IntToOCLSampler:
case CK_ZeroToOCLOpaqueType:
return false;
case CK_FixedPointCast:
case CK_FixedPointToBoolean:
case CK_FixedPointToFloating:
case CK_FixedPointToIntegral:
case CK_FloatingToFixedPoint:
case CK_IntegralToFixedPoint:
return false;
case CK_AddressSpaceConversion:
case CK_BaseToDerived:
case CK_DerivedToBase:
case CK_Dynamic:
case CK_NullToPointer:
case CK_PointerToBoolean:
return false;
case CK_ARCConsumeObject:
case CK_ARCExtendBlockObject:
case CK_ARCProduceObject:
case CK_ARCReclaimReturnedObject:
case CK_CopyAndAutoreleaseBlockObject:
case CK_ArrayToPointerDecay:
case CK_FunctionToPointerDecay:
case CK_BuiltinFnToFnPtr:
case CK_Dependent:
case CK_LValueBitCast:
case CK_LValueToRValue:
case CK_LValueToRValueBitCast:
case CK_UncheckedDerivedToBase:
return false;
}
llvm_unreachable("Unhandled clang::CastKind enum");
}
static bool isSimpleZero(const Expr *E, CodeGenFunction &CGF) {
E = E->IgnoreParens();
while (auto *CE = dyn_cast<CastExpr>(E)) {
if (!castPreservesZero(CE))
break;
E = CE->getSubExpr()->IgnoreParens();
}
if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(E))
return IL->getValue() == 0;
if (const FloatingLiteral *FL = dyn_cast<FloatingLiteral>(E))
return FL->getValue().isPosZero();
if ((isa<ImplicitValueInitExpr>(E) || isa<CXXScalarValueInitExpr>(E)) &&
CGF.getTypes().isZeroInitializable(E->getType()))
return true;
if (const CastExpr *ICE = dyn_cast<CastExpr>(E))
return ICE->getCastKind() == CK_NullToPointer &&
CGF.getTypes().isPointerZeroInitializable(E->getType()) &&
!E->HasSideEffects(CGF.getContext());
if (const CharacterLiteral *CL = dyn_cast<CharacterLiteral>(E))
return CL->getValue() == 0;
return false;
}
void
AggExprEmitter::EmitInitializationToLValue(Expr *E, LValue LV) {
QualType type = LV.getType();
if (Dest.isZeroed() && isSimpleZero(E, CGF)) {
return;
} else if (isa<ImplicitValueInitExpr>(E) || isa<CXXScalarValueInitExpr>(E)) {
return EmitNullInitializationToLValue(LV);
} else if (isa<NoInitExpr>(E)) {
return;
} else if (type->isReferenceType()) {
RValue RV = CGF.EmitReferenceBindingToExpr(E);
return CGF.EmitStoreThroughLValue(RV, LV);
}
switch (CGF.getEvaluationKind(type)) {
case TEK_Complex:
CGF.EmitComplexExprIntoLValue(E, LV, true);
return;
case TEK_Aggregate:
CGF.EmitAggExpr(
E, AggValueSlot::forLValue(LV, CGF, AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased,
AggValueSlot::MayOverlap, Dest.isZeroed()));
return;
case TEK_Scalar:
if (LV.isSimple()) {
CGF.EmitScalarInit(E, nullptr, LV, false);
} else {
CGF.EmitStoreThroughLValue(RValue::get(CGF.EmitScalarExpr(E)), LV);
}
return;
}
llvm_unreachable("bad evaluation kind");
}
void AggExprEmitter::EmitNullInitializationToLValue(LValue lv) {
QualType type = lv.getType();
if (Dest.isZeroed() && CGF.getTypes().isZeroInitializable(type))
return;
if (CGF.hasScalarEvaluationKind(type)) {
llvm::Value *null = CGF.CGM.EmitNullConstant(type);
if (lv.isBitField()) {
CGF.EmitStoreThroughBitfieldLValue(RValue::get(null), lv);
} else {
assert(lv.isSimple());
CGF.EmitStoreOfScalar(null, lv, true);
}
} else {
CGF.EmitNullInitialization(lv.getAddress(CGF), lv.getType());
}
}
void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
#if 0#endif
if (E->hadArrayRangeDesignator())
CGF.ErrorUnsupported(E, "GNU array range designator extension");
if (E->isTransparent())
return Visit(E->getInit(0));
AggValueSlot Dest = EnsureSlot(E->getType());
LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType());
if (E->getType()->isArrayType()) {
auto AType = cast<llvm::ArrayType>(Dest.getAddress().getElementType());
EmitArrayInit(Dest.getAddress(), AType, E->getType(), E);
return;
}
assert(E->getType()->isRecordType() && "Only support structs/unions here!");
unsigned NumInitElements = E->getNumInits();
RecordDecl *record = E->getType()->castAs<RecordType>()->getDecl();
SmallVector<EHScopeStack::stable_iterator, 16> cleanups;
llvm::Instruction *cleanupDominator = nullptr;
auto addCleanup = [&](const EHScopeStack::stable_iterator &cleanup) {
cleanups.push_back(cleanup);
if (!cleanupDominator) cleanupDominator = CGF.Builder.CreateAlignedLoad(
CGF.Int8Ty, llvm::Constant::getNullValue(CGF.Int8PtrTy),
CharUnits::One());
};
unsigned curInitIndex = 0;
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(record)) {
assert(E->getNumInits() >= CXXRD->getNumBases() &&
"missing initializer for base class");
for (auto &Base : CXXRD->bases()) {
assert(!Base.isVirtual() && "should not see vbases here");
auto *BaseRD = Base.getType()->getAsCXXRecordDecl();
Address V = CGF.GetAddressOfDirectBaseInCompleteClass(
Dest.getAddress(), CXXRD, BaseRD,
false);
AggValueSlot AggSlot = AggValueSlot::forAddr(
V, Qualifiers(),
AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased,
CGF.getOverlapForBaseInit(CXXRD, BaseRD, Base.isVirtual()));
CGF.EmitAggExpr(E->getInit(curInitIndex++), AggSlot);
if (QualType::DestructionKind dtorKind =
Base.getType().isDestructedType()) {
CGF.pushDestroy(dtorKind, V, Base.getType());
addCleanup(CGF.EHStack.stable_begin());
}
}
}
CodeGenFunction::FieldConstructionScope FCS(CGF, Dest.getAddress());
if (record->isUnion()) {
if (!E->getInitializedFieldInUnion()) {
#ifndef NDEBUG
for (const auto *Field : record->fields())
assert(Field->isUnnamedBitfield() && "Only unnamed bitfields allowed");
#endif
return;
}
FieldDecl *Field = E->getInitializedFieldInUnion();
LValue FieldLoc = CGF.EmitLValueForFieldInitialization(DestLV, Field);
if (NumInitElements) {
EmitInitializationToLValue(E->getInit(0), FieldLoc);
} else {
EmitNullInitializationToLValue(FieldLoc);
}
return;
}
for (const auto *field : record->fields()) {
if (field->getType()->isIncompleteArrayType())
break;
if (field->isUnnamedBitfield())
continue;
if (curInitIndex == NumInitElements && Dest.isZeroed() &&
CGF.getTypes().isZeroInitializable(E->getType()))
break;
LValue LV = CGF.EmitLValueForFieldInitialization(DestLV, field);
LV.setNonGC(true);
if (curInitIndex < NumInitElements) {
EmitInitializationToLValue(E->getInit(curInitIndex++), LV);
} else {
EmitNullInitializationToLValue(LV);
}
bool pushedCleanup = false;
if (QualType::DestructionKind dtorKind
= field->getType().isDestructedType()) {
assert(LV.isSimple());
if (CGF.needsEHCleanup(dtorKind)) {
CGF.pushDestroy(EHCleanup, LV.getAddress(CGF), field->getType(),
CGF.getDestroyer(dtorKind), false);
addCleanup(CGF.EHStack.stable_begin());
pushedCleanup = true;
}
}
if (!pushedCleanup && LV.isSimple())
if (llvm::GetElementPtrInst *GEP =
dyn_cast<llvm::GetElementPtrInst>(LV.getPointer(CGF)))
if (GEP->use_empty())
GEP->eraseFromParent();
}
assert((cleanupDominator || cleanups.empty()) &&
"Missing cleanupDominator before deactivating cleanup blocks");
for (unsigned i = cleanups.size(); i != 0; --i)
CGF.DeactivateCleanupBlock(cleanups[i-1], cleanupDominator);
if (cleanupDominator)
cleanupDominator->eraseFromParent();
}
void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E,
llvm::Value *outerBegin) {
CodeGenFunction::OpaqueValueMapping binding(CGF, E->getCommonExpr());
Address destPtr = EnsureSlot(E->getType()).getAddress();
uint64_t numElements = E->getArraySize().getZExtValue();
if (!numElements)
return;
llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0);
llvm::Value *indices[] = {zero, zero};
llvm::Value *begin = Builder.CreateInBoundsGEP(
destPtr.getElementType(), destPtr.getPointer(), indices,
"arrayinit.begin");
if (!outerBegin)
outerBegin = begin;
ArrayInitLoopExpr *InnerLoop = dyn_cast<ArrayInitLoopExpr>(E->getSubExpr());
QualType elementType =
CGF.getContext().getAsArrayType(E->getType())->getElementType();
CharUnits elementSize = CGF.getContext().getTypeSizeInChars(elementType);
CharUnits elementAlign =
destPtr.getAlignment().alignmentOfArrayElement(elementSize);
llvm::Type *llvmElementType = CGF.ConvertTypeForMem(elementType);
llvm::BasicBlock *entryBB = Builder.GetInsertBlock();
llvm::BasicBlock *bodyBB = CGF.createBasicBlock("arrayinit.body");
CGF.EmitBlock(bodyBB);
llvm::PHINode *index =
Builder.CreatePHI(zero->getType(), 2, "arrayinit.index");
index->addIncoming(zero, entryBB);
llvm::Value *element =
Builder.CreateInBoundsGEP(llvmElementType, begin, index);
QualType::DestructionKind dtorKind = elementType.isDestructedType();
EHScopeStack::stable_iterator cleanup;
if (CGF.needsEHCleanup(dtorKind) && !InnerLoop) {
if (outerBegin->getType() != element->getType())
outerBegin = Builder.CreateBitCast(outerBegin, element->getType());
CGF.pushRegularPartialArrayCleanup(outerBegin, element, elementType,
elementAlign,
CGF.getDestroyer(dtorKind));
cleanup = CGF.EHStack.stable_begin();
} else {
dtorKind = QualType::DK_none;
}
{
CodeGenFunction::RunCleanupsScope CleanupsScope(CGF);
CodeGenFunction::ArrayInitLoopExprScope Scope(CGF, index);
LValue elementLV = CGF.MakeAddrLValue(
Address(element, llvmElementType, elementAlign), elementType);
if (InnerLoop) {
auto elementSlot = AggValueSlot::forLValue(
elementLV, CGF, AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased,
AggValueSlot::DoesNotOverlap);
AggExprEmitter(CGF, elementSlot, false)
.VisitArrayInitLoopExpr(InnerLoop, outerBegin);
} else
EmitInitializationToLValue(E->getSubExpr(), elementLV);
}
llvm::Value *nextIndex = Builder.CreateNUWAdd(
index, llvm::ConstantInt::get(CGF.SizeTy, 1), "arrayinit.next");
index->addIncoming(nextIndex, Builder.GetInsertBlock());
llvm::Value *done = Builder.CreateICmpEQ(
nextIndex, llvm::ConstantInt::get(CGF.SizeTy, numElements),
"arrayinit.done");
llvm::BasicBlock *endBB = CGF.createBasicBlock("arrayinit.end");
Builder.CreateCondBr(done, endBB, bodyBB);
CGF.EmitBlock(endBB);
if (dtorKind)
CGF.DeactivateCleanupBlock(cleanup, index);
}
void AggExprEmitter::VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E) {
AggValueSlot Dest = EnsureSlot(E->getType());
LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType());
EmitInitializationToLValue(E->getBase(), DestLV);
VisitInitListExpr(E->getUpdater());
}
static CharUnits GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
E = MTE->getSubExpr();
E = E->IgnoreParenNoopCasts(CGF.getContext());
if (isSimpleZero(E, CGF)) return CharUnits::Zero();
const InitListExpr *ILE = dyn_cast<InitListExpr>(E);
while (ILE && ILE->isTransparent())
ILE = dyn_cast<InitListExpr>(ILE->getInit(0));
if (!ILE || !CGF.getTypes().isZeroInitializable(ILE->getType()))
return CGF.getContext().getTypeSizeInChars(E->getType());
if (const RecordType *RT = E->getType()->getAs<RecordType>()) {
if (!RT->isUnionType()) {
RecordDecl *SD = RT->getDecl();
CharUnits NumNonZeroBytes = CharUnits::Zero();
unsigned ILEElement = 0;
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(SD))
while (ILEElement != CXXRD->getNumBases())
NumNonZeroBytes +=
GetNumNonZeroBytesInInit(ILE->getInit(ILEElement++), CGF);
for (const auto *Field : SD->fields()) {
if (Field->getType()->isIncompleteArrayType() ||
ILEElement == ILE->getNumInits())
break;
if (Field->isUnnamedBitfield())
continue;
const Expr *E = ILE->getInit(ILEElement++);
if (Field->getType()->isReferenceType())
NumNonZeroBytes += CGF.getContext().toCharUnitsFromBits(
CGF.getTarget().getPointerWidth(0));
else
NumNonZeroBytes += GetNumNonZeroBytesInInit(E, CGF);
}
return NumNonZeroBytes;
}
}
CharUnits NumNonZeroBytes = CharUnits::Zero();
for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i)
NumNonZeroBytes += GetNumNonZeroBytesInInit(ILE->getInit(i), CGF);
return NumNonZeroBytes;
}
static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
CodeGenFunction &CGF) {
if (Slot.isZeroed() || Slot.isVolatile() || !Slot.getAddress().isValid())
return;
if (CGF.getLangOpts().CPlusPlus)
if (const RecordType *RT = CGF.getContext()
.getBaseElementType(E->getType())->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
if (RD->hasUserDeclaredConstructor())
return;
}
CharUnits Size = Slot.getPreferredSize(CGF.getContext(), E->getType());
if (Size <= CharUnits::fromQuantity(16))
return;
CharUnits NumNonZeroBytes = GetNumNonZeroBytesInInit(E, CGF);
if (NumNonZeroBytes*4 > Size)
return;
llvm::Constant *SizeVal = CGF.Builder.getInt64(Size.getQuantity());
Address Loc = Slot.getAddress();
Loc = CGF.Builder.CreateElementBitCast(Loc, CGF.Int8Ty);
CGF.Builder.CreateMemSet(Loc, CGF.Builder.getInt8(0), SizeVal, false);
Slot.setZeroed();
}
void CodeGenFunction::EmitAggExpr(const Expr *E, AggValueSlot Slot) {
assert(E && hasAggregateEvaluationKind(E->getType()) &&
"Invalid aggregate expression to emit");
assert((Slot.getAddress().isValid() || Slot.isIgnored()) &&
"slot has bits but no address");
CheckAggExprForMemSetUse(Slot, E, *this);
AggExprEmitter(*this, Slot, Slot.isIgnored()).Visit(const_cast<Expr*>(E));
}
LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) {
assert(hasAggregateEvaluationKind(E->getType()) && "Invalid argument!");
Address Temp = CreateMemTemp(E->getType());
LValue LV = MakeAddrLValue(Temp, E->getType());
EmitAggExpr(E, AggValueSlot::forLValue(
LV, *this, AggValueSlot::IsNotDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased, AggValueSlot::DoesNotOverlap));
return LV;
}
AggValueSlot::Overlap_t
CodeGenFunction::getOverlapForFieldInit(const FieldDecl *FD) {
if (!FD->hasAttr<NoUniqueAddressAttr>() || !FD->getType()->isRecordType())
return AggValueSlot::DoesNotOverlap;
const RecordDecl *ClassRD = FD->getParent();
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassRD);
if (Layout.getFieldOffset(FD->getFieldIndex()) +
getContext().getTypeSize(FD->getType()) <=
(uint64_t)getContext().toBits(Layout.getNonVirtualSize()))
return AggValueSlot::DoesNotOverlap;
return AggValueSlot::MayOverlap;
}
AggValueSlot::Overlap_t CodeGenFunction::getOverlapForBaseInit(
const CXXRecordDecl *RD, const CXXRecordDecl *BaseRD, bool IsVirtual) {
if (IsVirtual)
return AggValueSlot::MayOverlap;
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
if (Layout.getBaseClassOffset(BaseRD) +
getContext().getASTRecordLayout(BaseRD).getSize() <=
Layout.getNonVirtualSize())
return AggValueSlot::DoesNotOverlap;
return AggValueSlot::MayOverlap;
}
void CodeGenFunction::EmitAggregateCopy(LValue Dest, LValue Src, QualType Ty,
AggValueSlot::Overlap_t MayOverlap,
bool isVolatile) {
assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex");
Address DestPtr = Dest.getAddress(*this);
Address SrcPtr = Src.getAddress(*this);
if (getLangOpts().CPlusPlus) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl());
assert((Record->hasTrivialCopyConstructor() ||
Record->hasTrivialCopyAssignment() ||
Record->hasTrivialMoveConstructor() ||
Record->hasTrivialMoveAssignment() ||
Record->hasAttr<TrivialABIAttr>() || Record->isUnion()) &&
"Trying to aggregate-copy a type without a trivial copy/move "
"constructor or assignment operator");
if (Record->isEmpty())
return;
}
}
if (getLangOpts().CUDAIsDevice) {
if (Ty->isCUDADeviceBuiltinSurfaceType()) {
if (getTargetHooks().emitCUDADeviceBuiltinSurfaceDeviceCopy(*this, Dest,
Src))
return;
} else if (Ty->isCUDADeviceBuiltinTextureType()) {
if (getTargetHooks().emitCUDADeviceBuiltinTextureDeviceCopy(*this, Dest,
Src))
return;
}
}
TypeInfoChars TypeInfo;
if (MayOverlap)
TypeInfo = getContext().getTypeInfoDataSizeInChars(Ty);
else
TypeInfo = getContext().getTypeInfoInChars(Ty);
llvm::Value *SizeVal = nullptr;
if (TypeInfo.Width.isZero()) {
if (auto *VAT = dyn_cast_or_null<VariableArrayType>(
getContext().getAsArrayType(Ty))) {
QualType BaseEltTy;
SizeVal = emitArrayLength(VAT, BaseEltTy, DestPtr);
TypeInfo = getContext().getTypeInfoInChars(BaseEltTy);
assert(!TypeInfo.Width.isZero());
SizeVal = Builder.CreateNUWMul(
SizeVal,
llvm::ConstantInt::get(SizeTy, TypeInfo.Width.getQuantity()));
}
}
if (!SizeVal) {
SizeVal = llvm::ConstantInt::get(SizeTy, TypeInfo.Width.getQuantity());
}
DestPtr = Builder.CreateElementBitCast(DestPtr, Int8Ty);
SrcPtr = Builder.CreateElementBitCast(SrcPtr, Int8Ty);
if (CGM.getLangOpts().getGC() == LangOptions::NonGC) {
} else if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
RecordDecl *Record = RecordTy->getDecl();
if (Record->hasObjectMember()) {
CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr,
SizeVal);
return;
}
} else if (Ty->isArrayType()) {
QualType BaseType = getContext().getBaseElementType(Ty);
if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) {
if (RecordTy->getDecl()->hasObjectMember()) {
CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr,
SizeVal);
return;
}
}
}
auto Inst = Builder.CreateMemCpy(DestPtr, SrcPtr, SizeVal, isVolatile);
if (llvm::MDNode *TBAAStructTag = CGM.getTBAAStructInfo(Ty))
Inst->setMetadata(llvm::LLVMContext::MD_tbaa_struct, TBAAStructTag);
if (CGM.getCodeGenOpts().NewStructPathTBAA) {
TBAAAccessInfo TBAAInfo = CGM.mergeTBAAInfoForMemoryTransfer(
Dest.getTBAAInfo(), Src.getTBAAInfo());
CGM.DecorateInstructionWithTBAA(Inst, TBAAInfo);
}
}