About the concept of "materialization"

I’m current debugging one of my LLVM passes which utilized inline assembly. I constantly encounter crashes related to “value materialization”, according to the error messages I received. It seems a big concept in LLVM (or maybe generally in compilation), but I cannot find any document that is comprehensive enough to help me understand what exactly materialization is for. Could someone offer some pointers to useful materials introducing this concept or just explain it to me if it is straightforward enough?

Thanks!

Sincerely,

Pei Wang

You probably see it more often as “rematerialization”.

https://en.wikipedia.org/wiki/Rematerialization

I believe “materialization” by itself (not “re”) would usually be about things like getting a large constant (maybe a bit pattern or mask) into a register before it can be used. Some ISAs such as x86 support large constants directly in the instruction, but in RISC you usually have to choose between using a data load instruction to get the constant from a constant pool (maybe global, maybe just after the function using it), or using a series of instructions such as load-high, shift, or-immediate to create the constant.

Bruce,

Thanks for the explanation. But based on my inspection on the source code, it seems that materialization is related to lazily reading LLVM objects (Module, Function, etc.) into the memory from bitcode files, which is possibly useful during LTO. I’m not sure though.

Pei

You probably need to give us the error message you got, or the source code
you're reading about materialization, so that we can speak of the same thing.

Regards,
chenwj

OK. About the error it’s a long story, so it’s probably better to pin some source code here. Below is a piece of code related to my problem, clipped from lib/Transforms/Utils/ValueMapper.cpp. I was wondering what “materialized” means here.

Value *Mapper::mapBlockAddress(const BlockAddress &BA) {
   Function *F = cast<Function>(mapValue(BA.getFunction()));

   // F may not have materialized its initializer. In that case, create a
   // dummy basic block for now, and replace it once we've materialized all
   // the initializers.
   BasicBlock *BB;
   if (F->empty()) {
     DelayedBBs.push_back(DelayedBasicBlock(BA));
     BB = DelayedBBs.back().TempBB.get();
   } else {
     BB = cast_or_null<BasicBlock>(mapValue(BA.getBasicBlock()));
   }

   return getVM()[&BA] = BlockAddress::get(F, BB ? BB : BA.getBasicBlock());
}

Thanks,
Pei

Hi Duncan,

  Could you shed light on that? I guess the code you wrote here
relates to JIT, but I am not sure
what materialize actually means. Thanks.

Regards,
chenwj

OK. About the error it’s a long story, so it’s probably better to pin some source code here. Below is a piece of code related to my problem, clipped from lib/Transforms/Utils/ValueMapper.cpp. I was wondering what “materialized” means here.

Value *Mapper::mapBlockAddress(const BlockAddress &BA) {
  Function *F = cast<Function>(mapValue(BA.getFunction()));

  // F may not have materialized its initializer. In that case, create a
  // dummy basic block for now, and replace it once we've materialized all
  // the initializers.
  BasicBlock *BB;
  if (F->empty()) {
    DelayedBBs.push_back(DelayedBasicBlock(BA));
    BB = DelayedBBs.back().TempBB.get();
  } else {
    BB = cast_or_null<BasicBlock>(mapValue(BA.getBasicBlock()));
  }

  return getVM()[&BA] = BlockAddress::get(F, BB ? BB : BA.getBasicBlock());
}

Hi Duncan,

Could you shed light on that? I guess the code you wrote here
relates to JIT, but I am not sure
what materialize actually means. Thanks.

This is for when a bitcode file has been lazy-loaded, and you're materializing global values (and related metadata) into the in-memory representation.

Thanks for the explanation!

Pei

    >
    >> OK. About the error it’s a long story, so it’s probably better to pin some source code here. Below is a piece of code related to my problem, clipped from lib/Transforms/Utils/ValueMapper.cpp. I was wondering what “materialized” means here.
    >>
    >> Value *Mapper::mapBlockAddress(const BlockAddress &BA) {
    >> Function *F = cast<Function>(mapValue(BA.getFunction()));
    >>
    >> // F may not have materialized its initializer. In that case, create a
    >> // dummy basic block for now, and replace it once we've materialized all
    >> // the initializers.
    >> BasicBlock *BB;
    >> if (F->empty()) {
    >> DelayedBBs.push_back(DelayedBasicBlock(BA));
    >> BB = DelayedBBs.back().TempBB.get();
    >> } else {
    >> BB = cast_or_null<BasicBlock>(mapValue(BA.getBasicBlock()));
    >> }
    >>
    >> return getVM()[&BA] = BlockAddress::get(F, BB ? BB : BA.getBasicBlock());
    >> }
    >
    >
    > Hi Duncan,
    >
    > Could you shed light on that? I guess the code you wrote here
    > relates to JIT, but I am not sure
    > what materialize actually means. Thanks.
    
    This is for when a bitcode file has been lazy-loaded, and you're materializing global values (and related metadata) into the in-memory representation.