//===--- Builtins.cpp - Builtin function implementation -------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements various things for builtin functions. // //===----------------------------------------------------------------------===// #include "clang/AST/Builtins.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/TargetInfo.h" using namespace clang; static const Builtin::Info BuiltinInfo[] = { { "not a builtin function", 0, 0, 0, false }, #define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, false }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER, false }, #include "clang/AST/Builtins.def" }; const Builtin::Info &Builtin::Context::GetRecord(unsigned ID) const { if (ID < Builtin::FirstTSBuiltin) return BuiltinInfo[ID]; assert(ID - Builtin::FirstTSBuiltin < NumTSRecords && "Invalid builtin ID!"); return TSRecords[ID - Builtin::FirstTSBuiltin]; } /// \brief Load all of the target builtins. This must be called /// prior to initializing the builtin identifiers. void Builtin::Context::InitializeTargetBuiltins(const TargetInfo &Target) { Target.getTargetBuiltins(TSRecords, NumTSRecords); } /// InitializeBuiltins - Mark the identifiers for all the builtins with their /// appropriate builtin ID # and mark any non-portable builtin identifiers as /// such. void Builtin::Context::InitializeBuiltins(IdentifierTable &Table, bool NoBuiltins) { // Step #1: mark all target-independent builtins with their ID's. for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) if (!BuiltinInfo[i].Suppressed && (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f'))) Table.get(BuiltinInfo[i].Name).setBuiltinID(i); // Step #2: Register target-specific builtins. for (unsigned i = 0, e = NumTSRecords; i != e; ++i) if (!TSRecords[i].Suppressed && (!NoBuiltins || (TSRecords[i].Attributes && !strchr(TSRecords[i].Attributes, 'f')))) Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin); } void Builtin::Context::GetBuiltinNames(llvm::SmallVectorImpl &Names, bool NoBuiltins) { // Final all target-independent names for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) if (!BuiltinInfo[i].Suppressed && (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f'))) Names.push_back(BuiltinInfo[i].Name); // Find target-specific names. for (unsigned i = 0, e = NumTSRecords; i != e; ++i) if (!TSRecords[i].Suppressed && (!NoBuiltins || (TSRecords[i].Attributes && !strchr(TSRecords[i].Attributes, 'f')))) Names.push_back(TSRecords[i].Name); } bool Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg) { const char *Printf = strpbrk(GetRecord(ID).Attributes, "pP"); if (!Printf) return false; HasVAListArg = (*Printf == 'P'); ++Printf; assert(*Printf == ':' && "p or P specifier must have be followed by a ':'"); ++Printf; assert(strchr(Printf, ':') && "printf specifier must end with a ':'"); FormatIdx = strtol(Printf, 0, 10); return true; } /// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the /// pointer over the consumed characters. This returns the resultant type. static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, Builtin::Context::GetBuiltinTypeError &Error, bool AllowTypeModifiers = true) { // Modifiers. int HowLong = 0; bool Signed = false, Unsigned = false; // Read the modifiers first. bool Done = false; while (!Done) { switch (*Str++) { default: Done = true; --Str; break; case 'S': assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!"); assert(!Signed && "Can't use 'S' modifier multiple times!"); Signed = true; break; case 'U': assert(!Signed && "Can't use both 'S' and 'U' modifiers!"); assert(!Unsigned && "Can't use 'S' modifier multiple times!"); Unsigned = true; break; case 'L': assert(HowLong <= 2 && "Can't have LLLL modifier"); ++HowLong; break; } } QualType Type; // Read the base type. switch (*Str++) { default: assert(0 && "Unknown builtin type letter!"); case 'v': assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers used with 'v'!"); Type = Context.VoidTy; break; case 'f': assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers used with 'f'!"); Type = Context.FloatTy; break; case 'd': assert(HowLong < 2 && !Signed && !Unsigned && "Bad modifiers used with 'd'!"); if (HowLong) Type = Context.LongDoubleTy; else Type = Context.DoubleTy; break; case 's': assert(HowLong == 0 && "Bad modifiers used with 's'!"); if (Unsigned) Type = Context.UnsignedShortTy; else Type = Context.ShortTy; break; case 'i': if (HowLong == 3) Type = Unsigned ? Context.UnsignedInt128Ty : Context.Int128Ty; else if (HowLong == 2) Type = Unsigned ? Context.UnsignedLongLongTy : Context.LongLongTy; else if (HowLong == 1) Type = Unsigned ? Context.UnsignedLongTy : Context.LongTy; else Type = Unsigned ? Context.UnsignedIntTy : Context.IntTy; break; case 'c': assert(HowLong == 0 && "Bad modifiers used with 'c'!"); if (Signed) Type = Context.SignedCharTy; else if (Unsigned) Type = Context.UnsignedCharTy; else Type = Context.CharTy; break; case 'b': // boolean assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'b'!"); Type = Context.BoolTy; break; case 'z': // size_t. assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'z'!"); Type = Context.getSizeType(); break; case 'F': Type = Context.getCFConstantStringType(); break; case 'a': Type = Context.getBuiltinVaListType(); assert(!Type.isNull() && "builtin va list type not initialized!"); break; case 'A': // This is a "reference" to a va_list; however, what exactly // this means depends on how va_list is defined. There are two // different kinds of va_list: ones passed by value, and ones // passed by reference. An example of a by-value va_list is // x86, where va_list is a char*. An example of by-ref va_list // is x86-64, where va_list is a __va_list_tag[1]. For x86, // we want this argument to be a char*&; for x86-64, we want // it to be a __va_list_tag*. Type = Context.getBuiltinVaListType(); assert(!Type.isNull() && "builtin va list type not initialized!"); if (Type->isArrayType()) { Type = Context.getArrayDecayedType(Type); } else { Type = Context.getLValueReferenceType(Type); } break; case 'V': { char *End; unsigned NumElements = strtoul(Str, &End, 10); assert(End != Str && "Missing vector size"); Str = End; QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false); Type = Context.getVectorType(ElementType, NumElements); break; } case 'P': { IdentifierInfo *II = &Context.Idents.get("FILE"); DeclContext::lookup_result Lookup = Context.getTranslationUnitDecl()->lookup(Context, II); if (Lookup.first != Lookup.second && isa(*Lookup.first)) { Type = Context.getTypeDeclType(cast(*Lookup.first)); break; } else { Error = Builtin::Context::GE_Missing_FILE; return QualType(); } } } if (!AllowTypeModifiers) return Type; Done = false; while (!Done) { switch (*Str++) { default: Done = true; --Str; break; case '*': Type = Context.getPointerType(Type); break; case '&': Type = Context.getLValueReferenceType(Type); break; // FIXME: There's no way to have a built-in with an rvalue ref arg. case 'C': Type = Type.getQualifiedType(QualType::Const); break; } } return Type; } /// GetBuiltinType - Return the type for the specified builtin. QualType Builtin::Context::GetBuiltinType(unsigned id, ASTContext &Context, GetBuiltinTypeError &Error) const { const char *TypeStr = GetRecord(id).Type; llvm::SmallVector ArgTypes; Error = GE_None; QualType ResType = DecodeTypeFromStr(TypeStr, Context, Error); if (Error != GE_None) return QualType(); while (TypeStr[0] && TypeStr[0] != '.') { QualType Ty = DecodeTypeFromStr(TypeStr, Context, Error); if (Error != GE_None) return QualType(); // Do array -> pointer decay. The builtin should use the decayed type. if (Ty->isArrayType()) Ty = Context.getArrayDecayedType(Ty); ArgTypes.push_back(Ty); } assert((TypeStr[0] != '.' || TypeStr[1] == 0) && "'.' should only occur at end of builtin type list!"); // handle untyped/variadic arguments "T c99Style();" or "T cppStyle(...);". if (ArgTypes.size() == 0 && TypeStr[0] == '.') return Context.getFunctionNoProtoType(ResType); return Context.getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(), TypeStr[0] == '.', 0); }