slang_rs_export_foreach.cpp revision 593a894650e81be54173106ec266f0311cebebd3
1/*
2 * Copyright 2011, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "slang_rs_export_foreach.h"
18
19#include <string>
20
21#include "clang/AST/ASTContext.h"
22#include "clang/AST/Decl.h"
23
24#include "llvm/DerivedTypes.h"
25#include "llvm/Target/TargetData.h"
26
27#include "slang_assert.h"
28#include "slang_rs_context.h"
29#include "slang_rs_export_type.h"
30
31namespace slang {
32
33RSExportForEach *RSExportForEach::Create(RSContext *Context,
34                                         const clang::FunctionDecl *FD) {
35  llvm::StringRef Name = FD->getName();
36  RSExportForEach *F;
37
38  slangAssert(!Name.empty() && "Function must have a name");
39
40  F = new RSExportForEach(Context, Name, FD);
41
42  F->numParams = FD->getNumParams();
43
44  if (F->numParams == 0) {
45    slangAssert(false && "Should have at least one parameter for root");
46  }
47
48  clang::ASTContext &Ctx = Context->getASTContext();
49
50  std::string Id(DUMMY_RS_TYPE_NAME_PREFIX"helper_foreach_param:");
51  Id.append(F->getName()).append(DUMMY_RS_TYPE_NAME_POSTFIX);
52
53  clang::RecordDecl *RD =
54      clang::RecordDecl::Create(Ctx, clang::TTK_Struct,
55                                Ctx.getTranslationUnitDecl(),
56                                clang::SourceLocation(),
57                                clang::SourceLocation(),
58                                &Ctx.Idents.get(Id));
59
60  // Extract the usrData parameter (if we have one)
61  if (F->numParams >= 3) {
62    const clang::ParmVarDecl *PVD = FD->getParamDecl(2);
63    clang::QualType QT = PVD->getType().getCanonicalType();
64    slangAssert(QT->isPointerType() &&
65                QT->getPointeeType().isConstQualified());
66
67    const clang::ASTContext &C = Context->getASTContext();
68    if (QT->getPointeeType().getCanonicalType().getUnqualifiedType() ==
69        C.VoidTy) {
70      // In the case of using const void*, we can't reflect an appopriate
71      // Java type, so we fall back to just reflecting the ain/aout parameters
72      F->numParams = 2;
73    } else {
74      llvm::StringRef ParamName = PVD->getName();
75      clang::FieldDecl *FD =
76          clang::FieldDecl::Create(Ctx,
77                                   RD,
78                                   clang::SourceLocation(),
79                                   clang::SourceLocation(),
80                                   PVD->getIdentifier(),
81                                   QT->getPointeeType(),
82                                   NULL,
83                                   /* BitWidth = */NULL,
84                                   /* Mutable = */false);
85      RD->addDecl(FD);
86    }
87  }
88  RD->completeDefinition();
89
90  if (F->numParams >= 3) {
91    // Create an export type iff we have a valid usrData type
92    clang::QualType T = Ctx.getTagDeclType(RD);
93    slangAssert(!T.isNull());
94
95    RSExportType *ET =
96      RSExportType::Create(Context, T.getTypePtr());
97
98    if (ET == NULL) {
99      fprintf(stderr, "Failed to export the function %s. There's at least one "
100                      "parameter whose type is not supported by the "
101                      "reflection\n", F->getName().c_str());
102      delete F;
103      return NULL;
104    }
105
106    slangAssert((ET->getClass() == RSExportType::ExportClassRecord) &&
107           "Parameter packet must be a record");
108
109    F->mParamPacketType = static_cast<RSExportRecordType *>(ET);
110  }
111
112  return F;
113}
114
115bool RSExportForEach::isRSForEachFunc(const clang::FunctionDecl *FD) {
116  // We currently support only compute root() being exported via forEach
117  if (!isRootRSFunc(FD)) {
118    return false;
119  }
120
121  const clang::ASTContext &C = FD->getASTContext();
122  if (FD->getNumParams() == 0 &&
123      FD->getResultType().getCanonicalType() == C.IntTy) {
124    // Graphics compute function
125    return false;
126  }
127  return true;
128}
129
130bool RSExportForEach::validateSpecialFuncDecl(clang::Diagnostic *Diags,
131                                              const clang::FunctionDecl *FD) {
132  if (!FD) {
133    return false;
134  }
135
136  bool valid = true;
137  const clang::ASTContext &C = FD->getASTContext();
138
139  if (isRootRSFunc(FD)) {
140    unsigned int numParams = FD->getNumParams();
141    if (numParams == 0) {
142      // Graphics root function, so verify that it returns an int
143      if (FD->getResultType().getCanonicalType() != C.IntTy) {
144        Diags->Report(
145            clang::FullSourceLoc(FD->getLocation(), Diags->getSourceManager()),
146            Diags->getCustomDiagID(clang::Diagnostic::Error,
147                                   "root(void) is required to return "
148                                   "an int for graphics usage"));
149        valid = false;
150      }
151    } else {
152      // Compute root functions are required to return a void type for now
153      if (FD->getResultType().getCanonicalType() != C.VoidTy) {
154        Diags->Report(
155            clang::FullSourceLoc(FD->getLocation(), Diags->getSourceManager()),
156            Diags->getCustomDiagID(clang::Diagnostic::Error,
157                                   "compute root() is required to return a "
158                                   "void type"));
159        valid = false;
160      }
161
162      // Validate remaining parameter types
163      const clang::ParmVarDecl *tooManyParams = NULL;
164      for (unsigned int i = 0; i < numParams; i++) {
165        const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
166        clang::QualType QT = PVD->getType().getCanonicalType();
167        switch (i) {
168          case 0:     // const T1 *ain
169          case 2: {   // const T3 *usrData
170            if (!QT->isPointerType() ||
171                !QT->getPointeeType().isConstQualified()) {
172              Diags->Report(
173                  clang::FullSourceLoc(PVD->getLocation(),
174                                       Diags->getSourceManager()),
175                  Diags->getCustomDiagID(clang::Diagnostic::Error,
176                                         "compute root() parameter must be a "
177                                         "const pointer type"));
178              valid = false;
179            }
180            break;
181          }
182          case 1: {   // T2 *aout
183            if (!QT->isPointerType()) {
184              Diags->Report(
185                  clang::FullSourceLoc(PVD->getLocation(),
186                                       Diags->getSourceManager()),
187                  Diags->getCustomDiagID(clang::Diagnostic::Error,
188                                         "compute root() parameter must be a "
189                                         "pointer type"));
190              valid = false;
191            }
192            break;
193          }
194          case 3:     // unsigned int x
195          case 4:     // unsigned int y
196          case 5:     // unsigned int z
197          case 6: {   // unsigned int ar
198            if (QT.getUnqualifiedType() != C.UnsignedIntTy) {
199              Diags->Report(
200                  clang::FullSourceLoc(PVD->getLocation(),
201                                       Diags->getSourceManager()),
202                  Diags->getCustomDiagID(clang::Diagnostic::Error,
203                                         "compute root() parameter must be a "
204                                         "uint32_t type"));
205              valid = false;
206            }
207            break;
208          }
209          default: {
210            if (!tooManyParams) {
211              tooManyParams = PVD;
212            }
213            break;
214          }
215        }
216      }
217      if (tooManyParams) {
218        Diags->Report(
219            clang::FullSourceLoc(tooManyParams->getLocation(),
220                                 Diags->getSourceManager()),
221            Diags->getCustomDiagID(clang::Diagnostic::Error,
222                                   "too many compute root() parameters "
223                                   "specified"));
224        valid = false;
225      }
226    }
227  } else if (isInitRSFunc(FD)) {
228    if (FD->getNumParams() != 0) {
229      Diags->Report(
230          clang::FullSourceLoc(FD->getLocation(), Diags->getSourceManager()),
231          Diags->getCustomDiagID(clang::Diagnostic::Error,
232                                 "init(void) is required to have no "
233                                 "parameters"));
234      valid = false;
235    }
236
237    if (FD->getResultType().getCanonicalType() != C.VoidTy) {
238      Diags->Report(
239          clang::FullSourceLoc(FD->getLocation(), Diags->getSourceManager()),
240          Diags->getCustomDiagID(clang::Diagnostic::Error,
241                                 "init(void) is required to have a void "
242                                 "return type"));
243      valid = false;
244    }
245  } else {
246    slangAssert(false && "must be called on init or root function!");
247  }
248
249  return valid;
250}
251
252}  // namespace slang
253