Skip to content

[LoongArch] Avoid indirect branch jumps using the ra register #115424

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

Micro-architecture unconditionally treats a "jr $ra" as "return from
subroutine", hence doing "jr $ra" would interfere with both subroutine
return prediction and the more general indirect branch prediction.

GCC thread: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110136

Created using spr 1.3.5-bogner

[skip ci]
Created using spr 1.3.5-bogner
@llvmbot
Copy link
Member

llvmbot commented Nov 8, 2024

@llvm/pr-subscribers-backend-loongarch

Author: wanglei (wangleiat)

Changes

Micro-architecture unconditionally treats a "jr $ra" as "return from
subroutine", hence doing "jr $ra" would interfere with both subroutine
return prediction and the more general indirect branch prediction.

GCC thread: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110136


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

3 Files Affected:

  • (modified) llvm/lib/Target/LoongArch/LoongArchInstrInfo.td (+4-4)
  • (modified) llvm/lib/Target/LoongArch/LoongArchRegisterInfo.td (+6)
  • (modified) llvm/test/CodeGen/LoongArch/jr-without-ra.ll (+5-5)
diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
index ccdd5165728231..3de20d6e599dbf 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
@@ -1469,12 +1469,12 @@ def PseudoBR : Pseudo<(outs), (ins simm26_b:$imm26), [(br bb:$imm26)]>,
                PseudoInstExpansion<(B simm26_b:$imm26)>;
 
 let isBarrier = 1, isBranch = 1, isIndirectBranch = 1, isTerminator = 1 in
-def PseudoBRIND : Pseudo<(outs), (ins GPR:$rj, simm16_lsl2:$imm16)>,
+def PseudoBRIND : Pseudo<(outs), (ins GPRJR:$rj, simm16_lsl2:$imm16)>,
                   PseudoInstExpansion<(JIRL R0, GPR:$rj, simm16_lsl2:$imm16)>;
 
-def : Pat<(brind GPR:$rj), (PseudoBRIND GPR:$rj, 0)>;
-def : Pat<(brind (add GPR:$rj, simm16_lsl2:$imm16)),
-          (PseudoBRIND GPR:$rj, simm16_lsl2:$imm16)>;
+def : Pat<(brind GPRJR:$rj), (PseudoBRIND GPRJR:$rj, 0)>;
+def : Pat<(brind (add GPRJR:$rj, simm16_lsl2:$imm16)),
+          (PseudoBRIND GPRJR:$rj, simm16_lsl2:$imm16)>;
 
 // Function call with 'Small' code model.
 let isCall = 1, Defs = [R1] in
