blob: 5fc36f1546ebd0bcc7cc6799669dfc1c694e5657 [file] [log] [blame]
Zonr Changc383a502010-10-12 01:52:08 +08001/*
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
zonr6315f762010-10-05 15:35:14 +080017#include "slang_rs_export_func.h"
Shih-wei Liao462aefd2010-06-04 15:32:04 -070018
Stephen Hinese639eb52010-11-08 19:27:20 -080019#include <string>
Shih-wei Liao0a3f20e2010-08-10 13:09:49 -070020
Zonr Chang0da0a7d2010-10-05 21:26:37 +080021#include "clang/AST/ASTContext.h"
Shih-wei Liao9ef2f782010-10-01 12:31:37 -070022#include "clang/AST/Decl.h"
Shih-wei Liao462aefd2010-06-04 15:32:04 -070023
Stephen Hines23c43582013-01-09 20:02:04 -080024#include "llvm/IR/DataLayout.h"
25#include "llvm/IR/DerivedTypes.h"
Stephen Hinese639eb52010-11-08 19:27:20 -080026
Stephen Hines6e6578a2011-02-07 18:05:48 -080027#include "slang_assert.h"
zonr6315f762010-10-05 15:35:14 +080028#include "slang_rs_context.h"
zonr6315f762010-10-05 15:35:14 +080029
Stephen Hinese639eb52010-11-08 19:27:20 -080030namespace slang {
Shih-wei Liao462aefd2010-06-04 15:32:04 -070031
Stephen Hines5baf6322011-04-25 17:21:15 -070032namespace {
33
34// Ensure that the exported function is actually valid
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -080035static bool ValidateFuncDecl(slang::RSContext *Context,
Stephen Hines5baf6322011-04-25 17:21:15 -070036 const clang::FunctionDecl *FD) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -080037 slangAssert(Context && FD);
Stephen Hines5baf6322011-04-25 17:21:15 -070038 const clang::ASTContext &C = FD->getASTContext();
Tim Murrayee4016d2014-04-10 15:49:08 -070039 if (FD->getReturnType().getCanonicalType() != C.VoidTy) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -080040 Context->ReportError(
41 FD->getLocation(),
42 "invokable non-static functions are required to return void");
Stephen Hines5baf6322011-04-25 17:21:15 -070043 return false;
44 }
45 return true;
46}
47
48} // namespace
49
Shih-wei Liao9ef2f782010-10-01 12:31:37 -070050RSExportFunc *RSExportFunc::Create(RSContext *Context,
51 const clang::FunctionDecl *FD) {
52 llvm::StringRef Name = FD->getName();
53 RSExportFunc *F;
Shih-wei Liao462aefd2010-06-04 15:32:04 -070054
Stephen Hines6e6578a2011-02-07 18:05:48 -080055 slangAssert(!Name.empty() && "Function must have a name");
Shih-wei Liao462aefd2010-06-04 15:32:04 -070056
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -080057 if (!ValidateFuncDecl(Context, FD)) {
Stephen Hines5baf6322011-04-25 17:21:15 -070058 return NULL;
59 }
60
Shih-wei Liao3fa286b2011-02-10 11:04:44 -080061 F = new RSExportFunc(Context, Name, FD);
Shih-wei Liao462aefd2010-06-04 15:32:04 -070062
Zonr Chang0da0a7d2010-10-05 21:26:37 +080063 // Initialize mParamPacketType
64 if (FD->getNumParams() <= 0) {
65 F->mParamPacketType = NULL;
66 } else {
Stephen Hines9e5b5032010-11-03 13:19:14 -070067 clang::ASTContext &Ctx = Context->getASTContext();
Shih-wei Liao462aefd2010-06-04 15:32:04 -070068
Jean-Luc Brouilleteca05342014-05-15 12:44:21 -070069 std::string Id = CreateDummyName("helper_func_param", F->getName());
Shih-wei Liao462aefd2010-06-04 15:32:04 -070070
Zonr Chang0da0a7d2010-10-05 21:26:37 +080071 clang::RecordDecl *RD =
Stephen Hines9e5b5032010-11-03 13:19:14 -070072 clang::RecordDecl::Create(Ctx, clang::TTK_Struct,
73 Ctx.getTranslationUnitDecl(),
Zonr Chang0da0a7d2010-10-05 21:26:37 +080074 clang::SourceLocation(),
Shih-wei Liaocc887ba2011-04-19 18:36:20 -070075 clang::SourceLocation(),
Stephen Hines9e5b5032010-11-03 13:19:14 -070076 &Ctx.Idents.get(Id));
Shih-wei Liao462aefd2010-06-04 15:32:04 -070077
Zonr Chang0da0a7d2010-10-05 21:26:37 +080078 for (unsigned i = 0; i < FD->getNumParams(); i++) {
79 const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
80 llvm::StringRef ParamName = PVD->getName();
81
82 if (PVD->hasDefaultArg())
83 fprintf(stderr, "Note: parameter '%s' in function '%s' has default "
84 "value which is not supported\n",
85 ParamName.str().c_str(),
86 F->getName().c_str());
87
88 clang::FieldDecl *FD =
Stephen Hines9e5b5032010-11-03 13:19:14 -070089 clang::FieldDecl::Create(Ctx,
Zonr Chang0da0a7d2010-10-05 21:26:37 +080090 RD,
91 clang::SourceLocation(),
Shih-wei Liaocc887ba2011-04-19 18:36:20 -070092 clang::SourceLocation(),
Zonr Chang0da0a7d2010-10-05 21:26:37 +080093 PVD->getIdentifier(),
94 PVD->getOriginalType(),
95 NULL,
Shih-wei Liaofd6ea6a2011-06-22 04:50:15 -070096 /* BitWidth = */ NULL,
97 /* Mutable = */ false,
Shih-wei Liao43730fe2012-08-02 23:06:18 -070098 /* HasInit = */ clang::ICIS_NoInit);
Zonr Chang0da0a7d2010-10-05 21:26:37 +080099 RD->addDecl(FD);
100 }
101
102 RD->completeDefinition();
103
Stephen Hines9e5b5032010-11-03 13:19:14 -0700104 clang::QualType T = Ctx.getTagDeclType(RD);
Stephen Hines6e6578a2011-02-07 18:05:48 -0800105 slangAssert(!T.isNull());
Zonr Chang0da0a7d2010-10-05 21:26:37 +0800106
107 RSExportType *ET =
108 RSExportType::Create(Context, T.getTypePtr());
109
110 if (ET == NULL) {
Stephen Hines5baf6322011-04-25 17:21:15 -0700111 fprintf(stderr, "Failed to export the function %s. There's at least one "
Zonr Chang0da0a7d2010-10-05 21:26:37 +0800112 "parameter whose type is not supported by the "
Stephen Hines5baf6322011-04-25 17:21:15 -0700113 "reflection\n", F->getName().c_str());
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700114 return NULL;
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700115 }
Zonr Chang0da0a7d2010-10-05 21:26:37 +0800116
Stephen Hines6e6578a2011-02-07 18:05:48 -0800117 slangAssert((ET->getClass() == RSExportType::ExportClassRecord) &&
Zonr Chang0da0a7d2010-10-05 21:26:37 +0800118 "Parameter packet must be a record");
119
120 F->mParamPacketType = static_cast<RSExportRecordType *>(ET);
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700121 }
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700122
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700123 return F;
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700124}
125
Zonr Chang0da0a7d2010-10-05 21:26:37 +0800126bool
Logan Chienab992e52011-07-20 22:06:52 +0800127RSExportFunc::checkParameterPacketType(llvm::StructType *ParamTy) const {
Zonr Chang0da0a7d2010-10-05 21:26:37 +0800128 if (ParamTy == NULL)
129 return !hasParam();
130 else if (!hasParam())
131 return false;
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700132
Stephen Hines6e6578a2011-02-07 18:05:48 -0800133 slangAssert(mParamPacketType != NULL);
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700134
Zonr Chang0da0a7d2010-10-05 21:26:37 +0800135 const RSExportRecordType *ERT = mParamPacketType;
136 // must have same number of elements
137 if (ERT->getFields().size() != ParamTy->getNumElements())
138 return false;
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700139
Zonr Chang0da0a7d2010-10-05 21:26:37 +0800140 const llvm::StructLayout *ParamTySL =
Stephen Hines23c43582013-01-09 20:02:04 -0800141 getRSContext()->getDataLayout()->getStructLayout(ParamTy);
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700142
Zonr Chang0da0a7d2010-10-05 21:26:37 +0800143 unsigned Index = 0;
144 for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(),
145 FE = ERT->fields_end(); FI != FE; FI++, Index++) {
146 const RSExportRecordType::Field *F = *FI;
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700147
Logan Chienab992e52011-07-20 22:06:52 +0800148 llvm::Type *T1 = F->getType()->getLLVMType();
149 llvm::Type *T2 = ParamTy->getTypeAtIndex(Index);
Zonr Chang0da0a7d2010-10-05 21:26:37 +0800150
151 // Fast check
152 if (T1 == T2)
153 continue;
154
155 // Check offset
156 size_t T1Offset = F->getOffsetInParent();
157 size_t T2Offset = ParamTySL->getElementOffset(Index);
158
159 if (T1Offset != T2Offset)
160 return false;
161
162 // Check size
Jean-Luc Brouilletc95381a2014-05-14 21:24:45 -0700163 size_t T1Size = F->getType()->getAllocSize();
Stephen Hines23c43582013-01-09 20:02:04 -0800164 size_t T2Size = getRSContext()->getDataLayout()->getTypeAllocSize(T2);
Zonr Chang0da0a7d2010-10-05 21:26:37 +0800165
166 if (T1Size != T2Size)
167 return false;
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700168 }
169
Zonr Chang0da0a7d2010-10-05 21:26:37 +0800170 return true;
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700171}
Stephen Hinese639eb52010-11-08 19:27:20 -0800172
173} // namespace slang