185b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe/*
285b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe * Copyright (C) 2015 The Android Open Source Project
385b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe *
485b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe * Licensed under the Apache License, Version 2.0 (the "License");
585b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe * you may not use this file except in compliance with the License.
685b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe * You may obtain a copy of the License at
785b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe *
885b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe *      http://www.apache.org/licenses/LICENSE-2.0
985b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe *
1085b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe * Unless required by applicable law or agreed to in writing, software
1185b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe * distributed under the License is distributed on an "AS IS" BASIS,
1285b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1385b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe * See the License for the specific language governing permissions and
1485b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe * limitations under the License.
1585b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe */
1685b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe
1785b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe#ifndef ART_COMPILER_OPTIMIZING_INTRINSICS_UTILS_H_
1885b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe#define ART_COMPILER_OPTIMIZING_INTRINSICS_UTILS_H_
1985b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe
2085b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe#include "base/macros.h"
2185b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe#include "code_generator.h"
2285b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe#include "locations.h"
2385b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe#include "nodes.h"
2485b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe#include "utils/assembler.h"
2585b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe#include "utils/label.h"
2685b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe
2785b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampenamespace art {
2885b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe
2985b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe// Default slow-path for fallback (calling the managed code to handle the intrinsic) in an
3085b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe// intrinsified call. This will copy the arguments into the positions for a regular call.
3185b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe//
3285b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe// Note: The actual parameters are required to be in the locations given by the invoke's location
3385b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe//       summary. If an intrinsic modifies those locations before a slowpath call, they must be
3485b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe//       restored!
3585b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe//
3685b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe// Note: If an invoke wasn't sharpened, we will put down an invoke-virtual here. That's potentially
3785b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe//       sub-optimal (compared to a direct pointer call), but this is a slow-path.
3885b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe
3985b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampetemplate <typename TDexCallingConvention>
4085b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampeclass IntrinsicSlowPath : public SlowPathCode {
4185b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe public:
429cd6d378bd573cdc14d049d32bdd22a97fa4d84aDavid Srbecky  explicit IntrinsicSlowPath(HInvoke* invoke) : SlowPathCode(invoke), invoke_(invoke) { }
4385b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe
4485b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe  Location MoveArguments(CodeGenerator* codegen) {
4585b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe    TDexCallingConvention calling_convention_visitor;
4685b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe    IntrinsicVisitor::MoveArguments(invoke_, codegen, &calling_convention_visitor);
4785b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe    return calling_convention_visitor.GetMethodLocation();
4885b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe  }
4985b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe
5085b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
5185b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe    Assembler* assembler = codegen->GetAssembler();
5285b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe    assembler->Bind(GetEntryLabel());
5385b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe
5485b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe    SaveLiveRegisters(codegen, invoke_->GetLocations());
5585b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe
5685b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe    Location method_loc = MoveArguments(codegen);
5785b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe
5885b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe    if (invoke_->IsInvokeStaticOrDirect()) {
5985b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe      codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(), method_loc);
6085b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe    } else {
6185b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe      codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(), method_loc);
6285b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe    }
6385b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe    codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
6485b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe
6585b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe    // Copy the result back to the expected output.
6685b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe    Location out = invoke_->GetLocations()->Out();
6785b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe    if (out.IsValid()) {
6885b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe      DCHECK(out.IsRegister());  // TODO: Replace this when we support output in memory.
6985b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe      DCHECK(!invoke_->GetLocations()->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
7085b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe      codegen->MoveFromReturnRegister(out, invoke_->GetType());
7185b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe    }
7285b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe
7385b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe    RestoreLiveRegisters(codegen, invoke_->GetLocations());
7485b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe    assembler->Jump(GetExitLabel());
7585b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe  }
7685b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe
7785b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe  const char* GetDescription() const OVERRIDE { return "IntrinsicSlowPath"; }
7885b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe
7985b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe private:
8085b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe  // The instruction where this slow path is happening.
8185b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe  HInvoke* const invoke_;
8285b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe
8385b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe  DISALLOW_COPY_AND_ASSIGN(IntrinsicSlowPath);
8485b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe};
8585b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe
8685b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe}  // namespace art
8785b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe
8885b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe#endif  // ART_COMPILER_OPTIMIZING_INTRINSICS_UTILS_H_
89