Preserve exceptions information during calls code generation.

This patch changes the generation of CGFunctionInfo to contain 
the FunctionProtoType if it is available. This enables the code 
generation for call instructions to look into this type for 
exception information and therefore generate better quality 
IR - it will not create invoke instructions for functions that 
are know not to throw.

llvm-svn: 253926
This commit is contained in:
Samuel Antao 2015-11-23 22:04:44 +00:00
parent 2f16f25391
commit 798f11cfb7
10 changed files with 143 additions and 41 deletions

View File

@ -509,6 +509,29 @@ public:
}
};
/// CGCalleeInfo - Class to encapsulate the information about a callee to be
/// used during the generation of call/invoke instructions.
class CGCalleeInfo {
/// \brief The function proto type of the callee.
const FunctionProtoType *CalleeProtoTy;
/// \brief The function declaration of the callee.
const Decl *CalleeDecl;
public:
explicit CGCalleeInfo() : CalleeProtoTy(nullptr), CalleeDecl(nullptr) {}
CGCalleeInfo(const FunctionProtoType *calleeProtoTy, const Decl *calleeDecl)
: CalleeProtoTy(calleeProtoTy), CalleeDecl(calleeDecl) {}
CGCalleeInfo(const FunctionProtoType *calleeProtoTy)
: CalleeProtoTy(calleeProtoTy), CalleeDecl(nullptr) {}
CGCalleeInfo(const Decl *calleeDecl)
: CalleeProtoTy(nullptr), CalleeDecl(calleeDecl) {}
const FunctionProtoType *getCalleeFunctionProtoType() {
return CalleeProtoTy;
}
const Decl *getCalleeDecl() { return CalleeDecl; }
};
} // end namespace CodeGen
} // end namespace clang

View File

@ -1391,8 +1391,19 @@ llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) {
return GetFunctionType(*Info);
}
static void AddAttributesFromFunctionProtoType(ASTContext &Ctx,
llvm::AttrBuilder &FuncAttrs,
const FunctionProtoType *FPT) {
if (!FPT)
return;
if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) &&
FPT->isNothrow(Ctx))
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
}
void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
const Decl *TargetDecl,
CGCalleeInfo CalleeInfo,
AttributeListType &PAL,
unsigned &CallingConv,
bool AttrOnCallSite) {
@ -1405,6 +1416,13 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
if (FI.isNoReturn())
FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
// If we have information about the function prototype, we can learn
// attributes form there.
AddAttributesFromFunctionProtoType(getContext(), FuncAttrs,
CalleeInfo.getCalleeFunctionProtoType());
const Decl *TargetDecl = CalleeInfo.getCalleeDecl();
// FIXME: handle sseregparm someday...
if (TargetDecl) {
if (TargetDecl->hasAttr<ReturnsTwiceAttr>())
@ -1417,10 +1435,8 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate);
if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
const FunctionProtoType *FPT = Fn->getType()->getAs<FunctionProtoType>();
if (FPT && !isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) &&
FPT->isNothrow(getContext()))
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
AddAttributesFromFunctionProtoType(
getContext(), FuncAttrs, Fn->getType()->getAs<FunctionProtoType>());
// Don't use [[noreturn]] or _Noreturn for a call to a virtual function.
// These attributes are not inherited by overloads.
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn);
@ -3077,7 +3093,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
const CallArgList &CallArgs,
const Decl *TargetDecl,
CGCalleeInfo CalleeInfo,
llvm::Instruction **callOrInvoke) {
// FIXME: We no longer need the types from CallArgs; lift up and simplify.
@ -3406,8 +3422,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
unsigned CallingConv;
CodeGen::AttributeListType AttributeList;
CGM.ConstructAttributeList(CallInfo, TargetDecl, AttributeList,
CallingConv, true);
CGM.ConstructAttributeList(CallInfo, CalleeInfo, AttributeList, CallingConv,
true);
llvm::AttributeSet Attrs = llvm::AttributeSet::get(getLLVMContext(),
AttributeList);
@ -3487,9 +3503,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// lexical order, so deactivate it and run it manually here.
CallArgs.freeArgumentMemory(*this);
if (llvm::CallInst *Call = dyn_cast<llvm::CallInst>(CI))
if (llvm::CallInst *Call = dyn_cast<llvm::CallInst>(CI)) {
const Decl *TargetDecl = CalleeInfo.getCalleeDecl();
if (TargetDecl && TargetDecl->hasAttr<NotTailCalledAttr>())
Call->setTailCallKind(llvm::CallInst::TCK_NoTail);
}
RValue Ret = [&] {
switch (RetAI.getKind()) {
@ -3562,6 +3580,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm_unreachable("Unhandled ABIArgInfo::Kind");
} ();
const Decl *TargetDecl = CalleeInfo.getCalleeDecl();
if (Ret.isScalar() && TargetDecl) {
if (const auto *AA = TargetDecl->getAttr<AssumeAlignedAttr>()) {
llvm::Value *OffsetValue = nullptr;

View File

@ -3741,12 +3741,21 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) {
RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
const CallExpr *E, ReturnValueSlot ReturnValue,
const Decl *TargetDecl, llvm::Value *Chain) {
CGCalleeInfo CalleeInfo, llvm::Value *Chain) {
// Get the actual function type. The callee type will always be a pointer to
// function type or a block pointer type.
assert(CalleeType->isFunctionPointerType() &&
"Call must have function pointer type!");
// Preserve the non-canonical function type because things like exception
// specifications disappear in the canonical type. That information is useful
// to drive the generation of more accurate code for this call later on.
const FunctionProtoType *NonCanonicalFTP = CalleeType->getAs<PointerType>()
->getPointeeType()
->getAs<FunctionProtoType>();
const Decl *TargetDecl = CalleeInfo.getCalleeDecl();
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl))
// We can only guarantee that a function is called from the correct
// context/function based on the appropriate target attributes,
@ -3867,7 +3876,8 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
Callee = Builder.CreateBitCast(Callee, CalleeTy, "callee.knr.cast");
}
return EmitCall(FnInfo, Callee, ReturnValue, Args, TargetDecl);
return EmitCall(FnInfo, Callee, ReturnValue, Args,
CGCalleeInfo(NonCanonicalFTP, TargetDecl));
}
LValue CodeGenFunction::

