<div dir="ltr"><div>The assert is in eliminateFrameIndex, so this will be addressed within the ongoing frame pointer work.<br><br></div>Dan<br><br></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Jan 5, 2016 at 9:14 PM, JF Bastien <span dir="ltr"><<a href="mailto:jfb@chromium.org" target="_blank">jfb@chromium.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hi Dan,<div><br></div><div>This seems to cause a few unexpected follow-on breakages (same assert for all of them) when wasm compiles the GCC torture tests. Nothing worth reverting, but definitely worth calling out. Can you look into it?</div><div><br></div><div>Here's the list of failures: 20030313-1.c 20030916-1.c 20031012-1.c 20041126-1.c 20060420-1.c 20071202-1.c 20120808-1.c pr20527-1.c pr27073.c pr36339.c pr37573.c pr43236.c pr43835.c pr45070.c pr51933.c</div><div><br></div><div>Sources are here:</div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div><a href="https://github.com/gcc-mirror/gcc/tree/master/gcc/testsuite/gcc.c-torture/execute" target="_blank">https://github.com/gcc-mirror/gcc/tree/master/gcc/testsuite/gcc.c-torture/execute</a></div></blockquote><div><br></div><div><div>Sample failure:</div><div>clang-3.8: /b/build/slave/linux/build/src/buildbot/work/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp:70: virtual void llvm::WebAssemblyRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator, int, unsigned int, llvm::RegScavenger *) const: Assertion `MI.getOperand(1).getImm() == 0 && "Can't eliminate FI yet if offset is already set"' failed.</div><div>0  clang-3.8       0x00000000010787f8 llvm::sys::PrintStackTrace(llvm::raw_ostream&) + 40</div><div>1  clang-3.8       0x0000000001078f67</div><div>2  libpthread.so.0 0x00007f7aec33b340</div><div>3  libc.so.6       0x00007f7aeb563cc9 gsignal + 57</div><div>4  libc.so.6       0x00007f7aeb5670d8 abort + 328</div><div>5  libc.so.6       0x00007f7aeb55cb86</div><div>6  libc.so.6       0x00007f7aeb55cc32</div><div>7  clang-3.8       0x0000000000803dfc</div><div>8  clang-3.8       0x00000000008030f7</div><div>9  clang-3.8       0x0000000000801603</div><div>10 clang-3.8       0x00000000009e7f19 llvm::MachineFunctionPass::runOnFunction(llvm::Function&) + 153</div><div>11 clang-3.8       0x0000000000cb9554 llvm::FPPassManager::runOnFunction(llvm::Function&) + 564</div><div>12 clang-3.8       0x0000000000cb979b llvm::FPPassManager::runOnModule(llvm::Module&) + 43</div><div>13 clang-3.8       0x0000000000cb9c65 llvm::legacy::PassManagerImpl::run(llvm::Module&) + 869</div><div>14 clang-3.8       0x00000000011c0f12 clang::EmitBackendOutput(clang::DiagnosticsEngine&, clang::CodeGenOptions const&, clang::TargetOptions const&, clang::LangOptions const&, llvm::StringRef, llvm::Module*, clang::BackendAction, llvm::raw_pwrite_stream*, std::unique_ptr<llvm::FunctionInfoIndex, std::default_delete<llvm::FunctionInfoIndex> >) + 9090</div><div>15 clang-3.8       0x000000000184b70b</div><div>16 clang-3.8       0x0000000001c2f6b6 clang::ParseAST(clang::Sema&, bool, bool) + 598</div><div>17 clang-3.8       0x000000000155f215 clang::FrontendAction::Execute() + 69</div><div>18 clang-3.8       0x0000000001529ca1 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) + 1153</div><div>19 clang-3.8       0x00000000015f4f4e clang::ExecuteCompilerInvocation(clang::CompilerInstance*) + 3086</div><div>20 clang-3.8       0x0000000000675eac cc1_main(llvm::ArrayRef<char const*>, char const*, void*) + 1036</div><div>21 clang-3.8       0x0000000000674ad3 main + 12723</div><div>22 libc.so.6       0x00007f7aeb54eec5 __libc_start_main + 245</div><div>23 clang-3.8       0x000000000067181e</div><div><br></div></div></div><div class="HOEnZb"><div class="h5"><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Jan 5, 2016 at 4:43 PM, Dan Gohman via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: djg<br>
Date: Tue Jan  5 18:43:06 2016<br>
New Revision: 256890<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=256890&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=256890&view=rev</a><br>
Log:<br>
[SelectionDAGBuilder] Set NoUnsignedWrap for inbounds gep and load/store offsets.<br>
<br>
In an inbounds getelementptr, when an index produces a constant non-negative<br>
offset to add to the base, the add can be assumed to not have unsigned overflow.<br>
<br>
This relies on the assumption that addresses can't occupy more than half the<br>
address space, which isn't possible in C because it wouldn't be possible to<br>
represent the difference between the start of the object and one-past-the-end<br>
in a ptrdiff_t.<br>
<br>
Setting the NoUnsignedWrap flag is theoretically useful in general, and is<br>
specifically useful to the WebAssembly backend, since it permits stronger<br>
constant offset folding.<br>
<br>
Differential Revision: <a href="http://reviews.llvm.org/D15544" rel="noreferrer" target="_blank">http://reviews.llvm.org/D15544</a><br>
<br>
Modified:<br>
    llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp<br>
    llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp<br>
    llvm/trunk/test/CodeGen/WebAssembly/offset.ll<br>
