blob: ca75c5d51a81dbb5e2abf0a319adf7f1de3f4dca [file] [log] [blame]
Chris Lattner4b009652007-07-25 00:24:17 +00001//===--- Builtins.cpp - Builtin function implementation -------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
Chris Lattner959e5be2007-12-29 19:59:25 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Chris Lattner4b009652007-07-25 00:24:17 +00007//
8//===----------------------------------------------------------------------===//
9//
10// This file implements various things for builtin functions.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/AST/Builtins.h"
15#include "clang/AST/ASTContext.h"
Daniel Dunbarde300732008-08-11 04:54:23 +000016#include "clang/AST/Decl.h"
Chris Lattner2fd1c652007-10-07 08:58:51 +000017#include "clang/Basic/IdentifierTable.h"
Chris Lattner4b009652007-07-25 00:24:17 +000018#include "clang/Basic/TargetInfo.h"
19using namespace clang;
20
21static const Builtin::Info BuiltinInfo[] = {
Douglas Gregor2e8a7aa2009-02-16 21:58:21 +000022 { "not a builtin function", 0, 0, 0, false },
23#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, false },
24#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER, false },
Chris Lattner4b009652007-07-25 00:24:17 +000025#include "clang/AST/Builtins.def"
26};
27
28const Builtin::Info &Builtin::Context::GetRecord(unsigned ID) const {
29 if (ID < Builtin::FirstTSBuiltin)
30 return BuiltinInfo[ID];
31 assert(ID - Builtin::FirstTSBuiltin < NumTSRecords && "Invalid builtin ID!");
32 return TSRecords[ID - Builtin::FirstTSBuiltin];
33}
34
Douglas Gregor37f477e2009-04-22 04:56:28 +000035/// \brief Load all of the target builtins. This must be called
36/// prior to initializing the builtin identifiers.
37void Builtin::Context::InitializeTargetBuiltins(const TargetInfo &Target) {
38 Target.getTargetBuiltins(TSRecords, NumTSRecords);
39}
Chris Lattner4b009652007-07-25 00:24:17 +000040
41/// InitializeBuiltins - Mark the identifiers for all the builtins with their
42/// appropriate builtin ID # and mark any non-portable builtin identifiers as
43/// such.
44void Builtin::Context::InitializeBuiltins(IdentifierTable &Table,
Chris Lattner911b8672009-03-13 22:38:49 +000045 bool NoBuiltins) {
Chris Lattner4b009652007-07-25 00:24:17 +000046 // Step #1: mark all target-independent builtins with their ID's.
47 for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i)
Douglas Gregor23d23262009-02-14 20:49:29 +000048 if (!BuiltinInfo[i].Suppressed &&
Chris Lattner911b8672009-03-13 22:38:49 +000049 (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f')))
Douglas Gregor23d23262009-02-14 20:49:29 +000050 Table.get(BuiltinInfo[i].Name).setBuiltinID(i);
Chris Lattner4b009652007-07-25 00:24:17 +000051
Douglas Gregor37f477e2009-04-22 04:56:28 +000052 // Step #2: Register target-specific builtins.
Chris Lattner4b009652007-07-25 00:24:17 +000053 for (unsigned i = 0, e = NumTSRecords; i != e; ++i)
Douglas Gregor23d23262009-02-14 20:49:29 +000054 if (!TSRecords[i].Suppressed &&
Chris Lattner911b8672009-03-13 22:38:49 +000055 (!NoBuiltins ||
Daniel Dunbarbff577a2009-02-15 18:23:07 +000056 (TSRecords[i].Attributes &&
57 !strchr(TSRecords[i].Attributes, 'f'))))
Douglas Gregor23d23262009-02-14 20:49:29 +000058 Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin);
Chris Lattner4b009652007-07-25 00:24:17 +000059}
60
Douglas Gregorda38c6c2009-04-22 18:49:13 +000061void
62Builtin::Context::GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names,
63 bool NoBuiltins) {
64 // Final all target-independent names
65 for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i)
66 if (!BuiltinInfo[i].Suppressed &&
67 (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f')))
68 Names.push_back(BuiltinInfo[i].Name);
69
70 // Find target-specific names.
71 for (unsigned i = 0, e = NumTSRecords; i != e; ++i)
72 if (!TSRecords[i].Suppressed &&
73 (!NoBuiltins ||
74 (TSRecords[i].Attributes &&
75 !strchr(TSRecords[i].Attributes, 'f'))))
76 Names.push_back(TSRecords[i].Name);
77}
78
Douglas Gregor17429032009-02-14 00:32:47 +000079bool
80Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx,
81 bool &HasVAListArg) {
Cédric Venetc47ed4a2009-02-14 16:15:20 +000082 const char *Printf = strpbrk(GetRecord(ID).Attributes, "pP");
Douglas Gregor17429032009-02-14 00:32:47 +000083 if (!Printf)
84 return false;
85
86 HasVAListArg = (*Printf == 'P');
87
88 ++Printf;
89 assert(*Printf == ':' && "p or P specifier must have be followed by a ':'");
90 ++Printf;
91
Chris Lattnerca8de5d2009-02-19 06:41:13 +000092 assert(strchr(Printf, ':') && "printf specifier must end with a ':'");
Douglas Gregor17429032009-02-14 00:32:47 +000093 FormatIdx = strtol(Printf, 0, 10);
94 return true;
95}
96
Chris Lattner4b009652007-07-25 00:24:17 +000097/// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the
98/// pointer over the consumed characters. This returns the resultant type.
Anders Carlsson282a7cb2007-11-28 05:19:59 +000099static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
Douglas Gregor1fa246d2009-02-14 01:52:53 +0000100 Builtin::Context::GetBuiltinTypeError &Error,
Anders Carlsson282a7cb2007-11-28 05:19:59 +0000101 bool AllowTypeModifiers = true) {
Chris Lattner4b009652007-07-25 00:24:17 +0000102 // Modifiers.
Chris Lattnerdb8a02d2009-05-07 04:47:06 +0000103 int HowLong = 0;
104 bool Signed = false, Unsigned = false;
Chris Lattner4b009652007-07-25 00:24:17 +0000105
106 // Read the modifiers first.
107 bool Done = false;
108 while (!Done) {
109 switch (*Str++) {
110 default: Done = true; --Str; break;
111 case 'S':
112 assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!");
113 assert(!Signed && "Can't use 'S' modifier multiple times!");
114 Signed = true;
115 break;
116 case 'U':
117 assert(!Signed && "Can't use both 'S' and 'U' modifiers!");
118 assert(!Unsigned && "Can't use 'S' modifier multiple times!");
119 Unsigned = true;
120 break;
121 case 'L':
Chris Lattnerdb8a02d2009-05-07 04:47:06 +0000122 assert(HowLong <= 2 && "Can't have LLLL modifier");
123 ++HowLong;
Chris Lattner4b009652007-07-25 00:24:17 +0000124 break;
125 }
126 }
127
Anders Carlssone7e7aa22007-08-17 05:31:46 +0000128 QualType Type;
129
Chris Lattner4b009652007-07-25 00:24:17 +0000130 // Read the base type.
131 switch (*Str++) {
132 default: assert(0 && "Unknown builtin type letter!");
133 case 'v':
Chris Lattnerdb8a02d2009-05-07 04:47:06 +0000134 assert(HowLong == 0 && !Signed && !Unsigned &&
135 "Bad modifiers used with 'v'!");
Anders Carlssone7e7aa22007-08-17 05:31:46 +0000136 Type = Context.VoidTy;
137 break;
Chris Lattner4b009652007-07-25 00:24:17 +0000138 case 'f':
Chris Lattnerdb8a02d2009-05-07 04:47:06 +0000139 assert(HowLong == 0 && !Signed && !Unsigned &&
140 "Bad modifiers used with 'f'!");
Anders Carlssone7e7aa22007-08-17 05:31:46 +0000141 Type = Context.FloatTy;
142 break;
Chris Lattner4b009652007-07-25 00:24:17 +0000143 case 'd':
Chris Lattnerdb8a02d2009-05-07 04:47:06 +0000144 assert(HowLong < 2 && !Signed && !Unsigned &&
145 "Bad modifiers used with 'd'!");
146 if (HowLong)
Anders Carlssone7e7aa22007-08-17 05:31:46 +0000147 Type = Context.LongDoubleTy;
148 else
149 Type = Context.DoubleTy;
150 break;
Chris Lattner4b009652007-07-25 00:24:17 +0000151 case 's':
Chris Lattnerdb8a02d2009-05-07 04:47:06 +0000152 assert(HowLong == 0 && "Bad modifiers used with 's'!");
Chris Lattner4b009652007-07-25 00:24:17 +0000153 if (Unsigned)
Anders Carlssone7e7aa22007-08-17 05:31:46 +0000154 Type = Context.UnsignedShortTy;
155 else
156 Type = Context.ShortTy;
Chris Lattnerdb8a02d2009-05-07 04:47:06 +0000157 break;
Steve Naroff48a87932007-08-08 17:48:34 +0000158 case 'i':
Chris Lattnerdb8a02d2009-05-07 04:47:06 +0000159 if (HowLong == 3)
160 Type = Unsigned ? Context.UnsignedInt128Ty : Context.Int128Ty;
161 else if (HowLong == 2)
Anders Carlssone7e7aa22007-08-17 05:31:46 +0000162 Type = Unsigned ? Context.UnsignedLongLongTy : Context.LongLongTy;
Chris Lattnerdb8a02d2009-05-07 04:47:06 +0000163 else if (HowLong == 1)
Anders Carlssonfb0d1392007-11-27 07:22:09 +0000164 Type = Unsigned ? Context.UnsignedLongTy : Context.LongTy;
Chris Lattnerdb8a02d2009-05-07 04:47:06 +0000165 else
166 Type = Unsigned ? Context.UnsignedIntTy : Context.IntTy;
Anders Carlssone7e7aa22007-08-17 05:31:46 +0000167 break;
168 case 'c':
Chris Lattnerdb8a02d2009-05-07 04:47:06 +0000169 assert(HowLong == 0 && "Bad modifiers used with 'c'!");
Anders Carlssone7e7aa22007-08-17 05:31:46 +0000170 if (Signed)
171 Type = Context.SignedCharTy;
172 else if (Unsigned)
173 Type = Context.UnsignedCharTy;
174 else
175 Type = Context.CharTy;
176 break;
Mon P Wang651c8992008-10-18 02:49:28 +0000177 case 'b': // boolean
Chris Lattnerdb8a02d2009-05-07 04:47:06 +0000178 assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'b'!");
Mon P Wang651c8992008-10-18 02:49:28 +0000179 Type = Context.BoolTy;
180 break;
Chris Lattnerde4d2bd2007-10-29 04:18:06 +0000181 case 'z': // size_t.
Chris Lattnerdb8a02d2009-05-07 04:47:06 +0000182 assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'z'!");
Chris Lattnerde4d2bd2007-10-29 04:18:06 +0000183 Type = Context.getSizeType();
184 break;
Anders Carlssone7e7aa22007-08-17 05:31:46 +0000185 case 'F':
186 Type = Context.getCFConstantStringType();
187 break;
Anders Carlssonfb0d1392007-11-27 07:22:09 +0000188 case 'a':
Anders Carlssonfb5b1e82007-10-11 01:00:40 +0000189 Type = Context.getBuiltinVaListType();
Anders Carlssoncebb8d62007-10-12 23:56:29 +0000190 assert(!Type.isNull() && "builtin va list type not initialized!");
Anders Carlssonfb5b1e82007-10-11 01:00:40 +0000191 break;
Eli Friedman1d411122009-01-20 07:46:22 +0000192 case 'A':
193 // This is a "reference" to a va_list; however, what exactly
194 // this means depends on how va_list is defined. There are two
195 // different kinds of va_list: ones passed by value, and ones
196 // passed by reference. An example of a by-value va_list is
197 // x86, where va_list is a char*. An example of by-ref va_list
198 // is x86-64, where va_list is a __va_list_tag[1]. For x86,
199 // we want this argument to be a char*&; for x86-64, we want
200 // it to be a __va_list_tag*.
201 Type = Context.getBuiltinVaListType();
202 assert(!Type.isNull() && "builtin va list type not initialized!");
203 if (Type->isArrayType()) {
204 Type = Context.getArrayDecayedType(Type);
205 } else {
Sebastian Redlce6fff02009-03-16 23:22:08 +0000206 Type = Context.getLValueReferenceType(Type);
Eli Friedman1d411122009-01-20 07:46:22 +0000207 }
208 break;
Anders Carlssonfb0d1392007-11-27 07:22:09 +0000209 case 'V': {
210 char *End;
211
212 unsigned NumElements = strtoul(Str, &End, 10);
213 assert(End != Str && "Missing vector size");
214
215 Str = End;
216
Douglas Gregor1fa246d2009-02-14 01:52:53 +0000217 QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false);
Anders Carlssonfb0d1392007-11-27 07:22:09 +0000218 Type = Context.getVectorType(ElementType, NumElements);
219 break;
220 }
Douglas Gregor1fa246d2009-02-14 01:52:53 +0000221 case 'P': {
222 IdentifierInfo *II = &Context.Idents.get("FILE");
223 DeclContext::lookup_result Lookup
Douglas Gregorc55b0b02009-04-09 21:40:53 +0000224 = Context.getTranslationUnitDecl()->lookup(Context, II);
Douglas Gregor1fa246d2009-02-14 01:52:53 +0000225 if (Lookup.first != Lookup.second && isa<TypeDecl>(*Lookup.first)) {
226 Type = Context.getTypeDeclType(cast<TypeDecl>(*Lookup.first));
227 break;
228 }
229 else {
230 Error = Builtin::Context::GE_Missing_FILE;
231 return QualType();
232 }
233 }
Chris Lattner4b009652007-07-25 00:24:17 +0000234 }
Anders Carlssone7e7aa22007-08-17 05:31:46 +0000235
Anders Carlsson282a7cb2007-11-28 05:19:59 +0000236 if (!AllowTypeModifiers)
237 return Type;
238
Anders Carlssone7e7aa22007-08-17 05:31:46 +0000239 Done = false;
240 while (!Done) {
241 switch (*Str++) {
Anders Carlsson282a7cb2007-11-28 05:19:59 +0000242 default: Done = true; --Str; break;
Anders Carlssone7e7aa22007-08-17 05:31:46 +0000243 case '*':
244 Type = Context.getPointerType(Type);
245 break;
Anders Carlssoncebb8d62007-10-12 23:56:29 +0000246 case '&':
Sebastian Redlce6fff02009-03-16 23:22:08 +0000247 Type = Context.getLValueReferenceType(Type);
Anders Carlssoncebb8d62007-10-12 23:56:29 +0000248 break;
Sebastian Redlce6fff02009-03-16 23:22:08 +0000249 // FIXME: There's no way to have a built-in with an rvalue ref arg.
Anders Carlssone7e7aa22007-08-17 05:31:46 +0000250 case 'C':
251 Type = Type.getQualifiedType(QualType::Const);
252 break;
253 }
254 }
255
256 return Type;
Chris Lattner4b009652007-07-25 00:24:17 +0000257}
258
259/// GetBuiltinType - Return the type for the specified builtin.
Douglas Gregor1fa246d2009-02-14 01:52:53 +0000260QualType Builtin::Context::GetBuiltinType(unsigned id, ASTContext &Context,
261 GetBuiltinTypeError &Error) const {
Chris Lattner4b009652007-07-25 00:24:17 +0000262 const char *TypeStr = GetRecord(id).Type;
263
264 llvm::SmallVector<QualType, 8> ArgTypes;
265
Douglas Gregor1fa246d2009-02-14 01:52:53 +0000266 Error = GE_None;
267 QualType ResType = DecodeTypeFromStr(TypeStr, Context, Error);
268 if (Error != GE_None)
269 return QualType();
Chris Lattner27882f42008-09-29 22:28:25 +0000270 while (TypeStr[0] && TypeStr[0] != '.') {
Douglas Gregor1fa246d2009-02-14 01:52:53 +0000271 QualType Ty = DecodeTypeFromStr(TypeStr, Context, Error);
272 if (Error != GE_None)
273 return QualType();
274
Chris Lattner27882f42008-09-29 22:28:25 +0000275 // Do array -> pointer decay. The builtin should use the decayed type.
276 if (Ty->isArrayType())
277 Ty = Context.getArrayDecayedType(Ty);
278
279 ArgTypes.push_back(Ty);
280 }
Anders Carlsson282a7cb2007-11-28 05:19:59 +0000281
Chris Lattner4b009652007-07-25 00:24:17 +0000282 assert((TypeStr[0] != '.' || TypeStr[1] == 0) &&
283 "'.' should only occur at end of builtin type list!");
Steve Naroff48a87932007-08-08 17:48:34 +0000284
285 // handle untyped/variadic arguments "T c99Style();" or "T cppStyle(...);".
286 if (ArgTypes.size() == 0 && TypeStr[0] == '.')
Douglas Gregor4fa58902009-02-26 23:50:07 +0000287 return Context.getFunctionNoProtoType(ResType);
Chris Lattner4b009652007-07-25 00:24:17 +0000288 return Context.getFunctionType(ResType, &ArgTypes[0], ArgTypes.size(),
Argiris Kirtzidis65b99642008-10-26 16:43:14 +0000289 TypeStr[0] == '.', 0);
Chris Lattner4b009652007-07-25 00:24:17 +0000290}