diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp index 10a26554ed67..ac0f7421664c 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -198,6 +198,30 @@ static unsigned getRelaxedOpcode(unsigned Op) { return RISCV::PseudoLongBLTU; case RISCV::BGEU: return RISCV::PseudoLongBGEU; + case RISCV::QC_BEQI: + return RISCV::PseudoLongQC_BEQI; + case RISCV::QC_BNEI: + return RISCV::PseudoLongQC_BNEI; + case RISCV::QC_BLTI: + return RISCV::PseudoLongQC_BLTI; + case RISCV::QC_BGEI: + return RISCV::PseudoLongQC_BGEI; + case RISCV::QC_BLTUI: + return RISCV::PseudoLongQC_BLTUI; + case RISCV::QC_BGEUI: + return RISCV::PseudoLongQC_BGEUI; + case RISCV::QC_E_BEQI: + return RISCV::PseudoLongQC_E_BEQI; + case RISCV::QC_E_BNEI: + return RISCV::PseudoLongQC_E_BNEI; + case RISCV::QC_E_BLTI: + return RISCV::PseudoLongQC_E_BLTI; + case RISCV::QC_E_BGEI: + return RISCV::PseudoLongQC_E_BGEI; + case RISCV::QC_E_BLTUI: + return RISCV::PseudoLongQC_E_BLTUI; + case RISCV::QC_E_BGEUI: + return RISCV::PseudoLongQC_E_BGEUI; } } @@ -224,6 +248,18 @@ void RISCVAsmBackend::relaxInstruction(MCInst &Inst, case RISCV::BGE: case RISCV::BLTU: case RISCV::BGEU: + case RISCV::QC_BEQI: + case RISCV::QC_BNEI: + case RISCV::QC_BLTI: + case RISCV::QC_BGEI: + case RISCV::QC_BLTUI: + case RISCV::QC_BGEUI: + case RISCV::QC_E_BEQI: + case RISCV::QC_E_BNEI: + case RISCV::QC_E_BLTI: + case RISCV::QC_E_BGEI: + case RISCV::QC_E_BLTUI: + case RISCV::QC_E_BGEUI: Res.setOpcode(getRelaxedOpcode(Inst.getOpcode())); Res.addOperand(Inst.getOperand(0)); Res.addOperand(Inst.getOperand(1)); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp index fc9885931468..37a2ac336d20 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -68,6 +68,10 @@ public: SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + void expandQCLongCondBrImm(const MCInst &MI, SmallVectorImpl &CB, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI, unsigned Size) const; + /// TableGen'erated function for getting the binary encoding for an /// instruction. uint64_t getBinaryCodeForInstr(const MCInst &MI, @@ -240,6 +244,30 @@ static unsigned getInvertedBranchOp(unsigned BrOp) { return RISCV::BGEU; case RISCV::PseudoLongBGEU: return RISCV::BLTU; + case RISCV::PseudoLongQC_BEQI: + return RISCV::QC_BNEI; + case RISCV::PseudoLongQC_BNEI: + return RISCV::QC_BEQI; + case RISCV::PseudoLongQC_BLTI: + return RISCV::QC_BGEI; + case RISCV::PseudoLongQC_BGEI: + return RISCV::QC_BLTI; + case RISCV::PseudoLongQC_BLTUI: + return RISCV::QC_BGEUI; + case RISCV::PseudoLongQC_BGEUI: + return RISCV::QC_BLTUI; + case RISCV::PseudoLongQC_E_BEQI: + return RISCV::QC_E_BNEI; + case RISCV::PseudoLongQC_E_BNEI: + return RISCV::QC_E_BEQI; + case RISCV::PseudoLongQC_E_BLTI: + return RISCV::QC_E_BGEI; + case RISCV::PseudoLongQC_E_BGEI: + return RISCV::QC_E_BLTI; + case RISCV::PseudoLongQC_E_BLTUI: + return RISCV::QC_E_BGEUI; + case RISCV::PseudoLongQC_E_BGEUI: + return RISCV::QC_E_BLTUI; } } @@ -305,6 +333,57 @@ void RISCVMCCodeEmitter::expandLongCondBr(const MCInst &MI, } } +// Expand PseudoLongQC_(E_)Bxxx to an inverted conditional branch and an +// unconditional jump. +void RISCVMCCodeEmitter::expandQCLongCondBrImm(const MCInst &MI, + SmallVectorImpl &CB, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI, + unsigned Size) const { + MCRegister SrcReg1 = MI.getOperand(0).getReg(); + auto BrImm = MI.getOperand(1).getImm(); + MCOperand SrcSymbol = MI.getOperand(2); + unsigned Opcode = MI.getOpcode(); + uint32_t Offset; + unsigned InvOpc = getInvertedBranchOp(Opcode); + // Emit inverted conditional branch with offset: + // 8 (QC.BXXX(4) + JAL(4)) + // or + // 10 (QC.E.BXXX(6) + JAL(4)). + if (Size == 4) { + MCInst TmpBr = + MCInstBuilder(InvOpc).addReg(SrcReg1).addImm(BrImm).addImm(8); + uint32_t BrBinary = getBinaryCodeForInstr(TmpBr, Fixups, STI); + support::endian::write(CB, BrBinary, llvm::endianness::little); + } else { + MCInst TmpBr = + MCInstBuilder(InvOpc).addReg(SrcReg1).addImm(BrImm).addImm(10); + uint64_t BrBinary = + getBinaryCodeForInstr(TmpBr, Fixups, STI) & 0xffff'ffff'ffffu; + SmallVector Encoding; + support::endian::write(Encoding, BrBinary, llvm::endianness::little); + assert(Encoding[6] == 0 && Encoding[7] == 0 && + "Unexpected encoding for 48-bit instruction"); + Encoding.truncate(6); + CB.append(Encoding); + } + Offset = Size; + // Save the number fixups. + size_t FixupStartIndex = Fixups.size(); + // Emit an unconditional jump to the destination. + MCInst TmpJ = + MCInstBuilder(RISCV::JAL).addReg(RISCV::X0).addOperand(SrcSymbol); + uint32_t JBinary = getBinaryCodeForInstr(TmpJ, Fixups, STI); + support::endian::write(CB, JBinary, llvm::endianness::little); + // Drop any fixup added so we can add the correct one. + Fixups.resize(FixupStartIndex); + if (SrcSymbol.isExpr()) { + Fixups.push_back(MCFixup::create(Offset, SrcSymbol.getExpr(), + MCFixupKind(RISCV::fixup_riscv_jal), + MI.getLoc())); + } +} + void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, SmallVectorImpl &CB, SmallVectorImpl &Fixups, @@ -339,6 +418,24 @@ void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, expandLongCondBr(MI, CB, Fixups, STI); MCNumEmitted += 2; return; + case RISCV::PseudoLongQC_BEQI: + case RISCV::PseudoLongQC_BNEI: + case RISCV::PseudoLongQC_BLTI: + case RISCV::PseudoLongQC_BGEI: + case RISCV::PseudoLongQC_BLTUI: + case RISCV::PseudoLongQC_BGEUI: + expandQCLongCondBrImm(MI, CB, Fixups, STI, 4); + MCNumEmitted += 2; + return; + case RISCV::PseudoLongQC_E_BEQI: + case RISCV::PseudoLongQC_E_BNEI: + case RISCV::PseudoLongQC_E_BLTI: + case RISCV::PseudoLongQC_E_BGEI: + case RISCV::PseudoLongQC_E_BLTUI: + case RISCV::PseudoLongQC_E_BGEUI: + expandQCLongCondBrImm(MI, CB, Fixups, STI, 6); + MCNumEmitted += 2; + return; case RISCV::PseudoTLSDESCCall: expandTLSDESCCall(MI, CB, Fixups, STI); MCNumEmitted += 1; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td index 64d6f6d8f8bb..f762c4943f63 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td @@ -1152,6 +1152,39 @@ let EmitPriority = 0 in { } // EmitPriority = 0 } // Predicates = [HasVendorXqcilo, IsRV32] +//===----------------------------------------------------------------------===// +// Pseudo-instructions +//===----------------------------------------------------------------------===// + +class LongBcciPseudo + : Pseudo<(outs), (ins GPR:$rs1, InTyImm:$imm, simm21_lsb0_jal:$imm20), []> +{ + let Size = size; + let isBarrier = 1; + let isBranch = 1; + let hasSideEffects = 0; + let mayStore = 0; + let mayLoad = 0; + let isAsmParserOnly = 1; + let hasNoSchedulingInfo = 1; +} + +// This will be expanded into either: +// QC.BXXX(4 bytes) + JAL(4 bytes) +// or +// QC.E.BXXX(6 bytes) + JAL(4 bytes) +def PseudoLongQC_BEQI : LongBcciPseudo; +def PseudoLongQC_BNEI : LongBcciPseudo; +def PseudoLongQC_BLTI : LongBcciPseudo; +def PseudoLongQC_BGEI : LongBcciPseudo; +def PseudoLongQC_BLTUI : LongBcciPseudo; +def PseudoLongQC_BGEUI : LongBcciPseudo; +def PseudoLongQC_E_BEQI : LongBcciPseudo; +def PseudoLongQC_E_BNEI : LongBcciPseudo; +def PseudoLongQC_E_BLTI : LongBcciPseudo; +def PseudoLongQC_E_BGEI : LongBcciPseudo; +def PseudoLongQC_E_BLTUI : LongBcciPseudo; +def PseudoLongQC_E_BGEUI : LongBcciPseudo; //===----------------------------------------------------------------------===// // Code Gen Patterns diff --git a/llvm/test/MC/RISCV/xqcibi-long-conditional-jump.s b/llvm/test/MC/RISCV/xqcibi-long-conditional-jump.s new file mode 100644 index 000000000000..788fddaa9446 --- /dev/null +++ b/llvm/test/MC/RISCV/xqcibi-long-conditional-jump.s @@ -0,0 +1,134 @@ +# RUN: llvm-mc -filetype=obj --mattr=+experimental-xqcibi -triple=riscv32 %s \ +# RUN: | llvm-objdump --mattr=+experimental-xqcibi -d -M no-aliases - \ +# RUN: | FileCheck --check-prefix=CHECK-INST %s +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax,+experimental-xqcibi %s \ +# RUN: | llvm-objdump --mattr=+experimental-xqcibi -dr -M no-aliases - \ +# RUN: | FileCheck --check-prefix=CHECK-INST-RELAX %s + + .text + .type test,@function + +test: + +# CHECK-INST: qc.beqi a0, 0xa, 0x8 +# CHECK-INST-NEXT: jal zero, 0x1458 +# CHECK-INST-RELAX: qc.beqi a0, 0xa, 0x8 +# CHECK-INST-RELAX-NEXT: jal zero, {{.*}} +# CHECK-INST-RELAX-NEXT: R_RISCV_JAL .L1 + qc.bnei a0, 10, .L1 +.fill 1300, 4, 0 +.L1: + ret + +# CHECK-INST: qc.bnei a0, 0x6, 0x1462 +# CHECK-INST-NEXT: jal zero, 0x28b2 +# CHECK-INST-RELAX: qc.bnei a0, 0x6, 0x1462 +# CHECK-INST-RELAX-NEXT: jal zero, {{.*}} +# CHECK-INST-RELAX-NEXT: R_RISCV_JAL .L2 + qc.beqi a0, 6, .L2 +.fill 1300, 4, 0 +.L2: + ret + +# CHECK-INST: qc.bgei a0, 0xd, 0x28bc +# CHECK-INST-NEXT: jal zero, 0x3d0c +# CHECK-INST-RELAX: qc.bgei a0, 0xd, 0x28bc +# CHECK-INST-RELAX-NEXT: jal zero, {{.*}} +# CHECK-INST-RELAX-NEXT: R_RISCV_JAL .L3 + qc.blti a0, 13, .L3 +.fill 1300, 4, 0 +.L3: + ret + +# CHECK-INST: qc.blti a0, 0x1, 0x3d16 +# CHECK-INST-NEXT: jal zero, 0x5166 +# CHECK-INST-RELAX: qc.blti a0, 0x1, 0x3d16 +# CHECK-INST-RELAX-NEXT: jal zero, {{.*}} +# CHECK-INST-RELAX-NEXT: R_RISCV_JAL .L4 + qc.bgei a0, 1, .L4 +.fill 1300, 4, 0 +.L4: + ret + +# CHECK-INST: qc.bgeui a0, 0x5, 0x5170 +# CHECK-INST-NEXT: jal zero, 0x65c0 +# CHECK-INST-RELAX: qc.bgeui a0, 0x5, 0x5170 +# CHECK-INST-RELAX-NEXT: jal zero, {{.*}} +# CHECK-INST-RELAX-NEXT: R_RISCV_JAL .L5 + qc.bltui a0, 5, .L5 +.fill 1300, 4, 0 +.L5: + ret + +# CHECK-INST: qc.bltui a0, 0xc, 0x65ca +# CHECK-INST-NEXT: jal zero, 0x7a1a +# CHECK-INST-RELAX: qc.bltui a0, 0xc, 0x65ca +# CHECK-INST-RELAX-NEXT: jal zero, {{.*}} +# CHECK-INST-RELAX-NEXT: R_RISCV_JAL .L6 + qc.bgeui a0, 12, .L6 +.fill 1300, 4, 0 +.L6: + ret + +# CHECK-INST: qc.e.beqi a0, 0x1, 0x7a26 +# CHECK-INST-NEXT: jal zero, 0x8e76 +# CHECK-INST-RELAX: qc.e.beqi a0, 0x1, 0x7a26 +# CHECK-INST-RELAX-NEXT: jal zero, {{.*}} +# CHECK-INST-RELAX-NEXT: R_RISCV_JAL .L7 + qc.e.bnei a0, 1, .L7 +.fill 1300, 4, 0 +.L7: + ret + +# CHECK-INST: qc.e.bnei a0, 0x2, 0x8e82 +# CHECK-INST-NEXT: jal zero, 0xa2d2 +# CHECK-INST-RELAX: qc.e.bnei a0, 0x2, 0x8e82 +# CHECK-INST-RELAX-NEXT: jal zero, {{.*}} +# CHECK-INST-RELAX-NEXT: R_RISCV_JAL .L8 + qc.e.beqi a0, 2, .L8 +.fill 1300, 4, 0 +.L8: + ret + +# CHECK-INST: qc.e.bgei a0, 0x3, 0xa2de +# CHECK-INST-NEXT: jal zero, 0xb72e +# CHECK-INST-RELAX: qc.e.bgei a0, 0x3, 0xa2de +# CHECK-INST-RELAX-NEXT: jal zero, {{.*}} +# CHECK-INST-RELAX-NEXT: R_RISCV_JAL .L9 + qc.e.blti a0, 3, .L9 +.fill 1300, 4, 0 +.L9: + ret + +# CHECK-INST: qc.e.blti a0, 0x4, 0xb73a +# CHECK-INST-NEXT: jal zero, 0xcb8a +# CHECK-INST-RELAX: qc.e.blti a0, 0x4, 0xb73a +# CHECK-INST-RELAX-NEXT: jal zero, {{.*}} +# CHECK-INST-RELAX-NEXT: R_RISCV_JAL .L10 + qc.e.bgei a0, 4, .L10 +.fill 1300, 4, 0 +.L10: + ret + +# CHECK-INST: qc.e.bgeui a0, 0x5, 0xcb96 +# CHECK-INST-NEXT: jal zero, 0xdfe6 +# CHECK-INST-RELAX: qc.e.bgeui a0, 0x5, 0xcb96 +# CHECK-INST-RELAX-NEXT: jal zero, {{.*}} +# CHECK-INST-RELAX-NEXT: R_RISCV_JAL .L11 + qc.e.bltui a0, 5, .L11 +.fill 1300, 4, 0 +.L11: + ret + +# CHECK-INST: qc.e.bltui a0, 0x6, 0xdff2 +# CHECK-INST-NEXT: jal zero, 0xf442 +# CHECK-INST-RELAX: qc.e.bltui a0, 0x6, 0xdff2 +# CHECK-INST-RELAX-NEXT: jal zero, {{.*}} +# CHECK-INST-RELAX-NEXT: R_RISCV_JAL .L12 + qc.e.bgeui a0, 6, .L12 +.fill 1300, 4, 0 +.L12: + ret + +.Lfunc_end0: + .size test, .Lfunc_end0-test diff --git a/llvm/test/MC/RISCV/xqcibi-relocations.s b/llvm/test/MC/RISCV/xqcibi-relocations.s index 4899e5f1eac4..7028e8a737c8 100644 --- a/llvm/test/MC/RISCV/xqcibi-relocations.s +++ b/llvm/test/MC/RISCV/xqcibi-relocations.s @@ -10,23 +10,22 @@ .text -# Check that branch to an undefined symbol is handled -# FIXME: This should be relaxed to an inverse branch and jump +# Since foo is undefined, this will be relaxed to (qc.beqi + jal) qc.bnei x6, 10, foo -# RELOC: R_RISCV_BRANCH foo 0x0 +# RELOC: R_RISCV_JAL foo 0x0 # INSTR: qc.bnei t1, 10, foo # FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_branch -# FIXME: This should be relaxed to an inverse branch and jump +# Since foo is undefined, this will be relaxed to (qc.e.bltui + jal) qc.e.bgeui x8, 12, foo -# RELOC: R_RISCV_CUSTOM193 foo 0x0 +# RELOC: R_RISCV_JAL foo 0x0 # INSTR: qc.e.bgeui s0, 12, foo # FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_qc_e_branch -# Check that a label in a different section is handled similar to an undefined symbol -# FIXME: This should be relaxed to an inverse branch and jump +# Check that a label in a different section is handled similar to an undefined +# symbol and gets relaxed to (qc.e.bgeui + jal) qc.e.bltui x4, 9, .bar -# RELOC: R_RISCV_CUSTOM193 .bar 0x0 +# RELOC: R_RISCV_JAL .bar 0x0 # INSTR: qc.e.bltui tp, 9, .bar # FIXUP: fixup A - offset: 0, value: .bar, kind: fixup_riscv_qc_e_branch