unsigned test(unsigned val, unsigned a, unsigned b) { unsigned shift = (32 - a) - b; return val << shift; } clang produces mov eax, 32 sub eax, esi sub eax, edx shlx eax, edi, eax icc produces neg esi # <- yay sub esi, edx mov ecx, esi shl edi, cl https://godbolt.org/z/gdGx_u
https://rise4fun.com/Alive/jHD Hm, i wonder if instead of trying to do all this in `X86DAGToDAGISel::tryShiftAmountMod()`, we should do this more generally: https://rise4fun.com/Alive/L8sU 1. transform `imm - x` to `neg(x) + imm`, which *may* be good anyway since there is no subtraction from an immediate, 2. and then transform `(x + C) - y` -> `(x - y) + c` 3. That results in `z + c` which `X86DAGToDAGISel::tryShiftAmountMod()` will already handle. How does this sound?
(In reply to Roman Lebedev from comment #1) > https://rise4fun.com/Alive/jHD > > Hm, i wonder if instead of trying to do all this in > `X86DAGToDAGISel::tryShiftAmountMod()`, > we should do this more generally: https://rise4fun.com/Alive/L8sU > 1. transform `imm - x` to `neg(x) + imm`, which *may* be good anyway > since there is no subtraction from an immediate, > 2. and then transform `(x + C) - y` -> `(x - y) + c` > 3. That results in `z + c` which `X86DAGToDAGISel::tryShiftAmountMod()` will > already handle. Ah, good news, we seem to already do that in backend: (not middle-end though) https://godbolt.org/z/U9pdPl So transform `imm - x` to `neg(x) + imm` is the only missing piece. > How does this sound?
Added tests specific to shift amount masking in r361241. Will add more generic `imm - x`->`neg(x) + imm` tests later.
(In reply to Roman Lebedev from comment #2) > (In reply to Roman Lebedev from comment #1) > > https://rise4fun.com/Alive/jHD > > > > Hm, i wonder if instead of trying to do all this in > > `X86DAGToDAGISel::tryShiftAmountMod()`, > > we should do this more generally: https://rise4fun.com/Alive/L8sU > > 1. transform `imm - x` to `neg(x) + imm`, which *may* be good anyway > > since there is no subtraction from an immediate, > > 2. and then transform `(x + C) - y` -> `(x - y) + c` > > 3. That results in `z + c` which `X86DAGToDAGISel::tryShiftAmountMod()` will > > already handle. > Ah, good news, we seem to already do that in backend: (not middle-end though) > https://godbolt.org/z/U9pdPl No, apparently we do not. This ended up being 5 patches, +3 patches to address some regressions (more regressions to be addressed, for latter patches in series). Before i look any further, would be awesome to reduce that queue. First patch in series: https://reviews.llvm.org/D62223 (look at Stack) > So transform `imm - x` to `neg(x) + imm` is the only missing piece. > > > How does this sound?
Much to my surprise, https://reviews.llvm.org/D62774#change-GFoeh6tuzX9e fixes the motivational case. Not sure if other transforms i mentioned in https://bugs.llvm.org/show_bug.cgi?id=41952#c1 will be helpful.
Fixed by adding dagcombine folds to hoist add/sub from/to constant.