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