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_BACKEND_X86_64_INSN_FOLDING_H_
18 #define BERBERIS_BACKEND_X86_64_INSN_FOLDING_H_
19 
20 #include <tuple>
21 
22 #include "berberis/backend/x86_64/machine_ir.h"
23 #include "berberis/base/arena_vector.h"
24 
25 namespace berberis::x86_64 {
26 
27 // The DefMap class stores a map between registers and their latest definitions and positions.
28 class DefMap {
29  public:
DefMap(size_t size,Arena * arena)30   DefMap(size_t size, Arena* arena)
31       : def_map_(size, {nullptr, 0}, arena), flags_reg_(kInvalidMachineReg), index_(0) {}
Get(MachineReg reg)32   [[nodiscard]] std::pair<const MachineInsn*, int> Get(MachineReg reg) const {
33     if (!reg.IsVReg()) {
34       return {nullptr, 0};
35     }
36     return def_map_.at(reg.GetVRegIndex());
37   }
Get(MachineReg reg,int use_index)38   [[nodiscard]] std::pair<const MachineInsn*, int> Get(MachineReg reg, int use_index) const {
39     if (!reg.IsVReg()) {
40       return {nullptr, 0};
41     }
42     auto [def_insn, def_insn_index] = def_map_.at(reg.GetVRegIndex());
43     if (!def_insn || def_insn_index > use_index) {
44       return {nullptr, 0};
45     }
46     return {def_insn, def_insn_index};
47   }
48   void ProcessInsn(const MachineInsn* insn);
49   void Initialize();
50 
51  private:
Set(MachineReg reg,const MachineInsn * insn)52   void Set(MachineReg reg, const MachineInsn* insn) {
53     if (reg.IsVReg()) {
54       def_map_.at(reg.GetVRegIndex()) = std::pair(insn, index_);
55     }
56   }
57   void MapDefRegs(const MachineInsn* insn);
58   ArenaVector<std::pair<const MachineInsn*, int>> def_map_;
59   MachineReg flags_reg_;
60   int index_;
61 };
62 
63 class InsnFolding {
64  public:
InsnFolding(DefMap & def_map,MachineIR * machine_ir)65   explicit InsnFolding(DefMap& def_map, MachineIR* machine_ir)
66       : def_map_(def_map), machine_ir_(machine_ir) {}
67 
68   std::tuple<bool, MachineInsn*> TryFoldInsn(const MachineInsn* insn);
69 
70  private:
71   DefMap& def_map_;
72   MachineIR* machine_ir_;
73   bool IsRegImm(MachineReg reg, uint64_t* imm) const;
74   bool IsWritingSameFlagsValue(const MachineInsn* insn) const;
75   template <bool is_input_64bit>
76   std::tuple<bool, MachineInsn*> TryFoldImmediateInput(const MachineInsn* insn);
77   std::tuple<bool, MachineInsn*> TryFoldRedundantMovl(const MachineInsn* insn);
78   MachineInsn* NewImmInsnFromRegInsn(const MachineInsn* insn, int32_t imm);
79 };
80 
81 void FoldInsns(MachineIR* machine_ir);
82 
83 void FoldWriteFlags(MachineIR* machine_ir);
84 
85 }  // namespace berberis::x86_64
86 
87 #endif  // BERBERIS_BACKEND_X86_64_INSN_FOLDING_H_
88