1 /*
2  * Copyright 2012, 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 "bcc/Support/CompilerConfig.h"
18 #include "bcc/Config/Config.h"
19 #include "bcc/Support/Properties.h"
20 
21 #include <llvm/CodeGen/SchedulerRegistry.h>
22 #include <llvm/MC/SubtargetFeature.h>
23 #include <llvm/Support/Host.h>
24 #include <llvm/Support/TargetRegistry.h>
25 
26 #include "bcc/Support/Log.h"
27 
28 using namespace bcc;
29 
30 #if defined (PROVIDE_X86_CODEGEN) && !defined(__HOST__)
31 
32 namespace {
33 
34 // Utility function to test for f16c feature.  This function is only needed for
35 // on-device bcc for x86
HasF16C()36 bool HasF16C() {
37   llvm::StringMap<bool> features;
38   if (!llvm::sys::getHostCPUFeatures(features))
39     return false;
40 
41   if (features.count("f16c") && features["f16c"])
42     return true;
43   else
44     return false;
45 }
46 
47 }
48 #endif // (PROVIDE_X86_CODEGEN) && !defined(__HOST__)
49 
CompilerConfig(const std::string & pTriple)50 CompilerConfig::CompilerConfig(const std::string &pTriple)
51   : mTriple(pTriple), mFullPrecision(true), mTarget(nullptr) {
52   //===--------------------------------------------------------------------===//
53   // Default setting of target options
54   //===--------------------------------------------------------------------===//
55 
56   // Use soft-float ABI.  This only selects the ABI (and is applicable only to
57   // ARM targets).  Codegen still uses hardware FPU by default.  To use software
58   // floating point, add 'soft-float' feature to mFeatureString below.
59   mTargetOpts.FloatABIType = llvm::FloatABI::Soft;
60 
61   //===--------------------------------------------------------------------===//
62   // Default setting for code model
63   //===--------------------------------------------------------------------===//
64   mCodeModel = llvm::CodeModel::Small;
65 
66   //===--------------------------------------------------------------------===//
67   // Default setting for relocation model
68   //===--------------------------------------------------------------------===//
69   mRelocModel = llvm::Reloc::Default;
70 
71   //===--------------------------------------------------------------------===//
72   // Default setting for optimization level (-O2)
73   //===--------------------------------------------------------------------===//
74   mOptLevel = llvm::CodeGenOpt::Default;
75 
76   //===--------------------------------------------------------------------===//
77   // Default setting for architecture type
78   //===--------------------------------------------------------------------===//
79   mArchType = llvm::Triple::UnknownArch;
80 
81   initializeTarget();
82   initializeArch();
83 
84   return;
85 }
86 
initializeTarget()87 bool CompilerConfig::initializeTarget() {
88   std::string error;
89   mTarget = llvm::TargetRegistry::lookupTarget(mTriple, error);
90   if (mTarget != nullptr) {
91     return true;
92   } else {
93     ALOGE("Cannot initialize llvm::Target for given triple '%s'! (%s)",
94           mTriple.c_str(), error.c_str());
95     return false;
96   }
97 }
98 
initializeArch()99 bool CompilerConfig::initializeArch() {
100   if (mTarget != nullptr) {
101     mArchType = llvm::Triple::getArchTypeForLLVMName(mTarget->getName());
102   } else {
103     mArchType = llvm::Triple::UnknownArch;
104     return false;
105   }
106 
107   // Configure each architecture for any necessary additional flags.
108   std::vector<std::string> attributes;
109   switch (mArchType) {
110 #if defined(PROVIDE_ARM_CODEGEN)
111   case llvm::Triple::arm: {
112     llvm::StringMap<bool> features;
113     llvm::sys::getHostCPUFeatures(features);
114 
115 #if defined(__HOST__) || defined(ARCH_ARM_HAVE_VFP)
116     attributes.push_back("+vfp3");
117 #if !defined(__HOST__) && !defined(ARCH_ARM_HAVE_VFP_D32)
118     attributes.push_back("+d16");
119 #endif  // !__HOST__ && !ARCH_ARM_HAVE_VFP_D32
120 #endif  // __HOST__ || ARCH_ARM_HAVE_VFP
121 
122 #if defined(__HOST__) || defined(ARCH_ARM_HAVE_NEON)
123     // Only enable NEON on ARM if we have relaxed precision floats.
124     if (!mFullPrecision) {
125       attributes.push_back("+neon");
126     } else {
127 #endif  // __HOST__ || ARCH_ARM_HAVE_NEON
128       attributes.push_back("-neon");
129       attributes.push_back("-neonfp");
130 #if defined(__HOST__) || defined(ARCH_ARM_HAVE_NEON)
131     }
132 #endif  // __HOST__ || ARCH_ARM_HAVE_NEON
133 
134     if (!getProperty("debug.rs.arm-no-hwdiv")) {
135       if (features.count("hwdiv-arm") && features["hwdiv-arm"])
136         attributes.push_back("+hwdiv-arm");
137 
138       if (features.count("hwdiv") && features["hwdiv"])
139         attributes.push_back("+hwdiv");
140     }
141 
142     // Enable fp16 attribute if available in the feature list.  This feature
143     // will not be added in the host version of bcc or bcc_compat since
144     // 'features' would correspond to features in an x86 host.
145     if (features.count("fp16") && features["fp16"])
146       attributes.push_back("+fp16");
147 
148 #if defined(PROVIDE_ARM64_CODEGEN)
149     // On AArch64, asimd in /proc/cpuinfo signals the presence of hardware
150     // half-precision conversion instructions.  getHostCPUFeatures translates
151     // this to "neon".  If PROVIDE_ARM64_CODEGEN is set, enable "+fp16" for ARM
152     // codegen if "neon" is present in features.
153     if (features.count("neon") && features["neon"])
154       attributes.push_back("+fp16");
155 #endif // PROVIDE_ARM64_CODEGEN
156 
157 #if defined(TARGET_BUILD)
158     if (!getProperty("debug.rs.arm-no-tune-for-cpu")) {
159 #ifndef FORCE_CPU_VARIANT_32
160 #ifdef DEFAULT_ARM_CODEGEN
161       setCPU(llvm::sys::getHostCPUName());
162 #endif
163 #else
164 #define XSTR(S) #S
165 #define STR(S) XSTR(S)
166       setCPU(STR(FORCE_CPU_VARIANT_32));
167 #undef STR
168 #undef XSTR
169 #endif
170     }
171 #endif  // TARGET_BUILD
172 
173     break;
174   }
175 #endif  // PROVIDE_ARM_CODEGEN
176 
177 #if defined(PROVIDE_ARM64_CODEGEN)
178   case llvm::Triple::aarch64:
179 #if defined(TARGET_BUILD)
180     if (!getProperty("debug.rs.arm-no-tune-for-cpu")) {
181 #ifndef FORCE_CPU_VARIANT_64
182 #ifdef DEFAULT_ARM64_CODEGEN
183       setCPU(llvm::sys::getHostCPUName());
184 #endif
185 #else
186 #define XSTR(S) #S
187 #define STR(S) XSTR(S)
188       setCPU(STR(FORCE_CPU_VARIANT_64));
189 #undef STR
190 #undef XSTR
191 #endif
192 
193     }
194 #endif  // TARGET_BUILD
195     break;
196 #endif  // PROVIDE_ARM64_CODEGEN
197 
198 #if defined (PROVIDE_MIPS_CODEGEN)
199   case llvm::Triple::mips:
200   case llvm::Triple::mipsel:
201     if (getRelocationModel() == llvm::Reloc::Default) {
202       setRelocationModel(llvm::Reloc::Static);
203     }
204     break;
205 #endif  // PROVIDE_MIPS_CODEGEN
206 
207 #if defined (PROVIDE_MIPS64_CODEGEN)
208   case llvm::Triple::mips64:
209   case llvm::Triple::mips64el:
210     // Default revision for MIPS64 Android is R6.
211     setCPU("mips64r6");
212     break;
213 #endif // PROVIDE_MIPS64_CODEGEN
214 
215 #if defined (PROVIDE_X86_CODEGEN)
216   case llvm::Triple::x86:
217     getTargetOptions().UseInitArray = true;
218 #if defined (DEFAULT_X86_CODEGEN) && !defined (DEFAULT_X86_64_CODEGEN)
219     setCPU(llvm::sys::getHostCPUName());
220 #else
221     // generic fallback for 32bit x86 targets
222     setCPU("atom");
223 #endif // DEFAULT_X86_CODEGEN && !DEFAULT_X86_64_CODEGEN
224 
225 #ifndef __HOST__
226     // If not running on the host, and f16c is available, set it in the feature
227     // string
228     if (HasF16C())
229       attributes.push_back("+f16c");
230 #if defined(__SSE3__)
231     attributes.push_back("+sse3");
232     attributes.push_back("+ssse3");
233 #endif
234 #if defined(__SSE4_1__)
235     attributes.push_back("+sse4.1");
236 #endif
237 #if defined(__SSE4_2__)
238     attributes.push_back("+sse4.2");
239 #endif
240 #endif // __HOST__
241     break;
242 #endif  // PROVIDE_X86_CODEGEN
243 
244 #if defined (PROVIDE_X86_CODEGEN)
245 // PROVIDE_X86_CODEGEN is defined for both x86 and x86_64
246   case llvm::Triple::x86_64:
247 #if defined(DEFAULT_X86_64_CODEGEN) && !defined(__HOST__)
248     setCPU(llvm::sys::getHostCPUName());
249 #else
250     // generic fallback for 64bit x86 targets
251     setCPU("core2");
252 #endif
253     // x86_64 needs small CodeModel if use PIC_ reloc, or else dlopen failed with TEXTREL.
254     if (getRelocationModel() == llvm::Reloc::PIC_) {
255       setCodeModel(llvm::CodeModel::Small);
256     } else {
257       setCodeModel(llvm::CodeModel::Medium);
258     }
259     getTargetOptions().UseInitArray = true;
260 
261 #ifndef __HOST__
262     // If not running on the host, and f16c is available, set it in the feature
263     // string
264     if (HasF16C())
265       attributes.push_back("+f16c");
266 #endif // __HOST__
267 
268     break;
269 #endif  // PROVIDE_X86_CODEGEN
270 
271   default:
272     ALOGE("Unsupported architecture type: %s", mTarget->getName());
273     return false;
274   }
275 
276   setFeatureString(attributes);
277   return true;
278 }
279 
setFeatureString(const std::vector<std::string> & pAttrs)280 void CompilerConfig::setFeatureString(const std::vector<std::string> &pAttrs) {
281   llvm::SubtargetFeatures f;
282 
283   for (std::vector<std::string>::const_iterator attr_iter = pAttrs.begin(),
284            attr_end = pAttrs.end();
285        attr_iter != attr_end; attr_iter++) {
286     f.AddFeature(*attr_iter);
287   }
288 
289   mFeatureString = f.getString();
290   return;
291 }
292