<br>
Modified: llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp?rev=256890&r1=256889&r2=256890&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp?rev=256890&r1=256889&r2=256890&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp (original)<br>
+++ llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp Tue Jan  5 18:43:06 2016<br>
@@ -6843,9 +6843,13 @@ SDValue DAGCombiner::ReduceLoadWidth(SDN<br>
   uint64_t PtrOff = ShAmt / 8;<br>
   unsigned NewAlign = MinAlign(LN0->getAlignment(), PtrOff);<br>
   SDLoc DL(LN0);<br>
+  // The original load itself didn't wrap, so an offset within it doesn't.<br>
+  SDNodeFlags Flags;<br>
+  Flags.setNoUnsignedWrap(true);<br>
   SDValue NewPtr = DAG.getNode(ISD::ADD, DL,<br>
                                PtrType, LN0->getBasePtr(),<br>
-                               DAG.getConstant(PtrOff, DL, PtrType));<br>
+                               DAG.getConstant(PtrOff, DL, PtrType),<br>
+                               &Flags);<br>
   AddToWorklist(NewPtr.getNode());<br>
<br>
   SDValue Load;<br>
<br>
Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp?rev=256890&r1=256889&r2=256890&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp?rev=256890&r1=256889&r2=256890&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (original)<br>
+++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Tue Jan  5 18:43:06 2016<br>
@@ -1329,12 +1329,18 @@ void SelectionDAGBuilder::visitRet(const<br>
     ComputeValueVTs(TLI, DL, I.getOperand(0)->getType(), ValueVTs, &Offsets);<br>
     unsigned NumValues = ValueVTs.size();<br>
<br>
+    // An aggregate return value cannot wrap around the address space, so<br>
+    // offsets to its parts don't wrap either.<br>
+    SDNodeFlags Flags;<br>
+    Flags.setNoUnsignedWrap(true);<br>
+<br>
     SmallVector<SDValue, 4> Chains(NumValues);<br>
     for (unsigned i = 0; i != NumValues; ++i) {<br>
       SDValue Add = DAG.getNode(ISD::ADD, getCurSDLoc(),<br>
                                 RetPtr.getValueType(), RetPtr,<br>
                                 DAG.getIntPtrConstant(Offsets[i],<br>
-                                                      getCurSDLoc()));<br>
+                                                      getCurSDLoc()),<br>
+                                &Flags);<br>
       Chains[i] =<br>
         DAG.getStore(Chain, getCurSDLoc(),<br>
                      SDValue(RetOp.getNode(), RetOp.getResNo() + i),<br>
@@ -2994,8 +3000,15 @@ void SelectionDAGBuilder::visitGetElemen<br>
       if (Field) {<br>
         // N = N + Offset<br>
         uint64_t Offset = DL->getStructLayout(StTy)->getElementOffset(Field);<br>
+<br>
+        // In an inbouds GEP with an offset that is nonnegative even when<br>
+        // interpreted as signed, assume there is no unsigned overflow.<br>
+        SDNodeFlags Flags;<br>
+        if (int64_t(Offset) >= 0 && cast<GEPOperator>(I).isInBounds())<br>
+          Flags.setNoUnsignedWrap(true);<br>
+<br>
         N = DAG.getNode(ISD::ADD, dl, N.getValueType(), N,<br>
-                        DAG.getConstant(Offset, dl, N.getValueType()));<br>
+                        DAG.getConstant(Offset, dl, N.getValueType()), &Flags);<br>
       }<br>
