[llvm] c2d1d9f - [LoongArch] Implement prologue/epilogue insertion

Weining Lu via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 6 00:53:56 PDT 2022


Author: wanglei
Date: 2022-07-06T15:52:26+08:00
New Revision: c2d1d9f942a402569e226a2541e1bafcc02aa0b9

URL: https://github.com/llvm/llvm-project/commit/c2d1d9f942a402569e226a2541e1bafcc02aa0b9
DIFF: https://github.com/llvm/llvm-project/commit/c2d1d9f942a402569e226a2541e1bafcc02aa0b9.diff

LOG: [LoongArch] Implement prologue/epilogue insertion

Differential Revision: https://reviews.llvm.org/D128432

Added: 
    

Modified: 
    llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp
    llvm/lib/Target/LoongArch/LoongArchFrameLowering.h
    llvm/test/CodeGen/LoongArch/frame.ll
    llvm/test/CodeGen/LoongArch/ir-instruction/call.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp
index 55b8f17cc1691..0d9ec9e2eaaac 100644
--- a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp
@@ -11,7 +11,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "LoongArchFrameLowering.h"
+#include "LoongArchMachineFunctionInfo.h"
 #include "LoongArchSubtarget.h"
+#include "MCTargetDesc/LoongArchBaseInfo.h"
 #include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
@@ -44,14 +46,151 @@ bool LoongArchFrameLowering::hasBP(const MachineFunction &MF) const {
   return MFI.hasVarSizedObjects() && TRI->hasStackRealignment(MF);
 }
 
