diff --git a/llvm/lib/Target/RISCV/RISCV.h b/llvm/lib/Target/RISCV/RISCV.h --- a/llvm/lib/Target/RISCV/RISCV.h +++ b/llvm/lib/Target/RISCV/RISCV.h @@ -46,6 +46,9 @@ FunctionPass *createRISCVMergeBaseOffsetOptPass(); void initializeRISCVMergeBaseOffsetOptPass(PassRegistry &); +FunctionPass *createRISCVPostRAMergeBaseOffsetPass(); +void initializeRISCVPostRAMergeBaseOffsetPass(PassRegistry &); + FunctionPass *createRISCVExpandPseudoPass(); void initializeRISCVExpandPseudoPass(PassRegistry &); diff --git a/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp b/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp --- a/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp +++ b/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp @@ -291,3 +291,101 @@ FunctionPass *llvm::createRISCVMergeBaseOffsetOptPass() { return new RISCVMergeBaseOffsetOpt(); } + +#define RISCV_POSTRA_MERGE_BASE_OFFSET_NAME "RISCV Post-RA Merge Base Offset" + +namespace { +struct RISCVPostRAMergeBaseOffset : public MachineFunctionPass { + static char ID; + bool runOnMachineFunction(MachineFunction &Fn) override; + bool detectAndFoldOffset(MachineInstr &AddrHi, MachineInstr &AddrLo, + MachineInstr &Mem); + RISCVPostRAMergeBaseOffset() : MachineFunctionPass(ID) {} + + StringRef getPassName() const override { + return RISCV_POSTRA_MERGE_BASE_OFFSET_NAME; + } + +private: + MachineRegisterInfo *MRI; + std::set DeadInstrs; +}; +} // end anonymous namespace + +bool RISCVPostRAMergeBaseOffset::runOnMachineFunction(MachineFunction &Fn) { + if (skipFunction(Fn.getFunction())) + return false; + + bool MadeChange = false; + DeadInstrs.clear(); + MRI = &Fn.getRegInfo(); + for (MachineBasicBlock &MBB : Fn) { + if (MBB.size() < 3) + continue; + MachineBasicBlock::instr_iterator MII = MBB.instr_begin(); + MachineBasicBlock::instr_iterator MIE = MBB.instr_end(); + MachineInstr *AddrHi = &*MII++; + MachineInstr *AddrLo = &*MII++; + do { + MachineInstr *Mem = &*MII++; + MadeChange |= detectAndFoldOffset(*AddrHi, *AddrLo, *Mem); + AddrHi = AddrLo; + AddrLo = Mem; + } while (MII != MIE); + } + // Delete dead instructions. + for (auto *MI : DeadInstrs) + MI->eraseFromParent(); + return MadeChange; +} + +bool RISCVPostRAMergeBaseOffset::detectAndFoldOffset(MachineInstr &AddrHi, + MachineInstr &AddrLo, + MachineInstr &Mem) { + if (AddrHi.getOpcode() != RISCV::AUIPC || + AddrHi.getOperand(1).getTargetFlags() != RISCVII::MO_PCREL_HI || + AddrHi.getOperand(1).getType() != MachineOperand::MO_GlobalAddress || + AddrHi.getOperand(1).getOffset() != 0) + return false; + + if (AddrLo.getOpcode() != RISCV::ADDI || + AddrLo.getOperand(1).getReg() != AddrHi.getOperand(0).getReg() || + AddrLo.getOperand(2).getTargetFlags() != RISCVII::MO_PCREL_LO || + AddrLo.getOperand(2).getType() != MachineOperand::MO_MachineBasicBlock) + return false; + + switch (Mem.getOpcode()) { + default: + return false; + case RISCV::LB: + case RISCV::LH: + case RISCV::LW: + case RISCV::LBU: + case RISCV::LHU: + case RISCV::LWU: + case RISCV::LD: + case RISCV::FLH: + case RISCV::FLW: + case RISCV::FLD:; + } + + if (Mem.getOperand(0).getReg() != AddrLo.getOperand(0).getReg() || + Mem.getOperand(1).getReg() != AddrHi.getOperand(0).getReg() || + Mem.getOperand(2).getType() != MachineOperand::MO_Immediate || + Mem.getOperand(2).getImm() != 0) + return false; + + Mem.removeOperand(2); + Mem.addOperand(AddrLo.getOperand(2)); + DeadInstrs.insert(&AddrLo); + return true; +} + +char RISCVPostRAMergeBaseOffset::ID = 0; +INITIALIZE_PASS(RISCVPostRAMergeBaseOffset, "riscv-postra-merge-base-offset", + RISCV_POSTRA_MERGE_BASE_OFFSET_NAME, false, false) + +/// Returns an instance of the Post-RA Merge Base Offset Optimization pass. +FunctionPass *llvm::createRISCVPostRAMergeBaseOffsetPass() { + return new RISCVPostRAMergeBaseOffset(); +} diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp --- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp +++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -196,6 +196,8 @@ void RISCVPassConfig::addPreEmitPass2() { addPass(createRISCVExpandPseudoPass()); + if (TM->getOptLevel() != CodeGenOpt::None) + addPass(createRISCVPostRAMergeBaseOffsetPass()); // Schedule the expansion of AMOs at the last possible moment, avoiding the // possibility for other passes to break the requirements for forward // progress in the LR/SC block. diff --git a/llvm/test/CodeGen/RISCV/O3-pipeline.ll b/llvm/test/CodeGen/RISCV/O3-pipeline.ll --- a/llvm/test/CodeGen/RISCV/O3-pipeline.ll +++ b/llvm/test/CodeGen/RISCV/O3-pipeline.ll @@ -152,6 +152,7 @@ ; CHECK-NEXT: StackMap Liveness Analysis ; CHECK-NEXT: Live DEBUG_VALUE analysis ; CHECK-NEXT: RISCV pseudo instruction expansion pass +; CHECK-NEXT: RISCV Post-RA Merge Base Offset ; CHECK-NEXT: RISCV atomic pseudo instruction expansion pass ; CHECK-NEXT: Lazy Machine Block Frequency Analysis ; CHECK-NEXT: Machine Optimization Remark Emitter diff --git a/llvm/test/CodeGen/RISCV/codemodel-lowering.ll b/llvm/test/CodeGen/RISCV/codemodel-lowering.ll --- a/llvm/test/CodeGen/RISCV/codemodel-lowering.ll +++ b/llvm/test/CodeGen/RISCV/codemodel-lowering.ll @@ -18,8 +18,7 @@ ; RV32I-MEDIUM: # %bb.0: ; RV32I-MEDIUM-NEXT: .LBB0_1: # Label of block must be emitted ; RV32I-MEDIUM-NEXT: auipc a0, %pcrel_hi(G) -; RV32I-MEDIUM-NEXT: addi a0, a0, %pcrel_lo(.LBB0_1) -; RV32I-MEDIUM-NEXT: lw a0, 0(a0) +; RV32I-MEDIUM-NEXT: lw a0, %pcrel_lo(.LBB0_1)(a0) ; RV32I-MEDIUM-NEXT: ret %1 = load volatile i32, i32* @G ret i32 %1