0

I'm trying to cast an array of type [3 x double] to a ConstantArray to eventually change the underlying type from double to float. But whenever I try to cast it fails and I haven't been able to figure out why.

The snippet of code from the pass that is running (edited to add more info):

CallInst& inst; //passed in by function arg
CallInst* oldCall = &inst;
Constant *constant = dyn_cast<Constant>(oldCall->getOperand(1)->stripPointerCasts());
errs() << "Operand is: " << *constant->getOperand(0) << "\n";
errs() << "Operand type: " << *constant->getOperand(0)->getType() << "\n";
ConstantArray *constantArray = cast<ConstantArray>(constant->getOperand(0));

The output:

Operand is: [3 x double] [double 2.100000e+00, double 2.200000e+00, double 2.300000e+00]
Operand type: [3 x double]
opt: /include/llvm/Support/Casting.h:255: typename llvm::cast_retty<X, Y*>::ret_type llvm::cast(Y*) 
[with X = llvm::ConstantArray; Y = llvm::Value; typename llvm::cast_retty<X, Y*>::ret_type = 
llvm::ConstantArray*]: Assertion `isa<X>(Val) && "cast<Ty>() argument of incompatible type!"' failed.

As can be seen, the operand in our constant is an array type. When trying to cast it sees a Value due to the underlying nature of cast (I think?), but still fails to think they are compatible. Does anyone know why this is?

Note: This is using flang's LLVM release_70 branch, which is just a slightly modified LLVM 7.1.0 library.

Aroic
  • 479
  • 2
  • 12
  • What is `constant` declared as? –  Nov 05 '19 at 18:41
  • @Chipster Edited the code to show how it was initialized – Aroic Nov 05 '19 at 18:49
  • 1
    A cast doesn't actually *change* anything. It just tells the compiler to view a collection of bits through different glasses. Whether or not that new interpretation makes sense is something only you, the programmer, can know. If it does *not* make sense then you just silently broke your program. Remember: A cast does *not* change the underlying representation of your data *at all*. The only thing it does is cause your compiler to *interpret* it differently. A cast can't change a type into some other type of it's bit pattern doesn't make sense as that other type. Casts don't *convert* anything. – Jesper Juhl Nov 05 '19 at 19:00

1 Answers1

0

You cannot cast an array to anything else, including a different array (AIUI because casting rules are language-specific). The usual approach is to cast a pointer instead, something like this.

auto c = CastInst::Create(CastInst::BitCast,
                          sourcePointerToDoubleArray,
                          ArrayType::get(Type::getFloatTy(), 3)->getPointerto(),
                          "funny_little_ast",
                          targetBasicBlock);

There's also a ConstantExpr::getPointerCast(). Both of these simply reinterpret the bits you point at.

arnt
  • 8,949
  • 5
  • 24
  • 32
  • Thanks for the answer arnt, I guess I'm still a bit confused why, in my specific example, the underlying constant cannot be reinterpreted as a ConstantArray implicitly? When I print out the constant it is obviously seen as an array, thus I assume the cast should work in reinterpreting the bits to a ConstantArray. – Aroic Nov 05 '19 at 19:38
  • 1
    Maybe I should delete that answer... I'm not sure I understand the core of your problem. Anyway, some arrays are ConstantArray, some are ConstantDataArray, and the one you have is probably the latter. (I can't remember the reason for the different base classes, I'm afraid.) Try with `cast` if you want a compile-time cast and a pointer cast if you want a runtime cast. Both leave the bit pattern unchanged, they just reinterpret. – arnt Nov 05 '19 at 19:58