-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[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
[LoongArch] Avoid indirect branch jumps using the ra register #115424
Conversation
Created using spr 1.3.5-bogner [skip ci]
Created using spr 1.3.5-bogner
@llvm/pr-subscribers-backend-loongarch Author: wanglei (wangleiat) ChangesMicro-architecture unconditionally treats a "jr $ra" as "return from 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:
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
|
Created using spr 1.3.5-bogner [skip ci]
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
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