I am building a backend for a CISC-style target that has (a) a large variety of memory addressing modes, including many with pre/post increment/decrement, and (b) a large number of instructions that have one or more memory operands using those modes.
The traditional way of modeling post-increment in LLVM backends is to define two forms of each instruction: one that includes the writeback register as an “out” operand, and one that doesn’t.
I would like to avoid this if possible since it will result in a lot of duplication in the .td descriptions. Multidefs may help some but there are other dimensions of duplication that complicate things and it all turns into a tangled mess.
What I would like to do is model the writeback operand similar to the way ARM and possibly other targets model predicate registers: each instruction is declared to have the operand, but it’s set to “noreg” (0) if it’s not used. I would like to add the writeback operand as an explicit output for each memory instruction, and set it to 0 if the addressing mode does not use the writeback. In that case the operand would simply act like it’s not there.
I tried this and it works well, except that there are a number of places in the backend that process a def operand that now need to check the register and ignore it if it’s 0. These checks already exist for the case of uses, but not for defs.
I am still finding such places and fixing them little by little. But before I get too far down this path, I’d like some feedback as to whether this would be an acceptable thing to upstream. I really feel like this is the best solution and is justified. It should not break any existing target since none currently rely on it, it has the potential to simplify future targets, and it corrects what I see as an arbitrary asymmetry.