[TableGen] Examine entire subreg compositions to detect ambiguity

When tablegen detects that there exist two subregister compositions that
result in the same value for some register, it will emit a warning. This
kind of an overlap in compositions should only happen when it is caused
by a user-defined composition. It can happen, however, that the user-
defined composition is not identically equal to another one, but it does
produce the same value for one or more registers. In such cases suppress
the warning.
This patch is to silence the warning when building the System Z backend
after D50725.

Differential Revision: https://reviews.llvm.org/D50977

llvm-svn: 347894
This commit is contained in:
Krzysztof Parzyszek 2018-11-29 18:20:08 +00:00
parent cc6119f1d3
commit 49652486ed
2 changed files with 151 additions and 5 deletions

View File

@ -0,0 +1,92 @@
// RUN: llvm-tblgen -gen-register-info -I %p/../../include %s 2>&1 | FileCheck %s
//
// CHECK-NOT: warning: SubRegIndex Test::subreg_h64 and Test::subreg_h32 compose ambiguously as Test::subreg_hh32 or Test::subreg_h32
// CHECK: warning: SubRegIndex Test::subreg_l64 and Test::subreg_l32 compose ambiguously as Test::subreg_ll32 or Test::subreg_l32
include "llvm/Target/Target.td"
def TestInstrInfo : InstrInfo {
}
def Test : Target {
let InstructionSet = TestInstrInfo;
}
let Namespace = "Test" in {
def subreg_l32 : SubRegIndex<32, 0>;
def subreg_h32 : SubRegIndex<32, 32>;
def subreg_h64 : SubRegIndex<64, 64>;
def subreg_l64 : SubRegIndex<64, 0>;
def subreg_hh32 : ComposedSubRegIndex<subreg_h64, subreg_h32>;
def subreg_ll32 : ComposedSubRegIndex<subreg_l64, subreg_l32>;
}
class TestReg<string n, list<Register> s> : RegisterWithSubRegs<n, s> {
let Namespace = "Test";
}
// --------------------------------------------------------------------
// A situation that previously caused the warning about ambiguous
// composition.
//
// The actual subregister actions are:
// subreg_h64: { F0Q->F0D V0Q->F0D }
// subreg_h32: { F0D->F0S F0Q->F2S V0Q->F0S }
// composition: { F0Q->F0S V0Q->F0S } (this is the same as subreg_hh32)
//
// For the register V0Q, subreg_hh32(V0Q) = subreg_h32(V0Q) = F0S, which
// would be enough to trigger the warning about ambiguous composition.
// However, for F0Q, subreg_hh32(F0Q) = F0S, while subreg_h32(F0Q) = F2S,
// which shows that there two subregister indices are different.
// Make sure that the warning is not emitted in this case.
class FPR32<string n> : TestReg<n, []> {
}
class FPR64<string n, FPR32 high> : TestReg<n, [high]> {
let SubRegIndices = [subreg_h32];
}
class FPR128<string n, FPR64 high, FPR32 low> : TestReg<n, [high, low]> {
let SubRegIndices = [subreg_h64, subreg_h32];
}
class VPR128<string n, FPR64 high> : TestReg<n, [high]> {
let SubRegIndices = [subreg_h64];
}
def F0S : FPR32<"f0s">;
def F1S : FPR32<"f1s">;
def F2S : FPR32<"f2s">;
def F0D : FPR64<"f0d", F0S>;
def F0Q : FPR128<"f0q", F0D, F2S>;
def V0Q : VPR128<"v0q", F0D>;
def FP32 : RegisterClass<"FP32", [f32], 32, (add F0S)>;
def FP64 : RegisterClass<"FP64", [f64], 64, (add F0D)>;
def FP128 : RegisterClass<"FP128", [v2f64], 128, (add F0Q)>;
def VP128 : RegisterClass<"VP128", [v2f64], 128, (add V0Q)>;
// --------------------------------------------------------------------
// A situation where the warning is legitimate.
// Make sure that the warning is still displayed.
class GPR32<string n> : TestReg<n, []> {
}
class GPR64<string n, GPR32 low> : TestReg<n, [low]> {
let SubRegIndices = [subreg_l32];
}
class GPR128<string n, GPR64 low> : TestReg<n, [low]> {
let SubRegIndices = [subreg_l64];
}
def G0S : GPR32<"g0s">;
def G0D : GPR64<"g0d", G0S>;
def G0Q : GPR128<"g0q", G0D>;
def GP32 : RegisterClass<"GP32", [i32], 32, (add G0S)>;
def GP64 : RegisterClass<"GP64", [i64], 64, (add G0D)>;
def GP128 : RegisterClass<"GP128", [v2i64], 128, (add G0Q)>;

