1 /*
2  * Copyright 2014, 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 "clang/Basic/DiagnosticOptions.h"
18 #include "clang/Driver/DriverDiagnostic.h"
19 #include "clang/Driver/Options.h"
20 #include "clang/Frontend/Utils.h"
21 
22 #include "llvm/Option/Arg.h"
23 #include "llvm/Option/ArgList.h"
24 #include "llvm/Option/Option.h"
25 #include "llvm/Option/OptTable.h"
26 
27 #include "rs_cc_options.h"
28 #include "slang.h"
29 #include "slang_assert.h"
30 
31 #include <cstdlib>
32 #include <string>
33 #include <utility>
34 #include <vector>
35 
36 enum {
37   OPT_INVALID = 0,  // This is not an option ID.
38 #define PREFIX(NAME, VALUE)
39 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
40                HELPTEXT, METAVAR)                                             \
41   OPT_##ID,
42 #include "RSCCOptions.inc"
43   LastOption
44 #undef OPTION
45 #undef PREFIX
46 };
47 
48 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
49 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
50                HELPTEXT, METAVAR)
51 #include "RSCCOptions.inc"
52 #undef OPTION
53 #undef PREFIX
54 
55 static const llvm::opt::OptTable::Info RSCCInfoTable[] = {
56 #define PREFIX(NAME, VALUE)
57 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
58                HELPTEXT, METAVAR)                                              \
59   {                                                                            \
60     PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
61         PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS                      \
62   }                                                                            \
63   ,
64 #include "RSCCOptions.inc"
65 #undef OPTION
66 #undef PREFIX
67 };
68 
69 namespace {
70 
71 class RSCCOptTable : public llvm::opt::OptTable {
72  public:
RSCCOptTable()73   RSCCOptTable()
74       : OptTable(RSCCInfoTable,
75                  sizeof(RSCCInfoTable) / sizeof(RSCCInfoTable[0])) {}
76 };
77 }
78 
createRSCCOptTable()79 llvm::opt::OptTable *slang::createRSCCOptTable() { return new RSCCOptTable(); }
80 
ParseArguments(llvm::SmallVectorImpl<const char * > & ArgVector,llvm::SmallVectorImpl<const char * > & Inputs,slang::RSCCOptions & Opts,clang::DiagnosticsEngine & DiagEngine)81 void slang::ParseArguments(llvm::SmallVectorImpl<const char *> &ArgVector,
82                            llvm::SmallVectorImpl<const char *> &Inputs,
83                            slang::RSCCOptions &Opts,
84                            clang::DiagnosticsEngine &DiagEngine) {
85   if (ArgVector.size() > 1) {
86     const char **ArgBegin = ArgVector.data() + 1;
87     const char **ArgEnd = ArgVector.data() + ArgVector.size();
88     unsigned MissingArgIndex, MissingArgCount;
89     std::unique_ptr<llvm::opt::OptTable> OptParser(slang::createRSCCOptTable());
90     std::unique_ptr<llvm::opt::InputArgList> Args(OptParser->ParseArgs(
91         ArgBegin, ArgEnd, MissingArgIndex, MissingArgCount));
92 
93     // Check for missing argument error.
94     if (MissingArgCount)
95       DiagEngine.Report(clang::diag::err_drv_missing_argument)
96           << Args->getArgString(MissingArgIndex) << MissingArgCount;
97 
98     clang::DiagnosticOptions DiagOpts;
99     DiagOpts.IgnoreWarnings = Args->hasArg(OPT_w);
100     DiagOpts.Warnings = Args->getAllArgValues(OPT_W);
101     clang::ProcessWarningOptions(DiagEngine, DiagOpts);
102 
103     // Issue errors on unknown arguments.
104     for (llvm::opt::arg_iterator it = Args->filtered_begin(OPT_UNKNOWN),
105                                  ie = Args->filtered_end();
106          it != ie; ++it)
107       DiagEngine.Report(clang::diag::err_drv_unknown_argument)
108           << (*it)->getAsString(*Args);
109 
110     for (llvm::opt::ArgList::const_iterator it = Args->begin(),
111                                             ie = Args->end();
112          it != ie; ++it) {
113       const llvm::opt::Arg *A = *it;
114       if (A->getOption().getKind() == llvm::opt::Option::InputClass)
115         Inputs.push_back(A->getValue());
116     }
117 
118     Opts.mIncludePaths = Args->getAllArgValues(OPT_I);
119 
120     Opts.mBitcodeOutputDir = Args->getLastArgValue(OPT_o);
121 
122     if (const llvm::opt::Arg *A = Args->getLastArg(OPT_M_Group)) {
123       switch (A->getOption().getID()) {
124         case OPT_M: {
125           Opts.mEmitDependency = true;
126           Opts.mOutputType = slang::Slang::OT_Dependency;
127           break;
128         }
129         case OPT_MD: {
130           Opts.mEmitDependency = true;
131           Opts.mOutputType = slang::Slang::OT_Bitcode;
132           break;
133         }
134         default: { slangAssert(false && "Invalid option in M group!"); }
135       }
136     }
137 
138     if (const llvm::opt::Arg *A = Args->getLastArg(OPT_Output_Type_Group)) {
139       switch (A->getOption().getID()) {
140         case OPT_emit_asm: {
141           Opts.mOutputType = slang::Slang::OT_Assembly;
142           break;
143         }
144         case OPT_emit_llvm: {
145           Opts.mOutputType = slang::Slang::OT_LLVMAssembly;
146           break;
147         }
148         case OPT_emit_bc: {
149           Opts.mOutputType = slang::Slang::OT_Bitcode;
150           break;
151         }
152         case OPT_emit_nothing: {
153           Opts.mOutputType = slang::Slang::OT_Nothing;
154           break;
155         }
156         default: {
157           slangAssert(false && "Invalid option in output type group!");
158         }
159       }
160     }
161 
162     if (Opts.mEmitDependency &&
163         ((Opts.mOutputType != slang::Slang::OT_Bitcode) &&
164          (Opts.mOutputType != slang::Slang::OT_Dependency)))
165       DiagEngine.Report(clang::diag::err_drv_argument_not_allowed_with)
166           << Args->getLastArg(OPT_M_Group)->getAsString(*Args)
167           << Args->getLastArg(OPT_Output_Type_Group)->getAsString(*Args);
168 
169     Opts.mAllowRSPrefix = Args->hasArg(OPT_allow_rs_prefix);
170 
171     Opts.mJavaReflectionPathBase =
172         Args->getLastArgValue(OPT_java_reflection_path_base);
173     Opts.mJavaReflectionPackageName =
174         Args->getLastArgValue(OPT_java_reflection_package_name);
175 
176     Opts.mRSPackageName = Args->getLastArgValue(OPT_rs_package_name);
177 
178     llvm::StringRef BitcodeStorageValue =
179         Args->getLastArgValue(OPT_bitcode_storage);
180     if (BitcodeStorageValue == "ar")
181       Opts.mBitcodeStorage = slang::BCST_APK_RESOURCE;
182     else if (BitcodeStorageValue == "jc")
183       Opts.mBitcodeStorage = slang::BCST_JAVA_CODE;
184     else if (!BitcodeStorageValue.empty())
185       DiagEngine.Report(clang::diag::err_drv_invalid_value)
186           << OptParser->getOptionName(OPT_bitcode_storage)
187           << BitcodeStorageValue;
188 
189     llvm::opt::Arg *lastBitwidthArg = Args->getLastArg(OPT_m32, OPT_m64);
190     if (Args->hasArg(OPT_reflect_cpp)) {
191       Opts.mBitcodeStorage = slang::BCST_CPP_CODE;
192       // mJavaReflectionPathBase can be set for C++ reflected builds.
193       // Set it to the standard mBitcodeOutputDir (via -o) by default.
194       if (Opts.mJavaReflectionPathBase.empty()) {
195         Opts.mJavaReflectionPathBase = Opts.mBitcodeOutputDir;
196       }
197 
198       // Check for bitwidth arguments.
199       if (lastBitwidthArg) {
200         if (lastBitwidthArg->getOption().matches(OPT_m32)) {
201           Opts.mBitWidth = 32;
202         } else {
203           Opts.mBitWidth = 64;
204         }
205       }
206     } else if (lastBitwidthArg) {
207       // -m32/-m64 are forbidden for non-C++ reflection paths.
208       DiagEngine.Report(DiagEngine.getCustomDiagID(
209           clang::DiagnosticsEngine::Error,
210           "cannot use -m32/-m64 without specifying C++ reflection (-reflect-c++)"));
211     }
212 
213     Opts.mDependencyOutputDir =
214         Args->getLastArgValue(OPT_output_dep_dir, Opts.mBitcodeOutputDir);
215     Opts.mAdditionalDepTargets =
216         Args->getAllArgValues(OPT_additional_dep_target);
217 
218     Opts.mShowHelp = Args->hasArg(OPT_help);
219     Opts.mShowVersion = Args->hasArg(OPT_version);
220     Opts.mDebugEmission = Args->hasArg(OPT_emit_g);
221     Opts.mVerbose = Args->hasArg(OPT_verbose);
222 
223     // If we are emitting both 32-bit and 64-bit bitcode, we must embed it.
224 
225     size_t OptLevel =
226         clang::getLastArgIntValue(*Args, OPT_optimization_level, 3, DiagEngine);
227 
228     Opts.mOptimizationLevel =
229         OptLevel == 0 ? llvm::CodeGenOpt::None : llvm::CodeGenOpt::Aggressive;
230 
231     Opts.mTargetAPI = clang::getLastArgIntValue(*Args, OPT_target_api,
232                                                 RS_VERSION, DiagEngine);
233 
234     if (Opts.mTargetAPI == 0) {
235       Opts.mTargetAPI = UINT_MAX;
236     }
237 
238     Opts.mEmit3264 = (Opts.mTargetAPI >= 21) && (Opts.mBitcodeStorage != slang::BCST_CPP_CODE);
239     if (Opts.mEmit3264) {
240         Opts.mBitcodeStorage = slang::BCST_JAVA_CODE;
241     }
242   }
243 }
244