View File

@ -585,19 +585,25 @@ ComplexPairTy ComplexExprEmitter::EmitComplexBinOpLibCall(StringRef LibCallName,
// We *must* use the full CG function call building logic here because the
// complex type has special ABI handling. We also should not forget about
// special calling convention which may be used for compiler builtins.
const CGFunctionInfo &FuncInfo =
CGF.CGM.getTypes().arrangeFreeFunctionCall(
Op.Ty, Args, FunctionType::ExtInfo(/* No CC here - will be added later */),
RequiredArgs::All);
// We create a function qualified type to state that this call does not have
// any exceptions.
FunctionProtoType::ExtProtoInfo EPI;
EPI = EPI.withExceptionSpec(
FunctionProtoType::ExceptionSpecInfo(EST_BasicNoexcept));
SmallVector<QualType, 4> ArgsQTys(
4, Op.Ty->castAs<ComplexType>()->getElementType());
QualType FQTy = CGF.getContext().getFunctionType(Op.Ty, ArgsQTys, EPI);
const CGFunctionInfo &FuncInfo = CGF.CGM.getTypes().arrangeFreeFunctionCall(
Args, cast<FunctionType>(FQTy.getTypePtr()), false);
llvm::FunctionType *FTy = CGF.CGM.getTypes().GetFunctionType(FuncInfo);
llvm::Constant *Func = CGF.CGM.CreateBuiltinFunction(FTy, LibCallName);
llvm::Instruction *Call;
RValue Res = CGF.EmitCall(FuncInfo, Func, ReturnValueSlot(), Args,
nullptr, &Call);
FQTy->getAs<FunctionProtoType>(), &Call);
cast<llvm::CallInst>(Call)->setCallingConv(CGF.CGM.getBuiltinCC());
cast<llvm::CallInst>(Call)->setDoesNotThrow();
return Res.getComplexVal();
}

View File

@ -949,11 +949,11 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
// FIXME: We shouldn't need to get the function info here, the
// runtime already should have computed it to build the function.
llvm::Instruction *CallInstruction;
RValue RV = EmitCall(getTypes().arrangeFreeFunctionCall(propType, args,
FunctionType::ExtInfo(),
RequiredArgs::All),
getPropertyFn, ReturnValueSlot(), args, nullptr,
&CallInstruction);
RValue RV = EmitCall(
getTypes().arrangeFreeFunctionCall(
propType, args, FunctionType::ExtInfo(), RequiredArgs::All),
getPropertyFn, ReturnValueSlot(), args, CGCalleeInfo(),
&CallInstruction);
if (llvm::CallInst *call = dyn_cast<llvm::CallInst>(CallInstruction))
call->setTailCall();

View File