View File

@ -20,6 +20,7 @@
#include "llvm/ADT/IntEqClasses.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
@ -1309,6 +1310,55 @@ getConcatSubRegIndex(const SmallVector<CodeGenSubRegIndex *, 8> &Parts) {
}
void CodeGenRegBank::computeComposites() {
using RegMap = std::map<const CodeGenRegister*, const CodeGenRegister*>;
// Subreg -> { Reg->Reg }, where the right-hand side is the mapping from
// register to (sub)register associated with the action of the left-hand
// side subregister.
std::map<const CodeGenSubRegIndex*, RegMap> SubRegAction;
for (const CodeGenRegister &R : Registers) {
const CodeGenRegister::SubRegMap &SM = R.getSubRegs();
for (std::pair<const CodeGenSubRegIndex*, const CodeGenRegister*> P : SM)
SubRegAction[P.first].insert({&R, P.second});
}
// Calculate the composition of two subregisters as compositions of their
// associated actions.
auto compose = [&SubRegAction] (const CodeGenSubRegIndex *Sub1,
const CodeGenSubRegIndex *Sub2) {
RegMap C;
const RegMap &Img1 = SubRegAction.at(Sub1);
const RegMap &Img2 = SubRegAction.at(Sub2);
for (std::pair<const CodeGenRegister*, const CodeGenRegister*> P : Img1) {
auto F = Img2.find(P.second);
if (F != Img2.end())
C.insert({P.first, F->second});
}
return C;
};
// Check if the two maps agree on the intersection of their domains.
auto agree = [] (const RegMap &Map1, const RegMap &Map2) {
// Technically speaking, an empty map agrees with any other map, but
// this could flag false positives. We're interested in non-vacuous
// agreements.
if (Map1.empty() || Map2.empty())
return false;
for (std::pair<const CodeGenRegister*, const CodeGenRegister*> P : Map1) {
auto F = Map2.find(P.first);
if (F == Map2.end() || P.second != F->second)
return false;
}
return true;
};
using CompositePair = std::pair<const CodeGenSubRegIndex*,
const CodeGenSubRegIndex*>;
SmallSet<CompositePair,4> UserDefined;
for (const CodeGenSubRegIndex &Idx : SubRegIndices)
for (auto P : Idx.getComposites())
UserDefined.insert(std::make_pair(&Idx, P.first));
// Keep track of TopoSigs visited. We only need to visit each TopoSig once,
// and many registers will share TopoSigs on regular architectures.
BitVector TopoSigs(getNumTopoSigs());
@ -1341,11 +1391,15 @@ void CodeGenRegBank::computeComposites() {
assert(Idx3 && "Sub-register doesn't have an index");
// Conflicting composition? Emit a warning but allow it.
if (CodeGenSubRegIndex *Prev = Idx1->addComposite(Idx2, Idx3))
PrintWarning(Twine("SubRegIndex ") + Idx1->getQualifiedName() +
" and " + Idx2->getQualifiedName() +
" compose ambiguously as " + Prev->getQualifiedName() +
" or " + Idx3->getQualifiedName());
if (CodeGenSubRegIndex *Prev = Idx1->addComposite(Idx2, Idx3)) {
// If the composition was not user-defined, always emit a warning.
if (!UserDefined.count({Idx1, Idx2}) ||
agree(compose(Idx1, Idx2), SubRegAction.at(Idx3)))
PrintWarning(Twine("SubRegIndex ") + Idx1->getQualifiedName() +
" and " + Idx2->getQualifiedName() +
" compose ambiguously as " + Prev->getQualifiedName() +
" or " + Idx3->getQualifiedName());
}
}
}
}