[llvm] 98117f1 - [RISCV] MC relaxation for out-of-range conditional branch.

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 3 12:34:08 PST 2023


Author: Craig Topper
Date: 2023-02-03T12:33:44-08:00
New Revision: 98117f1a743cbddefa3dd1c678ce01478fa98454

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

LOG: [RISCV] MC relaxation for out-of-range conditional branch.

If .L1 is not within +-4KiB range,

convert

```
bge a0, a1, .L1
```

to

```
blt a0, a1, 8
j   .L1
```

In this patch, if the symbol is unresolved at assembly time, do not do
this relaxation.

Fix the bug reported in https://bugs.llvm.org/show_bug.cgi?id=47910

Co-authored-by: Hsiangkai Wang

Reviewed By: asb

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

Added: 
    llvm/test/MC/RISCV/long-conditional-jump.s

Modified: 
    llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
    llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
    llvm/lib/Target/RISCV/RISCVInstrInfo.td
    llvm/test/MC/RISCV/fixups-diagnostics.s
    llvm/test/MC/RISCV/rv64-relax-all.s

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
index 56c2a0de5bcd1..22cc65d7184b8 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
@@ -143,6 +143,15 @@ bool RISCVAsmBackend::fixupNeedsRelaxationAdvanced(const MCFixup &Fixup,
                                                    const MCRelaxableFragment *DF,
                                                    const MCAsmLayout &Layout,
                                                    const bool WasForced) const {
+  int64_t Offset = int64_t(Value);
+  unsigned Kind = Fixup.getTargetKind();
+
+  // We only do conditional branch relaxation when the symbol is resolved.
+  // For conditional branch, the immediate must be in the range
+  // [-4096, 4094].
+  if (Kind == RISCV::fixup_riscv_branch)
+    return Resolved && !isInt<13>(Offset);
+
   // Return true if the symbol is actually unresolved.
   // Resolved could be always false when shouldForceRelocation return true.
   // We use !WasForced to indicate that the symbol is unresolved and not forced
@@ -150,8 +159,7 @@ bool RISCVAsmBackend::fixupNeedsRelaxationAdvanced(const MCFixup &Fixup,
   if (!Resolved && !WasForced)
     return true;
 
-  int64_t Offset = int64_t(Value);
-  switch (Fixup.getTargetKind()) {
+  switch (Kind) {
   default:
     return false;
   case RISCV::fixup_riscv_rvc_branch:
@@ -174,12 +182,24 @@ void RISCVAsmBackend::relaxInstruction(MCInst &Inst,
   case RISCV::C_BEQZ:
   case RISCV::C_BNEZ:
   case RISCV::C_J:
-  case RISCV::C_JAL:
+  case RISCV::C_JAL: {
     bool Success = RISCVRVC::uncompress(Res, Inst, STI);
     assert(Success && "Can't uncompress instruction");
     (void)Success;
     break;
   }
+  case RISCV::BEQ:
+  case RISCV::BNE:
+  case RISCV::BLT:
+  case RISCV::BGE:
+  case RISCV::BLTU:
+  case RISCV::BGEU:
+    Res.setOpcode(getRelaxedOpcode(Inst.getOpcode()));
+    Res.addOperand(Inst.getOperand(0));
+    Res.addOperand(Inst.getOperand(1));
+    Res.addOperand(Inst.getOperand(2));
+    break;
+  }
   Inst = std::move(Res);
 }
 
@@ -321,6 +341,18 @@ unsigned RISCVAsmBackend::getRelaxedOpcode(unsigned Op) const {
   case RISCV::C_J:
   case RISCV::C_JAL: // fall through.
     return RISCV::JAL;
+  case RISCV::BEQ:
+    return RISCV::PseudoLongBEQ;
+  case RISCV::BNE:
+    return RISCV::PseudoLongBNE;
+  case RISCV::BLT:
+    return RISCV::PseudoLongBLT;
+  case RISCV::BGE:
+    return RISCV::PseudoLongBGE;
+  case RISCV::BLTU:
+    return RISCV::PseudoLongBLTU;
+  case RISCV::BGEU:
+    return RISCV::PseudoLongBGEU;
   }
 }
 

diff  --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
index 9f5561bfd2aee..c01f3aae447d9 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
@@ -61,6 +61,10 @@ class RISCVMCCodeEmitter : public MCCodeEmitter {
                       SmallVectorImpl<MCFixup> &Fixups,
                       const MCSubtargetInfo &STI) const;
 
+  void expandLongCondBr(const MCInst &MI, raw_ostream &OS,
+                        SmallVectorImpl<MCFixup> &Fixups,
+                        const MCSubtargetInfo &STI) const;
+
   /// TableGen'erated function for getting the binary encoding for an
   /// instruction.
   uint64_t getBinaryCodeForInstr(const MCInst &MI,
@@ -179,6 +183,81 @@ void RISCVMCCodeEmitter::expandAddTPRel(const MCInst &MI, raw_ostream &OS,
   support::endian::write(OS, Binary, support::little);
 }
 
+static unsigned getInvertedBranchOp(unsigned BrOp) {
+  switch (BrOp) {
+  default:
+    llvm_unreachable("Unexpected branch opcode!");
+  case RISCV::PseudoLongBEQ:
+    return RISCV::BNE;
+  case RISCV::PseudoLongBNE:
+    return RISCV::BEQ;
+  case RISCV::PseudoLongBLT:
+    return RISCV::BGE;
+  case RISCV::PseudoLongBGE:
+    return RISCV::BLT;
+  case RISCV::PseudoLongBLTU:
+    return RISCV::BGEU;
+  case RISCV::PseudoLongBGEU:
+    return RISCV::BLTU;
+  }
+}
+
+// Expand PseudoLongBxx to an inverted conditional branch and an unconditional
+// jump.
+void RISCVMCCodeEmitter::expandLongCondBr(const MCInst &MI, raw_ostream &OS,
+                                          SmallVectorImpl<MCFixup> &Fixups,
+                                          const MCSubtargetInfo &STI) const {
+  MCRegister SrcReg1 = MI.getOperand(0).getReg();
+  MCRegister SrcReg2 = MI.getOperand(1).getReg();
+  MCOperand SrcSymbol = MI.getOperand(2);
+  unsigned Opcode = MI.getOpcode();
+  bool IsEqTest =
+      Opcode == RISCV::PseudoLongBNE || Opcode == RISCV::PseudoLongBEQ;
+
+  bool UseCompressedBr = false;
+  if (IsEqTest && (STI.getFeatureBits()[RISCV::FeatureStdExtC] ||
+                   STI.getFeatureBits()[RISCV::FeatureExtZca])) {
+    if (RISCV::X8 <= SrcReg1.id() && SrcReg1.id() <= RISCV::X15 &&
+        SrcReg2.id() == RISCV::X0) {
+      UseCompressedBr = true;
+    } else if (RISCV::X8 <= SrcReg2.id() && SrcReg2.id() <= RISCV::X15 &&
+               SrcReg1.id() == RISCV::X0) {
+      std::swap(SrcReg1, SrcReg2);
+      UseCompressedBr = true;
+    }
+  }
+
+  uint32_t Offset;
+  if (UseCompressedBr) {
+    unsigned InvOpc =
+        Opcode == RISCV::PseudoLongBNE ? RISCV::C_BEQZ : RISCV::C_BNEZ;
+    MCInst TmpInst = MCInstBuilder(InvOpc).addReg(SrcReg1).addImm(6);
+    uint16_t Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI);
+    support::endian::write<uint16_t>(OS, Binary, support::little);
+    Offset = 2;
+  } else {
+    unsigned InvOpc = getInvertedBranchOp(Opcode);
+    MCInst TmpInst =
+        MCInstBuilder(InvOpc).addReg(SrcReg1).addReg(SrcReg2).addImm(8);
+    uint32_t Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI);
+    support::endian::write(OS, Binary, support::little);
+    Offset = 4;
+  }
+
+  // Emit an unconditional jump to the destination.
+  MCInst TmpInst =
+      MCInstBuilder(RISCV::JAL).addReg(RISCV::X0).addOperand(SrcSymbol);
+  uint32_t Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI);
+  support::endian::write(OS, Binary, support::little);
+
+  Fixups.clear();
+  if (SrcSymbol.isExpr()) {
+    Fixups.push_back(MCFixup::create(Offset, SrcSymbol.getExpr(),
+                                     MCFixupKind(RISCV::fixup_riscv_jal),
+                                     MI.getLoc()));
+  }
+}
+
 void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
                                            SmallVectorImpl<MCFixup> &Fixups,
                                            const MCSubtargetInfo &STI) const {
@@ -203,6 +282,15 @@ void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
     expandAddTPRel(MI, OS, Fixups, STI);
     MCNumEmitted += 1;
     return;
+  case RISCV::PseudoLongBEQ:
+  case RISCV::PseudoLongBNE:
+  case RISCV::PseudoLongBLT:
+  case RISCV::PseudoLongBGE:
+  case RISCV::PseudoLongBLTU:
+  case RISCV::PseudoLongBGEU:
+    expandLongCondBr(MI, OS, Fixups, STI);
+    MCNumEmitted += 2;
+    return;
   }
 
   switch (Size) {

diff  --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index fb313b935ff9c..81c25373352f9 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -1469,6 +1469,26 @@ let Predicates = [HasStdExtC, OptForMinSize] in {
   def : BrccCompessOpt<SETNE, BNE>;
 }
 
+class LongBccPseudo : Pseudo<(outs),
+                             (ins GPR:$rs1, GPR:$rs2, simm21_lsb0_jal:$imm20),
+                             []> {
+  let Size = 8;
+  let isBarrier = 1;
+  let isBranch = 1;
+  let hasSideEffects = 0;
+  let mayStore = 0;
+  let mayLoad = 0;
+  let isAsmParserOnly = 1;
+  let hasNoSchedulingInfo = 1;
+}
+
+def PseudoLongBEQ : LongBccPseudo;
+def PseudoLongBNE : LongBccPseudo;
+def PseudoLongBLT : LongBccPseudo;
+def PseudoLongBGE : LongBccPseudo;
+def PseudoLongBLTU : LongBccPseudo;
+def PseudoLongBGEU : LongBccPseudo;
+
 let isBarrier = 1, isBranch = 1, isTerminator = 1 in
 def PseudoBR : Pseudo<(outs), (ins simm21_lsb0_jal:$imm20), [(br bb:$imm20)]>,
                PseudoInstExpansion<(JAL X0, simm21_lsb0_jal:$imm20)>;

diff  --git a/llvm/test/MC/RISCV/fixups-diagnostics.s b/llvm/test/MC/RISCV/fixups-diagnostics.s
index d346605221c75..3c99673b81fc2 100644
--- a/llvm/test/MC/RISCV/fixups-diagnostics.s
+++ b/llvm/test/MC/RISCV/fixups-diagnostics.s
@@ -3,7 +3,6 @@
   jal a0, far_distant # CHECK: :[[@LINE]]:3: error: fixup value out of range
   jal a0, unaligned # CHECK: :[[@LINE]]:3: error: fixup value must be 2-byte aligned
 
-  beq a0, a1, distant # CHECK: :[[@LINE]]:3: error: fixup value out of range
   blt t0, t1, unaligned # CHECK: :[[@LINE]]:3: error: fixup value must be 2-byte aligned
 
   .byte 0
@@ -12,7 +11,5 @@ unaligned:
   .byte 0
   .byte 0
 
-  .space 1<<12
-distant:
   .space 1<<20
 far_distant:

diff  --git a/llvm/test/MC/RISCV/long-conditional-jump.s b/llvm/test/MC/RISCV/long-conditional-jump.s
new file mode 100644
index 0000000000000..27d3d105838d3
--- /dev/null
+++ b/llvm/test/MC/RISCV/long-conditional-jump.s
@@ -0,0 +1,93 @@
+# RUN: llvm-mc -filetype=obj -triple=riscv64 %s \
+# RUN:     | llvm-objdump -d -M no-aliases - \
+# RUN:     | FileCheck --check-prefix=CHECK-INST %s
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c %s \
+# RUN:     | llvm-objdump -d -M no-aliases - \
+# RUN:     | FileCheck --check-prefix=CHECK-INST-C %s
+
+       .text
+       .p2align        3
+       .type   test, at function
+test:
+# CHECK-INST:         beq     a0, a1, 0x8
+# CHECK-INST-NEXT:    jal     zero, 0x1458
+# CHECK-INST-C:       beq     a0, a1, 0x8
+# CHECK-INST-C-NEXT:  jal     zero, 0x1458
+   bne a0, a1, .L1
+.fill 1300, 4, 0
+.L1:
+   ret
+# CHECK-INST:         bne     a0, a1, 0x1464
+# CHECK-INST-NEXT:    jal     zero, 0x28b4
+# CHECK-INST-C:       bne     a0, a1, 0x1462
+# CHECK-INST-C-NEXT:  jal     zero, 0x28b2
+   beq a0, a1, .L2
+.fill 1300, 4, 0
+.L2:
+   ret
+# CHECK-INST:         bge     a0, a1, 0x28c0
+# CHECK-INST-NEXT:    jal     zero, 0x3d10
+# CHECK-INST-C:       bge     a0, a1, 0x28bc
+# CHECK-INST-C-NEXT:  jal     zero, 0x3d0c
+   blt a0, a1, .L3
+.fill 1300, 4, 0
+.L3:
+   ret
+# CHECK-INST:         blt     a0, a1, 0x3d1c
+# CHECK-INST-NEXT:    jal     zero, 0x516c
+# CHECK-INST-C:       blt     a0, a1, 0x3d16
+# CHECK-INST-C-NEXT:  jal     zero, 0x5166
+   bge a0, a1, .L4
+.fill 1300, 4, 0
+.L4:
+   ret
+# CHECK-INST:         bgeu    a0, a1, 0x5178
+# CHECK-INST-NEXT:    jal     zero, 0x65c8
+# CHECK-INST-C:       bgeu    a0, a1, 0x5170
+# CHECK-INST-C-NEXT:  jal     zero, 0x65c0
+   bltu a0, a1, .L5
+.fill 1300, 4, 0
+.L5:
+   ret
+# CHECK-INST:         bltu    a0, a1, 0x65d4
+# CHECK-INST-NEXT:    jal     zero, 0x7a24
+# CHECK-INST-C:       bltu    a0, a1, 0x65ca
+# CHECK-INST-C-NEXT:  jal     zero, 0x7a1a
+   bgeu a0, a1, .L6
+.fill 1300, 4, 0
+.L6:
+   ret
+# CHECK-INST:         bne     a0, zero, 0x7a30
+# CHECK-INST-NEXT:    jal     zero, 0x8e80
+# CHECK-INST-C:       c.bnez  a0, 0x7a22
+# CHECK-INST-C-NEXT:  jal     zero, 0x8e72
+   beqz a0, .L7
+.fill 1300, 4, 0
+.L7:
+   ret
+# CHECK-INST:         bne     zero, a0, 0x8e8c
+# CHECK-INST-NEXT:    jal     zero, 0xa2dc
+# CHECK-INST-C:       c.bnez  a0, 0x8e7a
+# CHECK-INST-C-NEXT:  jal     zero, 0xa2ca
+   beq x0, a0, .L8
+.fill 1300, 4, 0
+.L8:
+   ret
+# CHECK-INST:         beq     a0, zero, 0xa2e8
+# CHECK-INST-NEXT:    jal     zero, 0xb738
+# CHECK-INST-C:       c.beqz  a0, 0xa2d2
+# CHECK-INST-C-NEXT:  jal     zero, 0xb722
+   bnez a0, .L9
+.fill 1300, 4, 0
+.L9:
+   ret
+# CHECK-INST:         beq     a6, zero, 0xb744
+# CHECK-INST-NEXT:    jal     zero, 0xcb94
+# CHECK-INST-C:       beq     a6, zero, 0xb72c
+# CHECK-INST-C-NEXT:  jal     zero, 0xcb7c
+   bnez x16, .L10
+.fill 1300, 4, 0
+.L10:
+   ret
+.Lfunc_end0:
+       .size   test, .Lfunc_end0-test

diff  --git a/llvm/test/MC/RISCV/rv64-relax-all.s b/llvm/test/MC/RISCV/rv64-relax-all.s
index 84ef373b741b4..70a3f77540c99 100644
--- a/llvm/test/MC/RISCV/rv64-relax-all.s
+++ b/llvm/test/MC/RISCV/rv64-relax-all.s
@@ -7,7 +7,8 @@
 NEAR:
 
 # INSTR:           c.beqz    a0, 0x0 <NEAR>
-# RELAX-INSTR:     beq    a0, zero, 0x0 <NEAR>
+# RELAX-INSTR:     c.bnez    a0, 0x6
+# RELAX-INSTR-NEXT:jal       zero, 0x0 <NEAR>
 c.beqz a0, NEAR
 
 # INSTR:           c.j    0x0 <NEAR>


        


More information about the llvm-commits mailing list