1 /* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef MAPLEBE_INCLUDE_AARCH64_PROP_H 17 #define MAPLEBE_INCLUDE_AARCH64_PROP_H 18 19 #include "cg_prop.h" 20 #include "aarch64_cgfunc.h" 21 #include "aarch64_strldr.h" 22 namespace maplebe { 23 class AArch64Prop : public CGProp { 24 public: AArch64Prop(MemPool & mp,CGFunc & f,CGSSAInfo & sInfo,LiveIntervalAnalysis & ll)25 AArch64Prop(MemPool &mp, CGFunc &f, CGSSAInfo &sInfo, LiveIntervalAnalysis &ll) : CGProp(mp, f, sInfo, ll) {} 26 ~AArch64Prop() override = default; 27 28 /* do not extend life range */ 29 static bool IsInLimitCopyRange(VRegVersion *toBeReplaced); 30 31 private: 32 void CopyProp() override; 33 /* 34 * for aarch64 35 * 1. extended register prop 36 * 2. shift register prop 37 * 3. add/ext/shf prop -> str/ldr 38 * 4. const prop 39 */ 40 void TargetProp(Insn &insn) override; 41 void PropPatternOpt() override; 42 }; 43 44 class A64StrLdrProp { 45 public: A64StrLdrProp(MemPool & mp,CGFunc & f,CGSSAInfo & sInfo,Insn & insn,CGDce & dce)46 A64StrLdrProp(MemPool &mp, CGFunc &f, CGSSAInfo &sInfo, Insn &insn, CGDce &dce) 47 : cgFunc(&f), 48 ssaInfo(&sInfo), 49 curInsn(&insn), 50 a64StrLdrAlloc(&mp), 51 replaceVersions(a64StrLdrAlloc.Adapter()), 52 cgDce(&dce) 53 { 54 } 55 void DoOpt(); 56 57 private: 58 MemOperand *StrLdrPropPreCheck(const Insn &insn, MemPropMode prevMod = kUndef); 59 static MemPropMode SelectStrLdrPropMode(const MemOperand &currMemOpnd); 60 bool ReplaceMemOpnd(const MemOperand &currMemOpnd, const Insn *defInsn); 61 MemOperand *SelectReplaceMem(const Insn &defInsn, const MemOperand &currMemOpnd); 62 RegOperand *GetReplaceReg(RegOperand &a64Reg); 63 MemOperand *HandleArithImmDef(RegOperand &replace, Operand *oldOffset, int64 defVal, uint32 memSize) const; 64 MemOperand *SelectReplaceExt(const Insn &defInsn, RegOperand &base, uint32 amount, bool isSigned, uint32 memSize); 65 bool CheckNewMemOffset(const Insn &insn, MemOperand *newMemOpnd, uint32 opndIdx) const; 66 void DoMemReplace(const RegOperand &replacedReg, MemOperand &newMem, Insn &useInsn); 67 uint32 GetMemOpndIdx(MemOperand *newMemOpnd, const Insn &insn) const; 68 69 bool CheckSameReplace(const RegOperand &replacedReg, const MemOperand *memOpnd) const; 70 71 CGFunc *cgFunc; 72 CGSSAInfo *ssaInfo; 73 Insn *curInsn; 74 MapleAllocator a64StrLdrAlloc; 75 MapleMap<regno_t, VRegVersion *> replaceVersions; 76 MemPropMode memPropMode = kUndef; 77 CGDce *cgDce = nullptr; 78 }; 79 80 enum ArithmeticType { kAArch64Add, kAArch64Sub, kAArch64Orr, kAArch64Eor, kUndefArith }; 81 82 class A64ConstProp { 83 public: A64ConstProp(MemPool & mp,CGFunc & f,CGSSAInfo & sInfo,Insn & insn)84 A64ConstProp(MemPool &mp, CGFunc &f, CGSSAInfo &sInfo, Insn &insn) 85 : constPropMp(&mp), cgFunc(&f), ssaInfo(&sInfo), curInsn(&insn) 86 { 87 } 88 void DoOpt(); 89 /* false : default lsl #0 true: lsl #12 (only support 12 bit left shift in aarch64) */ 90 static MOperator GetRegImmMOP(MOperator regregMop, bool withLeftShift); 91 static MOperator GetReversalMOP(MOperator arithMop); 92 static MOperator GetFoldMopAndVal(int64 &newVal, int64 constVal, const Insn &arithInsn); 93 94 private: 95 bool ConstProp(DUInsnInfo &useDUInfo, ImmOperand &constOpnd); 96 /* use xzr/wzr in aarch64 to shrink register live range */ 97 void ZeroRegProp(DUInsnInfo &useDUInfo, RegOperand &toReplaceReg); 98 99 /* replace old Insn with new Insn, update ssa info automatically */ 100 void ReplaceInsnAndUpdateSSA(Insn &oriInsn, Insn &newInsn) const; 101 ImmOperand *CanDoConstFold(const ImmOperand &value1, const ImmOperand &value2, ArithmeticType aT, bool is64Bit); 102 103 /* optimization */ 104 bool MovConstReplace(DUInsnInfo &useDUInfo, ImmOperand &constOpnd); 105 bool ArithmeticConstReplace(DUInsnInfo &useDUInfo, ImmOperand &constOpnd, ArithmeticType aT); 106 bool ArithmeticConstFold(DUInsnInfo &useDUInfo, const ImmOperand &constOpnd, ArithmeticType aT); 107 bool ShiftConstReplace(DUInsnInfo &useDUInfo, const ImmOperand &constOpnd); 108 bool BitInsertReplace(DUInsnInfo &useDUInfo, const ImmOperand &constOpnd); 109 110 MemPool *constPropMp; 111 CGFunc *cgFunc; 112 CGSSAInfo *ssaInfo; 113 Insn *curInsn; 114 }; 115 116 class CopyRegProp : public PropOptimizePattern { 117 public: CopyRegProp(CGFunc & cgFunc,CGSSAInfo * cgssaInfo,LiveIntervalAnalysis * ll)118 CopyRegProp(CGFunc &cgFunc, CGSSAInfo *cgssaInfo, LiveIntervalAnalysis *ll) 119 : PropOptimizePattern(cgFunc, cgssaInfo, ll) 120 { 121 } 122 ~CopyRegProp() override = default; 123 bool CheckCondition(Insn &insn) final; 124 void Optimize(Insn &insn) final; 125 void Run() final; 126 127 protected: Init()128 void Init() final 129 { 130 destVersion = nullptr; 131 srcVersion = nullptr; 132 } 133 134 private: 135 bool IsValidCopyProp(const RegOperand &dstReg, const RegOperand &srcReg) const; 136 void VaildateImplicitCvt(RegOperand &destReg, const RegOperand &srcReg, Insn &movInsn); 137 VRegVersion *destVersion = nullptr; 138 VRegVersion *srcVersion = nullptr; 139 }; 140 141 class RedundantPhiProp : public PropOptimizePattern { 142 public: RedundantPhiProp(CGFunc & cgFunc,CGSSAInfo * cgssaInfo)143 RedundantPhiProp(CGFunc &cgFunc, CGSSAInfo *cgssaInfo) : PropOptimizePattern(cgFunc, cgssaInfo) {} 144 ~RedundantPhiProp() override = default; 145 bool CheckCondition(Insn &insn) final; 146 void Optimize(Insn &insn) final; 147 void Run() final; 148 149 protected: Init()150 void Init() final 151 { 152 destVersion = nullptr; 153 srcVersion = nullptr; 154 } 155 156 private: 157 VRegVersion *destVersion = nullptr; 158 VRegVersion *srcVersion = nullptr; 159 }; 160 161 class ValidBitNumberProp : public PropOptimizePattern { 162 public: ValidBitNumberProp(CGFunc & cgFunc,CGSSAInfo * cgssaInfo)163 ValidBitNumberProp(CGFunc &cgFunc, CGSSAInfo *cgssaInfo) : PropOptimizePattern(cgFunc, cgssaInfo) {} 164 ~ValidBitNumberProp() override = default; 165 bool CheckCondition(Insn &insn) final; 166 void Optimize(Insn &insn) final; 167 void Run() final; 168 169 protected: Init()170 void Init() final 171 { 172 destVersion = nullptr; 173 srcVersion = nullptr; 174 } 175 176 private: 177 VRegVersion *destVersion = nullptr; 178 VRegVersion *srcVersion = nullptr; 179 }; 180 181 /* 182 * frame pointer and stack pointer will not be varied in function body 183 * treat them as const 184 */ 185 class FpSpConstProp : public PropOptimizePattern { 186 public: FpSpConstProp(CGFunc & cgFunc,CGSSAInfo * cgssaInfo)187 FpSpConstProp(CGFunc &cgFunc, CGSSAInfo *cgssaInfo) : PropOptimizePattern(cgFunc, cgssaInfo) {} 188 ~FpSpConstProp() override = default; 189 bool CheckCondition(Insn &insn) final; 190 void Optimize(Insn &insn) final; 191 void Run() final; 192 193 protected: Init()194 void Init() final 195 { 196 fpSpBase = nullptr; 197 shiftOpnd = nullptr; 198 aT = kUndefArith; 199 replaced = nullptr; 200 } 201 202 private: 203 bool GetValidSSAInfo(Operand &opnd); 204 void PropInMem(DUInsnInfo &useDUInfo, Insn &useInsn); 205 void PropInArith(DUInsnInfo &useDUInfo, Insn &useInsn, ArithmeticType curAT); 206 void PropInCopy(DUInsnInfo &useDUInfo, Insn &useInsn, MOperator oriMop); 207 int64 ArithmeticFold(int64 valInUse, ArithmeticType useAT) const; 208 209 RegOperand *fpSpBase = nullptr; 210 ImmOperand *shiftOpnd = nullptr; 211 ArithmeticType aT = kUndefArith; 212 VRegVersion *replaced = nullptr; 213 }; 214 215 /* 216 * This pattern do: 217 * 1) 218 * uxtw vreg:Rm validBitNum:[64], vreg:Rn validBitNum:[32] 219 * ------> 220 * mov vreg:Rm validBitNum:[64], vreg:Rn validBitNum:[32] 221 * 2) 222 * ldrh R201, [...] 223 * and R202, R201, #65520 224 * uxth R203, R202 225 * -------> 226 * ldrh R201, [...] 227 * and R202, R201, #65520 228 * mov R203, R202 229 */ 230 class ExtendMovPattern : public PropOptimizePattern { 231 public: ExtendMovPattern(CGFunc & cgFunc,CGSSAInfo * cgssaInfo)232 ExtendMovPattern(CGFunc &cgFunc, CGSSAInfo *cgssaInfo) : PropOptimizePattern(cgFunc, cgssaInfo) {} 233 ~ExtendMovPattern() override = default; 234 bool CheckCondition(Insn &insn) final; 235 void Optimize(Insn &insn) final; 236 void Run() final; 237 238 protected: 239 void Init() final; 240 241 private: 242 bool BitNotAffected(const Insn &insn, uint32 validNum); /* check whether significant bits are affected */ 243 bool CheckSrcReg(regno_t srcRegNo, uint32 validNum); 244 245 MOperator replaceMop = MOP_undef; 246 }; 247 248 class ExtendShiftPattern : public PropOptimizePattern { 249 public: ExtendShiftPattern(CGFunc & cgFunc,CGSSAInfo * cgssaInfo)250 ExtendShiftPattern(CGFunc &cgFunc, CGSSAInfo *cgssaInfo) : PropOptimizePattern(cgFunc, cgssaInfo) {} 251 ~ExtendShiftPattern() override = default; 252 bool IsSwapInsn(const Insn &insn) const; 253 void SwapOpnd(Insn &insn); 254 bool CheckAllOpndCondition(Insn &insn); 255 bool CheckCondition(Insn &insn) final; 256 void Optimize(Insn &insn) final; 257 void Run() final; 258 void DoExtendShiftOpt(Insn &insn); 259 260 enum ExMOpType : uint8 { 261 kExUndef, 262 kExAdd, /* MOP_xaddrrr | MOP_xxwaddrrre | MOP_xaddrrrs */ 263 kEwAdd, /* MOP_waddrrr | MOP_wwwaddrrre | MOP_waddrrrs */ 264 kExSub, /* MOP_xsubrrr | MOP_xxwsubrrre | MOP_xsubrrrs */ 265 kEwSub, /* MOP_wsubrrr | MOP_wwwsubrrre | MOP_wsubrrrs */ 266 kExCmn, /* MOP_xcmnrr | MOP_xwcmnrre | MOP_xcmnrrs */ 267 kEwCmn, /* MOP_wcmnrr | MOP_wwcmnrre | MOP_wcmnrrs */ 268 kExCmp, /* MOP_xcmprr | MOP_xwcmprre | MOP_xcmprrs */ 269 kEwCmp, /* MOP_wcmprr | MOP_wwcmprre | MOP_wcmprrs */ 270 }; 271 272 enum LsMOpType : uint8 { 273 kLsUndef, 274 kLxAdd, /* MOP_xaddrrr | MOP_xaddrrrs */ 275 kLwAdd, /* MOP_waddrrr | MOP_waddrrrs */ 276 kLxSub, /* MOP_xsubrrr | MOP_xsubrrrs */ 277 kLwSub, /* MOP_wsubrrr | MOP_wsubrrrs */ 278 kLxCmn, /* MOP_xcmnrr | MOP_xcmnrrs */ 279 kLwCmn, /* MOP_wcmnrr | MOP_wcmnrrs */ 280 kLxCmp, /* MOP_xcmprr | MOP_xcmprrs */ 281 kLwCmp, /* MOP_wcmprr | MOP_wcmprrs */ 282 kLxEor, /* MOP_xeorrrr | MOP_xeorrrrs */ 283 kLwEor, /* MOP_weorrrr | MOP_weorrrrs */ 284 kLxNeg, /* MOP_xinegrr | MOP_xinegrrs */ 285 kLwNeg, /* MOP_winegrr | MOP_winegrrs */ 286 kLxIor, /* MOP_xiorrrr | MOP_xiorrrrs */ 287 kLwIor, /* MOP_wiorrrr | MOP_wiorrrrs */ 288 }; 289 290 enum SuffixType : uint8 { 291 kNoSuffix, /* no suffix or do not perform the optimization. */ 292 kLSL, /* logical shift left */ 293 kLSR, /* logical shift right */ 294 kASR, /* arithmetic shift right */ 295 kExten /* ExtendOp */ 296 }; 297 298 protected: 299 void Init() final; 300 301 private: 302 void SelectExtendOrShift(const Insn &def); 303 SuffixType CheckOpType(const Operand &lastOpnd) const; 304 void ReplaceUseInsn(Insn &use, const Insn &def, uint32 amount); 305 void SetExMOpType(const Insn &use); 306 void SetLsMOpType(const Insn &use); 307 308 MOperator replaceOp; 309 uint32 replaceIdx; 310 ExtendShiftOperand::ExtendOp extendOp; 311 BitShiftOperand::ShiftOp shiftOp; 312 Insn *defInsn = nullptr; 313 Insn *newInsn = nullptr; 314 Insn *curInsn = nullptr; 315 bool optSuccess; 316 ExMOpType exMOpType; 317 LsMOpType lsMOpType; 318 }; 319 320 /* 321 * optimization for call convention 322 * example: 323 * [BB26] [BB43] 324 * sub R287, R101, R275 sub R279, R101, R275 325 * \ / 326 * \ / 327 * [BB27] 328 * <---- insert new phi: R403, (R275 <26>, R275 <43>) 329 * old phi: R297, (R287 <26>, R279 <43>) 330 * / \ 331 * / \ 332 * [BB28] \ 333 * sub R310, R101, R309 \ 334 * | \ 335 * | \ 336 * [BB17] [BB29] [BB44] 337 * sub R314, R101, R275 | / 338 * \ | / 339 * \ | / 340 * \ | / 341 * \ | / 342 * [BB18] 343 * <---- insert new phi: R404, (R275 <17>, R309 <29>, R403 <44>) 344 * old phi: R318, (R314 <17>, R310 <29>, R297 <44>) 345 * mov R1, R318 ====> sub R1, R101, R404 346 * / \ 347 * / \ 348 * / \ 349 * [BB19] [BB34] 350 * sub R336, R101, R335 / 351 * \ / 352 * \ / 353 * \ / 354 * [BB20] 355 * <---- insert new phi: R405, (R335 <19>, R404<34>) 356 * old phi: R340, (R336 <19>, R318 <34>) 357 * mov R1, R340 ====> sub R1, R101, R405 358 */ 359 class A64PregCopyPattern : public PropOptimizePattern { 360 public: A64PregCopyPattern(CGFunc & cgFunc,CGSSAInfo * cgssaInfo)361 A64PregCopyPattern(CGFunc &cgFunc, CGSSAInfo *cgssaInfo) : PropOptimizePattern(cgFunc, cgssaInfo) {} ~A64PregCopyPattern()362 ~A64PregCopyPattern() override 363 { 364 firstPhiInsn = nullptr; 365 } 366 bool CheckCondition(Insn &insn) override; 367 void Optimize(Insn &insn) override; 368 void Run() override; 369 370 protected: Init()371 void Init() override 372 { 373 validDefInsns.clear(); 374 firstPhiInsn = nullptr; 375 differIdx = -1; 376 differOrigNO = 0; 377 isCrossPhi = false; 378 } 379 380 private: 381 bool CheckUselessDefInsn(const Insn *defInsn) const; 382 bool CheckValidDefInsn(const Insn *defInsn); 383 bool CheckMultiUsePoints(const Insn *defInsn) const; 384 bool CheckPhiCaseCondition(Insn &curInsn, Insn &defInsn); 385 bool DFSFindValidDefInsns(Insn *curDefInsn, RegOperand *lastPhiDef, std::unordered_map<uint32, bool> &visited); 386 Insn &CreateNewPhiInsn(std::unordered_map<uint32, RegOperand *> &newPhiList, Insn *curInsn); 387 RegOperand &DFSBuildPhiInsn(Insn *curInsn, std::unordered_map<uint32, RegOperand *> &visited); 388 RegOperand *CheckAndGetExistPhiDef(Insn &phiInsn, std::vector<regno_t> &validDifferRegNOs) const; 389 std::vector<Insn *> validDefInsns; 390 Insn *firstPhiInsn = nullptr; 391 int differIdx = -1; 392 regno_t differOrigNO = 0; 393 bool isCrossPhi = false; 394 }; 395 396 class A64ReplaceRegOpndVisitor : public ReplaceRegOpndVisitor { 397 public: A64ReplaceRegOpndVisitor(CGFunc & f,Insn & cInsn,uint32 cIdx,RegOperand & oldRegister,RegOperand & newRegister)398 A64ReplaceRegOpndVisitor(CGFunc &f, Insn &cInsn, uint32 cIdx, RegOperand &oldRegister, RegOperand &newRegister) 399 : ReplaceRegOpndVisitor(f, cInsn, cIdx, oldRegister, newRegister) 400 { 401 } 402 ~A64ReplaceRegOpndVisitor() override = default; 403 404 private: 405 void Visit(RegOperand *v) final; 406 void Visit(ListOperand *v) final; 407 void Visit(MemOperand *v) final; 408 void Visit(PhiOperand *v) final; 409 }; 410 } // namespace maplebe 411 #endif /* MAPLEBE_INCLUDE_AARCH64_PROP_H */ 412