[llvm-commits] Pointer subtraction for IRBuilder
Nick Lewycky
nicholas at mxc.ca
Thu Apr 9 21:46:52 PDT 2009
Jeffrey Yasskin wrote:
> The attached file implements IRBuilder::CreatePSub(), which performs a
> C-style pointer difference on its arguments. The included test passes,
> but it involves a warning that "ISO C++ forbids casting between
> pointer-to-function and pointer-to-object", which I don't know how to
> get rid of given the ExecutionEngine interface. I was also hoping to
> assert that constant folding could produce a constant integer, but I
> couldn't figure that out.
Instead, construct the IRBuilder with a TargetData with known pointer
size and use Constants of pointer type (ie. "gep ptrtotint null, i32 1")
as the Values when calling CreatePSub. That way, you'll get a simple
Constant value back which must be a ConstantInt you can easily check.
Whatever you do, don't submit a 46 line test for a 7 line function. :)
> Let me know what you think. (And I'm now subscribed, so I'll get your answer.)
--- include/llvm/Support/IRBuilder.h (revision 68715)
+++ include/llvm/Support/IRBuilder.h (working copy)
@@ -681,8 +681,26 @@
Name);
}
+ /// CreatePSub - Return the i64 difference between two pointer
values, taking
The name CreatePSub is too ambiguous. Either CreatePtrSub or
CreatePtrDiff. I prefer the latter.
+ /// the size of the pointed-to objects into account. This is intended to
+ /// implement C's pointer subtraction.
"implement C-style pointer subtraction."
+ Value *CreatePSub(Value *LHS, Value *RHS, const char *Name = "");
};
+template <bool preserveNames, typename T>
+Value *IRBuilder<preserveNames, T>::CreatePSub(
+ Value *LHS, Value *RHS, const char *Name) {
+ assert(LHS->getType() == RHS->getType() &&
+ "Pointer subtraction operand types must match!");
+ const PointerType *ArgType = cast<PointerType>(LHS->getType());
+ Value *LHS_int = CreatePtrToInt(LHS, Type::Int64Ty);
+ Value *RHS_int = CreatePtrToInt(RHS, Type::Int64Ty);
I'm don't think this is safe. With TargetData, you could use
TD->getIntPtrType(). Without it, I'm not convinced it's safe even if you
were to assume that pointer size is <= 64 bits...
+ Value *Difference = CreateSub(LHS_int, RHS_int);
+ return CreateSDiv(Difference,
+ ConstantExpr::getSizeOf(ArgType->getElementType()),
+ Name);
...and here's where it would matter. Consider i32* inttoptr(i32 -1 to
i32*). CreatePtrToInt zero-extends to produce the i64 LHS_int or RHS_int.
On a 32-bit system:
int32_t *a = -1;
int32_t *b = -13;
a - b
you would expand the -1 to 0x00000000ffffffff and the -13 to
0x00000000fffffff3. b - a = 0xfffffffffffffff4, not 0x00000000fffffff4
0xff...f4 sdiv 4 = i64 -3, while 0x00...0f...f4 sdiv 4 = 1073741821.
So the fix is for this method to use TargetData.
Unless you want it to also work without TargetData -- now, this is
hideous but functional -- you could fix it by truncating off the high
bits of the subtraction result before the sdiv.
But how do you know how many bits to clear? You don't. The way to do it
is to run it Different through an inttoptr/ptrtoint pair, because a
pointer magically has the right number of bits.
Nick
More information about the llvm-commits
mailing list