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
This commit is contained in:
Chris Lattner 2007-07-16 05:43:05 +00:00
parent f57999dcb1
commit 651f0e9c8f
1 changed files with 17 additions and 7 deletions

View File

@ -18,6 +18,7 @@
#include "llvm/DerivedTypes.h" #include "llvm/DerivedTypes.h"
#include "llvm/Function.h" #include "llvm/Function.h"
#include "llvm/GlobalVariable.h" #include "llvm/GlobalVariable.h"
#include "llvm/Support/MathExtras.h"
using namespace clang; using namespace clang;
using namespace CodeGen; using namespace CodeGen;
@ -1168,7 +1169,7 @@ RValue CodeGenFunction::EmitPointerSub(RValue LHS, QualType LHSTy,
QualType LHSElementType = LHSPtrType->getPointeeType(); QualType LHSElementType = LHSPtrType->getPointeeType();
assert(LHSElementType == RHSPtrType->getPointeeType() && assert(LHSElementType == RHSPtrType->getPointeeType() &&
"can't subtract pointers with differing element types"); "can't subtract pointers with differing element types");
unsigned ElementSize = getContext().getTypeSize(LHSElementType, uint64_t ElementSize = getContext().getTypeSize(LHSElementType,
SourceLocation()) / 8; SourceLocation()) / 8;
const llvm::Type *ResultType = ConvertType(ResTy); const llvm::Type *ResultType = ConvertType(ResTy);
llvm::Value *CastLHS = Builder.CreatePtrToInt(LHSValue, ResultType, llvm::Value *CastLHS = Builder.CreatePtrToInt(LHSValue, ResultType,
@ -1177,12 +1178,21 @@ RValue CodeGenFunction::EmitPointerSub(RValue LHS, QualType LHSTy,
"sub.ptr.rhs.cast"); "sub.ptr.rhs.cast");
llvm::Value *BytesBetween = Builder.CreateSub(CastLHS, CastRHS, llvm::Value *BytesBetween = Builder.CreateSub(CastLHS, CastRHS,
"sub.ptr.sub"); "sub.ptr.sub");
llvm::Value *BytesPerElement = llvm::ConstantInt::get(ResultType,
ElementSize); // HACK: LLVM doesn't have an divide instruction that 'knows' there is no
llvm::Value *ElementsBetween = Builder.CreateSDiv(BytesBetween, // remainder. As such, we handle common power-of-two cases here to generate
BytesPerElement, // better code.
"sub.ptr.div"); if (llvm::isPowerOf2_64(ElementSize)) {
return RValue::get(ElementsBetween); 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 { } else {
// pointer - int // pointer - int
llvm::Value *NegatedRHS = Builder.CreateNeg(RHSValue, "sub.ptr.neg"); llvm::Value *NegatedRHS = Builder.CreateNeg(RHSValue, "sub.ptr.neg");