Skip to content

Commit

Permalink
[TypePromotion] Make TypeSize a class member
Browse files Browse the repository at this point in the history
Having TypeSize as a static class variable was causing problems
with multi-threading. Several static functions have now been
converted into methods of TypePromotion and a few other members
of TypePromotion and IRPromoter have been added or removed.

Differential Revision: https://reviews.llvm.org/D71832
  • Loading branch information
sparker-arm committed Dec 24, 2019
1 parent fccac1e commit 42dba63
Showing 1 changed file with 98 additions and 87 deletions.
185 changes: 98 additions & 87 deletions llvm/lib/CodeGen/TypePromotion.cpp
Expand Up @@ -104,17 +104,14 @@ DisablePromotion("disable-type-promotion", cl::Hidden, cl::init(true),

namespace {
class IRPromoter {
LLVMContext &Ctx;
IntegerType *OrigTy = nullptr;
unsigned PromotedWidth = 0;
IntegerType *ExtTy = nullptr;
SmallPtrSet<Value*, 8> NewInsts;
SmallPtrSet<Instruction*, 4> InstsToRemove;
DenseMap<Value*, SmallVector<Type*, 4>> TruncTysMap;
SmallPtrSet<Value*, 8> Promoted;
LLVMContext &Ctx;
// The type we promote to: always i32
IntegerType *ExtTy = nullptr;
// The type of the value that the search began from, either i8 or i16.
// This defines the max range of the values that we allow in the promoted
// tree.
IntegerType *OrigTy = nullptr;
SetVector<Value*> *Visited;
SmallPtrSetImpl<Value*> *Sources;
SmallPtrSetImpl<Instruction*> *Sinks;
Expand All @@ -130,32 +127,58 @@ class IRPromoter {
void Cleanup(void);

public:
IRPromoter(Module *M) : Ctx(M->getContext()) { }

IRPromoter(LLVMContext &C, IntegerType *Ty, unsigned Width) :
Ctx(C), OrigTy(Ty), PromotedWidth(Width) {
ExtTy = IntegerType::get(Ctx, PromotedWidth);
assert(OrigTy->getPrimitiveSizeInBits() < ExtTy->getPrimitiveSizeInBits()
&& "Original type not smaller than extended type");
}

void Mutate(Type *OrigTy, unsigned PromotedWidth,
SetVector<Value*> &Visited,
void Mutate(SetVector<Value*> &Visited,
SmallPtrSetImpl<Value*> &Sources,
SmallPtrSetImpl<Instruction*> &Sinks,
SmallPtrSetImpl<Instruction*> &SafeToPromote,
SmallPtrSetImpl<Instruction*> &SafeWrap);
};

class TypePromotion : public FunctionPass {
IRPromoter *Promoter = nullptr;
unsigned TypeSize = 0;
LLVMContext *Ctx = nullptr;
unsigned RegisterBitWidth = 0;
SmallPtrSet<Value*, 16> AllVisited;
SmallPtrSet<Instruction*, 8> SafeToPromote;
SmallPtrSet<Instruction*, 4> SafeWrap;

// Does V have the same size result type as TypeSize.
bool EqualTypeSize(Value *V);
// Does V have the same size, or narrower, result type as TypeSize.
bool LessOrEqualTypeSize(Value *V);
// Does V have a result type that is wider than TypeSize.
bool GreaterThanTypeSize(Value *V);
// Does V have a result type that is narrower than TypeSize.
bool LessThanTypeSize(Value *V);
// Should V be a leaf in the promote tree?
bool isSource(Value *V);
// Should V be a root in the promotion tree?
bool isSink(Value *V);
// Should we change the result type of V? It will result in the users of V
// being visited.
bool shouldPromote(Value *V);
// Is I an add or a sub, which isn't marked as nuw, but where a wrapping
// result won't affect the computation?
bool isSafeWrap(Instruction *I);
// Can V have its integer type promoted, or can the type be ignored.
bool isSupportedType(Value *V);
// Is V an instruction with a supported opcode or another value that we can
// handle, such as constants and basic blocks.
bool isSupportedValue(Value *V);
// Is V an instruction thats result can trivially promoted, or has safe
// wrapping.
bool isLegalToPromote(Value *V);
bool TryToPromote(Value *V, unsigned PromotedWidth);

public:
static char ID;
static unsigned TypeSize;
Type *OrigTy = nullptr;

TypePromotion() : FunctionPass(ID) {}

Expand All @@ -166,9 +189,7 @@ class TypePromotion : public FunctionPass {

StringRef getPassName() const override { return PASS_NAME; }

bool doInitialization(Module &M) override;
bool runOnFunction(Function &F) override;
bool doFinalization(Module &M) override;
};

}
Expand All @@ -182,41 +203,20 @@ static bool GenerateSignBits(Value *V) {
Opc == Instruction::SRem || Opc == Instruction::SExt;
}

static bool EqualTypeSize(Value *V) {
return V->getType()->getScalarSizeInBits() == TypePromotion::TypeSize;
bool TypePromotion::EqualTypeSize(Value *V) {
return V->getType()->getScalarSizeInBits() == TypeSize;
}

static bool LessOrEqualTypeSize(Value *V) {
return V->getType()->getScalarSizeInBits() <= TypePromotion::TypeSize;
bool TypePromotion::LessOrEqualTypeSize(Value *V) {
return V->getType()->getScalarSizeInBits() <= TypeSize;
}

static bool GreaterThanTypeSize(Value *V) {
return V->getType()->getScalarSizeInBits() > TypePromotion::TypeSize;
bool TypePromotion::GreaterThanTypeSize(Value *V) {
return V->getType()->getScalarSizeInBits() > TypeSize;
}

static bool LessThanTypeSize(Value *V) {
return V->getType()->getScalarSizeInBits() < TypePromotion::TypeSize;
}

/// Some instructions can use 8- and 16-bit operands, and we don't need to
/// promote anything larger. We disallow booleans to make life easier when
/// dealing with icmps but allow any other integer that is <= 16 bits. Void
/// types are accepted so we can handle switches.
static bool isSupportedType(Value *V) {
Type *Ty = V->getType();

// Allow voids and pointers, these won't be promoted.
if (Ty->isVoidTy() || Ty->isPointerTy())
return true;

if (auto *Ld = dyn_cast<LoadInst>(V))
Ty = cast<PointerType>(Ld->getPointerOperandType())->getElementType();

if (!isa<IntegerType>(Ty) ||
cast<IntegerType>(V->getType())->getBitWidth() == 1)
return false;

return LessOrEqualTypeSize(V);
bool TypePromotion::LessThanTypeSize(Value *V) {
return V->getType()->getScalarSizeInBits() < TypeSize;
}

/// Return true if the given value is a source in the use-def chain, producing
Expand All @@ -226,7 +226,7 @@ static bool isSupportedType(Value *V) {
/// return values because we only accept ones that guarantee a zeroext ret val.
/// Many arguments will have the zeroext attribute too, so those would be free
/// too.
static bool isSource(Value *V) {
bool TypePromotion::isSource(Value *V) {
if (!isa<IntegerType>(V->getType()))
return false;

Expand All @@ -247,7 +247,7 @@ static bool isSource(Value *V) {
/// Return true if V will require any promoted values to be truncated for the
/// the IR to remain valid. We can't mutate the value type of these
/// instructions.
static bool isSink(Value *V) {
bool TypePromotion::isSink(Value *V) {
// TODO The truncate also isn't actually necessary because we would already
// proved that the data value is kept within the range of the original data
// type.
Expand Down Expand Up @@ -380,12 +380,13 @@ bool TypePromotion::isSafeWrap(Instruction *I) {
} else if (Total.ugt(Max))
return false;

LLVM_DEBUG(dbgs() << "IR Promotion: Allowing safe overflow for " << *I << "\n");
LLVM_DEBUG(dbgs() << "IR Promotion: Allowing safe overflow for "
<< *I << "\n");
SafeWrap.insert(I);
return true;
}

static bool shouldPromote(Value *V) {
bool TypePromotion::shouldPromote(Value *V) {
if (!isa<IntegerType>(V->getType()) || isSink(V))
return false;

Expand Down Expand Up @@ -540,7 +541,8 @@ void IRPromoter::PromoteTree() {
I->setOperand(i, UndefValue::get(ExtTy));
}

if (shouldPromote(I)) {
// Mutate the result type, unless this is an icmp.
if (!isa<ICmpInst>(I)) {
I->mutateType(ExtTy);
Promoted.insert(I);
}
Expand Down Expand Up @@ -644,13 +646,6 @@ void IRPromoter::Cleanup() {
I->dropAllReferences();
I->eraseFromParent();
}

InstsToRemove.clear();
NewInsts.clear();
TruncTysMap.clear();
Promoted.clear();
SafeToPromote->clear();
SafeWrap->clear();
}

void IRPromoter::ConvertTruncs() {
Expand Down Expand Up @@ -678,21 +673,13 @@ void IRPromoter::ConvertTruncs() {
}
}

void IRPromoter::Mutate(Type *OrigTy, unsigned PromotedWidth,
SetVector<Value*> &Visited,
void IRPromoter::Mutate(SetVector<Value*> &Visited,
SmallPtrSetImpl<Value*> &Sources,
SmallPtrSetImpl<Instruction*> &Sinks,
SmallPtrSetImpl<Instruction*> &SafeToPromote,
SmallPtrSetImpl<Instruction*> &SafeWrap) {
LLVM_DEBUG(dbgs() << "IR Promotion: Promoting use-def chains from "
<< TypePromotion::TypeSize << " to " << PromotedWidth
<< "-bits\n");

assert(isa<IntegerType>(OrigTy) && "expected integer type");
this->OrigTy = cast<IntegerType>(OrigTy);
ExtTy = IntegerType::get(Ctx, PromotedWidth);
assert(OrigTy->getPrimitiveSizeInBits() < ExtTy->getPrimitiveSizeInBits() &&
"original type not smaller than extended type");
<< OrigTy->getBitWidth() << " to " << PromotedWidth << "-bits\n");

this->Visited = &Visited;
this->Sources = &Sources;
Expand Down Expand Up @@ -744,6 +731,24 @@ void IRPromoter::Mutate(Type *OrigTy, unsigned PromotedWidth,
LLVM_DEBUG(dbgs() << "IR Promotion: Mutation complete\n");
}

/// We disallow booleans to make life easier when dealing with icmps but allow
/// any other integer that fits in a scalar register. Void types are accepted
/// so we can handle switches.
bool TypePromotion::isSupportedType(Value *V) {
Type *Ty = V->getType();

// Allow voids and pointers, these won't be promoted.
if (Ty->isVoidTy() || Ty->isPointerTy())
return true;

if (!isa<IntegerType>(Ty) ||
cast<IntegerType>(Ty)->getBitWidth() == 1 ||
cast<IntegerType>(Ty)->getBitWidth() > RegisterBitWidth)
return false;

return LessOrEqualTypeSize(V);
}

/// We accept most instructions, as well as Arguments and ConstantInsts. We
/// Disallow casts other than zext and truncs and only allow calls if their
/// return value is zeroext. We don't allow opcodes that can introduce sign
Expand Down Expand Up @@ -813,7 +818,7 @@ bool TypePromotion::isLegalToPromote(Value *V) {
}

bool TypePromotion::TryToPromote(Value *V, unsigned PromotedWidth) {
OrigTy = V->getType();
Type *OrigTy = V->getType();
TypeSize = OrigTy->getPrimitiveSizeInBits();
SafeToPromote.clear();
SafeWrap.clear();
Expand Down Expand Up @@ -903,28 +908,39 @@ bool TypePromotion::TryToPromote(Value *V, unsigned PromotedWidth) {
for (auto *I : CurrentVisited)
I->dump();
);

unsigned ToPromote = 0;
unsigned NonFreeArgs = 0;
SmallPtrSet<BasicBlock*, 4> Blocks;
for (auto *V : CurrentVisited) {
if (Sources.count(V))
if (auto *I = dyn_cast<Instruction>(V))
Blocks.insert(I->getParent());

if (Sources.count(V)) {
if (auto *Arg = dyn_cast<Argument>(V))
if (!Arg->hasZExtAttr() && !Arg->hasSExtAttr())
++NonFreeArgs;
continue;
}

if (Sinks.count(cast<Instruction>(V)))
continue;
++ToPromote;
}
++ToPromote;
}

// DAG optimisations should be able to handle these cases better, especially
// for function arguments.
if (ToPromote < 2 || (Blocks.size() == 1 && (NonFreeArgs > SafeWrap.size())))
return false;

if (ToPromote < 2)
return false;

Promoter->Mutate(OrigTy, PromotedWidth, CurrentVisited, Sources, Sinks,
SafeToPromote, SafeWrap);
IRPromoter Promoter(*Ctx, cast<IntegerType>(OrigTy), PromotedWidth);
Promoter.Mutate(CurrentVisited, Sources, Sinks, SafeToPromote, SafeWrap);
return true;
}

bool TypePromotion::doInitialization(Module &M) {
Promoter = new IRPromoter(&M);
return false;
}

bool TypePromotion::runOnFunction(Function &F) {
if (skipFunction(F) || DisablePromotion)
return false;
Expand All @@ -942,11 +958,12 @@ bool TypePromotion::runOnFunction(Function &F) {
const TargetLowering *TLI = SubtargetInfo->getTargetLowering();
const TargetTransformInfo &TII =
getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
RegisterBitWidth = TII.getRegisterBitWidth(false);
Ctx = &F.getParent()->getContext();

// Search up from icmps to try to promote their operands.
for (BasicBlock &BB : F) {
auto &Insts = BB.getInstList();
for (auto &I : Insts) {
for (auto &I : BB) {
if (AllVisited.count(&I))
continue;

Expand All @@ -972,7 +989,7 @@ bool TypePromotion::runOnFunction(Function &F) {
break;

EVT PromotedVT = TLI->getTypeToTransformTo(ICmp->getContext(), SrcVT);
if (TII.getRegisterBitWidth(false) < PromotedVT.getSizeInBits()) {
if (RegisterBitWidth < PromotedVT.getSizeInBits()) {
LLVM_DEBUG(dbgs() << "IR Promotion: Couldn't find target register "
<< "for promoted type\n");
break;
Expand All @@ -994,16 +1011,10 @@ bool TypePromotion::runOnFunction(Function &F) {
return MadeChange;
}

bool TypePromotion::doFinalization(Module &M) {
delete Promoter;
return false;
}

INITIALIZE_PASS_BEGIN(TypePromotion, DEBUG_TYPE, PASS_NAME, false, false)
INITIALIZE_PASS_END(TypePromotion, DEBUG_TYPE, PASS_NAME, false, false)

char TypePromotion::ID = 0;
unsigned TypePromotion::TypeSize = 0;

FunctionPass *llvm::createTypePromotionPass() {
return new TypePromotion();
Expand Down

0 comments on commit 42dba63

Please sign in to comment.