Skip to content

Commit

Permalink
llvm-reduce: Add reduction for custom register masks
Browse files Browse the repository at this point in the history
I have a register allocator failure that only reproduces with IPRA
enabled, and requires the specific regmask if I want to only run the
one relevant pass. The printed custom regmask is enormous and I would
like to reduce it.

This reduces each individual bit in the mask, but it would probably be
better to start at register units and clear all aliasing fields at a
time. This would require stricter verification that all aliasing bits
are set in regmasks (although I would prefer to switch regmasks to use
register units in the first place).
  • Loading branch information
arsenm committed Jul 18, 2022
1 parent 86c4242 commit 0f9d9ed
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 1 deletion.
23 changes: 23 additions & 0 deletions 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
...
1 change: 1 addition & 0 deletions llvm/tools/llvm-reduce/CMakeLists.txt
Expand Up @@ -45,6 +45,7 @@ add_llvm_tool(llvm-reduce
deltas/ReduceInstructionFlagsMIR.cpp
deltas/ReduceIRReferences.cpp
deltas/ReduceVirtualRegisters.cpp
deltas/ReduceRegisterMasks.cpp
deltas/ReduceRegisterUses.cpp
deltas/SimplifyInstructions.cpp
llvm-reduce.cpp
Expand Down
2 changes: 2 additions & 0 deletions llvm/tools/llvm-reduce/DeltaManager.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -85,6 +86,7 @@ static cl::opt<std::string>
DELTA_PASS("instruction-flags", reduceInstructionFlagsMIRDeltaPass) \
DELTA_PASS("register-uses", reduceRegisterUsesMIRDeltaPass) \
DELTA_PASS("register-hints", reduceVirtualRegisterHintsDeltaPass) \
DELTA_PASS("register-masks", reduceRegisterMasksMIRDeltaPass) \
} while (false)

static void runAllDeltaPasses(TestRunner &Tester) {
Expand Down
17 changes: 16 additions & 1 deletion llvm/tools/llvm-reduce/ReducerWorkItem.cpp
Expand Up @@ -291,6 +291,12 @@ static std::unique_ptr<MachineFunction> cloneMF(MachineFunction *SrcMF,
}
}

DenseSet<const uint32_t *> 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];
Expand All @@ -309,9 +315,18 @@ static std::unique_ptr<MachineFunction> cloneMF(MachineFunction *SrcMF,
// 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);
}

Expand Down
73 changes: 73 additions & 0 deletions 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<const uint32_t *> 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<uint32_t> 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);
}
18 changes: 18 additions & 0 deletions 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

0 comments on commit 0f9d9ed

Please sign in to comment.