Skip to content

[LoongArch] Add options for annotate tablejump #102411

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

wangleiat
Copy link
Contributor

@wangleiat wangleiat commented Aug 8, 2024

This aligns with GCC. LoongArch kernel developers requested that this
option generate some corresponding relations in a section, including the
addresses of the jump instruction(jr) and the MachineJumpTableEntry.

Created using spr 1.3.5-bogner
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' backend:loongarch labels Aug 8, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 8, 2024

@llvm/pr-subscribers-clang-driver
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-backend-loongarch

Author: wanglei (wangleiat)

Changes

draft pr.


Full diff: https://github.com/llvm/llvm-project/pull/102411.diff

6 Files Affected:

  • (modified) clang/include/clang/Driver/Options.td (+4)
  • (modified) clang/lib/Driver/ToolChains/Clang.cpp (+8)
  • (modified) llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp (+49)
  • (modified) llvm/lib/Target/LoongArch/LoongArchAsmPrinter.h (+1)
  • (modified) llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp (+17)
  • (added) llvm/test/CodeGen/LoongArch/annotate-tablejump.ll (+102)
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 51ec29f1dc321..18ad7f5868e48 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -5319,6 +5319,10 @@ def mno_lasx : Flag<["-"], "mno-lasx">, Group<m_loongarch_Features_Group>,
 def msimd_EQ : Joined<["-"], "msimd=">, Group<m_loongarch_Features_Group>,
   Flags<[TargetSpecific]>,
   HelpText<"Select the SIMD extension(s) to be enabled in LoongArch either 'none', 'lsx', 'lasx'.">;
+def mannotate_tablejump : Flag<["-"], "mannotate-tablejump">, Group<m_loongarch_Features_Group>,
+  HelpText<"Enable annotate table jump instruction to correlate it with the jump table.">;
+def mno_annotate_tablejump : Flag<["-"], "mno-annotate-tablejump">, Group<m_loongarch_Features_Group>,
+  HelpText<"Disable annotate table jump instruction to correlate it with the jump table.">;
 def mnop_mcount : Flag<["-"], "mnop-mcount">, HelpText<"Generate mcount/__fentry__ calls as nops. To activate they need to be patched in.">,
   Visibility<[ClangOption, CC1Option]>, Group<m_Group>,
   MarshallingInfoFlag<CodeGenOpts<"MNopMCount">>;
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 2054c8fe928e2..342c083b01101 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1876,6 +1876,14 @@ void Clang::AddLoongArchTargetArgs(const ArgList &Args,
     CmdArgs.push_back("-tune-cpu");
     CmdArgs.push_back(Args.MakeArgString(TuneCPU));
   }
