[llvm] r256890 - [SelectionDAGBuilder] Set NoUnsignedWrap for inbounds gep and load/store offsets.

Dan Gohman via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 6 08:06:11 PST 2016


The assert is in eliminateFrameIndex, so this will be addressed within the
ongoing frame pointer work.

Dan


On Tue, Jan 5, 2016 at 9:14 PM, JF Bastien <jfb at chromium.org> wrote:

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


More information about the llvm-commits mailing list