@ -1327,8 +1327,8 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD);
llvm::Instruction *call;
RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs, nullptr,
&call);
RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs,
CGCalleeInfo(), &call);
call->setMetadata(msgSendMDKind, node);
return msgRet;
}
@ -1440,8 +1440,8 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
imp = EnforceType(Builder, imp, MSI.MessengerType);
llvm::Instruction *call;
RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs, nullptr,
&call);
RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs,
CGCalleeInfo(), &call);
call->setMetadata(msgSendMDKind, node);

View File

@ -1947,7 +1947,7 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
llvm::Instruction *CallSite;
Fn = llvm::ConstantExpr::getBitCast(Fn, MSI.MessengerType);
RValue rvalue = CGF.EmitCall(MSI.CallInfo, Fn, Return, ActualArgs,
nullptr, &CallSite);
CGCalleeInfo(), &CallSite);
// Mark the call as noreturn if the method is marked noreturn and the
// receiver cannot be null.

View File

@ -2624,16 +2624,14 @@ public:
///
/// \param TargetDecl - If given, the decl of the function in a direct call;
/// used to set attributes on the call (noreturn, etc.).
RValue EmitCall(const CGFunctionInfo &FnInfo,
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
const CallArgList &Args,
const Decl *TargetDecl = nullptr,
RValue EmitCall(const CGFunctionInfo &FnInfo, llvm::Value *Callee,
ReturnValueSlot ReturnValue, const CallArgList &Args,
CGCalleeInfo CalleeInfo = CGCalleeInfo(),
llvm::Instruction **callOrInvoke = nullptr);
RValue EmitCall(QualType FnType, llvm::Value *Callee, const CallExpr *E,
ReturnValueSlot ReturnValue,
const Decl *TargetDecl = nullptr,
CGCalleeInfo CalleeInfo = CGCalleeInfo(),
llvm::Value *Chain = nullptr);
RValue EmitCallExpr(const CallExpr *E,
ReturnValueSlot ReturnValue = ReturnValueSlot());

View File

@ -968,16 +968,14 @@ public:
/// function type.
///
/// \param Info - The function type information.
/// \param TargetDecl - The decl these attributes are being constructed
/// for. If supplied the attributes applied to this decl may contribute to the
/// function attributes and calling convention.
/// \param CalleeInfo - The callee information these attributes are being
/// constructed for. If valid, the attributes applied to this decl may
/// contribute to the function attributes and calling convention.
/// \param PAL [out] - On return, the attribute list to use.
/// \param CallingConv [out] - On return, the LLVM calling convention to use.
void ConstructAttributeList(const CGFunctionInfo &Info,
const Decl *TargetDecl,
AttributeListType &PAL,
unsigned &CallingConv,
bool AttrOnCallSite);
CGCalleeInfo CalleeInfo, AttributeListType &PAL,
unsigned &CallingConv, bool AttrOnCallSite);
// Fills in the supplied string map with the set of target features for the
// passed in function.

View File

@ -0,0 +1,47 @@
// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -std=c++11 -fopenmp -fexceptions -fcxx-exceptions -O0 -emit-llvm %s -o - | FileCheck %s
// Check that regions that install a terminate scope in the exception stack can
// correctly generate complex arithmetic.
// CHECK-LABEL: ffcomplex
void ffcomplex (int a) {
double _Complex dc = (double)a;
// CHECK: call { double, double } @__muldc3(double %{{.+}}, double %{{.+}}, double %{{.+}}, double %{{.+}})
dc *= dc;
// CHECK: call {{.+}} @__kmpc_fork_call({{.+}} [[REGNAME1:@.*]] to void (i32*, i32*, ...)*), { double, double }* %{{.+}})
#pragma omp parallel
{
dc *= dc;
}
// CHECK: ret void
}
// CHECK: define internal {{.+}}[[REGNAME1]](
// CHECK-NOT: invoke
// CHECK: call { double, double } @__muldc3(double %{{.+}}, double %{{.+}}, double %{{.+}}, double %{{.+}})
// CHECK-NOT: invoke
// CHECK: ret void
// Check if we are observing the function pointer attribute regardless what is
// in the exception specification of the callees.
void fnoexcp(void) noexcept;
// CHECK-LABEL: foo
void foo(int a, int b) {
void (*fptr)(void) noexcept = fnoexcp;
// CHECK: call {{.+}} @__kmpc_fork_call({{.+}} [[REGNAME2:@.*]] to void (i32*, i32*, ...)*), void ()** %{{.+}})
#pragma omp parallel
{
fptr();
}
// CHECK: ret void
}
// CHECK: define internal {{.+}}[[REGNAME2]](
// CHECK-NOT: invoke
// CHECK: call void %{{[0-9]+}}()
// CHECK-NOT: invoke
// CHECK: ret void