diff --git a/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.td b/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.td
index 2d3a7c364f0bf4..a8419980868ee1 100644
--- a/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.td
@@ -121,6 +121,12 @@ def GPR : GPRRegisterClass<(add // Argument registers (a0...a7)
 def GPRT : GPRRegisterClass<(add // a0...a7, t0...t8
                                  (sequence "R%u", 4, 20))>;
 
+// Don't use R1 for JR since that micro-architecture unconditionally treats a
+// "jr $ra" as "return from subroutine", hence doing "jr $ra" would interfere
+// with both subroutine return prediction and the more general indirect branch
+// prediction.
+def GPRJR : GPRRegisterClass<(sub GPR, R1)>;
+
 // Floating point registers
 
 let RegAltNameIndices = [RegAliasName] in {
diff --git a/llvm/test/CodeGen/LoongArch/jr-without-ra.ll b/llvm/test/CodeGen/LoongArch/jr-without-ra.ll
index f32513deee82bd..d1c4459aaa6ee0 100644
--- a/llvm/test/CodeGen/LoongArch/jr-without-ra.ll
+++ b/llvm/test/CodeGen/LoongArch/jr-without-ra.ll
@@ -44,7 +44,6 @@ define void @jr_without_ra(ptr %rtwdev, ptr %chan, ptr %h2c, i8 %.pre, i1 %cmp.i
 ; CHECK-NEXT:    addi.w $s4, $zero, -41
 ; CHECK-NEXT:    ori $s3, $zero, 1
 ; CHECK-NEXT:    slli.d $s4, $s4, 3
-; CHECK-NEXT:    ori $s5, $zero, 50
 ; CHECK-NEXT:    ori $s6, $zero, 3
 ; CHECK-NEXT:    lu32i.d $s6, 262144
 ; CHECK-NEXT:    b .LBB0_4
@@ -54,8 +53,8 @@ define void @jr_without_ra(ptr %rtwdev, ptr %chan, ptr %h2c, i8 %.pre, i1 %cmp.i
 ; CHECK-NEXT:    ori $s8, $zero, 1
 ; CHECK-NEXT:  .LBB0_2: # %if.else.i106
 ; CHECK-NEXT:    # in Loop: Header=BB0_4 Depth=1
-; CHECK-NEXT:    alsl.d $ra, $s0, $s0, 3
-; CHECK-NEXT:    alsl.d $s0, $ra, $s0, 1
+; CHECK-NEXT:    alsl.d $s5, $s0, $s0, 3
+; CHECK-NEXT:    alsl.d $s0, $s5, $s0, 1
 ; CHECK-NEXT:    add.d $s0, $t0, $s0
 ; CHECK-NEXT:    ldx.bu $s8, $s0, $s8
 ; CHECK-NEXT:  .LBB0_3: # %phy_tssi_get_ofdm_de.exit
@@ -92,6 +91,7 @@ define void @jr_without_ra(ptr %rtwdev, ptr %chan, ptr %h2c, i8 %.pre, i1 %cmp.i
 ; CHECK-NEXT:  .LBB0_9: # %if.end.i
 ; CHECK-NEXT:    # in Loop: Header=BB0_4 Depth=1
 ; CHECK-NEXT:    andi $s7, $s7, 255
+; CHECK-NEXT:    ori $s5, $zero, 50
 ; CHECK-NEXT:    bltu $s5, $s7, .LBB0_15
 ; CHECK-NEXT:  # %bb.10: # %if.end.i
 ; CHECK-NEXT:    # in Loop: Header=BB0_4 Depth=1
@@ -113,8 +113,8 @@ define void @jr_without_ra(ptr %rtwdev, ptr %chan, ptr %h2c, i8 %.pre, i1 %cmp.i
 ; CHECK-NEXT:    # in Loop: Header=BB0_4 Depth=1
 ; CHECK-NEXT:    pcalau12i $ra, %pc_hi20(.LJTI0_1)
 ; CHECK-NEXT:    addi.d $ra, $ra, %pc_lo12(.LJTI0_1)
-; CHECK-NEXT:    ldx.d $ra, $s4, $ra
-; CHECK-NEXT:    ret
+; CHECK-NEXT:    ldx.d $s5, $s4, $ra
+; CHECK-NEXT:    jr $s5
 ; CHECK-NEXT:  .LBB0_13: # %phy_tssi_get_ofdm_trim_de.exit
 ; CHECK-NEXT:    # in Loop: Header=BB0_4 Depth=1
 ; CHECK-NEXT:    bnez $s3, .LBB0_1

@wangleiat wangleiat requested a review from SixWeining November 8, 2024 06:08
Created using spr 1.3.5-bogner

[skip ci]
Created using spr 1.3.5-bogner
@wangleiat wangleiat changed the base branch from users/wangleiat/spr/main.loongarch-avoid-indirect-branch-jumps-using-the-ra-register to main November 11, 2024 06:15
@wangleiat wangleiat merged commit 21ef17c into main Nov 11, 2024
3 of 7 checks passed
@wangleiat wangleiat deleted the users/wangleiat/spr/loongarch-avoid-indirect-branch-jumps-using-the-ra-register branch November 11, 2024 06:15
Groverkss pushed a commit to iree-org/llvm-project that referenced this pull request Nov 15, 2024
Micro-architecture unconditionally treats a "jr $ra" as "return from
subroutine", hence doing "jr $ra" would interfere with both subroutine
return prediction and the more general indirect branch prediction.

GCC thread: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110136

Reviewed By: SixWeining

Pull Request: llvm#115424
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants