blob: eae72ad0a6698bd97eab1f976b9fa633f758ed83 [file] [log] [blame]
Matt Walac0c5dd82015-07-23 17:29:37 -07001/*
2 * Copyright 2015, 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_reduce.h"
18
19#include <algorithm>
20#include <string>
21
22#include "clang/AST/Attr.h"
Matt Walaf59fffe2015-07-30 13:10:17 -070023#include "clang/AST/ASTContext.h"
Matt Walac0c5dd82015-07-23 17:29:37 -070024
25#include "slang_assert.h"
26#include "slang_rs_context.h"
27#include "slang_rs_export_type.h"
28#include "slang_version.h"
29
30
31namespace {
32
33bool haveReduceInTargetAPI(unsigned int TargetAPI) {
34 return TargetAPI == RS_DEVELOPMENT_API;
35}
36
37} // end anonymous namespace
38
39
40namespace slang {
41
42// Validate the parameters to a reduce kernel, and set up the
43// exportable object if the kernel is valid.
44//
45// This checks that the passed function declaration of a reduce kernel is
46// a function which satisfies all the requirements for a reduce
47// kernel. Namely, we check for:
48// - correct target API
49// - correct parameter count
50// - non void return type
51// - return type and parameter types match
52// - no pointer types in signature.
53//
54// We try to report useful errors to the user.
55//
56// On success, this function returns true and sets the fields mIns and
57// mType to point to the arguments and to the kernel type.
58//
59// If an error was detected, this function returns false.
60bool RSExportReduce::validateAndConstructParams(
61 RSContext *Context, const clang::FunctionDecl *FD) {
62 slangAssert(Context && FD);
63 bool Valid = true;
64
Matt Walaf59fffe2015-07-30 13:10:17 -070065 clang::ASTContext &ASTCtx = FD->getASTContext();
66
Matt Walac0c5dd82015-07-23 17:29:37 -070067 // Validate API version.
68 if (!haveReduceInTargetAPI(Context->getTargetAPI())) {
69 Context->ReportError(FD->getLocation(),
70 "Reduce-style kernel %0() unsupported in SDK level %1")
71 << FD->getName() << Context->getTargetAPI();
72 Valid = false;
73 }
74
75 // Validate parameter count.
76 if (FD->getNumParams() != 2) {
77 Context->ReportError(FD->getLocation(),
78 "Reduce-style kernel %0() must take 2 parameters "
79 "(found %1).")
80 << FD->getName() << FD->getNumParams();
81 Valid = false;
82 }
83
84 // Validate return type.
85 const clang::QualType ReturnTy = FD->getReturnType().getCanonicalType();
86
87 if (ReturnTy->isVoidType()) {
88 Context->ReportError(FD->getLocation(),
89 "Reduce-style kernel %0() cannot return void")
90 << FD->getName();
91 Valid = false;
92 } else if (ReturnTy->isPointerType()) {
93 Context->ReportError(FD->getLocation(),
94 "Reduce-style kernel %0() cannot return a pointer "
95 "type: %1")
96 << FD->getName() << ReturnTy.getAsString();
97 Valid = false;
98 }
99
100 // Validate parameter types.
101 if (FD->getNumParams() == 0) {
102 return false;
103 }
104
105 const clang::ParmVarDecl &FirstParam = *FD->getParamDecl(0);
106 const clang::QualType FirstParamTy = FirstParam.getType().getCanonicalType();
107
108 for (auto PVD = FD->param_begin(), PE = FD->param_end(); PVD != PE; ++PVD) {
109 const clang::ParmVarDecl &Param = **PVD;
110 const clang::QualType ParamTy = Param.getType().getCanonicalType();
111
112 // Check that the parameter is not a pointer.
113 if (ParamTy->isPointerType()) {
114 Context->ReportError(Param.getLocation(),
115 "Reduce-style kernel %0() cannot have "
116 "parameter '%1' of pointer type: '%2'")
117 << FD->getName() << Param.getName() << ParamTy.getAsString();
118 Valid = false;
119 }
120
121 // Check for type mismatch between this parameter and the return type.
Matt Walaf59fffe2015-07-30 13:10:17 -0700122 if (!ASTCtx.hasSameUnqualifiedType(ReturnTy, ParamTy)) {
Matt Walac0c5dd82015-07-23 17:29:37 -0700123 Context->ReportError(FD->getLocation(),
124 "Reduce-style kernel %0() return type '%1' is not "
125 "the same type as parameter '%2' (type '%3')")
126 << FD->getName() << ReturnTy.getAsString() << Param.getName()
127 << ParamTy.getAsString();
128 Valid = false;
129 }
130
131 // Check for type mismatch between parameters. It is sufficient to check
132 // for a mismatch with the type of the first argument.
133 if (ParamTy != FirstParamTy) {
134 Context->ReportError(FirstParam.getLocation(),
135 "In reduce-style kernel %0(): parameter '%1' "
136 "(type '%2') does not have the same type as "
137 "parameter '%3' (type '%4')")
138 << FD->getName() << FirstParam.getName() << FirstParamTy.getAsString()
139 << Param.getName() << ParamTy.getAsString();
140 Valid = false;
141 }
142 }
143
144 if (Valid) {
145 // If the validation was successful, then populate the fields of
146 // the exportable.
147 if (!(mType = RSExportType::Create(Context, ReturnTy.getTypePtr()))) {
148 // There was an error exporting the type for the reduce kernel.
149 return false;
150 }
151
152 slangAssert(mIns.size() == 2 && FD->param_end() - FD->param_begin() == 2);
153 std::copy(FD->param_begin(), FD->param_end(), mIns.begin());
154 }
155
156 return Valid;
157}
158
159RSExportReduce *RSExportReduce::Create(RSContext *Context,
160 const clang::FunctionDecl *FD) {
161 slangAssert(Context && FD);
162 llvm::StringRef Name = FD->getName();
163
164 slangAssert(!Name.empty() && "Function must have a name");
165
166 RSExportReduce *RE = new RSExportReduce(Context, Name);
167
168 if (!RE->validateAndConstructParams(Context, FD)) {
169 // Don't delete RE here - owned by Context.
170 return nullptr;
171 }
172
173 return RE;
174}
175
176bool RSExportReduce::isRSReduceFunc(unsigned int /* targetAPI */,
177 const clang::FunctionDecl *FD) {
178 slangAssert(FD);
179 clang::KernelAttr *KernelAttrOrNull = FD->getAttr<clang::KernelAttr>();
180 return KernelAttrOrNull && KernelAttrOrNull->getKernelKind().equals("reduce");
181}
182
183} // namespace slang