mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-11-01 15:11:24 +00:00
Allow readonly functions to unwind exceptions. Teach
the optimizers about this. For example, a readonly function with no uses cannot be removed unless it is also marked nounwind. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@71071 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
e031e4bcb9
commit
7af1c78b98
@ -1061,23 +1061,24 @@ unwind or exceptional control flow. If the function does unwind, its runtime
|
||||
behavior is undefined.</dd>
|
||||
|
||||
<dt><tt>readnone</tt></dt>
|
||||
<dd>This attribute indicates that the function computes its result (or the
|
||||
exception it throws) based strictly on its arguments, without dereferencing any
|
||||
<dd>This attribute indicates that the function computes its result (or decides to
|
||||
unwind an exception) based strictly on its arguments, without dereferencing any
|
||||
pointer arguments or otherwise accessing any mutable state (e.g. memory, control
|
||||
registers, etc) visible to caller functions. It does not write through any
|
||||
pointer arguments (including <tt><a href="#byval">byval</a></tt> arguments) and
|
||||
never changes any state visible to callers. readnone functions may not throw
|
||||
an exception that escapes into the caller.</dd>
|
||||
never changes any state visible to callers. This means that it cannot unwind
|
||||
exceptions by calling the <tt>C++</tt> exception throwing methods, but could
|
||||
use the <tt>unwind</tt> instruction.</dd>
|
||||
|
||||
<dt><tt><a name="readonly">readonly</a></tt></dt>
|
||||
<dd>This attribute indicates that the function does not write through any
|
||||
pointer arguments (including <tt><a href="#byval">byval</a></tt> arguments)
|
||||
or otherwise modify any state (e.g. memory, control registers, etc) visible to
|
||||
caller functions. It may dereference pointer arguments and read state that may
|
||||
be set in the caller. A readonly function always returns the same value when
|
||||
called with the same set of arguments and global
|
||||
state. readonly functions may not throw an exception that escapes into the
|
||||
caller.</dd>
|
||||
be set in the caller. A readonly function always returns the same value (or
|
||||
unwinds an exception identically) when called with the same set of arguments
|
||||
and global state. It cannot unwind an exception by calling the <tt>C++</tt>
|
||||
exception throwing methods, but may use the <tt>unwind</tt> instruction.</dd>
|
||||
|
||||
<dt><tt><a name="ssp">ssp</a></tt></dt>
|
||||
<dd>This attribute indicates that the function should emit a stack smashing
|
||||
|
@ -40,14 +40,6 @@ public:
|
||||
// Out of line virtual method, so the vtable, etc has a home.
|
||||
~Instruction();
|
||||
|
||||
/// mayWriteToMemory - Return true if this instruction may modify memory.
|
||||
///
|
||||
bool mayWriteToMemory() const;
|
||||
|
||||
/// mayReadFromMemory - Return true if this instruction may read memory.
|
||||
///
|
||||
bool mayReadFromMemory() const;
|
||||
|
||||
/// clone() - Create a copy of 'this' instruction that is identical in all
|
||||
/// ways except the following:
|
||||
/// * The instruction has no parent
|
||||
@ -181,6 +173,24 @@ public:
|
||||
}
|
||||
static bool isTrapping(unsigned op);
|
||||
|
||||
/// mayWriteToMemory - Return true if this instruction may modify memory.
|
||||
///
|
||||
bool mayWriteToMemory() const;
|
||||
|
||||
/// mayReadFromMemory - Return true if this instruction may read memory.
|
||||
///
|
||||
bool mayReadFromMemory() const;
|
||||
|
||||
/// mayThrow - Return true if this instruction may throw an exception.
|
||||
///
|
||||
bool mayThrow() const;
|
||||
|
||||
/// mayHaveSideEffects - Return true if the instruction may have side effects.
|
||||
///
|
||||
bool mayHaveSideEffects() const {
|
||||
return mayWriteToMemory() || mayThrow();
|
||||
}
|
||||
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const Instruction *) { return true; }
|
||||
static inline bool classof(const Value *V) {
|
||||
|
@ -57,7 +57,7 @@ bool ADCE::runOnFunction(Function& F) {
|
||||
for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I)
|
||||
if (isa<TerminatorInst>(I.getInstructionIterator()) ||
|
||||
isa<DbgInfoIntrinsic>(I.getInstructionIterator()) ||
|
||||
I->mayWriteToMemory()) {
|
||||
I->mayHaveSideEffects()) {
|
||||
alive.insert(I.getInstructionIterator());
|
||||
worklist.push_back(I.getInstructionIterator());
|
||||
}
|
||||
|
@ -1479,13 +1479,13 @@ bool GVN::performPRE(Function& F) {
|
||||
for (BasicBlock::iterator BI = CurrentBlock->begin(),
|
||||
BE = CurrentBlock->end(); BI != BE; ) {
|
||||
Instruction *CurInst = BI++;
|
||||
|
||||
|
||||
if (isa<AllocationInst>(CurInst) || isa<TerminatorInst>(CurInst) ||
|
||||
isa<PHINode>(CurInst) || (CurInst->getType() == Type::VoidTy) ||
|
||||
CurInst->mayReadFromMemory() || CurInst->mayWriteToMemory() ||
|
||||
CurInst->mayReadFromMemory() || CurInst->mayHaveSideEffects() ||
|
||||
isa<DbgInfoIntrinsic>(CurInst))
|
||||
continue;
|
||||
|
||||
|
||||
uint32_t valno = VN.lookup(CurInst);
|
||||
|
||||
// Look for the predecessors for PRE opportunities. We're
|
||||
|
@ -12579,7 +12579,7 @@ static bool TryToSinkInstruction(Instruction *I, BasicBlock *DestBlock) {
|
||||
assert(I->hasOneUse() && "Invariants didn't hold!");
|
||||
|
||||
// Cannot move control-flow-involving, volatile loads, vaarg, etc.
|
||||
if (isa<PHINode>(I) || I->mayWriteToMemory() || isa<TerminatorInst>(I))
|
||||
if (isa<PHINode>(I) || I->mayHaveSideEffects() || isa<TerminatorInst>(I))
|
||||
return false;
|
||||
|
||||
// Do not sink alloca instructions out of the entry block.
|
||||
|
@ -136,11 +136,8 @@ bool LoopDeletion::IsLoopDead(Loop* L,
|
||||
LI != LE; ++LI) {
|
||||
for (BasicBlock::iterator BI = (*LI)->begin(), BE = (*LI)->end();
|
||||
BI != BE; ++BI) {
|
||||
if (BI->mayWriteToMemory())
|
||||
if (BI->mayHaveSideEffects())
|
||||
return false;
|
||||
else if (LoadInst* L = dyn_cast<LoadInst>(BI))
|
||||
if (L->isVolatile())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1148,7 +1148,7 @@ bool LoopIndexSplit::cleanBlock(BasicBlock *BB) {
|
||||
|| isa<DbgInfoIntrinsic>(I))
|
||||
continue;
|
||||
|
||||
if (I->mayWriteToMemory())
|
||||
if (I->mayHaveSideEffects())
|
||||
return false;
|
||||
|
||||
// I is used only inside this block then it is OK.
|
||||
|
@ -300,7 +300,7 @@ static bool isTrivialLoopExitBlockHelper(Loop *L, BasicBlock *BB,
|
||||
// Okay, everything after this looks good, check to make sure that this block
|
||||
// doesn't include any side effects.
|
||||
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
|
||||
if (I->mayWriteToMemory())
|
||||
if (I->mayHaveSideEffects())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -383,7 +383,7 @@ bool LoopUnswitch::IsTrivialUnswitchCondition(Value *Cond, Constant **Val,
|
||||
// part of the loop that the code *would* execute. We already checked the
|
||||
// tail, check the header now.
|
||||
for (BasicBlock::iterator I = Header->begin(), E = Header->end(); I != E; ++I)
|
||||
if (I->mayWriteToMemory())
|
||||
if (I->mayHaveSideEffects())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -258,7 +258,7 @@ void TailDup::eliminateUnconditionalBranch(BranchInst *Branch) {
|
||||
while (!isa<TerminatorInst>(BBI)) {
|
||||
Instruction *I = BBI++;
|
||||
|
||||
bool CanHoist = !I->isTrapping() && !I->mayWriteToMemory();
|
||||
bool CanHoist = !I->isTrapping() && !I->mayHaveSideEffects();
|
||||
if (CanHoist) {
|
||||
for (unsigned op = 0, e = I->getNumOperands(); op != e; ++op)
|
||||
if (Instruction *OpI = dyn_cast<Instruction>(I->getOperand(op)))
|
||||
|
@ -201,7 +201,7 @@ bool TailCallElim::runOnFunction(Function &F) {
|
||||
bool TailCallElim::CanMoveAboveCall(Instruction *I, CallInst *CI) {
|
||||
// FIXME: We can move load/store/call/free instructions above the call if the
|
||||
// call does not mod/ref the memory location being processed.
|
||||
if (I->mayWriteToMemory() || isa<LoadInst>(I))
|
||||
if (I->mayHaveSideEffects() || isa<LoadInst>(I))
|
||||
return false;
|
||||
|
||||
// Otherwise, if this is a side-effect free instruction, check to make sure
|
||||
|
@ -164,17 +164,15 @@ bool llvm::isInstructionTriviallyDead(Instruction *I) {
|
||||
|
||||
// We don't want debug info removed by anything this general.
|
||||
if (isa<DbgInfoIntrinsic>(I)) return false;
|
||||
|
||||
if (!I->mayWriteToMemory())
|
||||
return true;
|
||||
|
||||
// Special case intrinsics that "may write to memory" but can be deleted when
|
||||
// dead.
|
||||
if (!I->mayHaveSideEffects()) return true;
|
||||
|
||||
// Special case intrinsics that "may have side effects" but can be deleted
|
||||
// when dead.
|
||||
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I))
|
||||
// Safe to delete llvm.stacksave if dead.
|
||||
if (II->getIntrinsicID() == Intrinsic::stacksave)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -230,7 +228,7 @@ llvm::RecursivelyDeleteDeadPHINode(PHINode *PN) {
|
||||
SmallPtrSet<PHINode *, 4> PHIs;
|
||||
PHIs.insert(PN);
|
||||
for (Instruction *J = cast<Instruction>(*PN->use_begin());
|
||||
J->hasOneUse() && !J->mayWriteToMemory();
|
||||
J->hasOneUse() && !J->mayHaveSideEffects();
|
||||
J = cast<Instruction>(*J->use_begin()))
|
||||
// If we find a PHI more than once, we're on a cycle that
|
||||
// won't prove fruitful.
|
||||
|
@ -320,6 +320,14 @@ bool Instruction::mayWriteToMemory() const {
|
||||
}
|
||||
}
|
||||
|
||||
/// mayThrow - Return true if this instruction may throw an exception.
|
||||
///
|
||||
bool Instruction::mayThrow() const {
|
||||
if (const CallInst *CI = dyn_cast<CallInst>(this))
|
||||
return !CI->doesNotThrow();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// isAssociative - Return true if the instruction is associative:
|
||||
///
|
||||
/// Associative operators satisfy: x op (y op z) === (x op y) op z)
|
||||
|
@ -1,8 +1,8 @@
|
||||
; RUN: llvm-as < %s | opt -adce | llvm-dis | not grep call
|
||||
|
||||
declare i32 @strlen(i8*) readonly
|
||||
declare i32 @strlen(i8*) readonly nounwind
|
||||
|
||||
define void @test() {
|
||||
call i32 @strlen( i8* null ) readonly ; <i32>:1 [#uses=0]
|
||||
call i32 @strlen( i8* null ) ; <i32>:1 [#uses=0]
|
||||
ret void
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user