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 register sheduler
54   //===--------------------------------------------------------------------===//
55   llvm::RegisterScheduler::setDefault(llvm::createDefaultScheduler);
56 
57   //===--------------------------------------------------------------------===//
58   // Default setting of target options
59   //===--------------------------------------------------------------------===//
60   // Use hardfloat ABI by default.
61   //
62   // TODO(all): Need to detect the CPU capability and decide whether to use
63   // softfp. To use softfp, change the following 2 lines to
64   //
65   // options.FloatABIType = llvm::FloatABI::Soft;
66   // options.UseSoftFloat = true;
67   mTargetOpts.FloatABIType = llvm::FloatABI::Soft;
68   mTargetOpts.UseSoftFloat = false;
69 
70   // Enable frame pointer elimination optimization by default.
71   mTargetOpts.NoFramePointerElim = false;
72 
73   //===--------------------------------------------------------------------===//
74   // Default setting for code model
75   //===--------------------------------------------------------------------===//
76   mCodeModel = llvm::CodeModel::Small;
77 
78   //===--------------------------------------------------------------------===//
79   // Default setting for relocation model
80   //===--------------------------------------------------------------------===//
81   mRelocModel = llvm::Reloc::Default;
82 
83   //===--------------------------------------------------------------------===//
84   // Default setting for optimization level (-O2)
85   //===--------------------------------------------------------------------===//
86   mOptLevel = llvm::CodeGenOpt::Default;
87 
88   //===--------------------------------------------------------------------===//
89   // Default setting for architecture type
90   //===--------------------------------------------------------------------===//
91   mArchType = llvm::Triple::UnknownArch;
92 
93   initializeTarget();
94   initializeArch();
95 
96   return;
97 }
98 
initializeTarget()99 bool CompilerConfig::initializeTarget() {
100   std::string error;
101   mTarget = llvm::TargetRegistry::lookupTarget(mTriple, error);
102   if (mTarget != nullptr) {
103     return true;
104   } else {
105     ALOGE("Cannot initialize llvm::Target for given triple '%s'! (%s)",
106           mTriple.c_str(), error.c_str());
107     return false;
108   }
109 }
110 
initializeArch()111 bool CompilerConfig::initializeArch() {
112   if (mTarget != nullptr) {
113     mArchType = llvm::Triple::getArchTypeForLLVMName(mTarget->getName());
114   } else {
115     mArchType = llvm::Triple::UnknownArch;
116     return false;
117   }
118 
119   // Configure each architecture for any necessary additional flags.
120   switch (mArchType) {
121 #if defined(PROVIDE_ARM_CODEGEN)
122   case llvm::Triple::arm: {
123     llvm::StringMap<bool> features;
124     llvm::sys::getHostCPUFeatures(features);
125     std::vector<std::string> attributes;
126 
127 #if defined(__HOST__) || defined(ARCH_ARM_HAVE_VFP)
128     attributes.push_back("+vfp3");
129 #if !defined(__HOST__) && !defined(ARCH_ARM_HAVE_VFP_D32)
130     attributes.push_back("+d16");
131 #endif  // !__HOST__ && !ARCH_ARM_HAVE_VFP_D32
132 #endif  // __HOST__ || ARCH_ARM_HAVE_VFP
133 
134 #if defined(__HOST__) || defined(ARCH_ARM_HAVE_NEON)
135     // Only enable NEON on ARM if we have relaxed precision floats.
136     if (!mFullPrecision) {
137       attributes.push_back("+neon");
138     } else {
139 #endif  // __HOST__ || ARCH_ARM_HAVE_NEON
140       attributes.push_back("-neon");
141       attributes.push_back("-neonfp");
142 #if defined(__HOST__) || defined(ARCH_ARM_HAVE_NEON)
143     }
144 #endif  // __HOST__ || ARCH_ARM_HAVE_NEON
145 
146     if (!getProperty("debug.rs.arm-no-hwdiv")) {
147       if (features.count("hwdiv-arm") && features["hwdiv-arm"])
148         attributes.push_back("+hwdiv-arm");
149 
150       if (features.count("hwdiv") && features["hwdiv"])
151         attributes.push_back("+hwdiv");
152     }
153 
154     // Enable fp16 attribute if available in the feature list.  This feature
155     // will not be added in the host version of bcc or bcc_compat since
156     // 'features' would correspond to features in an x86 host.
157     if (features.count("fp16") && features["fp16"])
158       attributes.push_back("+fp16");
159 
160     setFeatureString(attributes);
161 
162 #if defined(TARGET_BUILD)
163     if (!getProperty("debug.rs.arm-no-tune-for-cpu")) {
164 #ifndef FORCE_CPU_VARIANT_32
165       setCPU(llvm::sys::getHostCPUName());
166 #else
167 #define XSTR(S) #S
168 #define STR(S) XSTR(S)
169       setCPU(STR(FORCE_CPU_VARIANT_32));
170 #undef STR
171 #undef XSTR
172 #endif
173     }
174 #endif  // TARGET_BUILD
175 
176     break;
177   }
178 #endif  // PROVIDE_ARM_CODEGEN
179 
180 #if defined(PROVIDE_ARM64_CODEGEN)
181   case llvm::Triple::aarch64:
182 #if defined(TARGET_BUILD)
183     if (!getProperty("debug.rs.arm-no-tune-for-cpu")) {
184 #ifndef FORCE_CPU_VARIANT_64
185       setCPU(llvm::sys::getHostCPUName());
186 #else
187 #define XSTR(S) #S
188 #define STR(S) XSTR(S)
189       setCPU(STR(FORCE_CPU_VARIANT_64));
190 #undef STR
191 #undef XSTR
192 #endif
193 
194     }
195 #endif  // TARGET_BUILD
196     break;
197 #endif  // PROVIDE_ARM64_CODEGEN
198 
199 #if defined (PROVIDE_MIPS_CODEGEN)
200   case llvm::Triple::mips:
201   case llvm::Triple::mipsel:
202     if (getRelocationModel() == llvm::Reloc::Default) {
203       setRelocationModel(llvm::Reloc::Static);
204     }
205     break;
206 #endif  // PROVIDE_MIPS_CODEGEN
207 
208 #if defined (PROVIDE_MIPS64_CODEGEN)
209   case llvm::Triple::mips64:
210   case llvm::Triple::mips64el:
211     // Default revision for MIPS64 Android is R6.
212     setCPU("mips64r6");
213     break;
214 #endif // PROVIDE_MIPS64_CODEGEN
215 
216 #if defined (PROVIDE_X86_CODEGEN)
217   case llvm::Triple::x86:
218     // Disable frame pointer elimination optimization on x86 family.
219     getTargetOptions().NoFramePointerElim = true;
220     getTargetOptions().UseInitArray = true;
221 
222 #ifndef __HOST__
223     // If not running on the host, and f16c is available, set it in the feature
224     // string
225     if (HasF16C())
226       mFeatureString = "+f16c";
227 #endif // __HOST__
228 
229     break;
230 #endif  // PROVIDE_X86_CODEGEN
231 
232 #if defined (PROVIDE_X86_CODEGEN)
233   case llvm::Triple::x86_64:
234     // x86_64 needs small CodeModel if use PIC_ reloc, or else dlopen failed with TEXTREL.
235     if (getRelocationModel() == llvm::Reloc::PIC_) {
236       setCodeModel(llvm::CodeModel::Small);
237     } else {
238       setCodeModel(llvm::CodeModel::Medium);
239     }
240     // Disable frame pointer elimination optimization on x86 family.
241     getTargetOptions().NoFramePointerElim = true;
242     getTargetOptions().UseInitArray = true;
243 
244 #ifndef __HOST__
245     // If not running on the host, and f16c is available, set it in the feature
246     // string
247     if (HasF16C())
248       mFeatureString = "+f16c";
249 #endif // __HOST__
250 
251     break;
252 #endif  // PROVIDE_X86_CODEGEN
253 
254   default:
255     ALOGE("Unsupported architecture type: %s", mTarget->getName());
256     return false;
257   }
258 
259   return true;
260 }
261 
setFeatureString(const std::vector<std::string> & pAttrs)262 void CompilerConfig::setFeatureString(const std::vector<std::string> &pAttrs) {
263   llvm::SubtargetFeatures f;
264 
265   for (std::vector<std::string>::const_iterator attr_iter = pAttrs.begin(),
266            attr_end = pAttrs.end();
267        attr_iter != attr_end; attr_iter++) {
268     f.AddFeature(*attr_iter);
269   }
270 
271   mFeatureString = f.getString();
272   return;
273 }
274