Eliminate redundant bitwise operations when using a llvm/ADT/PointerUnion.
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Mon, 3 Dec 2012 19:59:23 +0000 (19:59 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Mon, 3 Dec 2012 19:59:23 +0000 (19:59 +0000)
For comparison, with this code sample:

PointerUnion<int *, char *> Data;
PointerUnion<int *, char *> foo1() {
Data = new int;
return new int;
}
PointerUnion<int *, char *> foo2() {
Data = new char;
return new char;
}

Before this patch we would get:

define i64 @_Z4foo1v() uwtable ssp {
  %1 = tail call noalias i8* @_Znwm(i64 4)
  %2 = ptrtoint i8* %1 to i64
  %3 = load i64* getelementptr inbounds (%"class.llvm::PointerUnion"* @Data, i64 0, i32 0, i32 0), align 8
  %4 = and i64 %3, 1
  %.masked.i = and i64 %2, -3
  %5 = or i64 %4, %.masked.i
  store i64 %5, i64* getelementptr inbounds (%"class.llvm::PointerUnion"* @Data, i64 0, i32 0, i32 0), align 8
  %6 = tail call noalias i8* @_Znwm(i64 4)
  %7 = ptrtoint i8* %6 to i64
  %8 = and i64 %7, -3
  ret i64 %8
}

define i64 @_Z4foo2v() uwtable ssp {
  %1 = tail call noalias i8* @_Znwm(i64 1)
  %2 = ptrtoint i8* %1 to i64
  %3 = load i64* getelementptr inbounds (%"class.llvm::PointerUnion"* @Data, i64 0, i32 0, i32 0), align 8
  %4 = and i64 %3, 1
  %5 = or i64 %2, %4
  %6 = or i64 %5, 2
  store i64 %6, i64* getelementptr inbounds (%"class.llvm::PointerUnion"* @Data, i64 0, i32 0, i32 0), align 8
  %7 = tail call noalias i8* @_Znwm(i64 1)
  %8 = ptrtoint i8* %7 to i64
  %9 = or i64 %8, 2
  ret i64 %9
}

After the patch:

define i64 @_Z4foo1v() uwtable ssp {
  %1 = tail call noalias i8* @_Znwm(i64 4)
  %2 = ptrtoint i8* %1 to i64
  store i64 %2, i64* getelementptr inbounds (%"class.llvm::PointerUnion"* @Data, i64 0, i32 0, i32 0), align 8
  %3 = tail call noalias i8* @_Znwm(i64 4)
  %4 = ptrtoint i8* %3 to i64
  ret i64 %4
}

declare noalias i8* @_Znwm(i64)

define i64 @_Z4foo2v() uwtable ssp {
  %1 = tail call noalias i8* @_Znwm(i64 1)
  %2 = ptrtoint i8* %1 to i64
  %3 = or i64 %2, 2
  store i64 %3, i64* getelementptr inbounds (%"class.llvm::PointerUnion"* @Data, i64 0, i32 0, i32 0), align 8
  %4 = tail call noalias i8* @_Znwm(i64 1)
  %5 = ptrtoint i8* %4 to i64
  %6 = or i64 %5, 2
  ret i64 %6
}

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@169147 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/ADT/PointerIntPair.h
include/llvm/ADT/PointerUnion.h

index 71c379bad5a46f6aaed7dfb5be651cc3d9949acf..cce2efb6ac996261471140c000459936c3b05325 100644 (file)
@@ -57,11 +57,13 @@ class PointerIntPair {
   };
 public:
   PointerIntPair() : Value(0) {}
-  PointerIntPair(PointerTy Ptr, IntType Int) : Value(0) {
+  PointerIntPair(PointerTy Ptr, IntType Int) {
     assert(IntBits <= PtrTraits::NumLowBitsAvailable &&
            "PointerIntPair formed with integer size too large for pointer");
-    setPointer(Ptr);
-    setInt(Int);
+    setPointerAndInt(Ptr, Int);
+  }
+  explicit PointerIntPair(PointerTy Ptr) {
+    initWithPointer(Ptr);
   }
 
   PointerTy getPointer() const {
@@ -91,6 +93,25 @@ public:
     Value |= IntVal << IntShift;  // Set new integer.
   }
 
+  void initWithPointer(PointerTy Ptr) {
+    intptr_t PtrVal
+      = reinterpret_cast<intptr_t>(PtrTraits::getAsVoidPointer(Ptr));
+    assert((PtrVal & ((1 << PtrTraits::NumLowBitsAvailable)-1)) == 0 &&
+           "Pointer is not sufficiently aligned");
+    Value = PtrVal;
+  }
+
+  void setPointerAndInt(PointerTy Ptr, IntType Int) {
+    intptr_t PtrVal
+      = reinterpret_cast<intptr_t>(PtrTraits::getAsVoidPointer(Ptr));
+    assert((PtrVal & ((1 << PtrTraits::NumLowBitsAvailable)-1)) == 0 &&
+           "Pointer is not sufficiently aligned");
+    intptr_t IntVal = Int;
+    assert(IntVal < (1 << IntBits) && "Integer too large for field");
+
+    Value = PtrVal | (IntVal << IntShift);
+  }
+
   PointerTy const *getAddrOfPointer() const {
     return const_cast<PointerIntPair *>(this)->getAddrOfPointer();
   }
index a9e86d22002de7f1b5c57b3a039ad2c809d6439e..f42515ac77a74be5ab18cd8dad3ae1d08e68e752 100644 (file)
@@ -95,15 +95,11 @@ namespace llvm {
   public:
     PointerUnion() {}
     
-    PointerUnion(PT1 V) {
-      Val.setPointer(
-         const_cast<void *>(PointerLikeTypeTraits<PT1>::getAsVoidPointer(V)));
-      Val.setInt(0);
+    PointerUnion(PT1 V) : Val(
+      const_cast<void *>(PointerLikeTypeTraits<PT1>::getAsVoidPointer(V))) {
     }
-    PointerUnion(PT2 V) {
-      Val.setPointer(
-         const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(V)));
-      Val.setInt(1);
+    PointerUnion(PT2 V) : Val(
+      const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(V)), 1) {
     }
     
     /// isNull - Return true if the pointer held in the union is null,
@@ -160,15 +156,14 @@ namespace llvm {
     /// Assignment operators - Allow assigning into this union from either
     /// pointer type, setting the discriminator to remember what it came from.
     const PointerUnion &operator=(const PT1 &RHS) {
-      Val.setPointer(
+      Val.initWithPointer(
          const_cast<void *>(PointerLikeTypeTraits<PT1>::getAsVoidPointer(RHS)));
-      Val.setInt(0);
       return *this;
     }
     const PointerUnion &operator=(const PT2 &RHS) {
-      Val.setPointer(
-        const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(RHS)));
-      Val.setInt(1);
+      Val.setPointerAndInt(
+        const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(RHS)),
+        1);
       return *this;
     }