Index: llvm/test/tools/llvm-reduce/mir/reduce-register-masks.mir =================================================================== --- /dev/null +++ llvm/test/tools/llvm-reduce/mir/reduce-register-masks.mir @@ -0,0 +1,23 @@ +# REQUIRES: amdgpu-registered-target +# RUN: llvm-reduce -abort-on-invalid-reduction -simplify-mir --delta-passes=register-masks -mtriple=amdgcn-amd-amdhsa --test FileCheck --test-arg --check-prefix=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t +# RUN: FileCheck --match-full-lines --check-prefix=RESULT %s < %t + +# CHECK-INTERESTINGNESS: CustomRegMask +# CHECK-INTERESTINGNESS-SAME: $vcc_lo, +# CHECK-INTERESTINGNESS-SAME: $agpr8, +# CHECK-INTERESTINGNESS-SAME: $sgpr99, +# CHECK-INTERESTINGNESS-SAME: $vgpr23, +# CHECK-INTERESTINGNESS-SAME: $vgpr48_vgpr49_vgpr50, + +# RESULT: $sgpr30_sgpr31 = SI_CALL %0, 0, CustomRegMask($vcc_lo,$agpr8,$sgpr99,$vgpr23,$vgpr48_vgpr49_vgpr50,$vgpr49_vgpr50_vgpr51) + +--- +name: func +tracksRegLiveness: true +body: | + bb.0: + liveins: $vgpr0, $vgpr1, $sgpr8_sgpr9 + %0:sreg_64_xexec = COPY $sgpr8_sgpr9 + $sgpr30_sgpr31 = SI_CALL %0:sreg_64_xexec, 0, CustomRegMask($vgpr8_vgpr9, $vgpr9_vgpr10_vgpr11,$vcc_lo,$agpr8,$sgpr99,$vgpr23,$vgpr48_vgpr49_vgpr50,$vgpr49_vgpr50_vgpr51, $vgpr52_vgpr53_vgpr54,$vcc_hi,$sgpr0_sgpr1_sgpr2_sgpr3,$sgpr4_sgpr5_sgpr6_sgpr7) + S_ENDPGM 0 +... Index: llvm/tools/llvm-reduce/CMakeLists.txt =================================================================== --- llvm/tools/llvm-reduce/CMakeLists.txt +++ llvm/tools/llvm-reduce/CMakeLists.txt @@ -43,6 +43,7 @@ deltas/ReduceInstructionFlagsMIR.cpp deltas/ReduceIRReferences.cpp deltas/ReduceVirtualRegisters.cpp + deltas/ReduceRegisterMasks.cpp deltas/ReduceRegisterUses.cpp deltas/SimplifyInstructions.cpp llvm-reduce.cpp Index: llvm/tools/llvm-reduce/DeltaManager.cpp =================================================================== --- llvm/tools/llvm-reduce/DeltaManager.cpp +++ llvm/tools/llvm-reduce/DeltaManager.cpp @@ -35,6 +35,7 @@ #include "deltas/ReduceOperands.h" #include "deltas/ReduceOperandsSkip.h" #include "deltas/ReduceOperandsToArgs.h" +#include "deltas/ReduceRegisterMasks.h" #include "deltas/ReduceRegisterUses.h" #include "deltas/ReduceSpecialGlobals.h" #include "deltas/ReduceVirtualRegisters.h" @@ -81,7 +82,8 @@ DELTA_PASS("ir-function-references", reduceIRFunctionReferencesDeltaPass) \ DELTA_PASS("instruction-flags", reduceInstructionFlagsMIRDeltaPass) \ DELTA_PASS("register-uses", reduceRegisterUsesMIRDeltaPass) \ - DELTA_PASS("register-hints", reduceVirtualRegisterHintsDeltaPass) + DELTA_PASS("register-hints", reduceVirtualRegisterHintsDeltaPass) \ + DELTA_PASS("register-masks", reduceRegisterMasksMIRDeltaPass) static void runAllDeltaPasses(TestRunner &Tester) { #define DELTA_PASS(NAME, FUNC) FUNC(Tester); Index: llvm/tools/llvm-reduce/ReducerWorkItem.cpp =================================================================== --- llvm/tools/llvm-reduce/ReducerWorkItem.cpp +++ llvm/tools/llvm-reduce/ReducerWorkItem.cpp @@ -282,6 +282,12 @@ } } + DenseSet ConstRegisterMasks; + + // Track predefined/named regmasks which we ignore. + for (const uint32_t *Mask : TRI->getRegMasks()) + ConstRegisterMasks.insert(Mask); + // Clone instructions. for (auto &SrcMBB : *SrcMF) { auto *DstMBB = Src2DstMBB[&SrcMBB]; @@ -300,9 +306,18 @@ // Update MBB. if (DstMO.isMBB()) DstMO.setMBB(Src2DstMBB[DstMO.getMBB()]); - else if (DstMO.isRegMask()) + else if (DstMO.isRegMask()) { DstMRI->addPhysRegsUsedFromRegMask(DstMO.getRegMask()); + if (!ConstRegisterMasks.count(DstMO.getRegMask())) { + uint32_t *DstMask = DstMF->allocateRegMask(); + std::memcpy(DstMask, SrcMO.getRegMask(), + sizeof(*DstMask) * + MachineOperand::getRegMaskSize(TRI->getNumRegs())); + DstMO.setRegMask(DstMask); + } + } + DstMI->addOperand(DstMO); } Index: llvm/tools/llvm-reduce/deltas/ReduceRegisterMasks.h =================================================================== --- /dev/null +++ llvm/tools/llvm-reduce/deltas/ReduceRegisterMasks.h @@ -0,0 +1,18 @@ +//===- ReduceRegisterMasks.h - Specialized Delta Pass ----------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEREGISTERMASKS_H +#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEREGISTERMASKS_H + +#include "Delta.h" + +namespace llvm { +void reduceRegisterMasksMIRDeltaPass(TestRunner &Test); +} // namespace llvm + +#endif Index: llvm/tools/llvm-reduce/deltas/ReduceRegisterMasks.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-reduce/deltas/ReduceRegisterMasks.cpp @@ -0,0 +1,73 @@ +//===- ReduceRegisterMasks.cpp - Specialized Delta Pass -------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce custom register masks from the MachineFunction. +// +//===----------------------------------------------------------------------===// + +#include "ReduceRegisterMasks.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" + +using namespace llvm; + +static void reduceMasksInFunction(Oracle &O, MachineFunction &MF) { + DenseSet ConstRegisterMasks; + const auto *TRI = MF.getSubtarget().getRegisterInfo(); + + // Track predefined/named regmasks which we ignore. + const unsigned NumRegs = TRI->getNumRegs(); + for (const uint32_t *Mask : TRI->getRegMasks()) + ConstRegisterMasks.insert(Mask); + + for (MachineBasicBlock &MBB : MF) { + for (MachineInstr &MI : MBB) { + for (MachineOperand &MO : MI.operands()) { + if (!MO.isRegMask()) + continue; + + const uint32_t *OldRegMask = MO.getRegMask(); + // We're only reducing custom reg masks. + if (ConstRegisterMasks.count(OldRegMask)) + continue; + unsigned RegMaskSize = + MachineOperand::getRegMaskSize(TRI->getNumRegs()); + std::vector NewMask(RegMaskSize); + + bool MadeChange = false; + for (unsigned I = 0; I != NumRegs; ++I) { + if (OldRegMask[I / 32] >> I % 32) { + if (O.shouldKeep()) + NewMask[I / 32] |= 1u << (I % 32); + } else + MadeChange = true; + } + + if (MadeChange) { + uint32_t *UpdatedMask = MF.allocateRegMask(); + std::memcpy(UpdatedMask, NewMask.data(), + RegMaskSize * sizeof(*OldRegMask)); + MO.setRegMask(UpdatedMask); + } + } + } + } +} + +static void reduceMasksInModule(Oracle &O, ReducerWorkItem &WorkItem) { + for (const Function &F : WorkItem.getModule()) { + if (auto *MF = WorkItem.MMI->getMachineFunction(F)) + reduceMasksInFunction(O, *MF); + } +} + +void llvm::reduceRegisterMasksMIRDeltaPass(TestRunner &Test) { + outs() << "*** Reducing register masks...\n"; + runDeltaPass(Test, reduceMasksInModule); +}