+
+  if (Arg *A = Args.getLastArg(options::OPT_mannotate_tablejump,
+                               options::OPT_mno_annotate_tablejump)) {
+    if (A->getOption().matches(options::OPT_mannotate_tablejump)) {
+      CmdArgs.push_back("-mllvm");
+      CmdArgs.push_back("-loongarch-annotate-tablejump");
+    }
+  }
 }
 
 void Clang::AddMIPSTargetArgs(const ArgList &Args,
diff --git a/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp b/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp
index f478870217ec6..b4c5be194bff5 100644
--- a/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp
@@ -15,16 +15,26 @@
 #include "LoongArch.h"
 #include "LoongArchTargetMachine.h"
 #include "MCTargetDesc/LoongArchInstPrinter.h"
+#include "MCTargetDesc/LoongArchMCTargetDesc.h"
 #include "TargetInfo/LoongArchTargetInfo.h"
 #include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/MachineJumpTableInfo.h"
+#include "llvm/CodeGen/MachineModuleInfoImpls.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCInstBuilder.h"
+#include "llvm/MC/MCSectionELF.h"
 #include "llvm/MC/TargetRegistry.h"
 
 using namespace llvm;
 
 #define DEBUG_TYPE "loongarch-asm-printer"
 
+cl::opt<bool> LArchAnnotateTableJump(
+    "loongarch-annotate-tablejump", cl::Hidden,
+    cl::desc(
+        "Annotate table jump instruction to correlate it with the jump table."),
+    cl::init(false));
+
 // Simple pseudo-instructions have their lowering (with expansion to real
 // instructions) auto-generated.
 #include "LoongArchGenMCPseudoLowering.inc"
@@ -189,6 +199,45 @@ void LoongArchAsmPrinter::emitSled(const MachineInstr &MI, SledKind Kind) {
   recordSled(BeginOfSled, MI, Kind, 2);
 }
 
+void LoongArchAsmPrinter::emitJumpTableInfo() {
+  AsmPrinter::emitJumpTableInfo();
+
+  if (!LArchAnnotateTableJump)
+    return;
+
+  assert(TM.getTargetTriple().isOSBinFormatELF());
+
+  const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
+  if (!MJTI)
+    return;
+
+  const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
+  if (JT.empty())
+    return;
+
+  OutStreamer->switchSection(MMI->getContext().getELFSection(
+      ".discard.tablejump_annotate", ELF::SHT_PROGBITS, 0));
+
+  unsigned Size = getDataLayout().getPointerSize();
+
+  for (unsigned JTI = 0, e = JT.size(); JTI != e; ++JTI) {
+    const std::vector<MachineBasicBlock *> &JTBBs = JT[JTI].MBBs;
+    if (JTBBs.empty())
+      continue;
+    for (auto *Pred : JTBBs[0]->predecessors()) {
+      for (auto &MI : Pred->instrs()) {
+        if (MI.getOpcode() != LoongArch::PseudoBRIND || !MI.getPreInstrSymbol())
+          continue;
+        OutStreamer->emitValue(
+            MCSymbolRefExpr::create(MI.getPreInstrSymbol(), OutContext), Size);
+        MCSymbol *JTISymbol = GetJTISymbol(JTI);
+        OutStreamer->emitValue(MCSymbolRefExpr::create(JTISymbol, OutContext),
+                               Size);
+      }
+    }
+  }
+}
+
 bool LoongArchAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
   AsmPrinter::runOnMachineFunction(MF);
   // Emit the XRay table for this function.
diff --git a/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.h b/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.h
index 9da90886627ec..b5239ab37e147 100644
--- a/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.h
+++ b/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.h
@@ -53,6 +53,7 @@ class LLVM_LIBRARY_VISIBILITY LoongArchAsmPrinter : public AsmPrinter {
   bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const {
     return lowerLoongArchMachineOperandToMCOperand(MO, MCOp, *this);
   }
+  void emitJumpTableInfo() override;
 };
 
 } // end namespace llvm
diff --git a/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp b/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp
index 33b93e42bb5c4..c72f9157525f4 100644
--- a/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp
@@ -27,6 +27,8 @@
 
 using namespace llvm;
 
+extern cl::opt<bool> LArchAnnotateTableJump;
+
 #define LOONGARCH_PRERA_EXPAND_PSEUDO_NAME                                     \
   "LoongArch Pre-RA pseudo instruction expansion pass"
 #define LOONGARCH_EXPAND_PSEUDO_NAME                                           \
@@ -167,6 +169,21 @@ bool LoongArchPreRAExpandPseudo::expandMI(
   case LoongArch::PseudoTAIL_MEDIUM:
   case LoongArch::PseudoTAIL_LARGE:
     return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true);
+  case LoongArch::PseudoBRIND:
+    // If the PseudoBRIND is used to table jump, then emit a label to annotate
+    // the `jr` instruction.
+    if (!LArchAnnotateTableJump)
+      return false;
+    for (auto &MI : MBB.instrs()) {
+      for (auto MO : MI.operands()) {
+        if (!MO.isJTI())
+          continue;
+        MachineFunction *MF = MBB.getParent();
+        MBBI->setPreInstrSymbol(
+            *MF, MF->getContext().createNamedTempSymbol("jrtb_"));
+        return false;
+      }
+    }
   }
   return false;
 }
