From 52c7d8e4ebe3be0890880026e174fd2fe6544220 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Wed, 21 Aug 2013 19:53:10 +0000 Subject: [PATCH] Teach InstCombine about address spaces git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188926 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../InstCombine/InstCombineCasts.cpp | 45 +++-- .../InstCombine/InstCombineCompares.cpp | 9 +- test/Transforms/InstCombine/cast_ptr.ll | 21 ++- test/Transforms/InstCombine/getelementptr.ll | 86 ++++++++- test/Transforms/InstCombine/icmp.ll | 86 ++++++++- .../multi-size-address-space-pointer.ll | 112 ++++++++++++ test/Transforms/InstCombine/sub.ll | 171 ++++++++++++------ 7 files changed, 439 insertions(+), 91 deletions(-) create mode 100644 test/Transforms/InstCombine/multi-size-address-space-pointer.ll diff --git a/lib/Transforms/InstCombine/InstCombineCasts.cpp b/lib/Transforms/InstCombine/InstCombineCasts.cpp index 76796b9163f..a35631fc15c 100644 --- a/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ b/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -1338,14 +1338,18 @@ Instruction *InstCombiner::visitIntToPtr(IntToPtrInst &CI) { // If the source integer type is not the intptr_t type for this target, do a // trunc or zext to the intptr_t type, then inttoptr of it. This allows the // cast to be exposed to other transforms. - if (TD && CI.getOperand(0)->getType()->getScalarSizeInBits() != - TD->getPointerSizeInBits()) { - Type *Ty = TD->getIntPtrType(CI.getContext()); - if (CI.getType()->isVectorTy()) // Handle vectors of pointers. - Ty = VectorType::get(Ty, CI.getType()->getVectorNumElements()); - - Value *P = Builder->CreateZExtOrTrunc(CI.getOperand(0), Ty); - return new IntToPtrInst(P, CI.getType()); + + if (TD) { + unsigned AS = CI.getAddressSpace(); + if (CI.getOperand(0)->getType()->getScalarSizeInBits() != + TD->getPointerSizeInBits(AS)) { + Type *Ty = TD->getIntPtrType(CI.getContext(), AS); + if (CI.getType()->isVectorTy()) // Handle vectors of pointers. + Ty = VectorType::get(Ty, CI.getType()->getVectorNumElements()); + + Value *P = Builder->CreateZExtOrTrunc(CI.getOperand(0), Ty); + return new IntToPtrInst(P, CI.getType()); + } } if (Instruction *I = commonCastTransforms(CI)) @@ -1377,7 +1381,8 @@ Instruction *InstCombiner::commonPointerCastTransforms(CastInst &CI) { // GEP computes a constant offset, see if we can convert these three // instructions into fewer. This typically happens with unions and other // non-type-safe code. - unsigned OffsetBits = TD->getPointerSizeInBits(); + unsigned AS = GEP->getPointerAddressSpace(); + unsigned OffsetBits = TD->getPointerSizeInBits(AS); APInt Offset(OffsetBits, 0); BitCastInst *BCI = dyn_cast(GEP->getOperand(0)); if (GEP->hasOneUse() && @@ -1412,16 +1417,22 @@ Instruction *InstCombiner::visitPtrToInt(PtrToIntInst &CI) { // If the destination integer type is not the intptr_t type for this target, // do a ptrtoint to intptr_t then do a trunc or zext. This allows the cast // to be exposed to other transforms. - if (TD && CI.getType()->getScalarSizeInBits() != TD->getPointerSizeInBits()) { - Type *Ty = TD->getIntPtrType(CI.getContext()); - if (CI.getType()->isVectorTy()) // Handle vectors of pointers. - Ty = VectorType::get(Ty, CI.getType()->getVectorNumElements()); - Value *P = Builder->CreatePtrToInt(CI.getOperand(0), Ty); - return CastInst::CreateIntegerCast(P, CI.getType(), /*isSigned=*/false); - } + if (!TD) + return commonPointerCastTransforms(CI); + + Type *Ty = CI.getType(); + unsigned AS = CI.getPointerAddressSpace(); + + if (Ty->getScalarSizeInBits() == TD->getPointerSizeInBits(AS)) + return commonPointerCastTransforms(CI); + + Type *PtrTy = TD->getIntPtrType(CI.getContext(), AS); + if (Ty->isVectorTy()) // Handle vectors of pointers. + PtrTy = VectorType::get(PtrTy, Ty->getVectorNumElements()); - return commonPointerCastTransforms(CI); + Value *P = Builder->CreatePtrToInt(CI.getOperand(0), PtrTy); + return CastInst::CreateIntegerCast(P, Ty, /*isSigned=*/false); } /// OptimizeVectorResize - This input value (which is known to have vector type) diff --git a/lib/Transforms/InstCombine/InstCombineCompares.cpp b/lib/Transforms/InstCombine/InstCombineCompares.cpp index 93466ead422..18a08725039 100644 --- a/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -563,16 +563,18 @@ static Value *EvaluateGEPOffsetExpression(User *GEP, InstCombiner &IC) { } } + + // Okay, we know we have a single variable index, which must be a // pointer/array/vector index. If there is no offset, life is simple, return // the index. - unsigned IntPtrWidth = TD.getPointerSizeInBits(); + Type *IntPtrTy = TD.getIntPtrType(GEP->getOperand(0)->getType()); + unsigned IntPtrWidth = IntPtrTy->getIntegerBitWidth(); if (Offset == 0) { // Cast to intptrty in case a truncation occurs. If an extension is needed, // we don't need to bother extending: the extension won't affect where the // computation crosses zero. if (VariableIdx->getType()->getPrimitiveSizeInBits() > IntPtrWidth) { - Type *IntPtrTy = TD.getIntPtrType(VariableIdx->getContext()); VariableIdx = IC.Builder->CreateTrunc(VariableIdx, IntPtrTy); } return VariableIdx; @@ -594,7 +596,6 @@ static Value *EvaluateGEPOffsetExpression(User *GEP, InstCombiner &IC) { return 0; // Okay, we can do this evaluation. Start by converting the index to intptr. - Type *IntPtrTy = TD.getIntPtrType(VariableIdx->getContext()); if (VariableIdx->getType() != IntPtrTy) VariableIdx = IC.Builder->CreateIntCast(VariableIdx, IntPtrTy, true /*Signed*/); @@ -2478,7 +2479,7 @@ Instruction *InstCombiner::visitICmpInst(ICmpInst &I) { case Instruction::IntToPtr: // icmp pred inttoptr(X), null -> icmp pred X, 0 if (RHSC->isNullValue() && TD && - TD->getIntPtrType(RHSC->getContext()) == + TD->getIntPtrType(RHSC->getType()) == LHSI->getOperand(0)->getType()) return new ICmpInst(I.getPredicate(), LHSI->getOperand(0), Constant::getNullValue(LHSI->getOperand(0)->getType())); diff --git a/test/Transforms/InstCombine/cast_ptr.ll b/test/Transforms/InstCombine/cast_ptr.ll index 7910ea333ad..62166adf01e 100644 --- a/test/Transforms/InstCombine/cast_ptr.ll +++ b/test/Transforms/InstCombine/cast_ptr.ll @@ -1,7 +1,7 @@ ; Tests to make sure elimination of casts is working correctly ; RUN: opt < %s -instcombine -S | FileCheck %s -target datalayout = "p:32:32" +target datalayout = "p:32:32-p1:32:32-p2:16:16" ; This shouldn't convert to getelementptr because the relationship ; between the arithmetic and the layout of allocated memory is @@ -43,11 +43,20 @@ define i1 @test4(i32 %A) { ret i1 %C ; CHECK-LABEL: @test4( ; CHECK-NEXT: %C = icmp eq i32 %A, 0 -; CHECK-NEXT: ret i1 %C +; CHECK-NEXT: ret i1 %C } +define i1 @test4_as2(i16 %A) { +; CHECK-LABEL: @test4_as2( +; CHECK-NEXT: %C = icmp eq i16 %A, 0 +; CHECK-NEXT: ret i1 %C + %B = inttoptr i16 %A to i8 addrspace(2)* + %C = icmp eq i8 addrspace(2)* %B, null + ret i1 %C +} -; Pulling the cast out of the load allows us to eliminate the load, and then + +; Pulling the cast out of the load allows us to eliminate the load, and then ; the whole array. %op = type { float } @@ -69,11 +78,11 @@ define %unop* @test5(%op* %O) { ; InstCombine can not 'load (cast P)' -> cast (load P)' if the cast changes ; the address space. -define i8 @test6(i8 addrspace(1)* %source) { -entry: +define i8 @test6(i8 addrspace(1)* %source) { +entry: %arrayidx223 = bitcast i8 addrspace(1)* %source to i8* %tmp4 = load i8* %arrayidx223 ret i8 %tmp4 ; CHECK-LABEL: @test6( ; CHECK: load i8* %arrayidx223 -} +} diff --git a/test/Transforms/InstCombine/getelementptr.ll b/test/Transforms/InstCombine/getelementptr.ll index a5d5ddc9016..ff8ad63cef3 100644 --- a/test/Transforms/InstCombine/getelementptr.ll +++ b/test/Transforms/InstCombine/getelementptr.ll @@ -185,6 +185,28 @@ define <2 x i1> @test13_vector(<2 x i64> %X, <2 x %S*> %P) nounwind { ret <2 x i1> %C } +define i1 @test13_as1(i16 %X, %S addrspace(1)* %P) { +; CHECK-LABEL: @test13_as1( +; CHECK-NEXT: %C = icmp eq i16 %X, -1 +; CHECK-NEXT: ret i1 %C + %A = getelementptr inbounds %S addrspace(1)* %P, i16 0, i32 1, i16 %X + %B = getelementptr inbounds %S addrspace(1)* %P, i16 0, i32 0 + %C = icmp eq i32 addrspace(1)* %A, %B + ret i1 %C +} + +define <2 x i1> @test13_vector_as1(<2 x i16> %X, <2 x %S addrspace(1)*> %P) { +; CHECK-LABEL: @test13_vector_as1( +; CHECK-NEXT: shl nuw <2 x i16> %X, +; CHECK-NEXT: add <2 x i16> %A.idx, +; CHECK-NEXT: icmp eq <2 x i16> %A.offs, zeroinitializer +; CHECK-NEXT: ret <2 x i1> + %A = getelementptr inbounds <2 x %S addrspace(1)*> %P, <2 x i16> , <2 x i32> , <2 x i16> %X + %B = getelementptr inbounds <2 x %S addrspace(1)*> %P, <2 x i16> , <2 x i32> + %C = icmp eq <2 x i32 addrspace(1)*> %A, %B + ret <2 x i1> %C +} + define i1 @test13_i32(i32 %X, %S* %P) { ; CHECK-LABEL: @test13_i32( ; CHECK: %C = icmp eq i32 %X, -1 @@ -258,6 +280,28 @@ define i1 @test18(i16* %P, i32 %I) { ; CHECK: %C = icmp slt i32 %I, 0 } +; Larger than the pointer size for a non-zero address space +define i1 @test18_as1(i16 addrspace(1)* %P, i32 %I) { +; CHECK-LABEL: @test18_as1( +; CHECK-NEXT: %1 = trunc i32 %I to i16 +; CHECK-NEXT: %C = icmp slt i16 %1, 0 +; CHECK-NEXT: ret i1 %C + %X = getelementptr inbounds i16 addrspace(1)* %P, i32 %I + %C = icmp ult i16 addrspace(1)* %X, %P + ret i1 %C +} + +; Smaller than the pointer size for a non-zero address space +define i1 @test18_as1_i32(i16 addrspace(1)* %P, i32 %I) { +; CHECK-LABEL: @test18_as1_i32( +; CHECK-NEXT: %1 = trunc i32 %I to i16 +; CHECK-NEXT: %C = icmp slt i16 %1, 0 +; CHECK-NEXT: ret i1 %C + %X = getelementptr inbounds i16 addrspace(1)* %P, i32 %I + %C = icmp ult i16 addrspace(1)* %X, %P + ret i1 %C +} + ; Smaller than pointer size define i1 @test18_i16(i16* %P, i16 %I) { ; CHECK-LABEL: @test18_i16( @@ -503,15 +547,38 @@ define i8* @test32(i8* %v) { %struct.Key = type { { i32, i32 } } %struct.anon = type <{ i8, [3 x i8], i32 }> -define i32 *@test33(%struct.Key *%A) { - %B = bitcast %struct.Key* %A to %struct.anon* - %C = getelementptr %struct.anon* %B, i32 0, i32 2 - ret i32 *%C +define i32* @test33(%struct.Key* %A) { ; CHECK-LABEL: @test33( ; CHECK: getelementptr %struct.Key* %A, i64 0, i32 0, i32 1 + %B = bitcast %struct.Key* %A to %struct.anon* + %C = getelementptr %struct.anon* %B, i32 0, i32 2 + ret i32* %C +} + +define i32 addrspace(1)* @test33_as1(%struct.Key addrspace(1)* %A) { +; CHECK-LABEL: @test33_as1( +; CHECK: getelementptr %struct.Key addrspace(1)* %A, i16 0, i32 0, i32 1 + %B = bitcast %struct.Key addrspace(1)* %A to %struct.anon addrspace(1)* + %C = getelementptr %struct.anon addrspace(1)* %B, i32 0, i32 2 + ret i32 addrspace(1)* %C } +define i32 addrspace(1)* @test33_array_as1([10 x i32] addrspace(1)* %A) { +; CHECK-LABEL: @test33_array_as1( +; CHECK: getelementptr [10 x i32] addrspace(1)* %A, i16 0, i16 2 + %B = bitcast [10 x i32] addrspace(1)* %A to [5 x i32] addrspace(1)* + %C = getelementptr [5 x i32] addrspace(1)* %B, i32 0, i32 2 + ret i32 addrspace(1)* %C +} +; Make sure the GEP indices use the right pointer sized integer +define i32 addrspace(1)* @test33_array_struct_as1([10 x %struct.Key] addrspace(1)* %A) { +; CHECK-LABEL: @test33_array_struct_as1( +; CHECK: getelementptr [10 x %struct.Key] addrspace(1)* %A, i16 0, i16 1, i32 0, i32 0 + %B = bitcast [10 x %struct.Key] addrspace(1)* %A to [20 x i32] addrspace(1)* + %C = getelementptr [20 x i32] addrspace(1)* %B, i32 0, i32 2 + ret i32 addrspace(1)* %C +} %T2 = type { i8*, i8 } define i8* @test34(i8* %Val, i64 %V) nounwind { @@ -638,6 +705,17 @@ define i1 @pr16483([1 x i8]* %a, [1 x i8]* %b) { ; CHECK-NEXT: icmp ult [1 x i8]* %a, %b } +define i8 @test_gep_bitcast_as1(i32 addrspace(1)* %arr, i16 %N) { +; CHECK-LABEL: @test_gep_bitcast_as1( +; CHECK: getelementptr i32 addrspace(1)* %arr, i16 %N +; CHECK: bitcast + %cast = bitcast i32 addrspace(1)* %arr to i8 addrspace(1)* + %V = mul i16 %N, 4 + %t = getelementptr i8 addrspace(1)* %cast, i16 %V + %x = load i8 addrspace(1)* %t + ret i8 %x +} + ; The element size of the array matches the element size of the pointer define i64 @test_gep_bitcast_array_same_size_element([100 x double]* %arr, i64 %N) { ; CHECK-LABEL: @test_gep_bitcast_array_same_size_element( diff --git a/test/Transforms/InstCombine/icmp.ll b/test/Transforms/InstCombine/icmp.ll index dfeac676e13..33636c47d3d 100644 --- a/test/Transforms/InstCombine/icmp.ll +++ b/test/Transforms/InstCombine/icmp.ll @@ -1,7 +1,7 @@ ; RUN: opt < %s -instcombine -S | FileCheck %s target datalayout = -"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" +"e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" define i32 @test1(i32 %X) { entry: @@ -79,7 +79,7 @@ entry: define i1 @test8(i32 %x){ entry: - %a = add i32 %x, -1 + %a = add i32 %x, -1 %b = icmp eq i32 %a, %x ret i1 %b ; CHECK-LABEL: @test8( @@ -89,7 +89,7 @@ entry: define i1 @test9(i32 %x) { entry: %a = add i32 %x, -2 - %b = icmp ugt i32 %x, %a + %b = icmp ugt i32 %x, %a ret i1 %b ; CHECK-LABEL: @test9( ; CHECK: icmp ugt i32 %x, 1 @@ -98,10 +98,9 @@ entry: define i1 @test10(i32 %x){ entry: - %a = add i32 %x, -1 - %b = icmp slt i32 %a, %x + %a = add i32 %x, -1 + %b = icmp slt i32 %a, %x ret i1 %b - ; CHECK-LABEL: @test10( ; CHECK: %b = icmp ne i32 %x, -2147483648 ; CHECK: ret i1 %b @@ -234,6 +233,18 @@ define i1 @test24(i64 %i) { ret i1 %cmp } +@X_as1 = addrspace(1) global [1000 x i32] zeroinitializer + +; CHECK: @test24_as1 +; CHECK: trunc i64 %i to i16 +; CHECK: %cmp = icmp eq i16 %1, 1000 +; CHECK: ret i1 %cmp +define i1 @test24_as1(i64 %i) { + %p1 = getelementptr inbounds i32 addrspace(1)* getelementptr inbounds ([1000 x i32] addrspace(1)* @X_as1, i64 0, i64 0), i64 %i + %cmp = icmp eq i32 addrspace(1)* %p1, getelementptr inbounds ([1000 x i32] addrspace(1)* @X_as1, i64 1, i64 0) + ret i1 %cmp +} + ; CHECK-LABEL: @test25( ; X + Z > Y + Z -> X > Y if there is no overflow. ; CHECK: %c = icmp sgt i32 %x, %y @@ -473,7 +484,7 @@ define <2 x i1> @test49(<2 x i32> %tmp3) { entry: %tmp11 = and <2 x i32> %tmp3, %cmp = icmp ult <2 x i32> %tmp11, - ret <2 x i1> %cmp + ret <2 x i1> %cmp } ; PR9343 #7 @@ -603,6 +614,21 @@ define i1 @test59(i8* %foo) { ; CHECK: ret i1 true } +define i1 @test59_as1(i8 addrspace(1)* %foo) { + %bit = bitcast i8 addrspace(1)* %foo to i32 addrspace(1)* + %gep1 = getelementptr inbounds i32 addrspace(1)* %bit, i64 2 + %gep2 = getelementptr inbounds i8 addrspace(1)* %foo, i64 10 + %cast1 = bitcast i32 addrspace(1)* %gep1 to i8 addrspace(1)* + %cmp = icmp ult i8 addrspace(1)* %cast1, %gep2 + %use = ptrtoint i8 addrspace(1)* %cast1 to i64 + %call = call i32 @test58_d(i64 %use) nounwind + ret i1 %cmp +; CHECK: @test59_as1 +; CHECK: %[[GEP:.+]] = getelementptr inbounds i8 addrspace(1)* %foo, i16 8 +; CHECK: ptrtoint i8 addrspace(1)* %[[GEP]] to i16 +; CHECK: ret i1 true +} + define i1 @test60(i8* %foo, i64 %i, i64 %j) { %bit = bitcast i8* %foo to i32* %gep1 = getelementptr inbounds i32* %bit, i64 %i @@ -616,6 +642,21 @@ define i1 @test60(i8* %foo, i64 %i, i64 %j) { ; CHECK-NEXT: ret i1 } +define i1 @test60_as1(i8 addrspace(1)* %foo, i64 %i, i64 %j) { + %bit = bitcast i8 addrspace(1)* %foo to i32 addrspace(1)* + %gep1 = getelementptr inbounds i32 addrspace(1)* %bit, i64 %i + %gep2 = getelementptr inbounds i8 addrspace(1)* %foo, i64 %j + %cast1 = bitcast i32 addrspace(1)* %gep1 to i8 addrspace(1)* + %cmp = icmp ult i8 addrspace(1)* %cast1, %gep2 + ret i1 %cmp +; CHECK: @test60_as1 +; CHECK: trunc i64 %i to i16 +; CHECK: trunc i64 %j to i16 +; CHECK: %gep1.idx = shl nuw i16 %{{.+}}, 2 +; CHECK-NEXT: icmp sgt i16 %{{.+}}, %gep1.idx +; CHECK-NEXT: ret i1 +} + define i1 @test61(i8* %foo, i64 %i, i64 %j) { %bit = bitcast i8* %foo to i32* %gep1 = getelementptr i32* %bit, i64 %i @@ -629,6 +670,19 @@ define i1 @test61(i8* %foo, i64 %i, i64 %j) { ; CHECK-NEXT: ret i1 } +define i1 @test61_as1(i8 addrspace(1)* %foo, i16 %i, i16 %j) { + %bit = bitcast i8 addrspace(1)* %foo to i32 addrspace(1)* + %gep1 = getelementptr i32 addrspace(1)* %bit, i16 %i + %gep2 = getelementptr i8 addrspace(1)* %foo, i16 %j + %cast1 = bitcast i32 addrspace(1)* %gep1 to i8 addrspace(1)* + %cmp = icmp ult i8 addrspace(1)* %cast1, %gep2 + ret i1 %cmp +; Don't transform non-inbounds GEPs. +; CHECK: @test61_as1 +; CHECK: icmp ult i8 addrspace(1)* %cast1, %gep2 +; CHECK-NEXT: ret i1 +} + define i1 @test62(i8* %a) { %arrayidx1 = getelementptr inbounds i8* %a, i64 1 %arrayidx2 = getelementptr inbounds i8* %a, i64 10 @@ -638,6 +692,15 @@ define i1 @test62(i8* %a) { ; CHECK-NEXT: ret i1 true } +define i1 @test62_as1(i8 addrspace(1)* %a) { +; CHECK-LABEL: @test62_as1( +; CHECK-NEXT: ret i1 true + %arrayidx1 = getelementptr inbounds i8 addrspace(1)* %a, i64 1 + %arrayidx2 = getelementptr inbounds i8 addrspace(1)* %a, i64 10 + %cmp = icmp slt i8 addrspace(1)* %arrayidx1, %arrayidx2 + ret i1 %cmp +} + define i1 @test63(i8 %a, i32 %b) nounwind { %z = zext i8 %a to i32 %t = and i32 %b, 255 @@ -999,6 +1062,15 @@ define i1 @test71(i8* %x) { ret i1 %c } +define i1 @test71_as1(i8 addrspace(1)* %x) { +; CHECK-LABEL: @test71_as1( +; CHECK-NEXT: ret i1 false + %a = getelementptr i8 addrspace(1)* %x, i64 8 + %b = getelementptr inbounds i8 addrspace(1)* %x, i64 8 + %c = icmp ugt i8 addrspace(1)* %a, %b + ret i1 %c +} + ; CHECK-LABEL: @icmp_shl_1_V_ult_32( ; CHECK-NEXT: [[CMP:%[a-z0-9]+]] = icmp ult i32 %V, 5 ; CHECK-NEXT: ret i1 [[CMP]] diff --git a/test/Transforms/InstCombine/multi-size-address-space-pointer.ll b/test/Transforms/InstCombine/multi-size-address-space-pointer.ll new file mode 100644 index 00000000000..2d88bed4e7b --- /dev/null +++ b/test/Transforms/InstCombine/multi-size-address-space-pointer.ll @@ -0,0 +1,112 @@ +; RUN: opt -S -instcombine %s -o - | FileCheck %s +target datalayout = "e-p:32:32:32-p1:64:64:64-p2:8:8:8-p3:16:16:16-p4:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:32" + + +define i32 @test_as0(i32 addrspace(0)* %a) { +; CHECK-LABEL: @test_as0( +; CHECK: %arrayidx = getelementptr i32* %a, i32 1 + %arrayidx = getelementptr i32 addrspace(0)* %a, i64 1 + %y = load i32 addrspace(0)* %arrayidx, align 4 + ret i32 %y +} + +define i32 @test_as1(i32 addrspace(1)* %a) { +; CHECK-LABEL: @test_as1( +; CHECK: %arrayidx = getelementptr i32 addrspace(1)* %a, i64 1 + %arrayidx = getelementptr i32 addrspace(1)* %a, i32 1 + %y = load i32 addrspace(1)* %arrayidx, align 4 + ret i32 %y +} + +define i32 @test_as2(i32 addrspace(2)* %a) { +; CHECK-LABEL: @test_as2( +; CHECK: %arrayidx = getelementptr i32 addrspace(2)* %a, i8 1 + %arrayidx = getelementptr i32 addrspace(2)* %a, i32 1 + %y = load i32 addrspace(2)* %arrayidx, align 4 + ret i32 %y +} + +define i32 @test_as3(i32 addrspace(3)* %a) { +; CHECK-LABEL: @test_as3( +; CHECK: %arrayidx = getelementptr i32 addrspace(3)* %a, i16 1 + %arrayidx = getelementptr i32 addrspace(3)* %a, i32 1 + %y = load i32 addrspace(3)* %arrayidx, align 4 + ret i32 %y +} + +define i32 @test_combine_ptrtoint(i32 addrspace(2)* %a) { +; CHECK-LABEL: @test_combine_ptrtoint( +; CHECK-NEXT: %y = load i32 addrspace(2)* %a +; CHECK-NEXT: ret i32 %y + %cast = ptrtoint i32 addrspace(2)* %a to i8 + %castback = inttoptr i8 %cast to i32 addrspace(2)* + %y = load i32 addrspace(2)* %castback, align 4 + ret i32 %y +} + +define i8 @test_combine_inttoptr(i8 %a) { +; CHECK-LABEL: @test_combine_inttoptr( +; CHECK-NEXT: ret i8 %a + %cast = inttoptr i8 %a to i32 addrspace(2)* + %castback = ptrtoint i32 addrspace(2)* %cast to i8 + ret i8 %castback +} + +define i32 @test_combine_vector_ptrtoint(<2 x i32 addrspace(2)*> %a) { +; CHECK-LABEL: @test_combine_vector_ptrtoint( +; CHECK-NEXT: %p = extractelement <2 x i32 addrspace(2)*> %a, i32 0 +; CHECK-NEXT: %y = load i32 addrspace(2)* %p, align 4 +; CHECK-NEXT: ret i32 %y + %cast = ptrtoint <2 x i32 addrspace(2)*> %a to <2 x i8> + %castback = inttoptr <2 x i8> %cast to <2 x i32 addrspace(2)*> + %p = extractelement <2 x i32 addrspace(2)*> %castback, i32 0 + %y = load i32 addrspace(2)* %p, align 4 + ret i32 %y +} + +define <2 x i8> @test_combine_vector_inttoptr(<2 x i8> %a) { +; CHECK-LABEL: @test_combine_vector_inttoptr( +; CHECK-NEXT: ret <2 x i8> %a + %cast = inttoptr <2 x i8> %a to <2 x i32 addrspace(2)*> + %castback = ptrtoint <2 x i32 addrspace(2)*> %cast to <2 x i8> + ret <2 x i8> %castback +} + +; Check that the GEP index is changed to the address space integer type (i64 -> i8) +define i32 addrspace(2)* @shrink_gep_constant_index_64_as2(i32 addrspace(2)* %p) { +; CHECK-LABEL: @shrink_gep_constant_index_64_as2( +; CHECK-NEXT: getelementptr i32 addrspace(2)* %p, i8 1 + %ret = getelementptr i32 addrspace(2)* %p, i64 1 + ret i32 addrspace(2)* %ret +} + +define i32 addrspace(2)* @shrink_gep_constant_index_32_as2(i32 addrspace(2)* %p) { +; CHECK-LABEL: @shrink_gep_constant_index_32_as2( +; CHECK-NEXT: getelementptr i32 addrspace(2)* %p, i8 1 + %ret = getelementptr i32 addrspace(2)* %p, i32 1 + ret i32 addrspace(2)* %ret +} + +define i32 addrspace(3)* @shrink_gep_constant_index_64_as3(i32 addrspace(3)* %p) { +; CHECK-LABEL: @shrink_gep_constant_index_64_as3( +; CHECK-NEXT: getelementptr i32 addrspace(3)* %p, i16 1 + %ret = getelementptr i32 addrspace(3)* %p, i64 1 + ret i32 addrspace(3)* %ret +} + +define i32 addrspace(2)* @shrink_gep_variable_index_64_as2(i32 addrspace(2)* %p, i64 %idx) { +; CHECK-LABEL: @shrink_gep_variable_index_64_as2( +; CHECK-NEXT: %1 = trunc i64 %idx to i8 +; CHECK-NEXT: getelementptr i32 addrspace(2)* %p, i8 %1 + %ret = getelementptr i32 addrspace(2)* %p, i64 %idx + ret i32 addrspace(2)* %ret +} + +define i32 addrspace(1)* @grow_gep_variable_index_8_as1(i32 addrspace(1)* %p, i8 %idx) { +; CHECK-LABEL: @grow_gep_variable_index_8_as1( +; CHECK-NEXT: %1 = sext i8 %idx to i64 +; CHECK-NEXT: getelementptr i32 addrspace(1)* %p, i64 %1 + %ret = getelementptr i32 addrspace(1)* %p, i8 %idx + ret i32 addrspace(1)* %ret +} + diff --git a/test/Transforms/InstCombine/sub.ll b/test/Transforms/InstCombine/sub.ll index 54496562b6d..36c523bd7b7 100644 --- a/test/Transforms/InstCombine/sub.ll +++ b/test/Transforms/InstCombine/sub.ll @@ -1,34 +1,34 @@ -target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" ; Optimize subtracts. ; ; RUN: opt < %s -instcombine -S | FileCheck %s define i32 @test1(i32 %A) { - %B = sub i32 %A, %A + %B = sub i32 %A, %A ret i32 %B ; CHECK-LABEL: @test1( ; CHECK: ret i32 0 } define i32 @test2(i32 %A) { - %B = sub i32 %A, 0 + %B = sub i32 %A, 0 ret i32 %B ; CHECK-LABEL: @test2( ; CHECK: ret i32 %A } define i32 @test3(i32 %A) { - %B = sub i32 0, %A - %C = sub i32 0, %B + %B = sub i32 0, %A + %C = sub i32 0, %B ret i32 %C ; CHECK-LABEL: @test3( ; CHECK: ret i32 %A } define i32 @test4(i32 %A, i32 %x) { - %B = sub i32 0, %A - %C = sub i32 %x, %B + %B = sub i32 0, %A + %C = sub i32 %x, %B ret i32 %C ; CHECK-LABEL: @test4( ; CHECK: %C = add i32 %x, %A @@ -36,8 +36,8 @@ define i32 @test4(i32 %A, i32 %x) { } define i32 @test5(i32 %A, i32 %B, i32 %C) { - %D = sub i32 %B, %C - %E = sub i32 %A, %D + %D = sub i32 %B, %C + %E = sub i32 %A, %D ret i32 %E ; CHECK-LABEL: @test5( ; CHECK: %D1 = sub i32 %C, %B @@ -46,17 +46,17 @@ define i32 @test5(i32 %A, i32 %B, i32 %C) { } define i32 @test6(i32 %A, i32 %B) { - %C = and i32 %A, %B - %D = sub i32 %A, %C + %C = and i32 %A, %B + %D = sub i32 %A, %C ret i32 %D ; CHECK-LABEL: @test6( ; CHECK-NEXT: xor i32 %B, -1 -; CHECK-NEXT: %D = and i32 +; CHECK-NEXT: %D = and i32 ; CHECK-NEXT: ret i32 %D } define i32 @test7(i32 %A) { - %B = sub i32 -1, %A + %B = sub i32 -1, %A ret i32 %B ; CHECK-LABEL: @test7( ; CHECK: %B = xor i32 %A, -1 @@ -64,8 +64,8 @@ define i32 @test7(i32 %A) { } define i32 @test8(i32 %A) { - %B = mul i32 9, %A - %C = sub i32 %B, %A + %B = mul i32 9, %A + %C = sub i32 %B, %A ret i32 %C ; CHECK-LABEL: @test8( ; CHECK: %C = shl i32 %A, 3 @@ -73,8 +73,8 @@ define i32 @test8(i32 %A) { } define i32 @test9(i32 %A) { - %B = mul i32 3, %A - %C = sub i32 %A, %B + %B = mul i32 3, %A + %C = sub i32 %A, %B ret i32 %C ; CHECK-LABEL: @test9( ; CHECK: %C = mul i32 %A, -2 @@ -82,9 +82,9 @@ define i32 @test9(i32 %A) { } define i32 @test10(i32 %A, i32 %B) { - %C = sub i32 0, %A - %D = sub i32 0, %B - %E = mul i32 %C, %D + %C = sub i32 0, %A + %D = sub i32 0, %B + %E = mul i32 %C, %D ret i32 %E ; CHECK-LABEL: @test10( ; CHECK: %E = mul i32 %A, %B @@ -92,8 +92,8 @@ define i32 @test10(i32 %A, i32 %B) { } define i32 @test10a(i32 %A) { - %C = sub i32 0, %A - %E = mul i32 %C, 7 + %C = sub i32 0, %A + %E = mul i32 %C, 7 ret i32 %E ; CHECK-LABEL: @test10a( ; CHECK: %E = mul i32 %A, -7 @@ -101,8 +101,8 @@ define i32 @test10a(i32 %A) { } define i1 @test11(i8 %A, i8 %B) { - %C = sub i8 %A, %B - %cD = icmp ne i8 %C, 0 + %C = sub i8 %A, %B + %cD = icmp ne i8 %C, 0 ret i1 %cD ; CHECK-LABEL: @test11( ; CHECK: %cD = icmp ne i8 %A, %B @@ -110,8 +110,8 @@ define i1 @test11(i8 %A, i8 %B) { } define i32 @test12(i32 %A) { - %B = ashr i32 %A, 31 - %C = sub i32 0, %B + %B = ashr i32 %A, 31 + %C = sub i32 0, %B ret i32 %C ; CHECK-LABEL: @test12( ; CHECK: %C = lshr i32 %A, 31 @@ -119,8 +119,8 @@ define i32 @test12(i32 %A) { } define i32 @test13(i32 %A) { - %B = lshr i32 %A, 31 - %C = sub i32 0, %B + %B = lshr i32 %A, 31 + %C = sub i32 0, %B ret i32 %C ; CHECK-LABEL: @test13( ; CHECK: %C = ashr i32 %A, 31 @@ -128,9 +128,9 @@ define i32 @test13(i32 %A) { } define i32 @test14(i32 %A) { - %B = lshr i32 %A, 31 - %C = bitcast i32 %B to i32 - %D = sub i32 0, %C + %B = lshr i32 %A, 31 + %C = bitcast i32 %B to i32 + %D = sub i32 0, %C ret i32 %D ; CHECK-LABEL: @test14( ; CHECK: %D = ashr i32 %A, 31 @@ -138,17 +138,17 @@ define i32 @test14(i32 %A) { } define i32 @test15(i32 %A, i32 %B) { - %C = sub i32 0, %A - %D = srem i32 %B, %C + %C = sub i32 0, %A + %D = srem i32 %B, %C ret i32 %D ; CHECK-LABEL: @test15( -; CHECK: %D = srem i32 %B, %A +; CHECK: %D = srem i32 %B, %A ; CHECK: ret i32 %D } define i32 @test16(i32 %A) { - %X = sdiv i32 %A, 1123 - %Y = sub i32 0, %X + %X = sdiv i32 %A, 1123 + %Y = sub i32 0, %X ret i32 %Y ; CHECK-LABEL: @test16( ; CHECK: %Y = sdiv i32 %A, -1123 @@ -158,8 +158,8 @@ define i32 @test16(i32 %A) { ; Can't fold subtract here because negation it might oveflow. ; PR3142 define i32 @test17(i32 %A) { - %B = sub i32 0, %A - %C = sdiv i32 %B, 1234 + %B = sub i32 0, %A + %C = sdiv i32 %B, 1234 ret i32 %C ; CHECK-LABEL: @test17( ; CHECK: %B = sub i32 0, %A @@ -168,25 +168,25 @@ define i32 @test17(i32 %A) { } define i64 @test18(i64 %Y) { - %tmp.4 = shl i64 %Y, 2 - %tmp.12 = shl i64 %Y, 2 - %tmp.8 = sub i64 %tmp.4, %tmp.12 + %tmp.4 = shl i64 %Y, 2 + %tmp.12 = shl i64 %Y, 2 + %tmp.8 = sub i64 %tmp.4, %tmp.12 ret i64 %tmp.8 ; CHECK-LABEL: @test18( ; CHECK: ret i64 0 } define i32 @test19(i32 %X, i32 %Y) { - %Z = sub i32 %X, %Y - %Q = add i32 %Z, %Y + %Z = sub i32 %X, %Y + %Q = add i32 %Z, %Y ret i32 %Q ; CHECK-LABEL: @test19( ; CHECK: ret i32 %X } define i1 @test20(i32 %g, i32 %h) { - %tmp.2 = sub i32 %g, %h - %tmp.4 = icmp ne i32 %tmp.2, %g + %tmp.2 = sub i32 %g, %h + %tmp.4 = icmp ne i32 %tmp.2, %g ret i1 %tmp.4 ; CHECK-LABEL: @test20( ; CHECK: %tmp.4 = icmp ne i32 %h, 0 @@ -194,8 +194,8 @@ define i1 @test20(i32 %g, i32 %h) { } define i1 @test21(i32 %g, i32 %h) { - %tmp.2 = sub i32 %g, %h - %tmp.4 = icmp ne i32 %tmp.2, %g + %tmp.2 = sub i32 %g, %h + %tmp.4 = icmp ne i32 %tmp.2, %g ret i1 %tmp.4 ; CHECK-LABEL: @test21( ; CHECK: %tmp.4 = icmp ne i32 %h, 0 @@ -204,9 +204,9 @@ define i1 @test21(i32 %g, i32 %h) { ; PR2298 define zeroext i1 @test22(i32 %a, i32 %b) nounwind { - %tmp2 = sub i32 0, %a - %tmp4 = sub i32 0, %b - %tmp5 = icmp eq i32 %tmp2, %tmp4 + %tmp2 = sub i32 0, %a + %tmp4 = sub i32 0, %b + %tmp5 = icmp eq i32 %tmp2, %tmp4 ret i1 %tmp5 ; CHECK-LABEL: @test22( ; CHECK: %tmp5 = icmp eq i32 %b, %a @@ -227,6 +227,19 @@ define i32 @test23(i8* %P, i64 %A){ ; CHECK-NEXT: ret i32 } +define i8 @test23_as1(i8 addrspace(1)* %P, i16 %A) { +; CHECK: @test23_as1 +; CHECK-NEXT: = trunc i16 %A to i8 +; CHECK-NEXT: ret i8 + %B = getelementptr inbounds i8 addrspace(1)* %P, i16 %A + %C = ptrtoint i8 addrspace(1)* %B to i16 + %D = trunc i16 %C to i8 + %E = ptrtoint i8 addrspace(1)* %P to i16 + %F = trunc i16 %E to i8 + %G = sub i8 %D, %F + ret i8 %G +} + define i64 @test24(i8* %P, i64 %A){ %B = getelementptr inbounds i8* %P, i64 %A %C = ptrtoint i8* %B to i64 @@ -237,6 +250,16 @@ define i64 @test24(i8* %P, i64 %A){ ; CHECK-NEXT: ret i64 %A } +define i16 @test24_as1(i8 addrspace(1)* %P, i16 %A) { +; CHECK: @test24_as1 +; CHECK-NEXT: ret i16 %A + %B = getelementptr inbounds i8 addrspace(1)* %P, i16 %A + %C = ptrtoint i8 addrspace(1)* %B to i16 + %E = ptrtoint i8 addrspace(1)* %P to i16 + %G = sub i16 %C, %E + ret i16 %G +} + define i64 @test24a(i8* %P, i64 %A){ %B = getelementptr inbounds i8* %P, i64 %A %C = ptrtoint i8* %B to i64 @@ -245,9 +268,21 @@ define i64 @test24a(i8* %P, i64 %A){ ret i64 %G ; CHECK-LABEL: @test24a( ; CHECK-NEXT: sub i64 0, %A -; CHECK-NEXT: ret i64 +; CHECK-NEXT: ret i64 } +define i16 @test24a_as1(i8 addrspace(1)* %P, i16 %A) { +; CHECK: @test24a_as1 +; CHECK-NEXT: sub i16 0, %A +; CHECK-NEXT: ret i16 + %B = getelementptr inbounds i8 addrspace(1)* %P, i16 %A + %C = ptrtoint i8 addrspace(1)* %B to i16 + %E = ptrtoint i8 addrspace(1)* %P to i16 + %G = sub i16 %E, %C + ret i16 %G +} + + @Arr = external global [42 x i16] define i64 @test24b(i8* %P, i64 %A){ @@ -257,7 +292,7 @@ define i64 @test24b(i8* %P, i64 %A){ ret i64 %G ; CHECK-LABEL: @test24b( ; CHECK-NEXT: shl nuw i64 %A, 1 -; CHECK-NEXT: ret i64 +; CHECK-NEXT: ret i64 } @@ -269,7 +304,21 @@ define i64 @test25(i8* %P, i64 %A){ ; CHECK-LABEL: @test25( ; CHECK-NEXT: shl nuw i64 %A, 1 ; CHECK-NEXT: add i64 {{.*}}, -84 -; CHECK-NEXT: ret i64 +; CHECK-NEXT: ret i64 +} + +@Arr_as1 = external addrspace(1) global [42 x i16] + +define i16 @test25_as1(i8 addrspace(1)* %P, i64 %A) { +; CHECK: @test25_as1 +; CHECK-NEXT: %1 = trunc i64 %A to i16 +; CHECK-NEXT: shl nuw i16 %1, 1 +; CHECK-NEXT: add i16 {{.*}}, -84 +; CHECK-NEXT: ret i16 + %B = getelementptr inbounds [42 x i16] addrspace(1)* @Arr_as1, i64 0, i64 %A + %C = ptrtoint i16 addrspace(1)* %B to i16 + %G = sub i16 %C, ptrtoint (i16 addrspace(1)* getelementptr ([42 x i16] addrspace(1)* @Arr_as1, i64 1, i64 0) to i16) + ret i16 %G } define i32 @test26(i32 %x) { @@ -327,3 +376,19 @@ define i64 @test30(i8* %foo, i64 %i, i64 %j) { ; CHECK-NEXT: sub i64 %gep1.idx, %j ; CHECK-NEXT: ret i64 } + +define i16 @test30_as1(i8 addrspace(1)* %foo, i16 %i, i16 %j) { +; CHECK-LABEL: @test30_as1( +; CHECK-NEXT: %gep1.idx = shl nuw i16 %i, 2 +; CHECK-NEXT: sub i16 %gep1.idx, %j +; CHECK-NEXT: ret i16 + %bit = bitcast i8 addrspace(1)* %foo to i32 addrspace(1)* + %gep1 = getelementptr inbounds i32 addrspace(1)* %bit, i16 %i + %gep2 = getelementptr inbounds i8 addrspace(1)* %foo, i16 %j + %cast1 = ptrtoint i32 addrspace(1)* %gep1 to i16 + %cast2 = ptrtoint i8 addrspace(1)* %gep2 to i16 + %sub = sub i16 %cast1, %cast2 + ret i16 %sub +} + + -- 2.34.1