[LLVMdev] LLVM 3.6 and ConstantExpr::replaceUsesOfWithOnConstant(...) strange behavior

Rafael Espíndola rafael.espindola at gmail.com
Fri Mar 20 06:34:11 PDT 2015


On 19 March 2015 at 12:07, Jobin, Gaël <gael.jobin at switzerlandmail.ch> wrote:
> I wrote a pass in LLVM 3.5 and I'm trying to port it into LLVM 3.6.
>
> Unfortunately, my pass replace the operand of some constants expressions
> using the function replaceUsesOfWithOnConstant(...) that have been modified
> in the 3.6 release...
>
>
>
> In both LLVM 3.5 and 3.6, the function
> ConstantExpr::replaceUsesOfWithOnConstant(...) receives 3 arguments : two
> Value and one Use.
>
> In LLVM 3.5, the Use object was not really used. So, I could easily replace
> an operand in a constant expression by giving the old and the new Value as
> arguments with nullptr for Use.
>
> myConstExpr->replaceUsesOfWithOnConstant(oldOp, newOp, nullptr);
>
> Since LLVM 3.6, the Use object is used in a strange manner and the function
> getWithOperands (used inside replaceUsesOfWithOnConstant(..)) take a new
> boolean argument OnlyIfReduced. The documentation says:
>
>   /// If \c OnlyIfReduced is \c true, nullptr will be returned unless
> something
>   /// gets constant-folded, the type changes, or the expression is otherwise
>   /// canonicalized.  This parameter should almost always be \c false.
>
> Strangely, the OnlyIfReduced is set to true as you can see in the source
> code below. Most of time, in my case, the getWithOperands(...) will return
> nullptr because of this new argument (in LLVM 3.5, the old
> getWithOperands(...) did the job).
>
>   if (Constant *C = getWithOperands(NewOps, getType(), true)) {
>     replaceUsesOfWithOnConstantImpl(C);
>     return;
>   }
>
>   // Update to the new value.
>   if (Constant *C =
> getContext().pImpl->ExprConstants.replaceOperandsInPlace(
>           NewOps, this, From, To, NumUpdated, U - OperandList))
>     replaceUsesOfWithOnConstantImpl(C);
>
> Because it return nullptr, the new function replaceOperandsInPlace(...)
> should do the job instead. Unfortunately, there's an "optimization" inside
> replaceOperandsInPlace(...) :
>
>   // Update to the new value.  Optimize for the case when we have a single
>   // operand that we're changing, but handle bulk updates efficiently.
>
>     remove(CP);
>     if (NumUpdated == 1) {
>       assert(OperandNo < CP->getNumOperands() && "Invalid index");
>       assert(CP->getOperand(OperandNo) != To && "I didn't contain From!");
>       CP->setOperand(OperandNo, To);
>     } else {
>       for (unsigned I = 0, E = CP->getNumOperands(); I != E; ++I)
>         if (CP->getOperand(I) == From)
>           CP->setOperand(I, To);
>     }
>
> Normally, the loop inside the else branch should work (iterate over the
> operands and change the old ones by the new ones) but when you have
> NumUpdated equal to 1 (means there's only one operand to change), it
> actually use the Use object to identify the operand number to change
> (????)...
>
>
>
> From my point of view, this behavior is not very logical...
>
>
>
> I see two differents situations:
>
> One want to replace an operand by another one in a constant expression. We
> don't know how many operands are used by the constant expression nor the
> opcode of this constant expression. So, we call
> replaceUsesOfWithOnConstant(...) without Use (should be a default argument
> Use=nullptr) and the function should do the job (iterate over the operands,
> identify those that need to be replaced and replace them). If the
> replacement does not include a constant-folding/type change/canonicalized,
> the function replaceOperandsInPlace(...) is called and the modifications are
> done in place.
> One want to replace only one operand by another one in a constant
> expression. We identified the correct operand so we know in advance the Use
> object linked to the operand and the constant expression. In that case, we
> call replaceUsesOfWithOnConstant with the Use object and the function should
> use the "optimization" inside replaceOperandsInPlace(...) to avoid doing an
> unnecessary loop.
>
> Furthemore, the function replaceOperandsInPlace(...) have defaults arguments
> for NumUpdated=0 and OperandNo=0 that means it can be explicitly called to
> avoid the "optimization" trick.
>
>
>
> Maybe I'm wrong, but for me this implementation seems more correct:
>
>
>
> Source Code
>
>    void ConstantExpr::replaceUsesOfWithOnConstant(Value *From, Value *ToV,
> -                                                 Use *U) {
> +                                                 Use *U = nullptr) {
>      assert(isa<Constant>(ToV) && "Cannot make Constant refer to
> non-constant!");
>      Constant *To = cast<Constant>(ToV);
>
>      SmallVector<Constant*, 8> NewOps;
>      unsigned NumUpdated = 0;
>      for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
>        Constant *Op = getOperand(i);
>        if (Op == From) {
>          ++NumUpdated;
>          Op = To;
>        }
>        NewOps.push_back(Op);
>      }
>      assert(NumUpdated && "I didn't contain From!");
>
>
>      if (Constant *C = getWithOperands(NewOps, getType(), true)) {
>        replaceUsesOfWithOnConstantImpl(C);
>        return;
>      }
>
> +    if (U == nullptr) {
> +      NumUpdated = 0;
> +      U = OperandList;
> +    }
>
>      // Update to the new value.
>      if (Constant *C =
> getContext().pImpl->ExprConstants.replaceOperandsInPlace(
>              NewOps, this, From, To, NumUpdated, U - OperandList))
>        replaceUsesOfWithOnConstantImpl(C);
>    }


Sounds reasonable. Can you send a patch and include a test in
unittests/IR/ConstantsTest.cpp?

Thanks,
Rafael




More information about the llvm-commits mailing list