Krzysztof Parzyszek via llvm-dev
2016-Sep-24 13:12 UTC
[llvm-dev] RFC: Implement variable-sized register classes
On 9/24/2016 7:20 AM, Alex Bradbury wrote:> My concern is that all of the above adds yet more complexity to what > is already (in my view) a fairly difficult part of LLVM to understand. > The definition of MyRegisterClass is not so bad though, and perhaps it > doesn't matter how it works under the hood to the average backend > writer.I agree with the complexity, but I would hope that more documentation, examples and explanations would clarify it.> What if RegisterClass contained a `list<RCInfo>`. Each RCInfo contains > RegTypes, RegSize, SpillSize, and SpillAlignment as well as a > Predicate the determines whether this individual RCInfo is the one > that should apply. To my taste this seems easier to understand than > the {Int,ValueType,ValueTypeList}Select mechanism.The "select" mechanism was intended to be extendable to be able to select any object of any type based on the predefined mode. It is entirely possible to use it in a similar way to what you describe below.> def Is64Bit : Predicate<"Subtarget->is64Bit()">; > def RCInfo64 : RCInfo<Is64Bit> { > let RegTypes = [i64, v2i32, v4i16, v8i8]; > ..... > } > > class MyRegisterClass : RegisterClass<...> { > let RCInfos = [RCInfo32, RCInfo64] > }With the RCInfo data, the new register class definition would be something like class MyRegisterClass : RegisterClass<...> { let RCInfos = HwModeSelect<[Is32Bit, Is64Bit, Is128Bit], [RCInfo32, RCInfo64, RCInfo128]>; } In either case, aggregating the info in a RCInfo class would require additional changes in TableGen so that it picks up the size/alignment/type data from the RCInfos list, instead of from individual members. This is doable and there are no technical barriers to do it. It may actually be a good idea, since it would isolate the part of the register class definition into a single object. On a side note---there is a distinction between "mode" and "predicate": modes are distinguished by name, which is necessary because they need to be distinguishable during the run-time of TableGen. Predicates are evaluated after TableGen is done, during the run-time of the code generated by it. I didn't want to differentiate predicates based on their names, since that would go against expectations of how predicates have behaved so far. -Krzysztof
Alex Bradbury via llvm-dev
2016-Sep-24 15:50 UTC
[llvm-dev] RFC: Implement variable-sized register classes
On 24 September 2016 at 14:12, Krzysztof Parzyszek <kparzysz at codeaurora.org> wrote:> On 9/24/2016 7:20 AM, Alex Bradbury wrote: >> >> My concern is that all of the above adds yet more complexity to what >> is already (in my view) a fairly difficult part of LLVM to understand. >> The definition of MyRegisterClass is not so bad though, and perhaps it >> doesn't matter how it works under the hood to the average backend >> writer. > > > I agree with the complexity, but I would hope that more documentation, > examples and explanations would clarify it.Agreed.> >> What if RegisterClass contained a `list<RCInfo>`. Each RCInfo contains >> RegTypes, RegSize, SpillSize, and SpillAlignment as well as a >> Predicate the determines whether this individual RCInfo is the one >> that should apply. To my taste this seems easier to understand than >> the {Int,ValueType,ValueTypeList}Select mechanism. > > > The "select" mechanism was intended to be extendable to be able to select > any object of any type based on the predefined mode. It is entirely possible > to use it in a similar way to what you describe below.<snip>> > class MyRegisterClass : RegisterClass<...> { > let RCInfos = HwModeSelect<[Is32Bit, Is64Bit, Is128Bit], > [RCInfo32, RCInfo64, RCInfo128]>; > }I think what I'm really suggesting is that rather than adding this special HwModeSelect mechanism where both HwMode and HwModeSelect are treated specially by TableGen, we instead make the RegisterClass itself (specifically its RCInfos field) be treated specially by TableGen.> On a side note---there is a distinction between "mode" and "predicate": > modes are distinguished by name, which is necessary because they need to be > distinguishable during the run-time of TableGen. Predicates are evaluated > after TableGen is done, during the run-time of the code generated by it. I > didn't want to differentiate predicates based on their names, since that > would go against expectations of how predicates have behaved so far.I think I don't fully understand the design limitations here. How exactly are HwModes used at tblgen execution time? As I understand it, the chosen HwMode couldn't be selected at tblgen time (after all, that's a subtarget property that will be known only when the compiler is invoked) but from what you say, there's a point where different HwModes must be differentiated? Also how will the generated output be different? e.g. right now in MIPS for OR in MipsGenInstrInfo we have: { 1754, 3, 1, 4, 232, 0|(1ULL<<MCID::Commutable)|(1ULL<<MCID::Rematerializable), 0x1ULL, nullptr, nullptr, OperandInfo25, -1 ,nullptr }, // Inst #1754 = OR { 1757, 3, 1, 4, 232, 0|(1ULL<<MCID::Commutable)|(1ULL<<MCID::Rematerializable), 0x1ULL, nullptr, nullptr, OperandInfo43, -1 ,nullptr }, // Inst #1757 = OR64 Where OperandInfo25 and OperandInfo43 obviously differ in terms of register class. As I understand it, with this proposal only one entry would be generated and OperandInfoNN would be defined in terms of our variable-sized register class. But for MipsGenDAGISel.inc, would multiple patterns be implicitly generated (one for each HwMode)? Thanks, Alex
Krzysztof Parzyszek via llvm-dev
2016-Sep-24 16:25 UTC
[llvm-dev] RFC: Implement variable-sized register classes
On 9/24/2016 10:50 AM, Alex Bradbury wrote:> I think what I'm really suggesting is that rather than adding this > special HwModeSelect mechanism where both HwMode and HwModeSelect are > treated specially by TableGen, we instead make the RegisterClass > itself (specifically its RCInfos field) be treated specially by > TableGen.The mode/select approach is general---you can make just about anything be specific to a particular hw mode. Changing TableGen to treat RCInfos specially is going to accomplish only that, nothing more.>> > On a side note---there is a distinction between "mode" and "predicate": >> > modes are distinguished by name, which is necessary because they need to be >> > distinguishable during the run-time of TableGen. Predicates are evaluated >> > after TableGen is done, during the run-time of the code generated by it. I >> > didn't want to differentiate predicates based on their names, since that >> > would go against expectations of how predicates have behaved so far. > I think I don't fully understand the design limitations here. How > exactly are HwModes used at tblgen execution time? As I understand it, > the chosen HwMode couldn't be selected at tblgen time (after all, > that's a subtarget property that will be known only when the compiler > is invoked) but from what you say, there's a point where different > HwModes must be differentiated?Type inference in TableGen relies on knowing the exact set of types allowed for a particular expression. This is exactly why this HwMode is needed: if a register class MyRegClass can hold i32 in one mode and i64 in another mode, TableGen must know that the list of allowable types is either [i32] or [i64], and it cannot be [i32, i64]. Tagging each type with a mode would instead make it look like [i32:Mode32, i64:Mode64], which is equivalent to saying "Mode32 -> [i32], Mode64 -> [i64]", or "[Mode32, Mode64], [i32, i64]" with the understanding that corresponding list elements are to be taken together. This is really only needed for selection patterns. If you just want to be able to define instructions (via def xxx : Instruction<...>), then the mode/select is not necessary.> Also how will the generated output be different? e.g. right now in > MIPS for OR in MipsGenInstrInfo we have: > { 1754, 3, 1, 4, 232, > 0|(1ULL<<MCID::Commutable)|(1ULL<<MCID::Rematerializable), 0x1ULL, > nullptr, nullptr, OperandInfo25, -1 ,nullptr }, // Inst #1754 = OR > { 1757, 3, 1, 4, 232, > 0|(1ULL<<MCID::Commutable)|(1ULL<<MCID::Rematerializable), 0x1ULL, > nullptr, nullptr, OperandInfo43, -1 ,nullptr }, // Inst #1757 = OR64 > > Where OperandInfo25 and OperandInfo43 obviously differ in terms of > register class. As I understand it, with this proposal only one entry > would be generated and OperandInfoNN would be defined in terms of our > variable-sized register class. But for MipsGenDAGISel.inc, would > multiple patterns be implicitly generated (one for each HwMode)?From the point of view of instruction descriptors nothing would really change. A ShortIntegerRegisterClass would still be different from LongIntegerRegisterClass. The difference would be that when you query them from TargetRegisterInfo about spill slot sizes, etc, you could get different answers for different subtargets. -Krzysztof