From 651f0e9c8f324615dd81c83e4cf0043b2488a628 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Mon, 16 Jul 2007 05:43:05 +0000 Subject: [PATCH] Add a hack (mirroring llvm-gcc) to pointer difference codegen to compile: int test(int *A, int *B) { return A-B; } into: _test: movl 4(%esp), %eax subl 8(%esp), %eax sarl $2, %eax ret instead of: _test: movl 4(%esp), %eax subl 8(%esp), %eax movl %eax, %ecx sarl $31, %ecx shrl $30, %ecx addl %ecx, %eax sarl $2, %eax ret llvm-svn: 39902 --- clang/CodeGen/CGExpr.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/clang/CodeGen/CGExpr.cpp b/clang/CodeGen/CGExpr.cpp index 3ec0f2506489..40c25ae0bbda 100644 --- a/clang/CodeGen/CGExpr.cpp +++ b/clang/CodeGen/CGExpr.cpp @@ -18,6 +18,7 @@ #include "llvm/DerivedTypes.h" #include "llvm/Function.h" #include "llvm/GlobalVariable.h" +#include "llvm/Support/MathExtras.h" using namespace clang; using namespace CodeGen; @@ -1168,7 +1169,7 @@ RValue CodeGenFunction::EmitPointerSub(RValue LHS, QualType LHSTy, QualType LHSElementType = LHSPtrType->getPointeeType(); assert(LHSElementType == RHSPtrType->getPointeeType() && "can't subtract pointers with differing element types"); - unsigned ElementSize = getContext().getTypeSize(LHSElementType, + uint64_t ElementSize = getContext().getTypeSize(LHSElementType, SourceLocation()) / 8; const llvm::Type *ResultType = ConvertType(ResTy); llvm::Value *CastLHS = Builder.CreatePtrToInt(LHSValue, ResultType, @@ -1177,12 +1178,21 @@ RValue CodeGenFunction::EmitPointerSub(RValue LHS, QualType LHSTy, "sub.ptr.rhs.cast"); llvm::Value *BytesBetween = Builder.CreateSub(CastLHS, CastRHS, "sub.ptr.sub"); - llvm::Value *BytesPerElement = llvm::ConstantInt::get(ResultType, - ElementSize); - llvm::Value *ElementsBetween = Builder.CreateSDiv(BytesBetween, - BytesPerElement, - "sub.ptr.div"); - return RValue::get(ElementsBetween); + + // HACK: LLVM doesn't have an divide instruction that 'knows' there is no + // remainder. As such, we handle common power-of-two cases here to generate + // better code. + if (llvm::isPowerOf2_64(ElementSize)) { + llvm::Value *ShAmt = + llvm::ConstantInt::get(ResultType, llvm::Log2_64(ElementSize)); + return RValue::get(Builder.CreateAShr(BytesBetween, ShAmt,"sub.ptr.shr")); + } else { + // Otherwise, do a full sdiv. + llvm::Value *BytesPerElement = + llvm::ConstantInt::get(ResultType, ElementSize); + return RValue::get(Builder.CreateSDiv(BytesBetween, BytesPerElement, + "sub.ptr.div")); + } } else { // pointer - int llvm::Value *NegatedRHS = Builder.CreateNeg(RHSValue, "sub.ptr.neg");