1194179Sed//===--- Builtins.cpp - Builtin function implementation -------------------===//
2194179Sed//
3194179Sed//                     The LLVM Compiler Infrastructure
4194179Sed//
5194179Sed// This file is distributed under the University of Illinois Open Source
6194179Sed// License. See LICENSE.TXT for details.
7194179Sed//
8194179Sed//===----------------------------------------------------------------------===//
9194179Sed//
10194179Sed//  This file implements various things for builtin functions.
11194179Sed//
12194179Sed//===----------------------------------------------------------------------===//
13194179Sed
14194179Sed#include "clang/Basic/Builtins.h"
15194179Sed#include "clang/Basic/IdentifierTable.h"
16252723Sdim#include "clang/Basic/LangOptions.h"
17194179Sed#include "clang/Basic/TargetInfo.h"
18235633Sdim#include "llvm/ADT/SmallVector.h"
19263509Sdim#include "llvm/ADT/StringRef.h"
20194179Sedusing namespace clang;
21194179Sed
22194179Sedstatic const Builtin::Info BuiltinInfo[] = {
23224145Sdim  { "not a builtin function", 0, 0, 0, ALL_LANGUAGES },
24224145Sdim#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
25263509Sdim#define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) { #ID, TYPE, ATTRS, 0, BUILTIN_LANG },
26218893Sdim#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, BUILTIN_LANG) { #ID, TYPE, ATTRS, HEADER,\
27224145Sdim                                                            BUILTIN_LANG },
28194179Sed#include "clang/Basic/Builtins.def"
29194179Sed};
30194179Sed
31194179Sedconst Builtin::Info &Builtin::Context::GetRecord(unsigned ID) const {
32194179Sed  if (ID < Builtin::FirstTSBuiltin)
33194179Sed    return BuiltinInfo[ID];
34194179Sed  assert(ID - Builtin::FirstTSBuiltin < NumTSRecords && "Invalid builtin ID!");
35194179Sed  return TSRecords[ID - Builtin::FirstTSBuiltin];
36194179Sed}
37194179Sed
38226890SdimBuiltin::Context::Context() {
39194613Sed  // Get the target specific builtins from the target.
40194613Sed  TSRecords = 0;
41194613Sed  NumTSRecords = 0;
42194613Sed}
43194613Sed
44226890Sdimvoid Builtin::Context::InitializeTarget(const TargetInfo &Target) {
45226890Sdim  assert(NumTSRecords == 0 && "Already initialized target?");
46226890Sdim  Target.getTargetBuiltins(TSRecords, NumTSRecords);
47226890Sdim}
48226890Sdim
49263509Sdimbool Builtin::Context::BuiltinIsSupported(const Builtin::Info &BuiltinInfo,
50263509Sdim                                          const LangOptions &LangOpts) {
51263509Sdim  bool BuiltinsUnsupported = LangOpts.NoBuiltin &&
52263509Sdim                             strchr(BuiltinInfo.Attributes, 'f');
53263509Sdim  bool MathBuiltinsUnsupported =
54263509Sdim    LangOpts.NoMathBuiltin && BuiltinInfo.HeaderName &&
55263509Sdim    llvm::StringRef(BuiltinInfo.HeaderName).equals("math.h");
56263509Sdim  bool GnuModeUnsupported = !LangOpts.GNUMode &&
57263509Sdim                            (BuiltinInfo.builtin_lang & GNU_LANG);
58263509Sdim  bool MSModeUnsupported = !LangOpts.MicrosoftExt &&
59263509Sdim                           (BuiltinInfo.builtin_lang & MS_LANG);
60263509Sdim  bool ObjCUnsupported = !LangOpts.ObjC1 &&
61263509Sdim                         BuiltinInfo.builtin_lang == OBJC_LANG;
62263509Sdim  return !BuiltinsUnsupported && !MathBuiltinsUnsupported &&
63263509Sdim         !GnuModeUnsupported && !MSModeUnsupported && !ObjCUnsupported;
64263509Sdim}
65263509Sdim
66194179Sed/// InitializeBuiltins - Mark the identifiers for all the builtins with their
67194179Sed/// appropriate builtin ID # and mark any non-portable builtin identifiers as
68194179Sed/// such.
69194179Sedvoid Builtin::Context::InitializeBuiltins(IdentifierTable &Table,
70218893Sdim                                          const LangOptions& LangOpts) {
71194179Sed  // Step #1: mark all target-independent builtins with their ID's.
72194179Sed  for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i)
73263509Sdim    if (BuiltinIsSupported(BuiltinInfo[i], LangOpts)) {
74263509Sdim      Table.get(BuiltinInfo[i].Name).setBuiltinID(i);
75218893Sdim    }
76194179Sed
77194179Sed  // Step #2: Register target-specific builtins.
78194179Sed  for (unsigned i = 0, e = NumTSRecords; i != e; ++i)
79224145Sdim    if (!LangOpts.NoBuiltin || !strchr(TSRecords[i].Attributes, 'f'))
80194179Sed      Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin);
81194179Sed}
82194179Sed
83198092Srdivackyvoid
84263509SdimBuiltin::Context::GetBuiltinNames(SmallVectorImpl<const char *> &Names) {
85194179Sed  // Final all target-independent names
86194179Sed  for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i)
87263509Sdim    if (!strchr(BuiltinInfo[i].Attributes, 'f'))
88194179Sed      Names.push_back(BuiltinInfo[i].Name);
89198092Srdivacky
90194179Sed  // Find target-specific names.
91194179Sed  for (unsigned i = 0, e = NumTSRecords; i != e; ++i)
92263509Sdim    if (!strchr(TSRecords[i].Attributes, 'f'))
93194179Sed      Names.push_back(TSRecords[i].Name);
94194179Sed}
95194179Sed
96218893Sdimvoid Builtin::Context::ForgetBuiltin(unsigned ID, IdentifierTable &Table) {
97218893Sdim  Table.get(GetRecord(ID).Name).setBuiltinID(0);
98218893Sdim}
99218893Sdim
100198092Srdivackybool
101198092SrdivackyBuiltin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx,
102194179Sed                               bool &HasVAListArg) {
103194179Sed  const char *Printf = strpbrk(GetRecord(ID).Attributes, "pP");
104194179Sed  if (!Printf)
105194179Sed    return false;
106194179Sed
107194179Sed  HasVAListArg = (*Printf == 'P');
108194179Sed
109194179Sed  ++Printf;
110194179Sed  assert(*Printf == ':' && "p or P specifier must have be followed by a ':'");
111194179Sed  ++Printf;
112194179Sed
113194179Sed  assert(strchr(Printf, ':') && "printf specifier must end with a ':'");
114194179Sed  FormatIdx = strtol(Printf, 0, 10);
115194179Sed  return true;
116194179Sed}
117194179Sed
118212904Sdim// FIXME: Refactor with isPrintfLike.
119212904Sdimbool
120212904SdimBuiltin::Context::isScanfLike(unsigned ID, unsigned &FormatIdx,
121212904Sdim                              bool &HasVAListArg) {
122212904Sdim  const char *Scanf = strpbrk(GetRecord(ID).Attributes, "sS");
123212904Sdim  if (!Scanf)
124212904Sdim    return false;
125212904Sdim
126212904Sdim  HasVAListArg = (*Scanf == 'S');
127212904Sdim
128212904Sdim  ++Scanf;
129212904Sdim  assert(*Scanf == ':' && "s or S specifier must have be followed by a ':'");
130212904Sdim  ++Scanf;
131212904Sdim
132212904Sdim  assert(strchr(Scanf, ':') && "printf specifier must end with a ':'");
133212904Sdim  FormatIdx = strtol(Scanf, 0, 10);
134212904Sdim  return true;
135212904Sdim}
136212904Sdim
137