1 //
2 // Copyright (c) 2017 The Khronos Group Inc.
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 #include "parseParameters.h"
17 
18 #include "errorHelpers.h"
19 #include "testHarness.h"
20 #include "ThreadPool.h"
21 
22 #include <iostream>
23 #include <sstream>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <string.h>
27 
28 using namespace std;
29 
30 #define DEFAULT_COMPILATION_PROGRAM "cl_offline_compiler"
31 
32 CompilationMode gCompilationMode = kOnline;
33 CompilationCacheMode gCompilationCacheMode = kCacheModeCompileIfAbsent;
34 std::string gCompilationCachePath = ".";
35 std::string gCompilationProgram = DEFAULT_COMPILATION_PROGRAM;
36 
helpInfo()37 void helpInfo()
38 {
39     log_info(
40         R"(Common options:
41     -h, --help
42         This help
43     --compilation-mode <mode>
44         Specify a compilation mode.  Mode can be:
45             online     Use online compilation (default)
46             binary     Use binary offline compilation
47             spir-v     Use SPIR-V offline compilation
48 
49 For offline compilation (binary and spir-v modes) only:
50     --compilation-cache-mode <cache-mode>
51         Specify a compilation caching mode:
52             compile-if-absent
53                 Read from cache if already populated, or else perform
54                 offline compilation (default)
55             force-read
56                 Force reading from the cache
57             overwrite
58                 Disable reading from the cache
59             dump-cl-files
60                 Dumps the .cl and build .options files used by the test suite
61     --compilation-cache-path <path>
62         Path for offline compiler output and CL source
63     --compilation-program <prog>
64         Program to use for offline compilation, defaults to:
65             )" DEFAULT_COMPILATION_PROGRAM "\n\n");
66 }
67 
parseCustomParam(int argc,const char * argv[],const char * ignore)68 int parseCustomParam(int argc, const char *argv[], const char *ignore)
69 {
70     int delArg = 0;
71 
72     for (int i = 1; i < argc; i++)
73     {
74         if (ignore != 0)
75         {
76             // skip parameters that require special/different treatment in
77             // application (generic interpretation and parameter removal will
78             // not be performed)
79             const char *ptr = strstr(ignore, argv[i]);
80             if (ptr != 0 && (ptr == ignore || ptr[-1] == ' ')
81                 && // first on list or ' ' before
82                 (ptr[strlen(argv[i])] == 0
83                  || ptr[strlen(argv[i])] == ' ')) // last on list or ' ' after
84                 continue;
85         }
86 
87         delArg = 0;
88 
89         if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0)
90         {
91             // Note: we don't increment delArg to delete this argument,
92             // to allow the caller's argument parsing routine to see the
93             // option and print its own help.
94             helpInfo();
95         }
96         else if (!strcmp(argv[i], "--compilation-mode"))
97         {
98             delArg++;
99             if ((i + 1) < argc)
100             {
101                 delArg++;
102                 const char *mode = argv[i + 1];
103 
104                 if (!strcmp(mode, "online"))
105                 {
106                     gCompilationMode = kOnline;
107                 }
108                 else if (!strcmp(mode, "binary"))
109                 {
110                     gCompilationMode = kBinary;
111                 }
112                 else if (!strcmp(mode, "spir-v"))
113                 {
114                     gCompilationMode = kSpir_v;
115                 }
116                 else
117                 {
118                     log_error("Compilation mode not recognized: %s\n", mode);
119                     return -1;
120                 }
121                 log_info("Compilation mode specified: %s\n", mode);
122             }
123             else
124             {
125                 log_error("Compilation mode parameters are incorrect. Usage:\n"
126                           "  --compilation-mode <online|binary|spir-v>\n");
127                 return -1;
128             }
129         }
130         else if (!strcmp(argv[i], "--compilation-cache-mode"))
131         {
132             delArg++;
133             if ((i + 1) < argc)
134             {
135                 delArg++;
136                 const char *mode = argv[i + 1];
137 
138                 if (!strcmp(mode, "compile-if-absent"))
139                 {
140                     gCompilationCacheMode = kCacheModeCompileIfAbsent;
141                 }
142                 else if (!strcmp(mode, "force-read"))
143                 {
144                     gCompilationCacheMode = kCacheModeForceRead;
145                 }
146                 else if (!strcmp(mode, "overwrite"))
147                 {
148                     gCompilationCacheMode = kCacheModeOverwrite;
149                 }
150                 else if (!strcmp(mode, "dump-cl-files"))
151                 {
152                     gCompilationCacheMode = kCacheModeDumpCl;
153                 }
154                 else
155                 {
156                     log_error("Compilation cache mode not recognized: %s\n",
157                               mode);
158                     return -1;
159                 }
160                 log_info("Compilation cache mode specified: %s\n", mode);
161             }
162             else
163             {
164                 log_error(
165                     "Compilation cache mode parameters are incorrect. Usage:\n"
166                     "  --compilation-cache-mode "
167                     "<compile-if-absent|force-read|overwrite>\n");
168                 return -1;
169             }
170         }
171         else if (!strcmp(argv[i], "--compilation-cache-path"))
172         {
173             delArg++;
174             if ((i + 1) < argc)
175             {
176                 delArg++;
177                 gCompilationCachePath = argv[i + 1];
178             }
179             else
180             {
181                 log_error("Path argument for --compilation-cache-path was not "
182                           "specified.\n");
183                 return -1;
184             }
185         }
186         else if (!strcmp(argv[i], "--compilation-program"))
187         {
188             delArg++;
189             if ((i + 1) < argc)
190             {
191                 delArg++;
192                 gCompilationProgram = argv[i + 1];
193             }
194             else
195             {
196                 log_error("Program argument for --compilation-program was not "
197                           "specified.\n");
198                 return -1;
199             }
200         }
201 
202         // cleaning parameters from argv tab
203         for (int j = i; j < argc - delArg; j++) argv[j] = argv[j + delArg];
204         argc -= delArg;
205         i -= delArg;
206     }
207 
208     if ((gCompilationCacheMode == kCacheModeForceRead
209          || gCompilationCacheMode == kCacheModeOverwrite)
210         && gCompilationMode == kOnline)
211     {
212         log_error("Compilation cache mode can only be specified when using an "
213                   "offline compilation mode.\n");
214         return -1;
215     }
216 
217     return argc;
218 }
219 
is_power_of_two(int number)220 bool is_power_of_two(int number) { return number && !(number & (number - 1)); }
221 
parseWimpyReductionFactor(const char * & arg,int & wimpyReductionFactor)222 extern void parseWimpyReductionFactor(const char *&arg,
223                                       int &wimpyReductionFactor)
224 {
225     const char *arg_temp = strchr(&arg[1], ']');
226     if (arg_temp != 0)
227     {
228         int new_factor = atoi(&arg[1]);
229         arg = arg_temp; // Advance until ']'
230         if (is_power_of_two(new_factor))
231         {
232             log_info("\n Wimpy reduction factor changed from %d to %d \n",
233                      wimpyReductionFactor, new_factor);
234             wimpyReductionFactor = new_factor;
235         }
236         else
237         {
238             log_info("\n WARNING: Incorrect wimpy reduction factor %d, must be "
239                      "power of 2. The default value will be used.\n",
240                      new_factor);
241         }
242     }
243 }
244