[llvm-commits] Pointer subtraction for IRBuilder
Nick Lewycky
nicholas at mxc.ca
Thu Apr 9 21:54:30 PDT 2009
Nick Lewycky wrote:
> 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.
*Erbl.*
Which means of course that your method produces the correct answer,
because you chose sdiv instead of udiv.
I got confused because inttoptr does zero-extension (implying that it's
unsigned) but the division is signed.
Anyways, please discard the above misanalysis. I'm still suspicious of
this code but I don't have example values of it misbehaving.
Sorry for the confusion!
Nick
More information about the llvm-commits
mailing list