<br>
       Ty = StTy->getElementType(Field);<br>
@@ -3020,7 +3033,14 @@ void SelectionDAGBuilder::visitGetElemen<br>
         SDValue OffsVal = VectorWidth ?<br>
           DAG.getConstant(Offs, dl, MVT::getVectorVT(PtrTy, VectorWidth)) :<br>
           DAG.getConstant(Offs, dl, PtrTy);<br>
-        N = DAG.getNode(ISD::ADD, dl, N.getValueType(), N, OffsVal);<br>
+<br>
+        // In an inbouds GEP with an offset that is nonnegative even when<br>
+        // interpreted as signed, assume there is no unsigned overflow.<br>
+        SDNodeFlags Flags;<br>
+        if (Offs.isNonNegative() && cast<GEPOperator>(I).isInBounds())<br>
+          Flags.setNoUnsignedWrap(true);<br>
+<br>
+        N = DAG.getNode(ISD::ADD, dl, N.getValueType(), N, OffsVal, &Flags);<br>
         continue;<br>
       }<br>
<br>
@@ -3092,10 +3112,13 @@ void SelectionDAGBuilder::visitAlloca(co<br>
     Align = 0;<br>
<br>
   // Round the size of the allocation up to the stack alignment size<br>
-  // by add SA-1 to the size.<br>
+  // by add SA-1 to the size. This doesn't overflow because we're computing<br>
+  // an address inside an alloca.<br>
+  SDNodeFlags Flags;<br>
+  Flags.setNoUnsignedWrap(true);<br>
   AllocSize = DAG.getNode(ISD::ADD, dl,<br>
                           AllocSize.getValueType(), AllocSize,<br>
-                          DAG.getIntPtrConstant(StackAlign - 1, dl));<br>
+                          DAG.getIntPtrConstant(StackAlign - 1, dl), &Flags);<br>
<br>
   // Mask out the low bits for alignment purposes.<br>
   AllocSize = DAG.getNode(ISD::AND, dl,<br>
@@ -3168,6 +3191,11 @@ void SelectionDAGBuilder::visitLoad(cons<br>
   if (isVolatile)<br>
     Root = TLI.prepareVolatileOrAtomicLoad(Root, dl, DAG);<br>
<br>
+  // An aggregate load cannot wrap around the address space, so offsets to its<br>
+  // parts don't wrap either.<br>
+  SDNodeFlags Flags;<br>
+  Flags.setNoUnsignedWrap(true);<br>
+<br>
   SmallVector<SDValue, 4> Values(NumValues);<br>
   SmallVector<SDValue, 4> Chains(std::min(MaxParallelChains, NumValues));<br>
   EVT PtrVT = Ptr.getValueType();<br>
@@ -3188,7 +3216,8 @@ void SelectionDAGBuilder::visitLoad(cons<br>
     }<br>
     SDValue A = DAG.getNode(ISD::ADD, dl,<br>
                             PtrVT, Ptr,<br>
-                            DAG.getConstant(Offsets[i], dl, PtrVT));<br>
+                            DAG.getConstant(Offsets[i], dl, PtrVT),<br>
+                            &Flags);<br>
     SDValue L = DAG.getLoad(ValueVTs[i], dl, Root,<br>
                             A, MachinePointerInfo(SV, Offsets[i]), isVolatile,<br>
                             isNonTemporal, isInvariant, Alignment, AAInfo,<br>
@@ -3243,6 +3272,11 @@ void SelectionDAGBuilder::visitStore(con<br>
   AAMDNodes AAInfo;<br>
   I.getAAMetadata(AAInfo);<br>
<br>
+  // An aggregate load cannot wrap around the address space, so offsets to its<br>
+  // parts don't wrap either.<br>
+  SDNodeFlags Flags;<br>
+  Flags.setNoUnsignedWrap(true);<br>
+<br>
   unsigned ChainI = 0;<br>
   for (unsigned i = 0; i != NumValues; ++i, ++ChainI) {<br>
     // See visitLoad comments.<br>
@@ -3253,7 +3287,7 @@ void SelectionDAGBuilder::visitStore(con<br>
       ChainI = 0;<br>
     }<br>
     SDValue Add = DAG.getNode(ISD::ADD, dl, PtrVT, Ptr,<br>
-                              DAG.getConstant(Offsets[i], dl, PtrVT));<br>
+                              DAG.getConstant(Offsets[i], dl, PtrVT), &Flags);<br>
     SDValue St = DAG.getStore(Root, dl,<br>
                               SDValue(Src.getNode(), Src.getResNo() + i),<br>
                               Add, MachinePointerInfo(PtrV, Offsets[i]),<br>
@@ -7202,10 +7236,15 @@ TargetLowering::LowerCallTo(TargetLoweri<br>
     ReturnValues.resize(NumValues);<br>
     SmallVector<SDValue, 4> Chains(NumValues);<br>
<br>
+    // An aggregate return value cannot wrap around the address space, so<br>
+    // offsets to its parts don't wrap either.<br>
+    SDNodeFlags Flags;<br>
+    Flags.setNoUnsignedWrap(true);<br>
+<br>
     for (unsigned i = 0; i < NumValues; ++i) {<br>
       SDValue Add = CLI.DAG.getNode(ISD::ADD, CLI.DL, PtrVT, DemoteStackSlot,<br>
                                     CLI.DAG.getConstant(Offsets[i], CLI.DL,<br>
-                                                        PtrVT));<br>
+                                                        PtrVT), &Flags);<br>
       SDValue L = CLI.DAG.getLoad(<br>
           RetTys[i], CLI.DL, CLI.Chain, Add,<br>
           MachinePointerInfo::getFixedStack(CLI.DAG.getMachineFunction(),<br>
<br>
Modified: llvm/trunk/test/CodeGen/WebAssembly/offset.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/offset.ll?rev=256890&r1=256889&r2=256890&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/offset.ll?rev=256890&r1=256889&r2=256890&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/CodeGen/WebAssembly/offset.ll (original)<br>
+++ llvm/trunk/test/CodeGen/WebAssembly/offset.ll Tue Jan  5 18:43:06 2016<br>
@@ -17,6 +17,28 @@ define i32 @load_i32_with_folded_offset(<br>
   ret i32 %t<br>
 }<br>
<br>
+; With an inbounds gep, we can fold an offset.<br>
+<br>
+; CHECK-LABEL: load_i32_with_folded_gep_offset:<br>
+; CHECK: i32.load  $push0=, 24($0){{$}}<br>
+define i32 @load_i32_with_folded_gep_offset(i32* %p) {<br>
+  %s = getelementptr inbounds i32, i32* %p, i32 6<br>
+  %t = load i32, i32* %s<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; We can't fold a negative offset though, even with an inbounds gep.<br>
+<br>
+; CHECK-LABEL: load_i32_with_unfolded_gep_negative_offset:<br>
+; CHECK: i32.const $push0=, -24{{$}}<br>
+; CHECK: i32.add   $push1=, $0, $pop0{{$}}<br>
+; CHECK: i32.load  $push2=, 0($pop1){{$}}<br>
+define i32 @load_i32_with_unfolded_gep_negative_offset(i32* %p) {<br>
+  %s = getelementptr inbounds i32, i32* %p, i32 -6<br>
+  %t = load i32, i32* %s<br>
+  ret i32 %t<br>
+}<br>
+<br>
 ; Without nuw, and even with nsw, we can't fold an offset.<br>
<br>
 ; CHECK-LABEL: load_i32_with_unfolded_offset:<br>
@@ -31,6 +53,18 @@ define i32 @load_i32_with_unfolded_offse<br>
   ret i32 %t<br>
 }<br>
<br>
+; Without inbounds, we can't fold a gep offset.<br>
+<br>
+; CHECK-LABEL: load_i32_with_unfolded_gep_offset:<br>
+; CHECK: i32.const $push0=, 24{{$}}<br>
+; CHECK: i32.add   $push1=, $0, $pop0{{$}}<br>
+; CHECK: i32.load  $push2=, 0($pop1){{$}}<br>
+define i32 @load_i32_with_unfolded_gep_offset(i32* %p) {<br>
+  %s = getelementptr i32, i32* %p, i32 6<br>
+  %t = load i32, i32* %s<br>
+  ret i32 %t<br>
+}<br>
+<br>
 ; Same as above but with i64.<br>
<br>
 ; CHECK-LABEL: load_i64_with_folded_offset:<br>
@@ -45,6 +79,28 @@ define i64 @load_i64_with_folded_offset(<br>
<br>
 ; Same as above but with i64.<br>
<br>
+; CHECK-LABEL: load_i64_with_folded_gep_offset:<br>
+; CHECK: i64.load  $push0=, 24($0){{$}}<br>
+define i64 @load_i64_with_folded_gep_offset(i64* %p) {<br>
+  %s = getelementptr inbounds i64, i64* %p, i32 3<br>
+  %t = load i64, i64* %s<br>
+  ret i64 %t<br>
+}<br>
+<br>
+; Same as above but with i64.<br>
+<br>
+; CHECK-LABEL: load_i64_with_unfolded_gep_negative_offset:<br>
+; CHECK: i32.const $push0=, -24{{$}}<br>
+; CHECK: i32.add   $push1=, $0, $pop0{{$}}<br>
+; CHECK: i64.load  $push2=, 0($pop1){{$}}<br>
+define i64 @load_i64_with_unfolded_gep_negative_offset(i64* %p) {<br>
+  %s = getelementptr inbounds i64, i64* %p, i32 -3<br>
+  %t = load i64, i64* %s<br>
+  ret i64 %t<br>
+}<br>
+<br>
+; Same as above but with i64.<br>
+<br>
 ; CHECK-LABEL: load_i64_with_unfolded_offset:<br>
 ; CHECK: i32.const $push0=, 24{{$}}<br>
 ; CHECK: i32.add   $push1=, $0, $pop0{{$}}<br>
@@ -57,6 +113,18 @@ define i64 @load_i64_with_unfolded_offse<br>
   ret i64 %t<br>
 }<br>
<br>
+; Same as above but with i64.<br>
+<br>
+; CHECK-LABEL: load_i64_with_unfolded_gep_offset:<br>
+; CHECK: i32.const $push0=, 24{{$}}<br>
+; CHECK: i32.add   $push1=, $0, $pop0{{$}}<br>
+; CHECK: i64.load  $push2=, 0($pop1){{$}}<br>
+define i64 @load_i64_with_unfolded_gep_offset(i64* %p) {<br>
+  %s = getelementptr i64, i64* %p, i32 3<br>
+  %t = load i64, i64* %s<br>
+  ret i64 %t<br>
+}<br>
+<br>
 ; Same as above but with store.<br>
<br>
 ; CHECK-LABEL: store_i32_with_folded_offset:<br>
@@ -71,6 +139,28 @@ define void @store_i32_with_folded_offse<br>
<br>
 ; Same as above but with store.<br>
<br>
+; CHECK-LABEL: store_i32_with_folded_gep_offset:<br>
+; CHECK: i32.store $discard=, 24($0), $pop0{{$}}<br>
+define void @store_i32_with_folded_gep_offset(i32* %p) {<br>
+  %s = getelementptr inbounds i32, i32* %p, i32 6<br>
+  store i32 0, i32* %s<br>
+  ret void<br>
+}<br>
+<br>
+; Same as above but with store.<br>
+<br>
+; CHECK-LABEL: store_i32_with_unfolded_gep_negative_offset:<br>
+; CHECK: i32.const $push0=, -24{{$}}<br>
+; CHECK: i32.add   $push1=, $0, $pop0{{$}}<br>
+; CHECK: i32.store $discard=, 0($pop1), $pop2{{$}}<br>
+define void @store_i32_with_unfolded_gep_negative_offset(i32* %p) {<br>
+  %s = getelementptr inbounds i32, i32* %p, i32 -6<br>
+  store i32 0, i32* %s<br>
+  ret void<br>
+}<br>
+<br>
+; Same as above but with store.<br>
+<br>
 ; CHECK-LABEL: store_i32_with_unfolded_offset:<br>
 ; CHECK: i32.const $push0=, 24{{$}}<br>
 ; CHECK: i32.add   $push1=, $0, $pop0{{$}}<br>
@@ -83,6 +173,18 @@ define void @store_i32_with_unfolded_off<br>
   ret void<br>
 }<br>
<br>
+; Same as above but with store.<br>
+<br>
+; CHECK-LABEL: store_i32_with_unfolded_gep_offset:<br>
+; CHECK: i32.const $push0=, 24{{$}}<br>
+; CHECK: i32.add   $push1=, $0, $pop0{{$}}<br>
+; CHECK: i32.store $discard=, 0($pop1), $pop2{{$}}<br>
+define void @store_i32_with_unfolded_gep_offset(i32* %p) {<br>
+  %s = getelementptr i32, i32* %p, i32 6<br>
+  store i32 0, i32* %s<br>
+  ret void<br>
+}<br>
+<br>
 ; Same as above but with store with i64.<br>
<br>
 ; CHECK-LABEL: store_i64_with_folded_offset:<br>
@@ -97,6 +199,28 @@ define void @store_i64_with_folded_offse<br>
<br>
 ; Same as above but with store with i64.<br>
<br>
+; CHECK-LABEL: store_i64_with_folded_gep_offset:<br>
+; CHECK: i64.store $discard=, 24($0), $pop0{{$}}<br>
+define void @store_i64_with_folded_gep_offset(i64* %p) {<br>
+  %s = getelementptr inbounds i64, i64* %p, i32 3<br>
+  store i64 0, i64* %s<br>
+  ret void<br>
+}<br>
+<br>
+; Same as above but with store with i64.<br>
+<br>
+; CHECK-LABEL: store_i64_with_unfolded_gep_negative_offset:<br>
+; CHECK: i32.const $push0=, -24{{$}}<br>
+; CHECK: i32.add   $push1=, $0, $pop0{{$}}<br>
+; CHECK: i64.store $discard=, 0($pop1), $pop2{{$}}<br>
+define void @store_i64_with_unfolded_gep_negative_offset(i64* %p) {<br>
+  %s = getelementptr inbounds i64, i64* %p, i32 -3<br>
+  store i64 0, i64* %s<br>
+  ret void<br>
+}<br>
+<br>
+; Same as above but with store with i64.<br>
+<br>
 ; CHECK-LABEL: store_i64_with_unfolded_offset:<br>
 ; CHECK: i32.const $push0=, 24{{$}}<br>
 ; CHECK: i32.add   $push1=, $0, $pop0{{$}}<br>
@@ -109,6 +233,18 @@ define void @store_i64_with_unfolded_off<br>
   ret void<br>
 }<br>
<br>
+; Same as above but with store with i64.<br>
+<br>
+; CHECK-LABEL: store_i64_with_unfolded_gep_offset:<br>
+; CHECK: i32.const $push0=, 24{{$}}<br>
+; CHECK: i32.add   $push1=, $0, $pop0{{$}}<br>
+; CHECK: i64.store $discard=, 0($pop1), $pop2{{$}}<br>
+define void @store_i64_with_unfolded_gep_offset(i64* %p) {<br>
+  %s = getelementptr i64, i64* %p, i32 3<br>
+  store i64 0, i64* %s<br>
+  ret void<br>
+}<br>
+<br>
 ; When loading from a fixed address, materialize a zero.<br>
<br>
 ; CHECK-LABEL: load_i32_from_numeric_address<br>
@@ -159,6 +295,17 @@ define i32 @load_i8_s_with_folded_offset<br>
   ret i32 %u<br>
 }<br>
<br>
+; Fold a gep offset into a sign-extending load.<br>
+<br>
+; CHECK-LABEL: load_i8_s_with_folded_gep_offset:<br>
+; CHECK: i32.load8_s $push0=, 24($0){{$}}<br>
+define i32 @load_i8_s_with_folded_gep_offset(i8* %p) {<br>
+  %s = getelementptr inbounds i8, i8* %p, i32 24<br>
+  %t = load i8, i8* %s<br>
+  %u = sext i8 %t to i32<br>
+  ret i32 %u<br>
+}<br>
+<br>
 ; Fold an offset into a zero-extending load.<br>
<br>
 ; CHECK-LABEL: load_i8_u_with_folded_offset:<br>
@@ -172,6 +319,17 @@ define i32 @load_i8_u_with_folded_offset<br>
   ret i32 %u<br>
 }<br>
<br>
+; Fold a gep offset into a zero-extending load.<br>
+<br>
+; CHECK-LABEL: load_i8_u_with_folded_gep_offset:<br>
+; CHECK: i32.load8_u $push0=, 24($0){{$}}<br>
+define i32 @load_i8_u_with_folded_gep_offset(i8* %p) {<br>
+  %s = getelementptr inbounds i8, i8* %p, i32 24<br>
+  %t = load i8, i8* %s<br>
+  %u = zext i8 %t to i32<br>
+  ret i32 %u<br>
+}<br>
+<br>
 ; Fold an offset into a truncating store.<br>
<br>
 ; CHECK-LABEL: store_i8_with_folded_offset:<br>
@@ -183,3 +341,43 @@ define void @store_i8_with_folded_offset<br>
   store i8 0, i8* %s<br>
   ret void<br>
 }<br>
+<br>
+; Fold a gep offset into a truncating store.<br>
+<br>
+; CHECK-LABEL: store_i8_with_folded_gep_offset:<br>
+; CHECK: i32.store8 $discard=, 24($0), $pop0{{$}}<br>
+define void @store_i8_with_folded_gep_offset(i8* %p) {<br>
+  %s = getelementptr inbounds i8, i8* %p, i32 24<br>
+  store i8 0, i8* %s<br>
+  ret void<br>
+}<br>
+<br>
+; Fold the offsets when lowering aggregate loads and stores.<br>
+<br>
+; CHECK-LABEL: aggregate_load_store:<br>
+; CHECK: i32.load  $2=, 0($0){{$}}<br>
+; CHECK: i32.load  $3=, 4($0){{$}}<br>
+; CHECK: i32.load  $4=, 8($0){{$}}<br>
+; CHECK: i32.load  $push0=, 12($0){{$}}<br>
+; CHECK: i32.store $discard=, 12($1), $pop0{{$}}<br>
+; CHECK: i32.store $discard=, 8($1), $4{{$}}<br>
+; CHECK: i32.store $discard=, 4($1), $3{{$}}<br>
+; CHECK: i32.store $discard=, 0($1), $2{{$}}<br>
+define void @aggregate_load_store({i32,i32,i32,i32}* %p, {i32,i32,i32,i32}* %q) {<br>
+  ; volatile so that things stay in order for the tests above<br>
+  %t = load volatile {i32,i32,i32,i32}, {i32, i32,i32,i32}* %p<br>
+  store volatile {i32,i32,i32,i32} %t, {i32, i32,i32,i32}* %q<br>
+  ret void<br>
+}<br>
+<br>
+; Fold the offsets when lowering aggregate return values.<br>
+<br>
+; CHECK-LABEL: aggregate_return:<br>
+; CHECK: i32.const   $push0=, 0{{$}}<br>
+; CHECK: i32.store   $push1=, 12($0), $pop0{{$}}<br>
+; CHECK: i32.store   $push2=, 8($0), $pop1{{$}}<br>
+; CHECK: i32.store   $push3=, 4($0), $pop2{{$}}<br>
+; CHECK: i32.store   $discard=, 0($0), $pop3{{$}}<br>
+define {i32,i32,i32,i32} @aggregate_return() {<br>
+  ret {i32,i32,i32,i32} zeroinitializer<br>
+}<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>
</div></div></blockquote></div><br></div>