1 /* 2 * Copyright (C) 2023 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 BERBERIS_LITE_TRANSLATOR_RISCV64_ALLOCATOR_H_ 18 #define BERBERIS_LITE_TRANSLATOR_RISCV64_ALLOCATOR_H_ 19 20 #include <algorithm> // std::max 21 #include <optional> 22 23 #include "berberis/assembler/x86_64.h" 24 #include "berberis/base/dependent_false.h" 25 26 namespace berberis { 27 28 template <typename RegType> 29 inline constexpr auto kAllocatableRegisters = []() { 30 static_assert(kDependentTypeFalse<RegType>, 31 "kAllocatableRegisters is only usable with x86_64::Assembler::Register or " 32 "x86_64::Assembler::XMMRegister"); 33 return true; 34 }; 35 36 // TODO(286261771): Add rdx to registers, push it on stack in all instances that are clobbering it. 37 template <> 38 inline constexpr x86_64::Assembler::Register kAllocatableRegisters<x86_64::Assembler::Register>[] = 39 {x86_64::Assembler::rbx, 40 x86_64::Assembler::rsi, 41 x86_64::Assembler::rdi, 42 x86_64::Assembler::r8, 43 x86_64::Assembler::r9, 44 x86_64::Assembler::r10, 45 x86_64::Assembler::r11, 46 x86_64::Assembler::r12, 47 x86_64::Assembler::r13, 48 x86_64::Assembler::r14, 49 x86_64::Assembler::r15}; 50 51 template <> 52 inline constexpr x86_64::Assembler::XMMRegister 53 kAllocatableRegisters<x86_64::Assembler::XMMRegister>[] = {x86_64::Assembler::xmm0, 54 x86_64::Assembler::xmm1, 55 x86_64::Assembler::xmm2, 56 x86_64::Assembler::xmm3, 57 x86_64::Assembler::xmm4, 58 x86_64::Assembler::xmm5, 59 x86_64::Assembler::xmm6, 60 x86_64::Assembler::xmm7, 61 x86_64::Assembler::xmm8, 62 x86_64::Assembler::xmm9, 63 x86_64::Assembler::xmm10, 64 x86_64::Assembler::xmm11, 65 x86_64::Assembler::xmm12, 66 x86_64::Assembler::xmm13, 67 x86_64::Assembler::xmm14, 68 x86_64::Assembler::xmm15}; 69 70 template <typename RegType> 71 class Allocator { 72 public: Alloc()73 std::optional<RegType> Alloc() { 74 if (regs_allocated_ + max_temp_regs_allocated >= kNumRegister) { 75 return std::nullopt; 76 } 77 return std::optional<RegType>(kAllocatableRegisters<RegType>[regs_allocated_++]); 78 } 79 AllocTemp()80 std::optional<RegType> AllocTemp() { 81 if (regs_allocated_ + temp_regs_allocated >= kNumRegister) { 82 return std::nullopt; 83 } 84 auto res = std::optional<RegType>( 85 kAllocatableRegisters<RegType>[kNumRegister - 1 - temp_regs_allocated]); 86 temp_regs_allocated++; 87 max_temp_regs_allocated = std::max(max_temp_regs_allocated, temp_regs_allocated); 88 return res; 89 } 90 FreeTemps()91 void FreeTemps() { temp_regs_allocated = 0; } 92 93 private: 94 inline static const uint32_t kNumRegister = std::size(kAllocatableRegisters<RegType>); 95 96 uint32_t regs_allocated_ = 0; 97 uint32_t temp_regs_allocated = 0; 98 uint32_t max_temp_regs_allocated = 0; 99 }; 100 101 } // namespace berberis 102 103 #endif // BERBERIS_LITE_TRANSLATOR_RISCV64_ALLOCATOR_H_ 104