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