[FuzzMutate] Support opaque pointers
authorNikita Popov <npopov@redhat.com>
Thu, 10 Mar 2022 13:18:37 +0000 (14:18 +0100)
committerNikita Popov <npopov@redhat.com>
Thu, 10 Mar 2022 13:36:20 +0000 (14:36 +0100)
Avoid checks that are irrelevant for opaque pointers, and pick
load/GEP types independently of the pointer type.

The GEP case at least could be done more efficiently by directly
generating a type, but this would require some significant API
changes.

llvm/include/llvm/FuzzMutate/OpDescriptor.h
llvm/lib/FuzzMutate/Operations.cpp
llvm/lib/FuzzMutate/RandomIRBuilder.cpp

index 43c8109..1d49cd5 100644 (file)
@@ -146,7 +146,8 @@ static inline SourcePred sizedPtrType() {
       return false;
 
     if (const auto *PtrT = dyn_cast<PointerType>(V->getType()))
-      return PtrT->getPointerElementType()->isSized();
+      return PtrT->isOpaque() ||
+             PtrT->getNonOpaquePointerElementType()->isSized();
     return false;
   };
   auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) {
index 221a3a8..7db24bb 100644 (file)
@@ -169,14 +169,21 @@ OpDescriptor llvm::fuzzerop::splitBlockDescriptor(unsigned Weight) {
 
 OpDescriptor llvm::fuzzerop::gepDescriptor(unsigned Weight) {
   auto buildGEP = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
-    Type *Ty = Srcs[0]->getType()->getPointerElementType();
-    auto Indices = makeArrayRef(Srcs).drop_front(1);
+    // TODO: It would be better to generate a random type here, rather than
+    // generating a random value and picking its type.
+    Type *Ty = Srcs[0]->getType()->isOpaquePointerTy()
+                   ? Srcs[1]->getType()
+                   : Srcs[0]->getType()->getNonOpaquePointerElementType();
+    auto Indices = makeArrayRef(Srcs).drop_front(2);
     return GetElementPtrInst::Create(Ty, Srcs[0], Indices, "G", Inst);
   };
   // TODO: Handle aggregates and vectors
   // TODO: Support multiple indices.
   // TODO: Try to avoid meaningless accesses.
-  return {Weight, {sizedPtrType(), anyIntType()}, buildGEP};
+  SourcePred sizedType(
+      [](ArrayRef<Value *>, const Value *V) { return V->getType()->isSized(); },
+      None);
+  return {Weight, {sizedPtrType(), sizedType, anyIntType()}, buildGEP};
 }
 
 static uint64_t getAggregateNumElements(Type *T) {
index 27c3bdf..0579dde 100644 (file)
@@ -53,8 +53,11 @@ Value *RandomIRBuilder::newSource(BasicBlock &BB, ArrayRef<Instruction *> Insts,
       IP = ++I->getIterator();
       assert(IP != BB.end() && "guaranteed by the findPointer");
     }
-    auto *NewLoad =
-        new LoadInst(Ptr->getType()->getPointerElementType(), Ptr, "L", &*IP);
+    // For opaque pointers, pick the type independently.
+    Type *AccessTy = Ptr->getType()->isOpaquePointerTy()
+                         ? RS.getSelection()->getType()
+                         : Ptr->getType()->getNonOpaquePointerElementType();
+    auto *NewLoad = new LoadInst(AccessTy, Ptr, "L", &*IP);
 
     // Only sample this load if it really matches the descriptor
     if (Pred.matches(Srcs, NewLoad))
@@ -139,9 +142,12 @@ Value *RandomIRBuilder::findPointer(BasicBlock &BB,
     if (Inst->isTerminator())
       return false;
 
-    if (auto PtrTy = dyn_cast<PointerType>(Inst->getType())) {
+    if (auto *PtrTy = dyn_cast<PointerType>(Inst->getType())) {
+      if (PtrTy->isOpaque())
+        return true;
+
       // We can never generate loads from non first class or non sized types
-      Type *ElemTy = PtrTy->getPointerElementType();
+      Type *ElemTy = PtrTy->getNonOpaquePointerElementType();
       if (!ElemTy->isSized() || !ElemTy->isFirstClassType())
         return false;