Index: include/llvm/Target/Target.td =================================================================== --- include/llvm/Target/Target.td +++ include/llvm/Target/Target.td @@ -272,6 +272,39 @@ // constrained classes first. The value has to be in the range [0,63]. int AllocationPriority = 0; + // Defines a mask for limiting the construction of inferred register classes. + // The idea is that we don't want to infer classes of register tuples + // that span two classes with disjoint ClassMasks. + // For example if we have these classes: + // def SRegs : MyClass<16, [i16], (sequence "S%u", 0, 15)>; + // def STup2 : RegisterTuples<[ssub0, ssub1], + // [(shl SRegs, 0), + // (shl SRegs, 1)]>; + // def SRegs2 : MyClass<32, [i32], (add Stup2)>; + // def SRegslow : MyClass<16, [i16], (trunc SRegs, 5)> + // def SRegshigh : MyClass<16, [i16], (shl SRegs, 5)> + // The main register file SReg is paritioned through additional constraints + // classes available with theSRegslow/high classes. + // We also have and also a tuple of registers SRegs2. + // Tablegen would normally create all the combinations of register classes + // for the query to getMatchingSuperRegClass() like: + // SRegs2_with_ssub0_in_SRegslow_and_SRegs2_with_ssub1_in_SRegshighRegClass + // ... and so on. + // All these inferred register classes grow exponentially with the number + // of overlapping tuples that potentially cross the boundary of the low/high + // constraint classes. + // By defining the constraint classes as: + // def SRegslow : MyClass<16, [i16], (trunc SRegs, 5)> { + // let ClassMask = 1; + // } + // def SRegshigh : MyClass<16, [i16], (shl SRegs, 5)> { + // let ClassMask = 2; + // } + // where the masks are disjoint Tablegen will make sure to not infer any + // class of tuples crossing the boundary between the low and high constraint + // file. + bits<32> ClassMask = -1; + // The diagnostic type to present when referencing this operand in a match // failure error message. If this is empty, the default Match_InvalidOperand // diagnostic type will be used. If this is "", a Match_ enum Index: test/TableGen/ClassMask1.td =================================================================== --- /dev/null +++ test/TableGen/ClassMask1.td @@ -0,0 +1,77 @@ +// RUN: llvm-tblgen -gen-register-info -I %p/../../include %s -o - 2>&1 | FileCheck %s +// Checks that classes disjoint through "ClassMask" do not generate extra inferred classes +include "llvm/Target/Target.td" + +class MyReg subregs = []> + : Register { + let Namespace = "Test"; + let SubRegs = subregs; + let CoveredBySubRegs = 1; +} +class MyClass types, dag registers> + : RegisterClass<"Test", types, size, registers> { + let Size = size; +} + +// Register Example: +// D0_D1 -- D0 (sub0) -- S0 (ssub0) +// \ \- S1 (ssub1) +// \ D1 (sub1) -- S2 (ssub2) +// \- S3 (ssub3) + +def sub0 : SubRegIndex<32>; +def sub1 : SubRegIndex<32, 32>; +def sub2 : SubRegIndex<32, 64>; + +def ssub0 : SubRegIndex<16>; +def ssub1 : SubRegIndex<16, 16>; +def ssub2 : ComposedSubRegIndex; +def ssub3 : ComposedSubRegIndex; +def ssub4 : ComposedSubRegIndex; + +def S0 : MyReg<"s0">; +def S1 : MyReg<"s1">; +def S2 : MyReg<"s2">; +def S3 : MyReg<"s3">; +def S4 : MyReg<"s4">; +def S5 : MyReg<"s5">; +def S6 : MyReg<"s6">; +def S7 : MyReg<"s7">; +def S8 : MyReg<"s8">; +def S9 : MyReg<"s9">; +def S10 : MyReg<"s10">; +def S11 : MyReg<"s11">; +def S12 : MyReg<"s12">; +def S13 : MyReg<"s13">; +def S14 : MyReg<"s14">; +def S15 : MyReg<"s15">; +def SRegs : MyClass<16, [i16], (sequence "S%u", 0, 15)>; +def SRegslow : MyClass<16, [i16], (trunc SRegs, 5)> +{ + let ClassMask = 1; +} +def SRegshigh : MyClass<16, [i16], (shl SRegs, 5)> +{ + let ClassMask = 2; +} +def Stup2 : RegisterTuples<[ssub0, ssub1], [ + (shl SRegs, 0), + (shl SRegs, 1) + ]>; + +def SRegs2 : MyClass<32, [i32], (add Stup2)>; + +def TestTarget : Target; + +// CHECK-LABEL: // Register classes +// CHECK: enum { +// CHECK-NEXT: SRegsRegClassID = 0, +// CHECK-NEXT: SRegshighRegClassID = 1, +// CHECK-NEXT: SRegslowRegClassID = 2, +// CHECK-NEXT: SRegs2RegClassID = 3, +// CHECK-NEXT: SRegs2_with_ssub1_in_SRegshighRegClassID = 4, +// CHECK-NEXT: SRegs2_with_ssub0_in_SRegshighRegClassID = 5, +// CHECK-NEXT: SRegs2_with_ssub0_in_SRegslowRegClassID = 6, +// CHECK-NEXT: SRegs2_with_ssub1_in_SRegslowRegClassID = 7, +// CHECK-EMPTY: +// CHECK-NEXT: }; Index: test/TableGen/ClassMask2.td =================================================================== --- /dev/null +++ test/TableGen/ClassMask2.td @@ -0,0 +1,96 @@ +// RUN: llvm-tblgen -gen-register-info -I %p/../../include %s -o - | FileCheck %s +// Checks that ClassMask works in the expected way when classes with overlapping +// class masks overlap. +include "llvm/Target/Target.td" + +class MyReg subregs = []> + : Register { + let Namespace = "Test"; + let SubRegs = subregs; + let CoveredBySubRegs = 1; +} +class MyClass types, dag registers> + : RegisterClass<"Test", types, size, registers> { + let Size = size; +} + +// Register Example: +// D0_D1 -- D0 (sub0) -- S0 (ssub0) +// \ \- S1 (ssub1) +// \ D1 (sub1) -- S2 (ssub2) +// \- S3 (ssub3) + +def sub0 : SubRegIndex<32>; +def sub1 : SubRegIndex<32, 32>; +def sub2 : SubRegIndex<32, 64>; + +def ssub0 : SubRegIndex<16>; +def ssub1 : SubRegIndex<16, 16>; +def ssub2 : ComposedSubRegIndex; +def ssub3 : ComposedSubRegIndex; +def ssub4 : ComposedSubRegIndex; + +def S0 : MyReg<"s0">; +def S1 : MyReg<"s1">; +def S2 : MyReg<"s2">; +def S3 : MyReg<"s3">; +def S4 : MyReg<"s4">; +def S5 : MyReg<"s5">; +def S6 : MyReg<"s6">; +def S7 : MyReg<"s7">; +def S8 : MyReg<"s8">; +def S9 : MyReg<"s9">; +def S10 : MyReg<"s10">; +def S11 : MyReg<"s11">; +def S12 : MyReg<"s12">; +def S13 : MyReg<"s13">; +def S14 : MyReg<"s14">; +def S15 : MyReg<"s15">; +def SRegs : MyClass<16, [i16], (sequence "S%u", 0, 15)>; +def SRegslow : MyClass<16, [i16], (trunc SRegs, 5)> +{ + let ClassMask = 3; +} +def SRegslowhigh : MyClass<16, [i16], (trunc (shl SRegs, 3), 4)> +{ + let ClassMask = 6; +} +def SRegshigh : MyClass<16, [i16], (shl SRegs, 5)> +{ + let ClassMask = 12; +} +def Stup2 : RegisterTuples<[ssub0, ssub1], [ + (shl SRegs, 0), + (shl SRegs, 1) + ]>; + +def SRegs2 : MyClass<32, [i32], (add Stup2)>; + +def TestTarget : Target; + +// CHECK-LABEL: // Register classes +// CHECK: enum { +// CHECK-NEXT: SRegsRegClassID = 0, +// CHECK-NEXT: SRegshighRegClassID = 1, +// CHECK-NEXT: SRegslowRegClassID = 2, +// CHECK-NEXT: SRegslowhighRegClassID = 3, +// CHECK-NEXT: SRegshigh_and_SRegslowhighRegClassID = 4, +// CHECK-NEXT: SRegslow_and_SRegslowhighRegClassID = 5, +// CHECK-NEXT: SRegs2RegClassID = 6, +// CHECK-NEXT: SRegs2_with_ssub1_in_SRegshighRegClassID = 7, +// CHECK-NEXT: SRegs2_with_ssub0_in_SRegshighRegClassID = 8, +// CHECK-NEXT: SRegs2_with_ssub0_in_SRegslowRegClassID = 9, +// CHECK-NEXT: SRegs2_with_ssub0_in_SRegslowhighRegClassID = 10, +// CHECK-NEXT: SRegs2_with_ssub1_in_SRegslowRegClassID = 11, +// CHECK-NEXT: SRegs2_with_ssub1_in_SRegslowhighRegClassID = 12, +// CHECK-NEXT: SRegs2_with_ssub0_in_SRegslow_and_SRegs2_with_ssub1_in_SRegslowhighRegClassID = 13, +// CHECK-NEXT: SRegs2_with_ssub0_in_SRegslowhigh_and_SRegs2_with_ssub1_in_SRegshighRegClassID = 14, +// CHECK-NEXT: SRegs2_with_ssub0_in_SRegslowhigh_and_SRegs2_with_ssub1_in_SRegslowhighRegClassID = 15, +// CHECK-NEXT: SRegs2_with_ssub0_in_SRegshigh_and_SRegslowhighRegClassID = 16, +// CHECK-NEXT: SRegs2_with_ssub0_in_SRegslow_and_SRegslowhighRegClassID = 17, +// CHECK-NEXT: SRegs2_with_ssub1_in_SRegshigh_and_SRegslowhighRegClassID = 18, +// CHECK-NEXT: SRegs2_with_ssub1_in_SRegslow_and_SRegslowhighRegClassID = 19, +// CHECK-NEXT: SRegs2_with_ssub0_in_SRegshigh_and_SRegs2_with_ssub1_in_SRegslowhighRegClassID = 20, +// CHECK-NEXT: SRegs2_with_ssub0_in_SRegslowhigh_and_SRegs2_with_ssub1_in_SRegslowRegClassID = 21, +// CHECK-EMPTY: +// CHECK-NEXT: }; Index: test/TableGen/ClassMask3.td =================================================================== --- /dev/null +++ test/TableGen/ClassMask3.td @@ -0,0 +1,77 @@ +// RUN: llvm-tblgen -gen-register-info -I %p/../../include %s -o - | FileCheck %s +// Checks that ClassMask don't interfere with classes that are completely disjoint. +include "llvm/Target/Target.td" + +class MyReg subregs = []> + : Register { + let Namespace = "Test"; + let SubRegs = subregs; + let CoveredBySubRegs = 1; +} +class MyClass types, dag registers> + : RegisterClass<"Test", types, size, registers> { + let Size = size; +} + +// Register Example: +// D0_D1 -- D0 (sub0) -- S0 (ssub0) +// \ \- S1 (ssub1) +// \ D1 (sub1) -- S2 (ssub2) +// \- S3 (ssub3) + +def sub0 : SubRegIndex<32>; +def sub1 : SubRegIndex<32, 32>; +def sub2 : SubRegIndex<32, 64>; + +def ssub0 : SubRegIndex<16>; +def ssub1 : SubRegIndex<16, 16>; +def ssub2 : ComposedSubRegIndex; +def ssub3 : ComposedSubRegIndex; +def ssub4 : ComposedSubRegIndex; + +def S0 : MyReg<"s0">; +def S1 : MyReg<"s1">; +def S2 : MyReg<"s2">; +def S3 : MyReg<"s3">; +def S4 : MyReg<"s4">; +def S5 : MyReg<"s5">; +def S6 : MyReg<"s6">; +def S7 : MyReg<"s7">; +def S8 : MyReg<"s8">; +def S9 : MyReg<"s9">; +def S10 : MyReg<"s10">; +def S11 : MyReg<"s11">; +def S12 : MyReg<"s12">; +def S13 : MyReg<"s13">; +def S14 : MyReg<"s14">; +def S15 : MyReg<"s15">; +def SRegs : MyClass<16, [i16], (sequence "S%u", 0, 15)>; +def SRegslow : MyClass<16, [i16], (trunc SRegs, 5)> +{ + let ClassMask = 3; +} +def SRegshigh : MyClass<16, [i16], (shl SRegs, 8)> +{ + let ClassMask = 12; +} +def Stup2 : RegisterTuples<[ssub0, ssub1], [ + (shl SRegs, 0), + (shl SRegs, 1) + ]>; + +def SRegs2 : MyClass<32, [i32], (add Stup2)>; + +def TestTarget : Target; + +// CHECK-LABEL: // Register classes +// CHECK: enum { +// CHECK-NEXT: SRegsRegClassID = 0, +// CHECK-NEXT: SRegshighRegClassID = 1, +// CHECK-NEXT: SRegslowRegClassID = 2, +// CHECK-NEXT: SRegs2RegClassID = 3, +// CHECK-NEXT: SRegs2_with_ssub1_in_SRegshighRegClassID = 4, +// CHECK-NEXT: SRegs2_with_ssub0_in_SRegshighRegClassID = 5, +// CHECK-NEXT: SRegs2_with_ssub0_in_SRegslowRegClassID = 6, +// CHECK-NEXT: SRegs2_with_ssub1_in_SRegslowRegClassID = 7, +// CHECK-EMPTY: +// CHECK-NEXT: }; Index: test/TableGen/ClassMask4.td =================================================================== --- /dev/null +++ test/TableGen/ClassMask4.td @@ -0,0 +1,86 @@ +// RUN: llvm-tblgen -gen-register-info -I %p/../../include %s -o - | FileCheck %s +// Checks that a class with ClassMask = 0 doesn't participate in creating +// inferred classes. +include "llvm/Target/Target.td" + +class MyReg subregs = []> + : Register { + let Namespace = "Test"; + let SubRegs = subregs; + let CoveredBySubRegs = 1; +} +class MyClass types, dag registers> + : RegisterClass<"Test", types, size, registers> { + let Size = size; +} + +// Register Example: +// D0_D1 -- D0 (sub0) -- S0 (ssub0) +// \ \- S1 (ssub1) +// \ D1 (sub1) -- S2 (ssub2) +// \- S3 (ssub3) + +def sub0 : SubRegIndex<32>; +def sub1 : SubRegIndex<32, 32>; +def sub2 : SubRegIndex<32, 64>; + +def ssub0 : SubRegIndex<16>; +def ssub1 : SubRegIndex<16, 16>; +def ssub2 : ComposedSubRegIndex; +def ssub3 : ComposedSubRegIndex; +def ssub4 : ComposedSubRegIndex; + +def S0 : MyReg<"s0">; +def S1 : MyReg<"s1">; +def S2 : MyReg<"s2">; +def S3 : MyReg<"s3">; +def S4 : MyReg<"s4">; +def S5 : MyReg<"s5">; +def S6 : MyReg<"s6">; +def S7 : MyReg<"s7">; +def S8 : MyReg<"s8">; +def S9 : MyReg<"s9">; +def S10 : MyReg<"s10">; +def S11 : MyReg<"s11">; +def S12 : MyReg<"s12">; +def S13 : MyReg<"s13">; +def S14 : MyReg<"s14">; +def S15 : MyReg<"s15">; +def SRegs : MyClass<16, [i16], (sequence "S%u", 0, 15)>; +def SRegslow : MyClass<16, [i16], (trunc SRegs, 5)> +{ + let ClassMask = 3; +} +def SRegslowhigh : MyClass<16, [i16], (trunc (shl SRegs, 2), 8)> +{ + let ClassMask = 0; +} +def SRegshigh : MyClass<16, [i16], (shl SRegs, 5)> +{ + let ClassMask = 12; +} +def Stup3 : RegisterTuples<[ssub0, ssub1, ssub2], [ + (shl SRegs, 0), + (shl SRegs, 1), + (shl SRegs, 2) + ]>; + +def SRegs3 : MyClass<48, [untyped], (add Stup3)>; + +def TestTarget : Target; + +// CHECK-LABEL: // Register classes +// CHECK: enum { +// CHECK-NEXT: SRegsRegClassID = 0, +// CHECK-NEXT: SRegshighRegClassID = 1, +// CHECK-NEXT: SRegslowhighRegClassID = 2, +// CHECK-NEXT: SRegslowRegClassID = 3, +// CHECK-NEXT: SRegs3RegClassID = 4, +// CHECK-NEXT: SRegs3_with_ssub2_in_SRegshighRegClassID = 5, +// CHECK-NEXT: SRegs3_with_ssub1_in_SRegshighRegClassID = 6, +// CHECK-NEXT: SRegs3_with_ssub0_in_SRegshighRegClassID = 7, +// CHECK-NEXT: SRegs3_with_ssub0_in_SRegslowRegClassID = 8, +// CHECK-NEXT: SRegs3_with_ssub1_in_SRegslowRegClassID = 9, +// CHECK-NEXT: SRegs3_with_ssub2_in_SRegslowRegClassID = 10, +// CHECK-EMPTY: +// CHECK-NEXT: }; Index: utils/TableGen/CodeGenRegisters.h =================================================================== --- utils/TableGen/CodeGenRegisters.h +++ utils/TableGen/CodeGenRegisters.h @@ -331,6 +331,7 @@ bool Allocatable; StringRef AltOrderSelect; uint8_t AllocationPriority; + unsigned ClassMask; /// Contains the combination of the lane masks of all subregisters. LaneBitmask LaneMask; /// True if there are at least 2 subregisters which do not interfere. @@ -447,17 +448,18 @@ RegSizeInfoByHwMode RSI; Key(const CodeGenRegister::Vec *M, const RegSizeInfoByHwMode &I) - : Members(M), RSI(I) {} + : Members(M), RSI(I) {} Key(const CodeGenRegisterClass &RC) - : Members(&RC.getMembers()), RSI(RC.RSI) {} + : Members(&RC.getMembers()), RSI(RC.RSI) {} // Lexicographical order of (Members, RegSizeInfoByHwMode). bool operator<(const Key&) const; }; // Create a non-user defined register class. - CodeGenRegisterClass(CodeGenRegBank&, StringRef Name, Key Props); + CodeGenRegisterClass(CodeGenRegBank &, StringRef Name, unsigned ClassMask, + Key Props); // Called by CodeGenRegBank::CodeGenRegBank(). static void computeSubClasses(CodeGenRegBank&); @@ -571,7 +573,8 @@ // Create a synthetic sub-class if it is missing. CodeGenRegisterClass *getOrCreateSubClass(const CodeGenRegisterClass *RC, const CodeGenRegister::Vec *Membs, - StringRef Name); + StringRef Name, + unsigned ClassMask); // Infer missing register classes. void computeInferredRegisterClasses(); Index: utils/TableGen/CodeGenRegisters.cpp =================================================================== --- utils/TableGen/CodeGenRegisters.cpp +++ utils/TableGen/CodeGenRegisters.cpp @@ -799,22 +799,25 @@ if (AllocationPriority < 0 || AllocationPriority > 63) PrintFatalError(R->getLoc(), "AllocationPriority out of range [0,63]"); this->AllocationPriority = AllocationPriority; + BitsInit *BI = R->getValueAsBitsInit("ClassMask"); + uint64_t Value = 0; + for (unsigned b = 0, be = BI->getNumBits(); b != be; ++b) { + if (BitInit *B = dyn_cast(BI->getBit(b))) + Value |= (uint64_t)B->getValue() << b; + } + this->ClassMask = static_cast(Value); } // Create an inferred register class that was missing from the .td files. // Most properties will be inherited from the closest super-class after the // class structure has been computed. CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, - StringRef Name, Key Props) - : Members(*Props.Members), - TheDef(nullptr), - Name(Name), - TopoSigs(RegBank.getNumTopoSigs()), - EnumValue(-1), - RSI(Props.RSI), - CopyCost(0), - Allocatable(true), - AllocationPriority(0) { + StringRef Name, unsigned ClassMask, + Key Props) + : Members(*Props.Members), TheDef(nullptr), Name(Name), + TopoSigs(RegBank.getNumTopoSigs()), EnumValue(-1), RSI(Props.RSI), + CopyCost(0), Allocatable(true), AllocationPriority(0), + ClassMask(ClassMask) { Artificial = true; for (const auto R : Members) { TopoSigs.set(R->getTopoSig()); @@ -838,7 +841,6 @@ Allocatable = Super.Allocatable; AltOrderSelect = Super.AltOrderSelect; AllocationPriority = Super.AllocationPriority; - // Copy all allocation orders, filter out foreign registers from the larger // super-class. Orders.resize(Super.Orders.size()); @@ -1233,10 +1235,11 @@ } // Create a synthetic sub-class if it is missing. -CodeGenRegisterClass* +CodeGenRegisterClass * CodeGenRegBank::getOrCreateSubClass(const CodeGenRegisterClass *RC, const CodeGenRegister::Vec *Members, - StringRef Name) { + StringRef Name, unsigned ClassMask) { + assert(ClassMask && "Trying to create an artificial class with 0 ClassMask"); // Synthetic sub-class has the same size and alignment as RC. CodeGenRegisterClass::Key K(Members, RC->RSI); RCKeyMap::const_iterator FoundI = Key2RC.find(K); @@ -1244,7 +1247,7 @@ return FoundI->second; // Sub-class doesn't exist, create a new one. - RegClasses.emplace_back(*this, Name, K); + RegClasses.emplace_back(*this, Name, ClassMask, K); addToMaps(&RegClasses.back()); return &RegClasses.back(); } @@ -2073,7 +2076,10 @@ CodeGenRegisterClass *RC2 = &*I; if (RC1 == RC2) continue; - + const unsigned CompositeMask = RC1->ClassMask & RC2->ClassMask; + // Create a subclass only if the masks of the classes are compatible + if (!CompositeMask) + continue; // Compute the set intersection of RC1 and RC2. const CodeGenRegister::Vec &Memb1 = RC1->getMembers(); const CodeGenRegister::Vec &Memb2 = RC2->getMembers(); @@ -2081,7 +2087,6 @@ std::set_intersection( Memb1.begin(), Memb1.end(), Memb2.begin(), Memb2.end(), std::inserter(Intersection, Intersection.begin()), deref()); - // Skip disjoint class pairs. if (Intersection.empty()) continue; @@ -2092,7 +2097,8 @@ std::swap(RC1, RC2); getOrCreateSubClass(RC1, &Intersection, - RC1->getName() + "_and_" + RC2->getName()); + RC1->getName() + "_and_" + RC2->getName(), + CompositeMask); } } @@ -2138,9 +2144,9 @@ continue; } // This is a real subset. See if we have a matching class. - CodeGenRegisterClass *SubRC = - getOrCreateSubClass(RC, &I->second, - RC->getName() + "_with_" + I->first->getName()); + CodeGenRegisterClass *SubRC = getOrCreateSubClass( + RC, &I->second, RC->getName() + "_with_" + I->first->getName(), + RC->ClassMask); RC->setSubClassWithSubReg(&SubIdx, SubRC); } } @@ -2152,8 +2158,9 @@ // has a maximal result for any SubIdx and any X >= FirstSubRegRC. // -void CodeGenRegBank::inferMatchingSuperRegClass(CodeGenRegisterClass *RC, - std::list::iterator FirstSubRegRC) { +void CodeGenRegBank::inferMatchingSuperRegClass( + CodeGenRegisterClass *RC, + std::list::iterator FirstSubRegRC) { SmallVector, 16> SSPairs; BitVector TopoSigs(getNumTopoSigs()); @@ -2189,6 +2196,9 @@ // Topological shortcut: SubRC members have the wrong shape. if (!TopoSigs.anyCommon(SubRC.getTopoSigs())) continue; + // If RC and SubRC are disjoint then skip + if (!(RC->ClassMask & SubRC.ClassMask)) + continue; // Compute the subset of RC that maps into SubRC. CodeGenRegister::Vec SubSetVec; for (unsigned i = 0, e = SSPairs.size(); i != e; ++i) @@ -2207,9 +2217,10 @@ // Only a subset of RC maps into SubRC. Make sure it is represented by a // class. - getOrCreateSubClass(RC, &SubSetVec, RC->getName() + "_with_" + - SubIdx.getName() + "_in_" + - SubRC.getName()); + getOrCreateSubClass(RC, &SubSetVec, + RC->getName() + "_with_" + SubIdx.getName() + "_in_" + + SubRC.getName(), + RC->ClassMask & SubRC.ClassMask); } } }