<html>
    <head>
      <base href="https://llvm.org/bugs/" />
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW --- - load/store address constant offsets with negative register values"
   href="https://llvm.org/bugs/show_bug.cgi?id=29127">29127</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>load/store address constant offsets with negative register values
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>libraries
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>Backend: WebAssembly
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>dschuff@google.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr>

        <tr>
          <th>Classification</th>
          <td>Unclassified
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Created <span class=""><a href="attachment.cgi?id=17038" name="attach_17038" title="input IR">attachment 17038</a> <a href="attachment.cgi?id=17038&action=edit" title="input IR">[details]</a></span>
input IR

The following C code:

int args[32];

int main() {
  int i;
  #pragma clang loop unroll(disable)
  for (i=0;i<32;i++) args[i]=1;
  return 0;
}

compiles with -O to the following IR:
@args = hidden local_unnamed_addr global [32 x i32] zeroinitializer, align 16
...
for.body:                                         ; preds = %for.body, %entry
  %i.04 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
  %arrayidx = getelementptr inbounds [32 x i32], [32 x i32]* @args, i32 0, i32
%i.04
  store i32 1, i32* %arrayidx, align 4, !tbaa !1


When the backend runs loop strength reduction, it becomes this:

for.body:                                         ; preds = %for.body, %entry
  %lsr.iv = phi i32 [ %lsr.iv.next, %for.body ], [ -128, %entry ]
  %lsr.iv1 = inttoptr i32 %lsr.iv to i32*
  %uglygep = getelementptr i8, i8* bitcast ([32 x i32]* @args to i8*), i32
%lsr.iv
  %uglygep2 = bitcast i8* %uglygep to i32*
  %scevgep = getelementptr i32, i32* %uglygep2, i32 32
  store i32 1, i32* %scevgep, align 4, !tbaa !1

After SelectionDAGBuilder we get

%vreg0 = -128
...
store(1, add( add(GlobalAddr<@args>, %vreg0), 128))

Which the DAGcombiner reduces to
%vreg0 = -128
store(1, add(%vreg0, Wrapper(TGlobalAddr<@args>+128)))

and then selects to
# BB#0:                                 # %entry
    i32.const    $0=, -128
.LBB0_1:                                # %for.body
                                        # =>This Inner Loop Header: Depth=1
    loop                            # label0:
    i32.const    $push4=, 1
    i32.store    $drop=, args+128($0), $pop4

The problem is that the address calculation:
@args+128 + $0 (where $0 starts at -128) 
is unsigned, so it overflows.

It seems there are a couple places we could prevent this:
One is in the LSR/SCEV cost modeling/formula selection. LSR chooses an address
formula it prints as  
@args + 128 + reg({-128,+,4}<nuw><nsw><%for.body>)

isLegalAddressingMode seems like it might be a way to disallow this, but it
doesn't quite cover it because GV + offset + reg is legal and we want to allow
it (currently we allow it if offset >= 0); the problem here is that LSR has
chosen a negative value range for the register.

This can be disabled by e.g. hacking Cost::RateFormula
(LoopStrengthReduce.cpp:1130) to cause a SCEV BaseReg to "Lose" (i.e. not be
selected) if it has a known negative value (or do something equivalent to
that). Changing the cost model or selection this way might entail adding
something to TargetTransformInfo alongside isLegalAddressingMode (i.e. if the
target address calculation is unsigned or something like that).
That selection is sort of the deepest cause of the problem.


Another way might be to prevent one of the other events down the chain. e.g.
the dag combiner folds the add(GlobalAddr<@args>, %vreg0) but that seems legit,
and isel folds the GA expression into the constant offset which it seems like
we'd want, and there are some subtleties around the changes we made to how the
nsw/nuw flags are treated that I'm not sure I fully understand yet, so I don't
yet see an obvious way to fix this there without disallowing other things we do
want to allow. I'm also not clear whether there are other potential sources of
similar issues, i.e. a register with a negative value combined with a constant
offset.</pre>
        </div>
      </p>
      <hr>
      <span>You are receiving this mail because:</span>
      
      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>