| Index: src/IceCfg.cpp
|
| diff --git a/src/IceCfg.cpp b/src/IceCfg.cpp
|
| index 9bc1ba58333d6ef000a824c67ac59fd2ad4192de..6ae12bb10b356bd38b0e474a24904f037e83aa43 100644
|
| --- a/src/IceCfg.cpp
|
| +++ b/src/IceCfg.cpp
|
| @@ -630,6 +630,108 @@ void Cfg::processAllocas(bool SortAndCombine) {
|
| AllocaBaseVariableType BasePointerType =
|
| (HasDynamicAllocation ? BVT_UserPointer : BVT_StackPointer);
|
| sortAndCombineAllocas(FixedAllocas, MaxAlignment, Insts, BasePointerType);
|
| +
|
| + if (!FixedAllocas.empty() || !AlignedAllocas.empty())
|
| + // No use calling findRematerializable() unless there is some
|
| + // rematerializable alloca instruction to seed it.
|
| + findRematerializable();
|
| +}
|
| +
|
| +namespace {
|
| +
|
| +// Helpers for findRematerializable(). For each of them, if a suitable
|
| +// rematerialization is found, the instruction's Dest variable is set to be
|
| +// rematerializable and it returns true, otherwise it returns false.
|
| +
|
| +bool rematerializeArithmetic(const Inst *Instr) {
|
| + // Check that it's an Arithmetic instruction with an Add operation.
|
| + auto *Arith = llvm::dyn_cast<InstArithmetic>(Instr);
|
| + if (Arith == nullptr || Arith->getOp() != InstArithmetic::Add)
|
| + return false;
|
| + // Check that Src(0) is rematerializable.
|
| + auto *Src0Var = llvm::dyn_cast<Variable>(Arith->getSrc(0));
|
| + if (Src0Var == nullptr || !Src0Var->isRematerializable())
|
| + return false;
|
| + // Check that Src(1) is an immediate.
|
| + auto *Src1Imm = llvm::dyn_cast<ConstantInteger32>(Arith->getSrc(1));
|
| + if (Src1Imm == nullptr)
|
| + return false;
|
| + Arith->getDest()->setRematerializable(
|
| + Src0Var->getRegNum(), Src0Var->getStackOffset() + Src1Imm->getValue());
|
| + return true;
|
| +}
|
| +
|
| +bool rematerializeAssign(const Inst *Instr) {
|
| + // An InstAssign only originates from an inttoptr or ptrtoint instruction,
|
| + // which never occurs in a MINIMAL build.
|
| + if (BuildDefs::minimal())
|
| + return false;
|
| + // Check that it's an Assign instruction.
|
| + if (!llvm::isa<InstAssign>(Instr))
|
| + return false;
|
| + // Check that Src(0) is rematerializable.
|
| + auto *Src0Var = llvm::dyn_cast<Variable>(Instr->getSrc(0));
|
| + if (Src0Var == nullptr || !Src0Var->isRematerializable())
|
| + return false;
|
| + Instr->getDest()->setRematerializable(Src0Var->getRegNum(),
|
| + Src0Var->getStackOffset());
|
| + return true;
|
| +}
|
| +
|
| +bool rematerializeCast(const Inst *Instr) {
|
| + // An pointer-type bitcast never occurs in a MINIMAL build.
|
| + if (BuildDefs::minimal())
|
| + return false;
|
| + // Check that it's a Cast instruction with a Bitcast operation.
|
| + auto *Cast = llvm::dyn_cast<InstCast>(Instr);
|
| + if (Cast == nullptr || Cast->getCastKind() != InstCast::Bitcast)
|
| + return false;
|
| + // Check that Src(0) is rematerializable.
|
| + auto *Src0Var = llvm::dyn_cast<Variable>(Cast->getSrc(0));
|
| + if (Src0Var == nullptr || !Src0Var->isRematerializable())
|
| + return false;
|
| + // Check that Dest and Src(0) have the same type.
|
| + Variable *Dest = Cast->getDest();
|
| + if (Dest->getType() != Src0Var->getType())
|
| + return false;
|
| + Dest->setRematerializable(Src0Var->getRegNum(), Src0Var->getStackOffset());
|
| + return true;
|
| +}
|
| +
|
| +} // end of anonymous namespace
|
| +
|
| +/// Scan the function to find additional rematerializable variables. This is
|
| +/// possible when the source operand of an InstAssignment is a rematerializable
|
| +/// variable, or the same for a pointer-type InstCast::Bitcast, or when an
|
| +/// InstArithmetic is an add of a rematerializable variable and an immediate.
|
| +/// Note that InstAssignment instructions and pointer-type InstCast::Bitcast
|
| +/// instructions generally only come about from the IceConverter's treatment of
|
| +/// inttoptr, ptrtoint, and bitcast instructions. TODO(stichnot): Consider
|
| +/// other possibilities, however unlikely, such as InstArithmetic::Sub, or
|
| +/// commutativity.
|
| +void Cfg::findRematerializable() {
|
| + // Scan the instructions in order, and repeat until no new opportunities are
|
| + // found. It may take more than one iteration because a variable's defining
|
| + // block may happen to come after a block where it is used, depending on the
|
| + // CfgNode linearization order.
|
| + bool FoundNewAssignment;
|
| + do {
|
| + FoundNewAssignment = false;
|
| + for (CfgNode *Node : getNodes()) {
|
| + // No need to process Phi instructions.
|
| + for (Inst &Instr : Node->getInsts()) {
|
| + if (Instr.isDeleted())
|
| + continue;
|
| + Variable *Dest = Instr.getDest();
|
| + if (Dest == nullptr || Dest->isRematerializable())
|
| + continue;
|
| + if (rematerializeArithmetic(&Instr) || rematerializeAssign(&Instr) ||
|
| + rematerializeCast(&Instr)) {
|
| + FoundNewAssignment = true;
|
| + }
|
| + }
|
| + }
|
| + } while (FoundNewAssignment);
|
| }
|
|
|
| void Cfg::doAddressOpt() {
|
| @@ -907,7 +1009,7 @@ void Cfg::emit() {
|
| deleteJumpTableInsts();
|
| if (Ctx->getFlags().getDecorateAsm()) {
|
| for (Variable *Var : getVariables()) {
|
| - if (Var->getStackOffset()) {
|
| + if (Var->getStackOffset() && !Var->isRematerializable()) {
|
| Str << "\t" << Var->getSymbolicStackOffset(this) << " = "
|
| << Var->getStackOffset() << "\n";
|
| }
|
|
|