Implement basic overload support via a new builtin, __builtin_overload.

__builtin_overload takes 2 or more arguments:
0) a non-zero constant-expr for the number of arguments the overloaded 
   functions will take
1) the arguments to pass to the matching overloaded function
2) a list of functions to match.

The return type of __builtin_overload is inferred from the function whose args
match the types of the arguments passed to the builtin.  For example:

float a;
float sinf(float);
int   sini(int);

float b = __builtin_overload(1, a, sini, sinf);

Says that we are overloading functions that take one argument, and trying to 
pass an argument of the same type as 'a'.  sini() does not match since it takes
and argument of type int.  sinf does match, so at codegen time this will turn
into float b = sinf(a);

llvm-svn: 46132
This commit is contained in:
Nate Begeman 2008-01-17 17:46:27 +00:00
parent ad134b987e
commit 1e36a85f64
14 changed files with 235 additions and 25 deletions

View File

@ -78,6 +78,7 @@ const char *UnaryOperator::getOpcodeStr(Opcode Op) {
// Postfix Operators.
//===----------------------------------------------------------------------===//
CallExpr::CallExpr(Expr *fn, Expr **args, unsigned numargs, QualType t,
SourceLocation rparenloc)
: Expr(CallExprClass, t), NumArgs(numargs) {
@ -1238,6 +1239,14 @@ Stmt::child_iterator ChooseExpr::child_end() {
return reinterpret_cast<Stmt**>(&SubExprs)+END_EXPR;
}
// OverloadExpr
Stmt::child_iterator OverloadExpr::child_begin() {
return reinterpret_cast<Stmt**>(&SubExprs[0]);
}
Stmt::child_iterator OverloadExpr::child_end() {
return reinterpret_cast<Stmt**>(&SubExprs[NumArgs]);
}
// VAArgExpr
Stmt::child_iterator VAArgExpr::child_begin() {
return reinterpret_cast<Stmt**>(&Val);

View File

@ -733,6 +733,15 @@ void StmtPrinter::VisitChooseExpr(ChooseExpr *Node) {
OS << ")";
}
void StmtPrinter::VisitOverloadExpr(OverloadExpr *Node) {
OS << "__builtin_overload(";
for (unsigned i = 0, e = Node->getNumArgs(); i != e; ++i) {
if (i) OS << ", ";
PrintExpr(Node->getArg(i));
}
OS << ")";
}
void StmtPrinter::VisitInitListExpr(InitListExpr* Node) {
OS << "{ ";
for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) {

View File

@ -29,7 +29,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E) {
switch (BuiltinID) {
default: {
if (getContext().BuiltinInfo.isLibFunction(BuiltinID))
return EmitCallExpr(CGM.getBuiltinLibFunction(BuiltinID), E);
return EmitCallExpr(CGM.getBuiltinLibFunction(BuiltinID), E->getType(),
E->arg_begin());
// See if we have a target specific intrinsic.
Intrinsic::ID IntrinsicID;

View File

@ -450,7 +450,12 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) {
return EmitBuiltinExpr(builtinID, E);
llvm::Value *Callee = EmitScalarExpr(E->getCallee());
return EmitCallExpr(Callee, E);
return EmitCallExpr(Callee, E->getType(), E->arg_begin());
}
RValue CodeGenFunction::EmitCallExpr(Expr *FnExpr, Expr *const *Args) {
llvm::Value *Callee = EmitScalarExpr(FnExpr);
return EmitCallExpr(Callee, FnExpr->getType(), Args);
}
LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
@ -459,45 +464,42 @@ LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
return LValue::MakeAddr(RV.getAggregateAddr());
}
RValue CodeGenFunction::EmitCallExpr(llvm::Value *Callee, const CallExpr *E) {
RValue CodeGenFunction::EmitCallExpr(llvm::Value *Callee, QualType FnType,
Expr *const *ArgExprs) {
// The callee type will always be a pointer to function type, get the function
// type.
QualType CalleeTy = E->getCallee()->getType();
CalleeTy = cast<PointerType>(CalleeTy.getCanonicalType())->getPointeeType();
// Get information about the argument types.
FunctionTypeProto::arg_type_iterator ArgTyIt = 0, ArgTyEnd = 0;
FnType = cast<PointerType>(FnType.getCanonicalType())->getPointeeType();
QualType ResultType = cast<FunctionType>(FnType)->getResultType();
// Calling unprototyped functions provides no argument info.
if (const FunctionTypeProto *FTP = dyn_cast<FunctionTypeProto>(CalleeTy)) {
ArgTyIt = FTP->arg_type_begin();
ArgTyEnd = FTP->arg_type_end();
}
unsigned NumArgs = 0;
if (const FunctionTypeProto *FTP = dyn_cast<FunctionTypeProto>(FnType))
NumArgs = FTP->getNumArgs();
llvm::SmallVector<llvm::Value*, 16> Args;
// Handle struct-return functions by passing a pointer to the location that
// we would like to return into.
if (hasAggregateLLVMType(E->getType())) {
if (hasAggregateLLVMType(ResultType)) {
// Create a temporary alloca to hold the result of the call. :(
Args.push_back(CreateTempAlloca(ConvertType(E->getType())));
Args.push_back(CreateTempAlloca(ConvertType(ResultType)));
// FIXME: set the stret attribute on the argument.
}
for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
QualType ArgTy = E->getArg(i)->getType();
for (unsigned i = 0, e = NumArgs; i != e; ++i) {
QualType ArgTy = ArgExprs[i]->getType();
if (!hasAggregateLLVMType(ArgTy)) {
// Scalar argument is passed by-value.
Args.push_back(EmitScalarExpr(E->getArg(i)));
Args.push_back(EmitScalarExpr(ArgExprs[i]));
} else if (ArgTy->isComplexType()) {
// Make a temporary alloca to pass the argument.
llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy));
EmitComplexExprIntoAddr(E->getArg(i), DestMem, false);
EmitComplexExprIntoAddr(ArgExprs[i], DestMem, false);
Args.push_back(DestMem);
} else {
llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy));
EmitAggExpr(E->getArg(i), DestMem, false);
EmitAggExpr(ArgExprs[i], DestMem, false);
Args.push_back(DestMem);
}
}
@ -505,14 +507,14 @@ RValue CodeGenFunction::EmitCallExpr(llvm::Value *Callee, const CallExpr *E) {
llvm::Value *V = Builder.CreateCall(Callee, &Args[0], &Args[0]+Args.size());
if (V->getType() != llvm::Type::VoidTy)
V->setName("call");
else if (E->getType()->isComplexType())
else if (ResultType->isComplexType())
return RValue::getComplex(LoadComplexFromAddr(Args[0], false));
else if (hasAggregateLLVMType(E->getType()))
else if (hasAggregateLLVMType(ResultType))
// Struct return.
return RValue::getAggregate(Args[0]);
else {
// void return.
assert(E->getType()->isVoidType() && "Should only have a void expr here");
assert(ResultType->isVoidType() && "Should only have a void expr here");
V = 0;
}

View File

@ -282,6 +282,7 @@ public:
// Other Operators.
Value *VisitConditionalOperator(const ConditionalOperator *CO);
Value *VisitChooseExpr(ChooseExpr *CE);
Value *VisitOverloadExpr(OverloadExpr *OE);
Value *VisitVAArgExpr(VAArgExpr *VE);
Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) {
return CGF.EmitObjCStringLiteral(E);
@ -991,6 +992,10 @@ Value *ScalarExprEmitter::VisitChooseExpr(ChooseExpr *E) {
Visit(E->isConditionTrue(CGF.getContext()) ? E->getLHS() : E->getRHS());
}
Value *ScalarExprEmitter::VisitOverloadExpr(OverloadExpr *E) {
return CGF.EmitCallExpr(E->getFn(), E->arg_begin()).getScalarVal();
}
Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
llvm::Value *ArgValue = EmitLValue(VE->getSubExpr()).getAddress();

View File

@ -388,7 +388,8 @@ public:
//===--------------------------------------------------------------------===//
RValue EmitCallExpr(const CallExpr *E);
RValue EmitCallExpr(llvm::Value *Callee, const CallExpr *E);
RValue EmitCallExpr(Expr *FnExpr, Expr *const *Args);
RValue EmitCallExpr(llvm::Value *Callee, QualType FnType, Expr *const *Args);
RValue EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E);

View File

@ -550,6 +550,7 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) {
case tok::kw___builtin_va_arg:
case tok::kw___builtin_offsetof:
case tok::kw___builtin_choose_expr:
case tok::kw___builtin_overload:
case tok::kw___builtin_types_compatible_p:
return ParseBuiltinPrimaryExpression();
case tok::plusplus: // unary-expression: '++' unary-expression
@ -774,6 +775,7 @@ Parser::ExprResult Parser::ParseSizeofAlignofExpression() {
/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ','
/// assign-expr ')'
/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
/// [CLANG] '__builtin_overload' '(' expr (',' expr)* ')'
///
/// [GNU] offsetof-member-designator:
/// [GNU] identifier
@ -909,6 +911,44 @@ Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() {
ConsumeParen());
break;
}
case tok::kw___builtin_overload: {
llvm::SmallVector<ExprTy*, 8> ArgExprs;
llvm::SmallVector<SourceLocation, 8> CommaLocs;
// For each iteration through the loop look for assign-expr followed by a
// comma. If there is no comma, break and attempt to match r-paren.
if (Tok.isNot(tok::r_paren)) {
while (1) {
ExprResult ArgExpr = ParseAssignmentExpression();
if (ArgExpr.isInvalid) {
SkipUntil(tok::r_paren);
return ExprResult(true);
} else
ArgExprs.push_back(ArgExpr.Val);
if (Tok.isNot(tok::comma))
break;
// Move to the next argument, remember where the comma was.
CommaLocs.push_back(ConsumeToken());
}
}
// Attempt to consume the r-paren
if (Tok.isNot(tok::r_paren)) {
Diag(Tok, diag::err_expected_rparen);
SkipUntil(tok::r_paren);
return ExprResult(true);
}
// __builtin_overload requires at least 2 arguments
if (ArgExprs.size() < 2) {
Diag(Tok, diag::err_typecheck_call_too_few_args);
return ExprResult(true);
}
Res = Actions.ActOnOverloadExpr(&ArgExprs[0], ArgExprs.size(),
&CommaLocs[0], StartLoc, ConsumeParen());
break;
}
case tok::kw___builtin_types_compatible_p:
TypeTy *Ty1 = ParseTypeName();

View File

@ -465,6 +465,12 @@ public:
ExprTy *cond, ExprTy *expr1, ExprTy *expr2,
SourceLocation RPLoc);
// __builtin_overload(...)
virtual ExprResult ActOnOverloadExpr(ExprTy **Args, unsigned NumArgs,
SourceLocation *CommaLocs,
SourceLocation BuiltinLoc,
SourceLocation RParenLoc);
// __builtin_va_arg(expr, type)
virtual ExprResult ActOnVAArg(SourceLocation BuiltinLoc,
ExprTy *expr, TypeTy *type,

View File

@ -892,7 +892,7 @@ void Sema::DefaultFunctionArrayConversion(Expr *&e) {
ImpCastExprToType(e, Context.getPointerType(ary->getElementType()));
}
/// UsualUnaryConversion - Performs various conversions that are common to most
/// UsualUnaryConversions - Performs various conversions that are common to most
/// operators (C99 6.3). The conversions of array and function types are
/// sometimes surpressed. For example, the array->pointer conversion doesn't
/// apply if the array is an argument to the sizeof or address (&) operators.
@ -2074,6 +2074,76 @@ Sema::ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, ExprTy *cond,
return new ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, resType, RPLoc);
}
/// ExprsCompatibleWithFnType - return true if the Exprs in array Args have
/// QualTypes that match the QualTypes of the arguments of the FnType.
static bool ExprsCompatibleWithFnType(Expr **Args, FunctionTypeProto *FnType) {
unsigned NumParams = FnType->getNumArgs();
for (unsigned i = 0; i != NumParams; ++i)
if (Args[i]->getType() != FnType->getArgType(i))
return false;
return true;
}
Sema::ExprResult Sema::ActOnOverloadExpr(ExprTy **args, unsigned NumArgs,
SourceLocation *CommaLocs,
SourceLocation BuiltinLoc,
SourceLocation RParenLoc) {
assert((NumArgs > 1) && "Too few arguments for OverloadExpr!");
Expr **Args = reinterpret_cast<Expr**>(args);
// The first argument is required to be a constant expression. It tells us
// the number of arguments to pass to each of the functions to be overloaded.
Expr *NParamsExpr = Args[0];
llvm::APSInt constEval(32);
SourceLocation ExpLoc;
if (!NParamsExpr->isIntegerConstantExpr(constEval, Context, &ExpLoc))
return Diag(ExpLoc, diag::err_overload_expr_requires_non_zero_constant,
NParamsExpr->getSourceRange());
// Verify that the number of parameters is > 0
unsigned NumParams = constEval.getZExtValue();
if (NumParams == 0)
return Diag(ExpLoc, diag::err_overload_expr_requires_non_zero_constant,
NParamsExpr->getSourceRange());
// Verify that we have at least 1 + NumParams arguments to the builtin.
if ((NumParams + 1) > NumArgs)
return Diag(RParenLoc, diag::err_typecheck_call_too_few_args,
SourceRange(BuiltinLoc, RParenLoc));
// Figure out the return type, by matching the args to one of the functions
// listed after the paramters.
for (unsigned i = NumParams + 1; i < NumArgs; ++i) {
// UsualUnaryConversions will convert the function DeclRefExpr into a
// pointer to function.
Expr *Fn = UsualUnaryConversions(Args[i]);
FunctionTypeProto *FnType = 0;
if (const PointerType *PT = Fn->getType()->getAsPointerType())
FnType = dyn_cast<FunctionTypeProto>(PT->getPointeeType());
// The Expr type must be FunctionTypeProto, since FunctionTypeProto has no
// parameters, and the number of parameters must match the value passed to
// the builtin.
if (!FnType || (FnType->getNumArgs() != NumParams))
continue;
// Scan the parameter list for the FunctionType, checking the QualType of
// each paramter against the QualTypes of the arguments to the builtin.
// If they match, return a new OverloadExpr.
if (ExprsCompatibleWithFnType(Args+1, FnType))
return new OverloadExpr(Args, NumArgs, i, FnType->getResultType(),
BuiltinLoc, RParenLoc);
}
// If we didn't find a matching function Expr in the __builtin_overload list
// the return an error.
std::string typeNames;
for (unsigned i = 0; i != NumParams; ++i)
typeNames += Args[i+1]->getType().getAsString() + " ";
return Diag(BuiltinLoc, diag::err_overload_no_match, typeNames,
SourceRange(BuiltinLoc, RParenLoc));
}
Sema::ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
ExprTy *expr, TypeTy *type,
SourceLocation RPLoc) {

View File

@ -1124,6 +1124,57 @@ public:
virtual child_iterator child_end();
};
/// OverloadExpr - Clang builtin-in function __builtin_overload.
/// This AST node provides a way to overload functions in C
/// i.e. float Z = __builtin_overload(2, X, Y, modf, mod, modl);
/// would pick whichever of the functions modf, mod, and modl that took two
/// arguments of the same type as X and Y.
class OverloadExpr : public Expr {
Expr **SubExprs;
unsigned NumArgs;
unsigned FnIndex;
SourceLocation BuiltinLoc;
SourceLocation RParenLoc;
public:
OverloadExpr(Expr **args, unsigned narg, unsigned idx, QualType t,
SourceLocation bloc, SourceLocation rploc)
: Expr(OverloadExprClass, t), NumArgs(narg), FnIndex(idx), BuiltinLoc(bloc),
RParenLoc(rploc) {
SubExprs = new Expr*[narg];
for (unsigned i = 0; i != narg; ++i)
SubExprs[i] = args[i];
}
~OverloadExpr() {
delete [] SubExprs;
}
typedef Expr * const *arg_const_iterator;
arg_const_iterator arg_begin() const { return SubExprs+1; }
/// getNumArgs - Return the number of actual arguments to this call.
///
unsigned getNumArgs() const { return NumArgs; }
/// getArg - Return the specified argument.
Expr *getArg(unsigned Arg) {
assert(Arg < NumArgs && "Arg access out of range!");
return SubExprs[Arg];
}
Expr *getFn() { return SubExprs[FnIndex]; }
virtual SourceRange getSourceRange() const {
return SourceRange(BuiltinLoc, RParenLoc);
}
static bool classof(const Stmt *T) {
return T->getStmtClass() == OverloadExprClass;
}
static bool classof(const OverloadExpr *) { return true; }
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
};
/// VAArgExpr, used for the builtin function __builtin_va_start.
class VAArgExpr : public Expr {
Expr *Val;

View File

@ -98,7 +98,10 @@ STMT(73, ObjCSelectorExpr , Expr)
STMT(74, ObjCProtocolExpr , Expr)
STMT(75, ObjCIvarRefExpr , Expr)
LAST_EXPR(75)
// Clang Extensions.
STMT(76, OverloadExpr , Expr)
LAST_EXPR(76)
#undef STMT
#undef FIRST_STMT

View File

@ -834,6 +834,10 @@ DIAG(err_invalid_conversion_between_vector_and_integer, ERROR,
"of different size")
DIAG(err_invalid_conversion_between_vector_and_scalar, ERROR,
"invalid conversion between vector type '%0' and scalar type '%1'")
DIAG(err_overload_expr_requires_non_zero_constant, ERROR,
"overload requires a non-zero constant expression as first argument")
DIAG(err_overload_no_match, ERROR,
"no matching overload found for arguments of type '%0'")
// CHECK: printf format string errors
DIAG(warn_printf_not_string_constant, WARNING,

View File

@ -289,6 +289,7 @@ KEYWORD(__null , NOTC90|NOTC99|EXTCPP|EXTCPP0x) // C++-only
KEYWORD(__alignof , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
KEYWORD(__attribute , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
KEYWORD(__builtin_choose_expr , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
KEYWORD(__builtin_overload , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
KEYWORD(__builtin_offsetof , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
KEYWORD(__builtin_types_compatible_p, EXTC90|EXTC99|EXTCPP|EXTCPP0x)
KEYWORD(__builtin_va_arg , EXTC90|EXTC99|EXTCPP|EXTCPP0x)

View File

@ -476,6 +476,14 @@ public:
SourceLocation RPLoc) {
return 0;
}
// __builtin_overload(...)
virtual ExprResult ActOnOverloadExpr(ExprTy **Args, unsigned NumArgs,
SourceLocation *CommaLocs,
SourceLocation BuiltinLoc,
SourceLocation RPLoc) {
return 0;
}
// __builtin_va_arg(expr, type)
virtual ExprResult ActOnVAArg(SourceLocation BuiltinLoc,