[llvm-commits] [llvm] r163302 - in /llvm/trunk: lib/Transforms/Utils/SimplifyCFG.cpp test/Transforms/SimplifyCFG/switch_create.ll test/Transforms/SimplifyCFG/switch_to_lookup_table.ll

Duncan Sands baldrick at free.fr
Wed Sep 12 06:50:51 PDT 2012


Hi Hans,

> +// FIXME: Maybe ConvertLoadToSwitch?
> +bool CodeGenPrepare::LoadToSwitch(LoadInst *LI) {
> +  GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(LI->getPointerOperand());
> +  if (!GEP || !GEP->isInBounds() || GEP->getPointerAddressSpace())
> +    return false;

rather than trying to decode GEPs like this, there's another possible approach.
First, determine what the load is from using, say, stripInBoundsOffsets.  As
below you need to check that this is a constant global G with initial value
something you can work with.  You should check hasDefinitiveInitializer and
not hasInitializer by the way.

Let A be the address being loaded from, i.e. LI->getOperand(0).

Lets suppose the initial value C is an array [3 x i32], say { 1, 2, 3 }.
Basically the idea is to output something like this:

if (A == &C[0])
   val = 1;
else if (A == &C[1])
   val = 2;
else if (A == &C[2])
   val = 3;
else
   val = undef

I.e. the idea is that don't need to care how A is computed from C, all that
matters is which element is being accessed.

For the above code to be correct though there are some things to check:

(0) the load should be loading an i32 (the element type of C).

(1) the load should be 4 byte (i32) aligned, otherwise it might be loading
part of one array element and part of the next.  The global G had better
also be aligned at least this much otherwise the alignment of the load
isn't telling you anything useful!

At this point you know that the load must be just reading one of the elements of
the array C, or it is outside of C and thus the value of the load is undefined.

Then you can compute the addresses of the elements of C using a ConstantExpr
GEP on the global G, and output a series of compares with the address A as
above.

The downside of this approach is that you can't output a switch because the
addresses &C[0] etc aren't explicit numbers.

The upside is that it should work in great generality.

Ciao, Duncan.

> +
> +  if (GEP->getNumIndices() != 2)
> +    return false;
> +  Value *FirstIndex = GEP->idx_begin()[0];
> +  ConstantInt *FirstIndexInt = dyn_cast<ConstantInt>(FirstIndex);
> +  if (!FirstIndexInt || !FirstIndexInt->isZero())
> +    return false;
> +
> +  Value *SecondIndex = GEP->idx_begin()[1];
> +  assert(isa<IntegerType>(SecondIndex->getType()));
> +  IntegerType *SecondIndexIntTy = cast<IntegerType>(SecondIndex->getType());
> +
> +  GlobalVariable *GV = dyn_cast<GlobalVariable>(GEP->getPointerOperand());
> +  if (!GV || !GV->isConstant() || !GV->hasInitializer())
> +    return false;
> +
> +  // FIXME: This could also be a ConstantArray.
> +  ConstantDataArray *Arr = dyn_cast<ConstantDataArray>(GV->getInitializer());
> +  if (!Arr)
> +    return false;
> +
> +  assert(Arr->getElementType() == LI->getType());
> +
> +  BasicBlock *OriginalBB = LI->getParent();
> +  BasicBlock *PostSwitchBB = OriginalBB->splitBasicBlock(LI);
> +
> +  IRBuilder<> Builder(PostSwitchBB->begin());
> +  PHINode *PHI = Builder.CreatePHI(LI->getType(), Arr->getNumElements());
> +
> +  Builder.SetInsertPoint(OriginalBB->getTerminator());
> +  SwitchInst *Switch = Builder.CreateSwitch(SecondIndex, PostSwitchBB,
> +                                            Arr->getNumElements() - 1);
> +  OriginalBB->getTerminator()->eraseFromParent();
> +
> +  // FIXME: We should be more clever in choosing the default case.
> +  PHI->addIncoming(Arr->getAggregateElement(0U), OriginalBB);
> +
> +  for (unsigned I = 1; I < Arr->getNumElements(); ++I) {
> +    BasicBlock *BB = BasicBlock::Create(PostSwitchBB->getContext(),
> +                                        "lookup.bb",
> +                                        PostSwitchBB->getParent(),
> +                                        PostSwitchBB);
> +    Switch->addCase(ConstantInt::get(SecondIndexIntTy, I), BB);
> +    Builder.SetInsertPoint(BB);
> +    Builder.CreateBr(PostSwitchBB);
> +    PHI->addIncoming(Arr->getAggregateElement(I), BB);
> +  }
> +
> +  LI->replaceAllUsesWith(PHI);
> +  LI->eraseFromParent();
> +
> +  if (!GEP->hasNUsesOrMore(1))
> +    GEP->eraseFromParent();
> +
> +  CurInstIterator = Switch;
> +  return true;
> +}





More information about the llvm-commits mailing list