[LLVMdev] Mutability of constant initializers

Chris Lattner
Wed, 16 Apr 2003 14:21:01 -0000

On 16 Apr 2003, Joel Stanley wrote:
> It seems that the contents of Constant{Array,Struct,etc} are immutable
> after construction.  The only available accessor function is
> getValues(), which returns a constant reference to a vector of uses.

Yes, all constants (and types) in LLVM are immutable.  The Constant*::get
methods in particular are the only way to get a constant.  This is an
important part of the design of LLVM: you don't have to worry about
deleting constants when they are unused, because the API will guarantee
that they will be recycled in the future, thus, no "leaking" of memory
occurs.  Because of this recycling of constants, however, it is imperative
that constants are not changed after they are created by the constant
manager.

> a) force access (i.e. const_cast or some such thing) to the underlying
> vector of struct values, and modify them. This seems gross.

That would break a lot of stuff also.  :)

> b) go out of my way to build a temporary map which contains the proper
> links, and use the map to fill in the fields upon construction.

Unfortunately, you have to do this.

> Furthermore, if the answer is (b), I'd like to know why the values are
> immutable. Presumably, there's a Constant-instance-caching mechanism
> behind the scenes, so that'd be my guess as to why I can't modify
these
> values after I construct a Constant-derived instance.

In the bad-old-days of early LLVM, we had to explicitly manage the
lifetimes of constants that were created.  This seems pretty easy, but it
infects all aspects of the transformations in a horrible way.  Imagine a
simple "DCE" pass.  In currently llvm, it would looks something like
this:

if (instruction I is dead and has no side effects) {
  remove I from basic block
  delete I
}

In the old days, it would look something like this:

if (instruction I is dead and has no side effects) {
  remove I from basic block
  for each operand O of I
    if (operand O is a constant && constant is dead)
      delete constant;
  delete I
}

As you can see, this makes things a lot more complex for simple cases.
Unfortunately, the current solution makes a few transformations harder to
write, but you can't please everyone.  ;)

-Chris

--