Index: llvm/lib/Target/RISCV/CMakeLists.txt =================================================================== --- llvm/lib/Target/RISCV/CMakeLists.txt +++ llvm/lib/Target/RISCV/CMakeLists.txt @@ -31,6 +31,7 @@ RISCVRegisterBankInfo.cpp RISCVRegisterInfo.cpp RISCVSubtarget.cpp + RISCVMacroFusion.cpp RISCVTargetMachine.cpp RISCVTargetObjectFile.cpp RISCVTargetTransformInfo.cpp Index: llvm/lib/Target/RISCV/RISCVMacroFusion.h =================================================================== --- /dev/null +++ llvm/lib/Target/RISCV/RISCVMacroFusion.h @@ -0,0 +1,28 @@ +//===- RISCVMacroFusion.h - RISCV Macro Fusion ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file This file contains the RISCV definition of the DAG scheduling mutation +/// to pair instructions back to back. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_RISCV_RISCVMACROFUSION_H +#define LLVM_LIB_TARGET_RISCV_RISCVMACROFUSION_H + +#include "llvm/CodeGen/MachineScheduler.h" + +namespace llvm { + +/// Note that you have to add: +/// DAG.addMutation(createRISCVMacroFusionDAGMutation()); +/// to RISCVPassConfig::createMachineScheduler() to have an effect. +std::unique_ptr createRISCVMacroFusionDAGMutation(); + +} // llvm + +#endif Index: llvm/lib/Target/RISCV/RISCVMacroFusion.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/RISCV/RISCVMacroFusion.cpp @@ -0,0 +1,82 @@ +//===- RISCVMacroFusion.cpp - RISCV Macro Fusion ----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file This file contains the RISCV implementation of the DAG scheduling +/// mutation to pair instructions back to back. +// +//===----------------------------------------------------------------------===// + +#include "RISCVMacroFusion.h" +#include "RISCVSubtarget.h" +#include "llvm/CodeGen/MacroFusion.h" +#include "llvm/CodeGen/TargetInstrInfo.h" + +namespace llvm { + +// Fuse Idiom +static bool isLEAPair(const MachineInstr *FirstMI, + const MachineInstr &SecondMI) { + if (FirstMI->getOpcode() == RISCV::SLLI) { + switch (SecondMI.getOpcode()) { + // LEA + case RISCV::ADD: + return true; + // Indexed Load + case RISCV::LD: + return true; + // Clear Upper Word + case RISCV::SRLI: + return true; + } + } + return false; +} + +// Fuse Load Immediate Idioms +static bool isClearUpWord(const MachineInstr *FirstMI, + const MachineInstr &SecondMI) { + if (FirstMI->getOpcode() == RISCV::LUI) { + switch (SecondMI.getOpcode()) { + case RISCV::ADDI: + return true; + // LUI based Loads + case RISCV::LD: + return true; + } + } + return false; +} + + +/// Check if the instr pair, FirstMI and SecondMI, should be fused +/// together. Given SecondMI, when FirstMI is unspecified, then check if +/// SecondMI may be part of a fused pair at all. +static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, + const TargetSubtargetInfo &TSI, + const MachineInstr *FirstMI, + const MachineInstr &SecondMI) { + const RISCVSubtarget &ST = static_cast(TSI); + + // We're only checking whether Second can be fused at all. + if (FirstMI == nullptr) + return true; + + if (isLEAPair(FirstMI, SecondMI)) + return true; + + if (isClearUpWord(FirstMI, SecondMI)) + return true; + + return false; +} + +std::unique_ptr createRISCVMacroFusionDAGMutation () { + return createMacroFusionDAGMutation(shouldScheduleAdjacent); +} + +} // end namespace llvm Index: llvm/lib/Target/RISCV/RISCVTargetMachine.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVTargetMachine.cpp +++ llvm/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -12,6 +12,7 @@ #include "RISCVTargetMachine.h" #include "RISCV.h" +#include "RISCVMacroFusion.h" #include "RISCVTargetObjectFile.h" #include "RISCVTargetTransformInfo.h" #include "TargetInfo/RISCVTargetInfo.h" @@ -119,7 +120,12 @@ RISCVTargetMachine &getRISCVTargetMachine() const { return getTM(); } - + ScheduleDAGInstrs * + createMachineScheduler(MachineSchedContext *C) const override { + ScheduleDAGMILive *DAG = createGenericSchedLive(C); + DAG->addMutation(createRISCVMacroFusionDAGMutation()); + return DAG; + } void addIRPasses() override; bool addInstSelector() override; bool addIRTranslator() override; Index: llvm/test/CodeGen/RISCV/add-before-shl.ll =================================================================== --- llvm/test/CodeGen/RISCV/add-before-shl.ll +++ llvm/test/CodeGen/RISCV/add-before-shl.ll @@ -30,8 +30,8 @@ define signext i32 @add_large_const(i32 signext %a) nounwind { ; RV32I-LABEL: add_large_const: ; RV32I: # %bb.0: -; RV32I-NEXT: slli a0, a0, 16 ; RV32I-NEXT: lui a1, 65520 +; RV32I-NEXT: slli a0, a0, 16 ; RV32I-NEXT: add a0, a0, a1 ; RV32I-NEXT: srai a0, a0, 16 ; RV32I-NEXT: ret @@ -53,8 +53,8 @@ define signext i32 @add_huge_const(i32 signext %a) nounwind { ; RV32I-LABEL: add_huge_const: ; RV32I: # %bb.0: -; RV32I-NEXT: slli a0, a0, 16 ; RV32I-NEXT: lui a1, 524272 +; RV32I-NEXT: slli a0, a0, 16 ; RV32I-NEXT: add a0, a0, a1 ; RV32I-NEXT: srai a0, a0, 16 ; RV32I-NEXT: ret