slang_rs_export_func.cpp revision 3fa286b4c2f110c6be2bbfac9c715bb1ec880338
1/*
2 * Copyright 2010, 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_func.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
30namespace slang {
31
32RSExportFunc *RSExportFunc::Create(RSContext *Context,
33                                   const clang::FunctionDecl *FD) {
34  llvm::StringRef Name = FD->getName();
35  RSExportFunc *F;
36
37  slangAssert(!Name.empty() && "Function must have a name");
38
39  F = new RSExportFunc(Context, Name, FD);
40
41  // Initialize mParamPacketType
42  if (FD->getNumParams() <= 0) {
43    F->mParamPacketType = NULL;
44  } else {
45    clang::ASTContext &Ctx = Context->getASTContext();
46
47    std::string Id(DUMMY_RS_TYPE_NAME_PREFIX"helper_func_param:");
48    Id.append(F->getName()).append(DUMMY_RS_TYPE_NAME_POSTFIX);
49
50    clang::RecordDecl *RD =
51        clang::RecordDecl::Create(Ctx, clang::TTK_Struct,
52                                  Ctx.getTranslationUnitDecl(),
53                                  clang::SourceLocation(),
54                                  &Ctx.Idents.get(Id));
55
56    for (unsigned i = 0; i < FD->getNumParams(); i++) {
57      const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
58      llvm::StringRef ParamName = PVD->getName();
59
60      if (PVD->hasDefaultArg())
61        fprintf(stderr, "Note: parameter '%s' in function '%s' has default "
62                        "value which is not supported\n",
63                        ParamName.str().c_str(),
64                        F->getName().c_str());
65
66      clang::FieldDecl *FD =
67          clang::FieldDecl::Create(Ctx,
68                                   RD,
69                                   clang::SourceLocation(),
70                                   PVD->getIdentifier(),
71                                   PVD->getOriginalType(),
72                                   NULL,
73                                   /* BitWidth = */NULL,
74                                   /* Mutable = */false);
75      RD->addDecl(FD);
76    }
77
78    RD->completeDefinition();
79
80    clang::QualType T = Ctx.getTagDeclType(RD);
81    slangAssert(!T.isNull());
82
83    RSExportType *ET =
84      RSExportType::Create(Context, T.getTypePtr());
85
86    if (ET == NULL) {
87      fprintf(stderr, "Failed to export the function %s. There's at least one  "
88                      "parameter whose type is not supported by the "
89                      "reflection", F->getName().c_str());
90      delete F;
91      return NULL;
92    }
93
94    slangAssert((ET->getClass() == RSExportType::ExportClassRecord) &&
95           "Parameter packet must be a record");
96
97    F->mParamPacketType = static_cast<RSExportRecordType *>(ET);
98  }
99
100  return F;
101}
102
103bool
104RSExportFunc::checkParameterPacketType(const llvm::StructType *ParamTy) const {
105  if (ParamTy == NULL)
106    return !hasParam();
107  else if (!hasParam())
108    return false;
109
110  slangAssert(mParamPacketType != NULL);
111
112  const RSExportRecordType *ERT = mParamPacketType;
113  // must have same number of elements
114  if (ERT->getFields().size() != ParamTy->getNumElements())
115    return false;
116
117  const llvm::StructLayout *ParamTySL =
118      getRSContext()->getTargetData()->getStructLayout(ParamTy);
119
120  unsigned Index = 0;
121  for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(),
122       FE = ERT->fields_end(); FI != FE; FI++, Index++) {
123    const RSExportRecordType::Field *F = *FI;
124
125    const llvm::Type *T1 = F->getType()->getLLVMType();
126    const llvm::Type *T2 = ParamTy->getTypeAtIndex(Index);
127
128    // Fast check
129    if (T1 == T2)
130      continue;
131
132    // Check offset
133    size_t T1Offset = F->getOffsetInParent();
134    size_t T2Offset = ParamTySL->getElementOffset(Index);
135
136    if (T1Offset != T2Offset)
137      return false;
138
139    // Check size
140    size_t T1Size = RSExportType::GetTypeAllocSize(F->getType());
141    size_t T2Size = getRSContext()->getTargetData()->getTypeAllocSize(T2);
142
143    if (T1Size != T2Size)
144      return false;
145  }
146
147  return true;
148}
149
150}  // namespace slang
151