blob: e345898b79cde5af4bc6adcfd22d65b69ccb28ca [file] [log] [blame]
Reid Spencer5f016e22007-07-11 17:01:13 +00001//===--- Builtins.cpp - Builtin function implementation -------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
Chris Lattner0bc735f2007-12-29 19:59:25 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Reid Spencer5f016e22007-07-11 17:01:13 +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 Dunbare91593e2008-08-11 04:54:23 +000016#include "clang/AST/Decl.h"
Chris Lattnerc7229c32007-10-07 08:58:51 +000017#include "clang/Basic/IdentifierTable.h"
Reid Spencer5f016e22007-07-11 17:01:13 +000018#include "clang/Basic/TargetInfo.h"
19using namespace clang;
20
21static const Builtin::Info BuiltinInfo[] = {
22 { "not a builtin function", 0, 0 },
23#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS },
24#include "clang/AST/Builtins.def"
25};
26
27const Builtin::Info &Builtin::Context::GetRecord(unsigned ID) const {
28 if (ID < Builtin::FirstTSBuiltin)
29 return BuiltinInfo[ID];
30 assert(ID - Builtin::FirstTSBuiltin < NumTSRecords && "Invalid builtin ID!");
31 return TSRecords[ID - Builtin::FirstTSBuiltin];
32}
33
34
35/// InitializeBuiltins - Mark the identifiers for all the builtins with their
36/// appropriate builtin ID # and mark any non-portable builtin identifiers as
37/// such.
38void Builtin::Context::InitializeBuiltins(IdentifierTable &Table,
39 const TargetInfo &Target) {
40 // Step #1: mark all target-independent builtins with their ID's.
41 for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i)
42 Table.get(BuiltinInfo[i].Name).setBuiltinID(i);
43
Chris Lattner42e67372008-03-05 01:18:20 +000044 // Step #2: Get target builtins.
45 Target.getTargetBuiltins(TSRecords, NumTSRecords);
Reid Spencer5f016e22007-07-11 17:01:13 +000046
Chris Lattner42e67372008-03-05 01:18:20 +000047 // Step #3: Register target-specific builtins.
Reid Spencer5f016e22007-07-11 17:01:13 +000048 for (unsigned i = 0, e = NumTSRecords; i != e; ++i)
49 Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin);
Reid Spencer5f016e22007-07-11 17:01:13 +000050}
51
Douglas Gregora316e7b2009-02-14 00:32:47 +000052std::string Builtin::Context::getHeaderName(unsigned ID) const {
53 char *Name = strchr(GetRecord(ID).Attributes, 'f');
54 if (!Name)
55 return 0;
56 ++Name;
57
58 if (*Name != ':')
59 return 0;
60
61 ++Name;
62 char *NameEnd = strchr(Name, ':');
63 assert(NameEnd && "Missing ':' after header name");
64 return std::string(Name, NameEnd);
65}
66
67bool
68Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx,
69 bool &HasVAListArg) {
70 char *Printf = strpbrk(GetRecord(ID).Attributes, "pP");
71 if (!Printf)
72 return false;
73
74 HasVAListArg = (*Printf == 'P');
75
76 ++Printf;
77 assert(*Printf == ':' && "p or P specifier must have be followed by a ':'");
78 ++Printf;
79
80 char *PrintfEnd = strchr(Printf, ':');
81 assert(PrintfEnd && "printf specifier must end with a ':'");
82
83 FormatIdx = strtol(Printf, 0, 10);
84 return true;
85}
86
Reid Spencer5f016e22007-07-11 17:01:13 +000087/// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the
88/// pointer over the consumed characters. This returns the resultant type.
Anders Carlssondd1b5162007-11-28 05:19:59 +000089static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
Douglas Gregor370ab3f2009-02-14 01:52:53 +000090 Builtin::Context::GetBuiltinTypeError &Error,
Anders Carlssondd1b5162007-11-28 05:19:59 +000091 bool AllowTypeModifiers = true) {
Reid Spencer5f016e22007-07-11 17:01:13 +000092 // Modifiers.
93 bool Long = false, LongLong = false, Signed = false, Unsigned = false;
94
95 // Read the modifiers first.
96 bool Done = false;
97 while (!Done) {
98 switch (*Str++) {
99 default: Done = true; --Str; break;
100 case 'S':
101 assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!");
102 assert(!Signed && "Can't use 'S' modifier multiple times!");
103 Signed = true;
104 break;
105 case 'U':
106 assert(!Signed && "Can't use both 'S' and 'U' modifiers!");
107 assert(!Unsigned && "Can't use 'S' modifier multiple times!");
108 Unsigned = true;
109 break;
110 case 'L':
111 assert(!LongLong && "Can't have LLL modifier");
112 if (Long)
113 LongLong = true;
114 else
115 Long = true;
116 break;
117 }
118 }
119
Anders Carlsson71993dd2007-08-17 05:31:46 +0000120 QualType Type;
121
Reid Spencer5f016e22007-07-11 17:01:13 +0000122 // Read the base type.
123 switch (*Str++) {
124 default: assert(0 && "Unknown builtin type letter!");
125 case 'v':
Steve Naroffe8770422007-08-08 17:48:34 +0000126 assert(!Long && !Signed && !Unsigned && "Bad modifiers used with 'v'!");
Anders Carlsson71993dd2007-08-17 05:31:46 +0000127 Type = Context.VoidTy;
128 break;
Reid Spencer5f016e22007-07-11 17:01:13 +0000129 case 'f':
130 assert(!Long && !Signed && !Unsigned && "Bad modifiers used with 'f'!");
Anders Carlsson71993dd2007-08-17 05:31:46 +0000131 Type = Context.FloatTy;
132 break;
Reid Spencer5f016e22007-07-11 17:01:13 +0000133 case 'd':
134 assert(!LongLong && !Signed && !Unsigned && "Bad modifiers used with 'd'!");
135 if (Long)
Anders Carlsson71993dd2007-08-17 05:31:46 +0000136 Type = Context.LongDoubleTy;
137 else
138 Type = Context.DoubleTy;
139 break;
Reid Spencer5f016e22007-07-11 17:01:13 +0000140 case 's':
141 assert(!LongLong && "Bad modifiers used with 's'!");
142 if (Unsigned)
Anders Carlsson71993dd2007-08-17 05:31:46 +0000143 Type = Context.UnsignedShortTy;
144 else
145 Type = Context.ShortTy;
146 break;
Steve Naroffe8770422007-08-08 17:48:34 +0000147 case 'i':
Anders Carlsson142f36d2007-11-27 07:22:09 +0000148 if (LongLong)
Anders Carlsson71993dd2007-08-17 05:31:46 +0000149 Type = Unsigned ? Context.UnsignedLongLongTy : Context.LongLongTy;
Anders Carlsson142f36d2007-11-27 07:22:09 +0000150 else if (Long)
151 Type = Unsigned ? Context.UnsignedLongTy : Context.LongTy;
Anders Carlsson71993dd2007-08-17 05:31:46 +0000152 else if (Unsigned)
153 Type = Context.UnsignedIntTy;
154 else
155 Type = Context.IntTy; // default is signed.
156 break;
157 case 'c':
158 assert(!Long && !LongLong && "Bad modifiers used with 'c'!");
159 if (Signed)
160 Type = Context.SignedCharTy;
161 else if (Unsigned)
162 Type = Context.UnsignedCharTy;
163 else
164 Type = Context.CharTy;
165 break;
Mon P Wang7ae48ee2008-10-18 02:49:28 +0000166 case 'b': // boolean
167 assert(!Long && !Signed && !Unsigned && "Bad modifiers for 'b'!");
168 Type = Context.BoolTy;
169 break;
Chris Lattner52735a02007-10-29 04:18:06 +0000170 case 'z': // size_t.
171 assert(!Long && !Signed && !Unsigned && "Bad modifiers for 'z'!");
172 Type = Context.getSizeType();
173 break;
Anders Carlsson71993dd2007-08-17 05:31:46 +0000174 case 'F':
175 Type = Context.getCFConstantStringType();
176 break;
Anders Carlsson142f36d2007-11-27 07:22:09 +0000177 case 'a':
Anders Carlssonb2cf3572007-10-11 01:00:40 +0000178 Type = Context.getBuiltinVaListType();
Anders Carlsson793680e2007-10-12 23:56:29 +0000179 assert(!Type.isNull() && "builtin va list type not initialized!");
Anders Carlssonb2cf3572007-10-11 01:00:40 +0000180 break;
Eli Friedman6597f982009-01-20 07:46:22 +0000181 case 'A':
182 // This is a "reference" to a va_list; however, what exactly
183 // this means depends on how va_list is defined. There are two
184 // different kinds of va_list: ones passed by value, and ones
185 // passed by reference. An example of a by-value va_list is
186 // x86, where va_list is a char*. An example of by-ref va_list
187 // is x86-64, where va_list is a __va_list_tag[1]. For x86,
188 // we want this argument to be a char*&; for x86-64, we want
189 // it to be a __va_list_tag*.
190 Type = Context.getBuiltinVaListType();
191 assert(!Type.isNull() && "builtin va list type not initialized!");
192 if (Type->isArrayType()) {
193 Type = Context.getArrayDecayedType(Type);
194 } else {
195 Type = Context.getReferenceType(Type);
196 }
197 break;
Anders Carlsson142f36d2007-11-27 07:22:09 +0000198 case 'V': {
199 char *End;
200
201 unsigned NumElements = strtoul(Str, &End, 10);
202 assert(End != Str && "Missing vector size");
203
204 Str = End;
205
Douglas Gregor370ab3f2009-02-14 01:52:53 +0000206 QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false);
Anders Carlsson142f36d2007-11-27 07:22:09 +0000207 Type = Context.getVectorType(ElementType, NumElements);
208 break;
209 }
Douglas Gregor370ab3f2009-02-14 01:52:53 +0000210 case 'P': {
211 IdentifierInfo *II = &Context.Idents.get("FILE");
212 DeclContext::lookup_result Lookup
213 = Context.getTranslationUnitDecl()->lookup(II);
214 if (Lookup.first != Lookup.second && isa<TypeDecl>(*Lookup.first)) {
215 Type = Context.getTypeDeclType(cast<TypeDecl>(*Lookup.first));
216 break;
217 }
218 else {
219 Error = Builtin::Context::GE_Missing_FILE;
220 return QualType();
221 }
222 }
Reid Spencer5f016e22007-07-11 17:01:13 +0000223 }
Anders Carlsson71993dd2007-08-17 05:31:46 +0000224
Anders Carlssondd1b5162007-11-28 05:19:59 +0000225 if (!AllowTypeModifiers)
226 return Type;
227
Anders Carlsson71993dd2007-08-17 05:31:46 +0000228 Done = false;
229 while (!Done) {
230 switch (*Str++) {
Anders Carlssondd1b5162007-11-28 05:19:59 +0000231 default: Done = true; --Str; break;
Anders Carlsson71993dd2007-08-17 05:31:46 +0000232 case '*':
233 Type = Context.getPointerType(Type);
234 break;
Anders Carlsson793680e2007-10-12 23:56:29 +0000235 case '&':
236 Type = Context.getReferenceType(Type);
237 break;
Anders Carlsson71993dd2007-08-17 05:31:46 +0000238 case 'C':
239 Type = Type.getQualifiedType(QualType::Const);
240 break;
241 }
242 }
243
244 return Type;
Reid Spencer5f016e22007-07-11 17:01:13 +0000245}
246
247/// GetBuiltinType - Return the type for the specified builtin.
Douglas Gregor370ab3f2009-02-14 01:52:53 +0000248QualType Builtin::Context::GetBuiltinType(unsigned id, ASTContext &Context,
249 GetBuiltinTypeError &Error) const {
Reid Spencer5f016e22007-07-11 17:01:13 +0000250 const char *TypeStr = GetRecord(id).Type;
251
252 llvm::SmallVector<QualType, 8> ArgTypes;
253
Douglas Gregor370ab3f2009-02-14 01:52:53 +0000254 Error = GE_None;
255 QualType ResType = DecodeTypeFromStr(TypeStr, Context, Error);
256 if (Error != GE_None)
257 return QualType();
Chris Lattnerf77d5452008-09-29 22:28:25 +0000258 while (TypeStr[0] && TypeStr[0] != '.') {
Douglas Gregor370ab3f2009-02-14 01:52:53 +0000259 QualType Ty = DecodeTypeFromStr(TypeStr, Context, Error);
260 if (Error != GE_None)
261 return QualType();
262
Chris Lattnerf77d5452008-09-29 22:28:25 +0000263 // Do array -> pointer decay. The builtin should use the decayed type.
264 if (Ty->isArrayType())
265 Ty = Context.getArrayDecayedType(Ty);
266
267 ArgTypes.push_back(Ty);
268 }
Anders Carlssondd1b5162007-11-28 05:19:59 +0000269
Reid Spencer5f016e22007-07-11 17:01:13 +0000270 assert((TypeStr[0] != '.' || TypeStr[1] == 0) &&
271 "'.' should only occur at end of builtin type list!");
Steve Naroffe8770422007-08-08 17:48:34 +0000272
273 // handle untyped/variadic arguments "T c99Style();" or "T cppStyle(...);".
274 if (ArgTypes.size() == 0 && TypeStr[0] == '.')
275 return Context.getFunctionTypeNoProto(ResType);
Reid Spencer5f016e22007-07-11 17:01:13 +0000276 return Context.getFunctionType(ResType, &ArgTypes[0], ArgTypes.size(),
Argyrios Kyrtzidis7fb5e482008-10-26 16:43:14 +0000277 TypeStr[0] == '.', 0);
Reid Spencer5f016e22007-07-11 17:01:13 +0000278}