diff --git a/llvm/test/CodeGen/LoongArch/annotate-tablejump.ll b/llvm/test/CodeGen/LoongArch/annotate-tablejump.ll
new file mode 100644
index 0000000000000..ddea8c80b0ea4
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/annotate-tablejump.ll
@@ -0,0 +1,102 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc --mtriple=loongarch32 -mattr=+d \
+; RUN:   --min-jump-table-entries=4 < %s \
+; RUN:   --loongarch-annotate-tablejump \
+; RUN:   | FileCheck %s --check-prefix=LA32-JT
+; RUN: llc --mtriple=loongarch64 -mattr=+d \
+; RUN:   --min-jump-table-entries=4 < %s \
+; RUN:   --loongarch-annotate-tablejump \
+; RUN:   | FileCheck %s --check-prefix=LA64-JT
+
+define void @switch_4_arms(i32 %in, ptr %out) nounwind {
+; LA32-JT-LABEL: switch_4_arms:
+; LA32-JT:       # %bb.0: # %entry
+; LA32-JT-NEXT:    addi.w $a0, $a0, -1
+; LA32-JT-NEXT:    ori $a2, $zero, 3
+; LA32-JT-NEXT:    bltu $a2, $a0, .LBB0_7
+; LA32-JT-NEXT:  # %bb.1: # %entry
+; LA32-JT-NEXT:    pcalau12i $a2, %pc_hi20(.LJTI0_0)
+; LA32-JT-NEXT:    addi.w $a2, $a2, %pc_lo12(.LJTI0_0)
+; LA32-JT-NEXT:    alsl.w $a0, $a0, $a2, 2
+; LA32-JT-NEXT:    ld.w $a0, $a0, 0
+; LA32-JT-NEXT:  .Ljrtb_0:
+; LA32-JT-NEXT:    jr $a0
+; LA32-JT-NEXT:  .LBB0_2: # %bb1
+; LA32-JT-NEXT:    ori $a0, $zero, 4
+; LA32-JT-NEXT:    b .LBB0_6
+; LA32-JT-NEXT:  .LBB0_3: # %bb3
+; LA32-JT-NEXT:    ori $a0, $zero, 2
+; LA32-JT-NEXT:    b .LBB0_6
+; LA32-JT-NEXT:  .LBB0_4: # %bb4
+; LA32-JT-NEXT:    ori $a0, $zero, 1
+; LA32-JT-NEXT:    b .LBB0_6
+; LA32-JT-NEXT:  .LBB0_5: # %bb2
+; LA32-JT-NEXT:    ori $a0, $zero, 3
+; LA32-JT-NEXT:  .LBB0_6: # %exit
+; LA32-JT-NEXT:    st.w $a0, $a1, 0
+; LA32-JT-NEXT:  .LBB0_7: # %exit
+; LA32-JT-NEXT:    ret
+;
+; LA64-JT-LABEL: switch_4_arms:
+; LA64-JT:       # %bb.0: # %entry
+; LA64-JT-NEXT:    addi.w $a0, $a0, 0
+; LA64-JT-NEXT:    addi.d $a0, $a0, -1
+; LA64-JT-NEXT:    ori $a2, $zero, 3
+; LA64-JT-NEXT:    bltu $a2, $a0, .LBB0_7
+; LA64-JT-NEXT:  # %bb.1: # %entry
+; LA64-JT-NEXT:    slli.d $a0, $a0, 3
+; LA64-JT-NEXT:    pcalau12i $a2, %pc_hi20(.LJTI0_0)
+; LA64-JT-NEXT:    addi.d $a2, $a2, %pc_lo12(.LJTI0_0)
+; LA64-JT-NEXT:    ldx.d $a0, $a0, $a2
+; LA64-JT-NEXT:  .Ljrtb_0:
+; LA64-JT-NEXT:    jr $a0
+; LA64-JT-NEXT:  .LBB0_2: # %bb1
+; LA64-JT-NEXT:    ori $a0, $zero, 4
+; LA64-JT-NEXT:    b .LBB0_6
+; LA64-JT-NEXT:  .LBB0_3: # %bb3
+; LA64-JT-NEXT:    ori $a0, $zero, 2
+; LA64-JT-NEXT:    b .LBB0_6
+; LA64-JT-NEXT:  .LBB0_4: # %bb4
+; LA64-JT-NEXT:    ori $a0, $zero, 1
+; LA64-JT-NEXT:    b .LBB0_6
+; LA64-JT-NEXT:  .LBB0_5: # %bb2
+; LA64-JT-NEXT:    ori $a0, $zero, 3
+; LA64-JT-NEXT:  .LBB0_6: # %exit
+; LA64-JT-NEXT:    st.w $a0, $a1, 0
+; LA64-JT-NEXT:  .LBB0_7: # %exit
+; LA64-JT-NEXT:    ret
+entry:
+  switch i32 %in, label %exit [
+    i32 1, label %bb1
+    i32 2, label %bb2
+    i32 3, label %bb3
+    i32 4, label %bb4
+  ]
+bb1:
+  store i32 4, ptr %out
+  br label %exit
+bb2:
+  store i32 3, ptr %out
+  br label %exit
+bb3:
+  store i32 2, ptr %out
+  br label %exit
+bb4:
+  store i32 1, ptr %out
+  br label %exit
+exit:
+  ret void
+}
+
+; UTC_ARGS: --disable
+
+; LA32-JT-LABEL: .LJTI0_0:
+; LA32-JT:       .section .discard.tablejump_annotate,"",@progbits
+; LA32-JT-NEXT:  .word .Ljrtb_0
+; LA32-JT-NEXT:  .word .LJTI0_0
+
+; UTC_ARGS: --disable
+; LA64-JT-LABEL: .LJTI0_0:
+; LA64-JT:       .section .discard.tablejump_annotate,"",@progbits
+; LA64-JT-NEXT:  .dword .Ljrtb_0
+; LA64-JT-NEXT:  .dword .LJTI0_0