+void LoongArchFrameLowering::adjustReg(MachineBasicBlock &MBB,
+                                       MachineBasicBlock::iterator MBBI,
+                                       const DebugLoc &DL, Register DestReg,
+                                       Register SrcReg, int64_t Val,
+                                       MachineInstr::MIFlag Flag) const {
+  const LoongArchInstrInfo *TII = STI.getInstrInfo();
+  bool IsLA64 = STI.is64Bit();
+
+  if (DestReg == SrcReg && Val == 0)
+    return;
+
+  if (isInt<12>(Val)) {
+    // addi.w/d $DstReg, $SrcReg, Val
+    BuildMI(MBB, MBBI, DL,
+            TII->get(IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W), DestReg)
+        .addReg(SrcReg)
+        .addImm(Val)
+        .setMIFlag(Flag);
+    return;
+  }
+
+  report_fatal_error("adjustReg cannot yet handle adjustments >12 bits");
+}
+
+// Determine the size of the frame and maximum call frame size.
+void LoongArchFrameLowering::determineFrameLayout(MachineFunction &MF) const {
+  MachineFrameInfo &MFI = MF.getFrameInfo();
+
+  // Get the number of bytes to allocate from the FrameInfo.
+  uint64_t FrameSize = MFI.getStackSize();
+
+  // Make sure the frame is aligned.
+  FrameSize = alignTo(FrameSize, getStackAlign());
+
+  // Update frame info.
+  MFI.setStackSize(FrameSize);
+}
+
 void LoongArchFrameLowering::emitPrologue(MachineFunction &MF,
                                           MachineBasicBlock &MBB) const {
-  // TODO: Implement this when we have function calls
+  MachineFrameInfo &MFI = MF.getFrameInfo();
+  const LoongArchRegisterInfo *RI = STI.getRegisterInfo();
+  const LoongArchInstrInfo *TII = STI.getInstrInfo();
+  MachineBasicBlock::iterator MBBI = MBB.begin();
+
+  Register SPReg = LoongArch::R3;
+  Register FPReg = LoongArch::R22;
+
+  // Debug location must be unknown since the first debug location is used
+  // to determine the end of the prologue.
+  DebugLoc DL;
+
+  // Determine the correct frame layout
+  determineFrameLayout(MF);
+
+  // First, compute final stack size.
+  uint64_t StackSize = MFI.getStackSize();
+
+  // Early exit if there is no need to allocate space in the stack.
+  if (StackSize == 0 && !MFI.adjustsStack())
+    return;
+
+  // Adjust stack.
+  adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup);
+  // Emit ".cfi_def_cfa_offset StackSize".
+  unsigned CFIIndex =
+      MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));
+  BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
+      .addCFIIndex(CFIIndex)
+      .setMIFlag(MachineInstr::FrameSetup);
+
+  const auto &CSI = MFI.getCalleeSavedInfo();
+
+  // The frame pointer is callee-saved, and code has been generated for us to
+  // save it to the stack. We need to skip over the storing of callee-saved
+  // registers as the frame pointer must be modified after it has been saved
+  // to the stack, not before.
+  std::advance(MBBI, CSI.size());
+
+  // Iterate over list of callee-saved registers and emit .cfi_offset
+  // directives.
+  for (const auto &Entry : CSI) {
+    int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx());
+    unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
+        nullptr, RI->getDwarfRegNum(Entry.getReg(), true), Offset));
+    BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
+        .addCFIIndex(CFIIndex)
+        .setMIFlag(MachineInstr::FrameSetup);
+  }
+
+  // Generate new FP.
+  if (hasFP(MF)) {
+    adjustReg(MBB, MBBI, DL, FPReg, SPReg, StackSize, MachineInstr::FrameSetup);
+
+    // Emit ".cfi_def_cfa $fp, 0"
+    unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa(
+        nullptr, RI->getDwarfRegNum(FPReg, true), 0));
+    BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
+        .addCFIIndex(CFIIndex)
+        .setMIFlag(MachineInstr::FrameSetup);
+  }
 }
 
 void LoongArchFrameLowering::emitEpilogue(MachineFunction &MF,
                                           MachineBasicBlock &MBB) const {
-  // TODO: Implement this when we have function calls
+  const LoongArchRegisterInfo *RI = STI.getRegisterInfo();
+  MachineFrameInfo &MFI = MF.getFrameInfo();
+  Register SPReg = LoongArch::R3;
+
+  MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
+  DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
+
+  const auto &CSI = MFI.getCalleeSavedInfo();
+  // Skip to before the restores of callee-saved registers.
+  auto LastFrameDestroy = MBBI;
+  if (!CSI.empty())
+    LastFrameDestroy = std::prev(MBBI, CSI.size());
+
+  // Get the number of bytes from FrameInfo.
+  uint64_t StackSize = MFI.getStackSize();
+
+  // Restore the stack pointer.
+  if (RI->hasStackRealignment(MF) || MFI.hasVarSizedObjects()) {
+    assert(hasFP(MF) && "frame pointer should not have been eliminated");
+    adjustReg(MBB, LastFrameDestroy, DL, SPReg, LoongArch::R22, -StackSize,
+              MachineInstr::FrameDestroy);
+  }
+
+  // Deallocate stack
+  adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy);
+}
+
+void LoongArchFrameLowering::determineCalleeSaves(MachineFunction &MF,
+                                                  BitVector &SavedRegs,
+                                                  RegScavenger *RS) const {
+  TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
+  // Unconditionally spill RA and FP only if the function uses a frame
+  // pointer.
+  if (hasFP(MF)) {
+    SavedRegs.set(LoongArch::R1);
+    SavedRegs.set(LoongArch::R22);
+  }
+  // Mark BP as used if function has dedicated base pointer.
+  if (hasBP(MF))
+    SavedRegs.set(LoongArchABI::getBPReg());
 }
 
 StackOffset LoongArchFrameLowering::getFrameIndexReference(

diff  --git a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h
index 2575219de749f..014b666de7117 100644
--- a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h
@@ -31,6 +31,9 @@ class LoongArchFrameLowering : public TargetFrameLowering {
   void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
   void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
 
+  void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
+                            RegScavenger *RS) const override;
+
   MachineBasicBlock::iterator
   eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
                                 MachineBasicBlock::iterator MI) const override {
@@ -42,6 +45,12 @@ class LoongArchFrameLowering : public TargetFrameLowering {
 
   bool hasFP(const MachineFunction &MF) const override;
   bool hasBP(const MachineFunction &MF) const;
+
+private:
+  void determineFrameLayout(MachineFunction &MF) const;
+  void adjustReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
+                 const DebugLoc &DL, Register DestReg, Register SrcReg,
+                 int64_t Val, MachineInstr::MIFlag Flag) const;
 };
 } // namespace llvm
 #endif // LLVM_LIB_TARGET_LOONGARCH_LOONGARCHFRAMELOWERING_H

diff  --git a/llvm/test/CodeGen/LoongArch/frame.ll b/llvm/test/CodeGen/LoongArch/frame.ll
index a27eaa44b74aa..e0aa7db13f728 100644
--- a/llvm/test/CodeGen/LoongArch/frame.ll
+++ b/llvm/test/CodeGen/LoongArch/frame.ll
@@ -2,12 +2,10 @@
 
 %struct.key_t = type { i32, [16 x i8] }
 
-;; FIXME: prologue and epilogue insertion must be implemented to complete this
-;; test
-
 define i32 @test() nounwind {
 ; CHECK-LABEL: test:
 ; CHECK:       # %bb.0:
+; CHECK-NEXT:    addi.d $sp, $sp, -32
 ; CHECK-NEXT:    st.d $ra, $sp, 24 # 8-byte Folded Spill
 ; CHECK-NEXT:    st.w $zero, $sp, 16
 ; CHECK-NEXT:    st.d $zero, $sp, 8
@@ -17,6 +15,7 @@ define i32 @test() nounwind {
 ; CHECK-NEXT:    bl test1
 ; CHECK-NEXT:    move $a0, $zero
 ; CHECK-NEXT:    ld.d $ra, $sp, 24 # 8-byte Folded Reload
+; CHECK-NEXT:    addi.d $sp, $sp, 32
 ; CHECK-NEXT:    jirl $zero, $ra, 0
   %key = alloca %struct.key_t, align 4
   call void @llvm.memset.p0i8.i64(ptr %key, i8 0, i64 20, i1 false)

diff  --git a/llvm/test/CodeGen/LoongArch/ir-instruction/call.ll b/llvm/test/CodeGen/LoongArch/ir-instruction/call.ll
index a5a5bdbd7f564..596ea22e5854e 100644
--- a/llvm/test/CodeGen/LoongArch/ir-instruction/call.ll
+++ b/llvm/test/CodeGen/LoongArch/ir-instruction/call.ll
@@ -1,24 +1,25 @@
 ; RUN: llc --mtriple=loongarch32 < %s | FileCheck --check-prefix=LA32 %s
 ; RUN: llc --mtriple=loongarch64 < %s | FileCheck --check-prefix=LA64 %s
 
-;; FIXME: prologue and epilogue insertion must be implemented to complete this
-;; test
-
 declare i32 @external_function(i32)
 
 define i32 @test_call_external(i32 %a) nounwind {
 ; LA32-LABEL: test_call_external:
 ; LA32:       # %bb.0:
+; LA32-NEXT:    addi.w $sp, $sp, -16
 ; LA32-NEXT:    st.w $ra, $sp, 12 # 4-byte Folded Spill
 ; LA32-NEXT:    bl external_function
 ; LA32-NEXT:    ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32-NEXT:    addi.w $sp, $sp, 16
 ; LA32-NEXT:    jirl $zero, $ra, 0
 ;
 ; LA64-LABEL: test_call_external:
 ; LA64:       # %bb.0:
+; LA64-NEXT:    addi.d $sp, $sp, -16
 ; LA64-NEXT:    st.d $ra, $sp, 8 # 8-byte Folded Spill
 ; LA64-NEXT:    bl external_function
 ; LA64-NEXT:    ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; LA64-NEXT:    addi.d $sp, $sp, 16
 ; LA64-NEXT:    jirl $zero, $ra, 0
   %1 = call i32 @external_function(i32 %a)
   ret i32 %1
@@ -41,16 +42,20 @@ define i32 @defined_function(i32 %a) nounwind {
 define i32 @test_call_defined(i32 %a) nounwind {
 ; LA32-LABEL: test_call_defined:
 ; LA32:       # %bb.0:
+; LA32-NEXT:    addi.w $sp, $sp, -16
 ; LA32-NEXT:    st.w $ra, $sp, 12 # 4-byte Folded Spill
 ; LA32-NEXT:    bl defined_function
 ; LA32-NEXT:    ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32-NEXT:    addi.w $sp, $sp, 16
 ; LA32-NEXT:    jirl $zero, $ra, 0
 ;
 ; LA64-LABEL: test_call_defined:
 ; LA64:       # %bb.0:
+; LA64-NEXT:    addi.d $sp, $sp, -16
 ; LA64-NEXT:    st.d $ra, $sp, 8 # 8-byte Folded Spill
 ; LA64-NEXT:    bl defined_function
 ; LA64-NEXT:    ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; LA64-NEXT:    addi.d $sp, $sp, 16
 ; LA64-NEXT:    jirl $zero, $ra, 0
   %1 = call i32 @defined_function(i32 %a) nounwind
   ret i32 %1
@@ -59,20 +64,24 @@ define i32 @test_call_defined(i32 %a) nounwind {
 define i32 @test_call_indirect(ptr %a, i32 %b) nounwind {
 ; LA32-LABEL: test_call_indirect:
 ; LA32:       # %bb.0:
+; LA32-NEXT:    addi.w $sp, $sp, -16
 ; LA32-NEXT:    st.w $ra, $sp, 12 # 4-byte Folded Spill
 ; LA32-NEXT:    move $a2, $a0
 ; LA32-NEXT:    move $a0, $a1
 ; LA32-NEXT:    jirl $ra, $a2, 0
 ; LA32-NEXT:    ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32-NEXT:    addi.w $sp, $sp, 16
 ; LA32-NEXT:    jirl $zero, $ra, 0
 ;
 ; LA64-LABEL: test_call_indirect:
 ; LA64:       # %bb.0:
+; LA64-NEXT:    addi.d $sp, $sp, -16
 ; LA64-NEXT:    st.d $ra, $sp, 8 # 8-byte Folded Spill
 ; LA64-NEXT:    move $a2, $a0
 ; LA64-NEXT:    move $a0, $a1
 ; LA64-NEXT:    jirl $ra, $a2, 0
 ; LA64-NEXT:    ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; LA64-NEXT:    addi.d $sp, $sp, 16
 ; LA64-NEXT:    jirl $zero, $ra, 0
   %1 = call i32 %a(i32 %b)
   ret i32 %1


        


More information about the llvm-commits mailing list