From 92b969ba80a6ed6d461c5e874db259f8c0a95290 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 14 Jul 2009 20:57:04 +0000 Subject: [PATCH] Fix the expansion of umax and smax in the case where one or more of the operands have pointer type, so that the resulting type matches the original SCEV type, and so that unnecessary ptrtoints are avoided in common cases. llvm-svn: 75680 --- llvm/lib/Analysis/ScalarEvolutionExpander.cpp | 32 +++- .../Transforms/IndVarSimplify/max-pointer.ll | 145 ++++++++++++++++++ 2 files changed, 171 insertions(+), 6 deletions(-) create mode 100644 llvm/test/Transforms/IndVarSimplify/max-pointer.ll diff --git a/llvm/lib/Analysis/ScalarEvolutionExpander.cpp b/llvm/lib/Analysis/ScalarEvolutionExpander.cpp index ecfbc8ec79f2..20d6e20601f2 100644 --- a/llvm/lib/Analysis/ScalarEvolutionExpander.cpp +++ b/llvm/lib/Analysis/ScalarEvolutionExpander.cpp @@ -609,9 +609,15 @@ Value *SCEVExpander::visitSignExtendExpr(const SCEVSignExtendExpr *S) { } Value *SCEVExpander::visitSMaxExpr(const SCEVSMaxExpr *S) { - const Type *Ty = SE.getEffectiveSCEVType(S->getType()); - Value *LHS = expandCodeFor(S->getOperand(0), Ty); - for (unsigned i = 1; i < S->getNumOperands(); ++i) { + Value *LHS = expand(S->getOperand(S->getNumOperands()-1)); + const Type *Ty = LHS->getType(); + for (int i = S->getNumOperands()-2; i >= 0; --i) { + // In the case of mixed integer and pointer types, do the + // rest of the comparisons as integer. + if (S->getOperand(i)->getType() != Ty) { + Ty = SE.getEffectiveSCEVType(Ty); + LHS = InsertNoopCastOfTo(LHS, Ty); + } Value *RHS = expandCodeFor(S->getOperand(i), Ty); Value *ICmp = Builder.CreateICmpSGT(LHS, RHS, "tmp"); InsertedValues.insert(ICmp); @@ -619,13 +625,23 @@ Value *SCEVExpander::visitSMaxExpr(const SCEVSMaxExpr *S) { InsertedValues.insert(Sel); LHS = Sel; } + // In the case of mixed integer and pointer types, cast the + // final result back to the pointer type. + if (LHS->getType() != S->getType()) + LHS = InsertNoopCastOfTo(LHS, S->getType()); return LHS; } Value *SCEVExpander::visitUMaxExpr(const SCEVUMaxExpr *S) { - const Type *Ty = SE.getEffectiveSCEVType(S->getType()); - Value *LHS = expandCodeFor(S->getOperand(0), Ty); - for (unsigned i = 1; i < S->getNumOperands(); ++i) { + Value *LHS = expand(S->getOperand(S->getNumOperands()-1)); + const Type *Ty = LHS->getType(); + for (int i = S->getNumOperands()-2; i >= 0; --i) { + // In the case of mixed integer and pointer types, do the + // rest of the comparisons as integer. + if (S->getOperand(i)->getType() != Ty) { + Ty = SE.getEffectiveSCEVType(Ty); + LHS = InsertNoopCastOfTo(LHS, Ty); + } Value *RHS = expandCodeFor(S->getOperand(i), Ty); Value *ICmp = Builder.CreateICmpUGT(LHS, RHS, "tmp"); InsertedValues.insert(ICmp); @@ -633,6 +649,10 @@ Value *SCEVExpander::visitUMaxExpr(const SCEVUMaxExpr *S) { InsertedValues.insert(Sel); LHS = Sel; } + // In the case of mixed integer and pointer types, cast the + // final result back to the pointer type. + if (LHS->getType() != S->getType()) + LHS = InsertNoopCastOfTo(LHS, S->getType()); return LHS; } diff --git a/llvm/test/Transforms/IndVarSimplify/max-pointer.ll b/llvm/test/Transforms/IndVarSimplify/max-pointer.ll new file mode 100644 index 000000000000..ba2b2fa83486 --- /dev/null +++ b/llvm/test/Transforms/IndVarSimplify/max-pointer.ll @@ -0,0 +1,145 @@ +; RUN: llvm-as < %s | opt -indvars | llvm-dis > %t +; RUN: grep {icmp ugt i8\\\*} %t | count 1 +; RUN: grep {icmp sgt i8\\\*} %t | count 1 + +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" + + %struct.CKenCodeCodec = type <{ i8 }> + +define void @foo(i8* %str1Ptr, i8* %str2Ptr, i8* %inLastBytePtr) nounwind { +entry: + %0 = icmp ult i8* %str2Ptr, %str1Ptr ; [#uses=1] + %str2Ptr_addr.0 = select i1 %0, i8* %str1Ptr, i8* %str2Ptr ; [#uses=1] + br label %bb2 + +bb2: ; preds = %bb2, %entry + %str2Ptr_addr.1 = phi i8* [ %str2Ptr_addr.0, %entry ], [ %1, %bb2 ] ; [#uses=1] + %1 = getelementptr i8* %str2Ptr_addr.1, i64 1 ; [#uses=2] + %2 = icmp ult i8* %1, %inLastBytePtr ; [#uses=0] + br i1 false, label %bb2, label %return + +return: ; preds = %bb2 + ret void +} + +define void @bar(i8* %str1Ptr, i64 %s, i8* %inLastBytePtr) nounwind { +entry: + %str2Ptr = inttoptr i64 %s to i8* + %0 = icmp ult i8* %str2Ptr, %str1Ptr ; [#uses=1] + %str2Ptr_addr.0 = select i1 %0, i8* %str1Ptr, i8* %str2Ptr ; [#uses=1] + br label %bb2 + +bb2: ; preds = %bb2, %entry + %str2Ptr_addr.1 = phi i8* [ %str2Ptr_addr.0, %entry ], [ %1, %bb2 ] ; [#uses=1] + %1 = getelementptr i8* %str2Ptr_addr.1, i64 1 ; [#uses=2] + %2 = icmp ult i8* %1, %inLastBytePtr ; [#uses=0] + br i1 false, label %bb2, label %return + +return: ; preds = %bb2 + ret void +} + +define void @qux(i64 %t, i64 %s, i8* %inLastBytePtr) nounwind { +entry: + %str1Ptr = inttoptr i64 %t to i8* + %str2Ptr = inttoptr i64 %s to i8* + %0 = icmp ult i8* %str2Ptr, %str1Ptr ; [#uses=1] + %str2Ptr_addr.0 = select i1 %0, i8* %str1Ptr, i8* %str2Ptr ; [#uses=1] + br label %bb2 + +bb2: ; preds = %bb2, %entry + %str2Ptr_addr.1 = phi i8* [ %str2Ptr_addr.0, %entry ], [ %1, %bb2 ] ; [#uses=1] + %1 = getelementptr i8* %str2Ptr_addr.1, i64 1 ; [#uses=2] + %2 = icmp ult i8* %1, %inLastBytePtr ; [#uses=0] + br i1 false, label %bb2, label %return + +return: ; preds = %bb2 + ret void +} + +define void @vor(i64 %t, i8* %str2Ptr, i8* %inLastBytePtr) nounwind { +entry: + %str1Ptr = inttoptr i64 %t to i8* + %0 = icmp ult i8* %str2Ptr, %str1Ptr ; [#uses=1] + %str2Ptr_addr.0 = select i1 %0, i8* %str1Ptr, i8* %str2Ptr ; [#uses=1] + br label %bb2 + +bb2: ; preds = %bb2, %entry + %str2Ptr_addr.1 = phi i8* [ %str2Ptr_addr.0, %entry ], [ %1, %bb2 ] ; [#uses=1] + %1 = getelementptr i8* %str2Ptr_addr.1, i64 1 ; [#uses=2] + %2 = icmp ult i8* %1, %inLastBytePtr ; [#uses=0] + br i1 false, label %bb2, label %return + +return: ; preds = %bb2 + ret void +} + +define void @sfoo(i8* %str1Ptr, i8* %str2Ptr, i8* %inLastBytePtr) nounwind { +entry: + %0 = icmp slt i8* %str2Ptr, %str1Ptr ; [#uses=1] + %str2Ptr_addr.0 = select i1 %0, i8* %str1Ptr, i8* %str2Ptr ; [#uses=1] + br label %bb2 + +bb2: ; preds = %bb2, %entry + %str2Ptr_addr.1 = phi i8* [ %str2Ptr_addr.0, %entry ], [ %1, %bb2 ] ; [#uses=1] + %1 = getelementptr i8* %str2Ptr_addr.1, i64 1 ; [#uses=2] + %2 = icmp slt i8* %1, %inLastBytePtr ; [#uses=0] + br i1 false, label %bb2, label %return + +return: ; preds = %bb2 + ret void +} + +define void @sbar(i8* %str1Ptr, i64 %s, i8* %inLastBytePtr) nounwind { +entry: + %str2Ptr = inttoptr i64 %s to i8* + %0 = icmp slt i8* %str2Ptr, %str1Ptr ; [#uses=1] + %str2Ptr_addr.0 = select i1 %0, i8* %str1Ptr, i8* %str2Ptr ; [#uses=1] + br label %bb2 + +bb2: ; preds = %bb2, %entry + %str2Ptr_addr.1 = phi i8* [ %str2Ptr_addr.0, %entry ], [ %1, %bb2 ] ; [#uses=1] + %1 = getelementptr i8* %str2Ptr_addr.1, i64 1 ; [#uses=2] + %2 = icmp slt i8* %1, %inLastBytePtr ; [#uses=0] + br i1 false, label %bb2, label %return + +return: ; preds = %bb2 + ret void +} + +define void @squx(i64 %t, i64 %s, i8* %inLastBytePtr) nounwind { +entry: + %str1Ptr = inttoptr i64 %t to i8* + %str2Ptr = inttoptr i64 %s to i8* + %0 = icmp slt i8* %str2Ptr, %str1Ptr ; [#uses=1] + %str2Ptr_addr.0 = select i1 %0, i8* %str1Ptr, i8* %str2Ptr ; [#uses=1] + br label %bb2 + +bb2: ; preds = %bb2, %entry + %str2Ptr_addr.1 = phi i8* [ %str2Ptr_addr.0, %entry ], [ %1, %bb2 ] ; [#uses=1] + %1 = getelementptr i8* %str2Ptr_addr.1, i64 1 ; [#uses=2] + %2 = icmp slt i8* %1, %inLastBytePtr ; [#uses=0] + br i1 false, label %bb2, label %return + +return: ; preds = %bb2 + ret void +} + +define void @svor(i64 %t, i8* %str2Ptr, i8* %inLastBytePtr) nounwind { +entry: + %str1Ptr = inttoptr i64 %t to i8* + %0 = icmp slt i8* %str2Ptr, %str1Ptr ; [#uses=1] + %str2Ptr_addr.0 = select i1 %0, i8* %str1Ptr, i8* %str2Ptr ; [#uses=1] + br label %bb2 + +bb2: ; preds = %bb2, %entry + %str2Ptr_addr.1 = phi i8* [ %str2Ptr_addr.0, %entry ], [ %1, %bb2 ] ; [#uses=1] + %1 = getelementptr i8* %str2Ptr_addr.1, i64 1 ; [#uses=2] + %2 = icmp slt i8* %1, %inLastBytePtr ; [#uses=0] + br i1 false, label %bb2, label %return + +return: ; preds = %bb2 + ret void +} + +