Created using spr 1.3.5-bogner
@heiher
Copy link
Member

heiher commented Oct 12, 2024

define void @switch_4_arms(i32 %in, ptr %out) nounwind {
entry:
  switch i32 %in, label %exit [
    i32 1, label %bb1
    i32 2, label %bb2
    i32 3, label %bb3
    i32 4, label %bb4
  ]
bb1:
  store i32 4, ptr %out
  br label %exit
bb2:
  store i32 3, ptr %out
  br label %exit
bb3:
  store i32 2, ptr %out
  br label %exit
bb4:
  store i32 1, ptr %out
  br label %exit
exit:
  switch i32 %in, label %exit2 [
    i32 5, label %bb1
    i32 6, label %bb2
    i32 7, label %bb3
    i32 8, label %bb4
  ]
exit2:
  ret void
}

or

extern void asdf0(void);
extern void asdf1(void);
extern void asdf2(void);
extern void asdf3(void);
extern void asdf4(void);

void foo(int x, int y) {
  switch (x) {
  case 0: goto l0;
  case 1: goto l1;
  case 2: goto l2;
  case 3: goto l3;
  case 4: goto l4;
  }

  switch (y) {
  case 5: goto l0;
  case 6: goto l1;
  case 7: goto l2;
  case 8: goto l3;
  case 9: goto l4;
  }
  return;

l0:
  asdf0();
  return;
l1:
  asdf1();
  return;
l2:
  asdf2();
  return;
l3:
  asdf3();
  return;
l4:
  asdf4();
  return;
}
.Ljrtb_0:                                                                       
    jr  $a3
    ...
.Ljrtb_1:                                                                       
    jr  $a3
    ...
    .section    .discard.tablejump_annotate,"",@progbits                        
    .dword  .Ljrtb_0                                                            
    .dword  .LJTI0_0                                                            
    .dword  .Ljrtb_1                                                            
    .dword  .LJTI0_0                                                            
    .dword  .Ljrtb_0                                                            
    .dword  .LJTI0_1                                                            
    .dword  .Ljrtb_1                                                            
    .dword  .LJTI0_1

Is this expected?

Copy link
Contributor

@SixWeining SixWeining left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to add gcc's links to commit message to let people know the background.

@@ -5340,6 +5340,10 @@ def mno_lasx : Flag<["-"], "mno-lasx">, Group<m_loongarch_Features_Group>,
def msimd_EQ : Joined<["-"], "msimd=">, Group<m_loongarch_Features_Group>,
Flags<[TargetSpecific]>,
HelpText<"Select the SIMD extension(s) to be enabled in LoongArch either 'none', 'lsx', 'lasx'.">;
def mannotate_tablejump : Flag<["-"], "mannotate-tablejump">, Group<m_loongarch_Features_Group>,
HelpText<"Enable annotate table jump instruction to correlate it with the jump table.">;
def mno_annotate_tablejump : Flag<["-"], "mno-annotate-tablejump">, Group<m_loongarch_Features_Group>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The negative option is useless?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aligns gcc.

if (A->getOption().matches(options::OPT_mannotate_tablejump)) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-loongarch-annotate-tablejump");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else: -loongarch-annotate-tablejump=false

@wangleiat
Copy link
Contributor Author

Is this expected?

Thank you very much. I didn't take into account the situation where a basic block belongs to multiple MachineJumpTableEntry. It seems that traversing the entire MF would provide a more accurate output.

Created using spr 1.3.5-bogner
Created using spr 1.3.5-bogner
Copy link
Member

@heiher heiher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, Thanks.

Created using spr 1.3.5-bogner
@wangleiat wangleiat merged commit 4c2c177 into main Oct 16, 2024
8 checks passed
@wangleiat wangleiat deleted the users/wangleiat/spr/loongarch-add-options-for-annotate-tablejump branch October 16, 2024 03:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:loongarch clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants