summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/test/TableGen/ambiguous-composition.td92
-rw-r--r--llvm/utils/TableGen/CodeGenRegisters.cpp64
2 files changed, 151 insertions, 5 deletions
diff --git a/llvm/test/TableGen/ambiguous-composition.td b/llvm/test/TableGen/ambiguous-composition.td
new file mode 100644
index 00000000000..da83466b4d0
--- /dev/null
+++ b/llvm/test/TableGen/ambiguous-composition.td
@@ -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)>;
diff --git a/llvm/utils/TableGen/CodeGenRegisters.cpp b/llvm/utils/TableGen/CodeGenRegisters.cpp
index e70a79f08af..74a2b078dfb 100644
--- a/llvm/utils/TableGen/CodeGenRegisters.cpp
+++ b/llvm/utils/TableGen/CodeGenRegisters.cpp
@@ -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());
+ }
}
}
}
OpenPOWER on IntegriCloud