//===---- LoongArchMergeBaseOffset.cpp - Optimise address calculations ----===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Merge the offset of address calculation into the offset field // of instructions in a global address lowering sequence. // //===----------------------------------------------------------------------===// #include "LoongArch.h" #include "LoongArchTargetMachine.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/Passes.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/Debug.h" #include "llvm/Target/TargetOptions.h" #include <optional> usingnamespacellvm; #define DEBUG_TYPE … #define LoongArch_MERGE_BASE_OFFSET_NAME … namespace { class LoongArchMergeBaseOffsetOpt : public MachineFunctionPass { … }; } // end anonymous namespace char LoongArchMergeBaseOffsetOpt::ID = …; INITIALIZE_PASS(…) // Detect either of the patterns: // // 1. (small/medium): // pcalau12i vreg1, %pc_hi20(s) // addi.d vreg2, vreg1, %pc_lo12(s) // // 2. (large): // pcalau12i vreg1, %pc_hi20(s) // addi.d vreg2, $zero, %pc_lo12(s) // lu32i.d vreg3, vreg2, %pc64_lo20(s) // lu52i.d vreg4, vreg3, %pc64_hi12(s) // add.d vreg5, vreg4, vreg1 // The pattern is only accepted if: // 1) For small and medium pattern, the first instruction has only one use, // which is the ADDI. // 2) For large pattern, the first four instructions each have only one use, // and the user of the fourth instruction is ADD. // 3) The address operands have the appropriate type, reflecting the // lowering of a global address or constant pool using the pattern. // 4) The offset value in the Global Address or Constant Pool is 0. bool LoongArchMergeBaseOffsetOpt::detectFoldable(MachineInstr &Hi20, MachineInstr *&Lo12, MachineInstr *&Lo20, MachineInstr *&Hi12, MachineInstr *&Last) { … } // Update the offset in Hi20, Lo12, Lo20 and Hi12 instructions. // Delete the tail instruction and update all the uses to use the // output from Last. void LoongArchMergeBaseOffsetOpt::foldOffset( MachineInstr &Hi20, MachineInstr &Lo12, MachineInstr *&Lo20, MachineInstr *&Hi12, MachineInstr *&Last, MachineInstr &Tail, int64_t Offset) { … } // Detect patterns for large offsets that are passed into an ADD instruction. // If the pattern is found, updates the offset in Hi20, Lo12, Lo20 and Hi12 // instructions and deletes TailAdd and the instructions that produced the // offset. // // Base address lowering is of the form: // Hi20: pcalau12i vreg1, %pc_hi20(s) // Lo12: addi.d vreg2, vreg1, %pc_lo12(s) // / \ // / \ // / \ // / The large offset can be of two forms: \ // 1) Offset that has non zero bits in lower 2) Offset that has non zero // 12 bits and upper 20 bits bits in upper 20 bits only // OffsetHi: lu12i.w vreg3, 4 // OffsetLo: ori voff, vreg3, 188 OffsetHi: lu12i.w voff, 128 // \ / // \ / // \ / // \ / // TailAdd: add.d vreg4, vreg2, voff bool LoongArchMergeBaseOffsetOpt::foldLargeOffset( MachineInstr &Hi20, MachineInstr &Lo12, MachineInstr *&Lo20, MachineInstr *&Hi12, MachineInstr *&Last, MachineInstr &TailAdd, Register GAReg) { … } bool LoongArchMergeBaseOffsetOpt::detectAndFoldOffset(MachineInstr &Hi20, MachineInstr &Lo12, MachineInstr *&Lo20, MachineInstr *&Hi12, MachineInstr *&Last) { … } // Memory access opcode mapping for transforms. static unsigned getNewOpc(unsigned Op, bool isLarge) { … } bool LoongArchMergeBaseOffsetOpt::foldIntoMemoryOps(MachineInstr &Hi20, MachineInstr &Lo12, MachineInstr *&Lo20, MachineInstr *&Hi12, MachineInstr *&Last) { … } bool LoongArchMergeBaseOffsetOpt::runOnMachineFunction(MachineFunction &Fn) { … } /// Returns an instance of the Merge Base Offset Optimization pass. FunctionPass *llvm::createLoongArchMergeBaseOffsetOptPass() { … }