Andreas Gampe | 71fb52f | 2014-12-29 17:43:08 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2015 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 | #ifndef ART_COMPILER_OPTIMIZING_INTRINSICS_H_ |
| 18 | #define ART_COMPILER_OPTIMIZING_INTRINSICS_H_ |
| 19 | |
Roland Levillain | ec525fc | 2015-04-28 15:50:20 +0100 | [diff] [blame] | 20 | #include "code_generator.h" |
Andreas Gampe | 71fb52f | 2014-12-29 17:43:08 -0800 | [diff] [blame] | 21 | #include "nodes.h" |
| 22 | #include "optimization.h" |
Roland Levillain | ec525fc | 2015-04-28 15:50:20 +0100 | [diff] [blame] | 23 | #include "parallel_move_resolver.h" |
Andreas Gampe | 71fb52f | 2014-12-29 17:43:08 -0800 | [diff] [blame] | 24 | |
| 25 | namespace art { |
| 26 | |
| 27 | class CompilerDriver; |
| 28 | class DexFile; |
| 29 | |
| 30 | // Recognize intrinsics from HInvoke nodes. |
| 31 | class IntrinsicsRecognizer : public HOptimization { |
| 32 | public: |
Nicolas Geoffray | d5111bf | 2015-05-22 15:37:09 +0100 | [diff] [blame] | 33 | IntrinsicsRecognizer(HGraph* graph, CompilerDriver* driver) |
David Brazdil | 69ba7b7 | 2015-06-23 18:27:30 +0100 | [diff] [blame] | 34 | : HOptimization(graph, kIntrinsicsRecognizerPassName), |
Nicolas Geoffray | d5111bf | 2015-05-22 15:37:09 +0100 | [diff] [blame] | 35 | driver_(driver) {} |
Andreas Gampe | 71fb52f | 2014-12-29 17:43:08 -0800 | [diff] [blame] | 36 | |
| 37 | void Run() OVERRIDE; |
| 38 | |
Andreas Gampe | 7c3952f | 2015-02-19 18:21:24 -0800 | [diff] [blame] | 39 | static constexpr const char* kIntrinsicsRecognizerPassName = "intrinsics_recognition"; |
| 40 | |
Andreas Gampe | 71fb52f | 2014-12-29 17:43:08 -0800 | [diff] [blame] | 41 | private: |
Andreas Gampe | 71fb52f | 2014-12-29 17:43:08 -0800 | [diff] [blame] | 42 | CompilerDriver* driver_; |
| 43 | |
| 44 | DISALLOW_COPY_AND_ASSIGN(IntrinsicsRecognizer); |
| 45 | }; |
| 46 | |
| 47 | class IntrinsicVisitor : public ValueObject { |
| 48 | public: |
| 49 | virtual ~IntrinsicVisitor() {} |
| 50 | |
| 51 | // Dispatch logic. |
| 52 | |
| 53 | void Dispatch(HInvoke* invoke) { |
| 54 | switch (invoke->GetIntrinsic()) { |
| 55 | case Intrinsics::kNone: |
| 56 | return; |
agicsaki | 57b81ec | 2015-08-11 17:39:37 -0700 | [diff] [blame] | 57 | #define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment) \ |
Andreas Gampe | 71fb52f | 2014-12-29 17:43:08 -0800 | [diff] [blame] | 58 | case Intrinsics::k ## Name: \ |
| 59 | Visit ## Name(invoke); \ |
| 60 | return; |
| 61 | #include "intrinsics_list.h" |
| 62 | INTRINSICS_LIST(OPTIMIZING_INTRINSICS) |
| 63 | #undef INTRINSICS_LIST |
| 64 | #undef OPTIMIZING_INTRINSICS |
| 65 | |
| 66 | // Do not put a default case. That way the compiler will complain if we missed a case. |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | // Define visitor methods. |
| 71 | |
agicsaki | 57b81ec | 2015-08-11 17:39:37 -0700 | [diff] [blame] | 72 | #define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment) \ |
Andreas Gampe | 71fb52f | 2014-12-29 17:43:08 -0800 | [diff] [blame] | 73 | virtual void Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \ |
| 74 | } |
| 75 | #include "intrinsics_list.h" |
| 76 | INTRINSICS_LIST(OPTIMIZING_INTRINSICS) |
| 77 | #undef INTRINSICS_LIST |
| 78 | #undef OPTIMIZING_INTRINSICS |
| 79 | |
Roland Levillain | ec525fc | 2015-04-28 15:50:20 +0100 | [diff] [blame] | 80 | static void MoveArguments(HInvoke* invoke, |
| 81 | CodeGenerator* codegen, |
| 82 | InvokeDexCallingConventionVisitor* calling_convention_visitor) { |
| 83 | if (kIsDebugBuild && invoke->IsInvokeStaticOrDirect()) { |
| 84 | HInvokeStaticOrDirect* invoke_static_or_direct = invoke->AsInvokeStaticOrDirect(); |
| 85 | // When we do not run baseline, explicit clinit checks triggered by static |
| 86 | // invokes must have been pruned by art::PrepareForRegisterAllocation. |
| 87 | DCHECK(codegen->IsBaseline() || !invoke_static_or_direct->IsStaticWithExplicitClinitCheck()); |
| 88 | } |
| 89 | |
| 90 | if (invoke->GetNumberOfArguments() == 0) { |
| 91 | // No argument to move. |
| 92 | return; |
| 93 | } |
| 94 | |
| 95 | LocationSummary* locations = invoke->GetLocations(); |
| 96 | |
| 97 | // We're moving potentially two or more locations to locations that could overlap, so we need |
| 98 | // a parallel move resolver. |
| 99 | HParallelMove parallel_move(codegen->GetGraph()->GetArena()); |
| 100 | |
| 101 | for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) { |
| 102 | HInstruction* input = invoke->InputAt(i); |
| 103 | Location cc_loc = calling_convention_visitor->GetNextLocation(input->GetType()); |
| 104 | Location actual_loc = locations->InAt(i); |
| 105 | |
| 106 | parallel_move.AddMove(actual_loc, cc_loc, input->GetType(), nullptr); |
| 107 | } |
| 108 | |
| 109 | codegen->GetMoveResolver()->EmitNativeCode(¶llel_move); |
| 110 | } |
| 111 | |
Andreas Gampe | 71fb52f | 2014-12-29 17:43:08 -0800 | [diff] [blame] | 112 | protected: |
| 113 | IntrinsicVisitor() {} |
| 114 | |
| 115 | private: |
| 116 | DISALLOW_COPY_AND_ASSIGN(IntrinsicVisitor); |
| 117 | }; |
| 118 | |
Nicolas Geoffray | a83a54d | 2015-10-02 17:30:26 +0100 | [diff] [blame^] | 119 | #define GENERIC_OPTIMIZATION(name, bit) \ |
| 120 | public: \ |
| 121 | void Set##name() { SetBit(k##name); } \ |
| 122 | bool Get##name() const { return IsBitSet(k##name); } \ |
| 123 | private: \ |
| 124 | static constexpr int k##name = bit |
| 125 | |
| 126 | class IntrinsicOptimizations : public ValueObject { |
| 127 | public: |
| 128 | IntrinsicOptimizations(HInvoke* invoke) : value_(invoke->GetIntrinsicOptimizations()) {} |
| 129 | IntrinsicOptimizations(const HInvoke& invoke) : value_(invoke.GetIntrinsicOptimizations()) {} |
| 130 | |
| 131 | static constexpr int kNumberOfGenericOptimizations = 2; |
| 132 | GENERIC_OPTIMIZATION(DoesNotNeedDexCache, 0); |
| 133 | GENERIC_OPTIMIZATION(DoesNotNeedEnvironment, 1); |
| 134 | |
| 135 | protected: |
| 136 | bool IsBitSet(uint32_t bit) const { |
| 137 | return (*value_ & (1 << bit)) != 0u; |
| 138 | } |
| 139 | |
| 140 | void SetBit(uint32_t bit) { |
| 141 | *(const_cast<uint32_t*>(value_)) |= (1 << bit); |
| 142 | } |
| 143 | |
| 144 | private: |
| 145 | const uint32_t *value_; |
| 146 | |
| 147 | DISALLOW_COPY_AND_ASSIGN(IntrinsicOptimizations); |
| 148 | }; |
| 149 | |
| 150 | #undef GENERIC_OPTIMIZATION |
| 151 | |
| 152 | #define INTRINSIC_OPTIMIZATION(name, bit) \ |
| 153 | public: \ |
| 154 | void Set##name() { SetBit(k##name); } \ |
| 155 | bool Get##name() const { return IsBitSet(k##name); } \ |
| 156 | private: \ |
| 157 | static constexpr int k##name = bit + kNumberOfGenericOptimizations |
| 158 | |
| 159 | class StringEqualsOptimizations : public IntrinsicOptimizations { |
| 160 | public: |
| 161 | StringEqualsOptimizations(HInvoke* invoke) : IntrinsicOptimizations(invoke) {} |
| 162 | |
| 163 | INTRINSIC_OPTIMIZATION(ArgumentNotNull, 0); |
| 164 | INTRINSIC_OPTIMIZATION(ArgumentIsString, 1); |
| 165 | |
| 166 | private: |
| 167 | DISALLOW_COPY_AND_ASSIGN(StringEqualsOptimizations); |
| 168 | }; |
| 169 | |
| 170 | #undef INTRISIC_OPTIMIZATION |
| 171 | |
Andreas Gampe | 71fb52f | 2014-12-29 17:43:08 -0800 | [diff] [blame] | 172 | } // namespace art |
| 173 | |
| 174 | #endif // ART_COMPILER_OPTIMIZING_INTRINSICS_H_ |