diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1284,8 +1284,19 @@ return EmitVAArgExprLValue(cast(E)); case Expr::DeclRefExprClass: return EmitDeclRefLValue(cast(E)); - case Expr::ConstantExprClass: - return EmitLValue(cast(E)->getSubExpr()); + case Expr::ConstantExprClass: { + const ConstantExpr *CE = cast(E); + + if (CE->hasAPValueResult()) { + QualType T = getContext().getPointerType(CE->getType()); + llvm::Constant *C = EmitConstantValue(CE->getAPValueResult(), T); + ConstantAddress Addr(C, getContext().getTypeAlignInChars(T)); + LValueBaseInfo BI; + return LValue::MakeAddr(Addr, T, getContext(), BI, TBAAAccessInfo()); + } + + return EmitLValue(CE->getSubExpr()); + } case Expr::ParenExprClass: return EmitLValue(cast(E)->getSubExpr()); case Expr::GenericSelectionExprClass: diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -126,7 +126,17 @@ } void VisitConstantExpr(ConstantExpr *E) { - return Visit(E->getSubExpr()); + if (E->hasAPValueResult()) { + // Create a temporary for the value and store the constant. + llvm::Constant *Const = CGF.EmitConstantValue( + E->getAPValueResult(), E->getType()); + Address Addr = CGF.CreateMemTemp(E->getType()); + CGF.InitTempAlloca(Addr, Const); + RValue RV = RValue::getAggregate(Addr); + EmitFinalDestCopy(E->getType(), RV); + } else { + Visit(E->getSubExpr()); + } } // l-values. diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -1312,6 +1312,138 @@ llvm::Type *ConvertType(QualType T) { return CGM.getTypes().ConvertType(T); } + +public: + ConstantAddress EmitLValue(APValue::LValueBase LVBase) { + if (const ValueDecl *Decl = LVBase.dyn_cast()) { + if (Decl->hasAttr()) + return CGM.GetWeakRefReference(Decl); + if (const FunctionDecl *FD = dyn_cast(Decl)) + return ConstantAddress(CGM.GetAddrOfFunction(FD), CharUnits::One()); + if (const VarDecl* VD = dyn_cast(Decl)) { + // We can never refer to a variable with local storage. + if (!VD->hasLocalStorage()) { + CharUnits Align = CGM.getContext().getDeclAlign(VD); + if (VD->isFileVarDecl() || VD->hasExternalStorage()) + return ConstantAddress(CGM.GetAddrOfGlobalVar(VD), Align); + else if (VD->isLocalVarDecl()) { + auto Ptr = CGM.getOrCreateStaticVarDecl( + *VD, CGM.getLLVMLinkageVarDefinition(VD, /*isConstant=*/false)); + return ConstantAddress(Ptr, Align); + } + } + } + return ConstantAddress::invalid(); + } + + Expr *E = const_cast(LVBase.get()); + switch (E->getStmtClass()) { + default: break; + case Expr::CompoundLiteralExprClass: { + CompoundLiteralExpr *CLE = cast(E); + CharUnits Align = CGM.getContext().getTypeAlignInChars(E->getType()); + if (llvm::GlobalVariable *Addr = + CGM.getAddrOfConstantCompoundLiteralIfEmitted(CLE)) + return ConstantAddress(Addr, Align); + + llvm::Constant* C = CGM.EmitConstantExpr(CLE->getInitializer(), + CLE->getType(), Emitter.CGF); + // FIXME: "Leaked" on failure. + if (!C) return ConstantAddress::invalid(); + + auto GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), + E->getType().isConstant(CGM.getContext()), + llvm::GlobalValue::InternalLinkage, + C, ".compoundliteral", nullptr, + llvm::GlobalVariable::NotThreadLocal, + CGM.getContext().getTargetAddressSpace(E->getType())); + GV->setAlignment(Align.getAsAlign()); + CGM.setAddrOfConstantCompoundLiteral(CLE, GV); + return ConstantAddress(GV, Align); + } + case Expr::StringLiteralClass: + return CGM.GetAddrOfConstantStringFromLiteral(cast(E)); + case Expr::ObjCEncodeExprClass: + return CGM.GetAddrOfConstantStringFromObjCEncode(cast(E)); + case Expr::ObjCStringLiteralClass: { + ObjCStringLiteral* SL = cast(E); + ConstantAddress C = + CGM.getObjCRuntime().GenerateConstantString(SL->getString()); + return C.getElementBitCast(ConvertType(E->getType())); + } + case Expr::PredefinedExprClass: { + PredefinedExpr::IdentKind Kind = cast(E)->getIdentKind(); + if (Emitter.CGF) { + LValue Res = Emitter.CGF->EmitPredefinedLValue(cast(E)); + return cast(Res.getAddress(*Emitter.CGF)); + } else if (Kind == PredefinedExpr::PrettyFunction) { + return CGM.GetAddrOfConstantCString("top level", ".tmp"); + } + + return CGM.GetAddrOfConstantCString("", ".tmp"); + } + case Expr::AddrLabelExprClass: { + assert(Emitter.CGF && "Invalid address of label expression outside function."); + llvm::Constant *Ptr = + Emitter.CGF->GetAddrOfLabel(cast(E)->getLabel()); + Ptr = llvm::ConstantExpr::getBitCast(Ptr, ConvertType(E->getType())); + return ConstantAddress(Ptr, CharUnits::One()); + } + case Expr::CallExprClass: { + CallExpr* CE = cast(E); + unsigned builtin = CE->getBuiltinCallee(); + if (builtin != + Builtin::BI__builtin___CFStringMakeConstantString && + builtin != + Builtin::BI__builtin___NSStringMakeConstantString) + break; + const Expr *Arg = CE->getArg(0)->IgnoreParenCasts(); + const StringLiteral *Literal = cast(Arg); + if (builtin == + Builtin::BI__builtin___NSStringMakeConstantString) { + return CGM.getObjCRuntime().GenerateConstantString(Literal); + } + // FIXME: need to deal with UCN conversion issues. + return CGM.GetAddrOfConstantCFString(Literal); + } + case Expr::BlockExprClass: { + StringRef FunctionName; + if (Emitter.CGF) + FunctionName = Emitter.CGF->CurFn->getName(); + else + FunctionName = "global"; + + // This is not really an l-value. + llvm::Constant *Ptr = + CGM.GetAddrOfGlobalBlock(cast(E), FunctionName); + return ConstantAddress(Ptr, CGM.getPointerAlign()); + } + case Expr::CXXTypeidExprClass: { + CXXTypeidExpr *Typeid = cast(E); + QualType T; + if (Typeid->isTypeOperand()) + T = Typeid->getTypeOperand(CGM.getContext()); + else + T = Typeid->getExprOperand()->getType(); + return ConstantAddress(CGM.GetAddrOfRTTIDescriptor(T), + CGM.getPointerAlign()); + } + case Expr::CXXUuidofExprClass: { + return CGM.GetAddrOfUuidDescriptor(cast(E)); + } + case Expr::MaterializeTemporaryExprClass: { + MaterializeTemporaryExpr *MTE = cast(E); + assert(MTE->getStorageDuration() == SD_Static); + SmallVector CommaLHSs; + SmallVector Adjustments; + const Expr *Inner = MTE->getSubExpr() + ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments); + return CGM.GetAddrOfGlobalTemporary(MTE, Inner); + } + } + + return ConstantAddress::invalid(); + } }; } // end anonymous namespace. @@ -1708,6 +1840,263 @@ return getTargetCodeGenInfo().getNullPointer(*this, T, QT); } +llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, + QualType DestType, + CodeGenFunction *CGF) { + Expr::EvalResult Result; + bool Success = false; + + if (DestType->isReferenceType()) + Success = E->EvaluateAsLValue(Result, Context); + else + Success = E->EvaluateAsRValue(Result, Context); + + llvm::Constant *C = nullptr; + if (Success && !Result.HasSideEffects) + C = EmitConstantValue(Result.Val, DestType, CGF); + else { + ConstantEmitter Emitter(*this, CGF); + // FIXME: Is this a DestType? + C = ConstExprEmitter(Emitter).Visit(const_cast(E), DestType); + } + + if (C && C->getType()->isIntegerTy(1)) { + llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType()); + C = llvm::ConstantExpr::getZExt(C, BoolTy); + } + return C; +} + +llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value, + QualType DestType, + CodeGenFunction *CGF) { + // For an _Atomic-qualified constant, we may need to add tail padding. + if (auto *AT = DestType->getAs()) { + QualType InnerType = AT->getValueType(); + auto *Inner = EmitConstantValue(Value, InnerType, CGF); + + uint64_t InnerSize = Context.getTypeSize(InnerType); + uint64_t OuterSize = Context.getTypeSize(DestType); + if (InnerSize == OuterSize) + return Inner; + + assert(InnerSize < OuterSize && "emitted over-large constant for atomic"); + llvm::Constant *Elts[] = { + Inner, + llvm::ConstantAggregateZero::get( + llvm::ArrayType::get(Int8Ty, (OuterSize - InnerSize) / 8)) + }; + return llvm::ConstantStruct::getAnon(Elts); + } + + switch (Value.getKind()) { + case APValue::None: + case APValue::Indeterminate: + case APValue::FixedPoint: + llvm_unreachable("Unsupported value type."); + case APValue::LValue: { + llvm::Type *DestTy = getTypes().ConvertTypeForMem(DestType); + llvm::Constant *Offset = + llvm::ConstantInt::get(Int64Ty, Value.getLValueOffset().getQuantity()); + + llvm::Constant *C = nullptr; + + if (APValue::LValueBase LVBase = Value.getLValueBase()) { + // An array can be represented as an lvalue referring to the base. + if (isa(DestTy)) { + assert(Offset->isNullValue() && "offset on array initializer"); + ConstantEmitter Emitter(*this, CGF); + /// FIXME: Is this the right ParamTy? + return ConstExprEmitter(Emitter).Visit( + const_cast(LVBase.get()), DestType); + } + + ConstantEmitter Emitter(*this, CGF); + C = ConstExprEmitter(Emitter).EmitLValue(LVBase).getPointer(); + + // Apply offset if necessary. + if (!Offset->isNullValue()) { + unsigned AS = C->getType()->getPointerAddressSpace(); + llvm::Type *CharPtrTy = Int8Ty->getPointerTo(AS); + llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(C, CharPtrTy); + Casted = llvm::ConstantExpr::getGetElementPtr(Int8Ty, Casted, Offset); + C = llvm::ConstantExpr::getPointerCast(Casted, C->getType()); + } + + // Convert to the appropriate type; this could be an lvalue for + // an integer. + if (isa(DestTy)) + return llvm::ConstantExpr::getPointerCast(C, DestTy); + + return llvm::ConstantExpr::getPtrToInt(C, DestTy); + } else { + C = Offset; + + // Convert to the appropriate type; this could be an lvalue for + // an integer. + if (auto PT = dyn_cast(DestTy)) { + if (Value.isNullPointer()) + return getNullPointer(PT, DestType); + // Convert the integer to a pointer-sized integer before converting it + // to a pointer. + C = llvm::ConstantExpr::getIntegerCast( + C, getDataLayout().getIntPtrType(DestTy), + /*isSigned=*/false); + return llvm::ConstantExpr::getIntToPtr(C, DestTy); + } + + // If the types don't match this should only be a truncate. + if (C->getType() != DestTy) + return llvm::ConstantExpr::getTrunc(C, DestTy); + + return C; + } + } + case APValue::Int: + return llvm::ConstantInt::get(VMContext, Value.getInt()); + case APValue::ComplexInt: { + llvm::Constant *Complex[2]; + + Complex[0] = llvm::ConstantInt::get(VMContext, + Value.getComplexIntReal()); + Complex[1] = llvm::ConstantInt::get(VMContext, + Value.getComplexIntImag()); + + // FIXME: the target may want to specify that this is packed. + llvm::StructType *STy = + llvm::StructType::get(Complex[0]->getType(), Complex[1]->getType()); + return llvm::ConstantStruct::get(STy, Complex); + } + case APValue::Float: { + const llvm::APFloat &Init = Value.getFloat(); + if (&Init.getSemantics() == &llvm::APFloat::IEEEhalf() && + !Context.getLangOpts().NativeHalfType && + !Context.getLangOpts().HalfArgsAndReturns) + return llvm::ConstantInt::get(VMContext, Init.bitcastToAPInt()); + else + return llvm::ConstantFP::get(VMContext, Init); + } + case APValue::ComplexFloat: { + llvm::Constant *Complex[2]; + + Complex[0] = llvm::ConstantFP::get(VMContext, + Value.getComplexFloatReal()); + Complex[1] = llvm::ConstantFP::get(VMContext, + Value.getComplexFloatImag()); + + // FIXME: the target may want to specify that this is packed. + llvm::StructType *STy = + llvm::StructType::get(Complex[0]->getType(), Complex[1]->getType()); + return llvm::ConstantStruct::get(STy, Complex); + } + case APValue::Vector: { + unsigned NumElts = Value.getVectorLength(); + SmallVector Inits(NumElts); + + for (unsigned I = 0; I != NumElts; ++I) { + const APValue &Elt = Value.getVectorElt(I); + if (Elt.isInt()) + Inits[I] = llvm::ConstantInt::get(VMContext, Elt.getInt()); + else if (Elt.isFloat()) + Inits[I] = llvm::ConstantFP::get(VMContext, Elt.getFloat()); + else + llvm_unreachable("unsupported vector element type"); + } + return llvm::ConstantVector::get(Inits); + } + case APValue::AddrLabelDiff: { + const AddrLabelExpr *LHSExpr = Value.getAddrLabelDiffLHS(); + const AddrLabelExpr *RHSExpr = Value.getAddrLabelDiffRHS(); + llvm::Constant *LHS = EmitConstantExpr(LHSExpr, LHSExpr->getType(), CGF); + llvm::Constant *RHS = EmitConstantExpr(RHSExpr, RHSExpr->getType(), CGF); + + // Compute difference + llvm::Type *ResultType = getTypes().ConvertType(DestType); + LHS = llvm::ConstantExpr::getPtrToInt(LHS, IntPtrTy); + RHS = llvm::ConstantExpr::getPtrToInt(RHS, IntPtrTy); + llvm::Constant *AddrLabelDiff = llvm::ConstantExpr::getSub(LHS, RHS); + + // LLVM is a bit sensitive about the exact format of the + // address-of-label difference; make sure to truncate after + // the subtraction. + return llvm::ConstantExpr::getTruncOrBitCast(AddrLabelDiff, ResultType); + } + case APValue::Struct: + case APValue::Union: + { + ConstantEmitter Emitter(*this, CGF); + return ConstStructBuilder::BuildStruct(Emitter, Value, DestType); + } + case APValue::Array: { + const ArrayType *CAT = Context.getAsArrayType(DestType); + unsigned NumElements = Value.getArraySize(); + unsigned NumInitElts = Value.getArrayInitializedElts(); + + // Emit array filler, if there is one. + llvm::Constant *Filler = nullptr; + if (Value.hasArrayFiller()) + Filler = EmitConstantValueForMemory(Value.getArrayFiller(), + CAT->getElementType(), CGF); + + // Emit initializer elements. + llvm::Type *CommonElementType = + 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); + } + + std::vector Elts; + Elts.reserve(NumElements); + for (unsigned I = 0; I < NumElements; ++I) { + llvm::Constant *C = Filler; + if (I < NumInitElts) + C = EmitConstantValueForMemory(Value.getArrayInitializedElt(I), + CAT->getElementType(), CGF); + else + assert(Filler && "Missing filler for implicit elements of initializer"); + if (I == 0) + CommonElementType = C->getType(); + else if (C->getType() != CommonElementType) + CommonElementType = nullptr; + Elts.push_back(C); + } + + if (!CommonElementType) { + // FIXME: Try to avoid packing the array + std::vector 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(VMContext, Types, true); + return llvm::ConstantStruct::get(SType, Elts); + } + + llvm::ArrayType *AType = + llvm::ArrayType::get(CommonElementType, NumElements); + return llvm::ConstantArray::get(AType, Elts); + } + case APValue::MemberPointer: + return getCXXABI().EmitMemberPointer(Value, DestType); + } + llvm_unreachable("Unknown APValue kind"); +} + +llvm::Constant * +CodeGenModule::EmitConstantValueForMemory(const APValue &Value, + QualType DestType, + CodeGenFunction *CGF) { + llvm::Constant *C = EmitConstantValue(Value, DestType, CGF); + if (C->getType()->isIntegerTy(1)) { + llvm::Type *BoolTy = getTypes().ConvertTypeForMem(DestType); + C = llvm::ConstantExpr::getZExt(C, BoolTy); + } + return C; +} + namespace { /// A struct which can be used to peephole certain kinds of finalization /// that normally happen during l-value emission. diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -433,7 +433,12 @@ Value *VisitExpr(Expr *S); Value *VisitConstantExpr(ConstantExpr *E) { - return Visit(E->getSubExpr()); + if (E->hasAPValueResult()) { + assert(!E->getType()->isVoidType()); + return CGF.EmitConstantValue(E->getAPValueResult(), E->getType()); + } else { + return Visit(E->getSubExpr()); + } } Value *VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr()); diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -1089,8 +1089,13 @@ // statements following block literals with non-trivial cleanups. RunCleanupsScope cleanupScope(*this); if (const FullExpr *fe = dyn_cast_or_null(RV)) { - enterFullExpression(fe); - RV = fe->getSubExpr(); + // Constant expressions will emit their cached APValues, so + // we don't want to handle this here, as it will unwrap them, + // preventing the cached results from being used. + if (!isa(fe)) { + enterFullExpression(fe); + RV = fe->getSubExpr(); + } } // FIXME: Clean this up by using an LValue for ReturnTemp, diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -2289,6 +2289,8 @@ TBAAAccessInfo *TBAAInfo = nullptr); LValue EmitLoadOfPointerLValue(Address Ptr, const PointerType *PtrTy); + llvm::Constant *EmitConstantValue(const APValue &Value, QualType DestType); + /// CreateTempAlloca - This creates an alloca and inserts it into the entry /// block if \p ArraySize is nullptr, otherwise inserts it at the current /// insertion point of the builder. The caller is responsible for setting an diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2529,3 +2529,9 @@ return llvm::DebugLoc(); } + + +llvm::Constant *CodeGenFunction::EmitConstantValue(const APValue& Value, + QualType DestType) { + return CGM.EmitConstantValue(Value, DestType, this); +} diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1390,6 +1390,21 @@ /// \param QT is the clang QualType of the null pointer. llvm::Constant *getNullPointer(llvm::PointerType *T, QualType QT); + /// Try to emit the given expression as a constant; returns 0 if the + /// expression cannot be emitted as a constant. + llvm::Constant *EmitConstantExpr(const Expr *E, QualType DestType, + CodeGenFunction *CGF = nullptr); + + /// Emit the given constant value as a constant, in the type's scalar + /// representation. + llvm::Constant *EmitConstantValue(const APValue &Value, QualType DestType, + CodeGenFunction *CGF = nullptr); + + /// Emit the given constant value as a constant, in the type's memory + /// representation. + llvm::Constant *EmitConstantValueForMemory(const APValue &Value, + QualType DestType, + CodeGenFunction *CGF = nullptr); private: llvm::Constant *GetOrCreateLLVMFunction( StringRef MangledName, llvm::Type *Ty, GlobalDecl D, bool ForVTable,