aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2007-07-16 05:43:05 +0000
committerChris Lattner <sabre@nondot.org>2007-07-16 05:43:05 +0000
commit99e0d7905d1576ac85bb6f969a2d969c4d2e7f82 (patch)
treeae2e410c174b02e47bed22f43d26492d714de229
parent1467e03df1dce515ed3013c7dcb6f5c541ab0d5f (diff)
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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@39902 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--CodeGen/CGExpr.cpp24
1 files changed, 17 insertions, 7 deletions
diff --git a/CodeGen/CGExpr.cpp b/CodeGen/CGExpr.cpp
index 3ec0f25064..40c25ae0bb 100644
--- a/CodeGen/CGExpr.cpp
+++ b/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");