mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
IRGen for break/continue.
Swift SVN r2089
This commit is contained in:
@@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
namespace swift {
|
namespace swift {
|
||||||
namespace irgen {
|
namespace irgen {
|
||||||
class IRGenFunction;
|
|
||||||
|
|
||||||
// These classes are private to GenCleanup.cpp.
|
// These classes are private to GenCleanup.cpp.
|
||||||
class CleanupControl;
|
class CleanupControl;
|
||||||
|
|||||||
@@ -33,13 +33,13 @@ namespace irgen {
|
|||||||
/// cleanup.
|
/// cleanup.
|
||||||
class ManagedValue {
|
class ManagedValue {
|
||||||
llvm::Value *Value;
|
llvm::Value *Value;
|
||||||
IRGenFunction::CleanupsDepth Cleanup;
|
CleanupsDepth Cleanup;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ManagedValue() = default;
|
ManagedValue() = default;
|
||||||
explicit ManagedValue(llvm::Value *value)
|
explicit ManagedValue(llvm::Value *value)
|
||||||
: Value(value), Cleanup(IRGenFunction::CleanupsDepth::invalid()) {}
|
: Value(value), Cleanup(CleanupsDepth::invalid()) {}
|
||||||
ManagedValue(llvm::Value *value, IRGenFunction::CleanupsDepth cleanup)
|
ManagedValue(llvm::Value *value, CleanupsDepth cleanup)
|
||||||
: Value(value), Cleanup(cleanup) {}
|
: Value(value), Cleanup(cleanup) {}
|
||||||
|
|
||||||
llvm::Value *getUnmanagedValue() const {
|
llvm::Value *getUnmanagedValue() const {
|
||||||
@@ -49,7 +49,7 @@ public:
|
|||||||
llvm::Value *getValue() const { return Value; }
|
llvm::Value *getValue() const { return Value; }
|
||||||
|
|
||||||
bool hasCleanup() const { return Cleanup.isValid(); }
|
bool hasCleanup() const { return Cleanup.isValid(); }
|
||||||
IRGenFunction::CleanupsDepth getCleanup() const { return Cleanup; }
|
CleanupsDepth getCleanup() const { return Cleanup; }
|
||||||
|
|
||||||
/// Forward this value, deactivating the cleanup and returning the
|
/// Forward this value, deactivating the cleanup and returning the
|
||||||
/// underlying value.
|
/// underlying value.
|
||||||
@@ -60,8 +60,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Split this value into its underlying value and, if present, its cleanup.
|
/// Split this value into its underlying value and, if present, its cleanup.
|
||||||
llvm::Value *split(llvm::SmallVectorImpl<IRGenFunction::CleanupsDepth>
|
llvm::Value *split(llvm::SmallVectorImpl<CleanupsDepth> &cleanups) {
|
||||||
&cleanups) {
|
|
||||||
if (hasCleanup()) cleanups.push_back(getCleanup());
|
if (hasCleanup()) cleanups.push_back(getCleanup());
|
||||||
return getValue();
|
return getValue();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -663,7 +663,7 @@ static void popAndEmitTopCleanup(IRGenFunction &IGF,
|
|||||||
/// Remove all the dead cleanups on the top of the cleanup stack.
|
/// Remove all the dead cleanups on the top of the cleanup stack.
|
||||||
static void popAndEmitTopDeadCleanups(IRGenFunction &IGF,
|
static void popAndEmitTopDeadCleanups(IRGenFunction &IGF,
|
||||||
DiverseStackImpl<Cleanup> &stack,
|
DiverseStackImpl<Cleanup> &stack,
|
||||||
IRGenFunction::CleanupsDepth end) {
|
CleanupsDepth end) {
|
||||||
stack.checkIterator(end);
|
stack.checkIterator(end);
|
||||||
|
|
||||||
while (stack.stable_begin() != end && stack.begin()->isDead()) {
|
while (stack.stable_begin() != end && stack.begin()->isDead()) {
|
||||||
|
|||||||
@@ -1040,7 +1040,7 @@ namespace {
|
|||||||
|
|
||||||
unsigned LastArgWritten;
|
unsigned LastArgWritten;
|
||||||
SmallVector<llvm::Value*, 16> Args;
|
SmallVector<llvm::Value*, 16> Args;
|
||||||
SmallVector<IRGenFunction::CleanupsDepth, 16> ArgCleanups;
|
SmallVector<CleanupsDepth, 16> ArgCleanups;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
CallEmitter(IRGenFunction &IGF, const Callee &callee,
|
CallEmitter(IRGenFunction &IGF, const Callee &callee,
|
||||||
|
|||||||
@@ -591,7 +591,7 @@ namespace {
|
|||||||
/// Enter a cleanup to call swift_dealloc on the given pointer.
|
/// Enter a cleanup to call swift_dealloc on the given pointer.
|
||||||
/// This cleanup will usually be deactivated as soon as the
|
/// This cleanup will usually be deactivated as soon as the
|
||||||
/// initializer completes.
|
/// initializer completes.
|
||||||
IRGenFunction::CleanupsDepth
|
CleanupsDepth
|
||||||
IRGenFunction::pushDeallocCleanup(llvm::Value *allocation,
|
IRGenFunction::pushDeallocCleanup(llvm::Value *allocation,
|
||||||
llvm::Value *size) {
|
llvm::Value *size) {
|
||||||
pushFullExprCleanup<CallDealloc>(allocation, size);
|
pushFullExprCleanup<CallDealloc>(allocation, size);
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ static OnHeap_t isOnHeap(VarDecl *var) {
|
|||||||
void Initialization::registerObject(IRGenFunction &IGF, Object object,
|
void Initialization::registerObject(IRGenFunction &IGF, Object object,
|
||||||
OnHeap_t onHeap, const TypeInfo &objectTI) {
|
OnHeap_t onHeap, const TypeInfo &objectTI) {
|
||||||
// Create the appropriate destroy cleanup.
|
// Create the appropriate destroy cleanup.
|
||||||
IRGenFunction::CleanupsDepth destroy;
|
CleanupsDepth destroy;
|
||||||
|
|
||||||
// We need a destroy cleanup if the object is on the heap or non-POD.
|
// We need a destroy cleanup if the object is on the heap or non-POD.
|
||||||
if (onHeap || !objectTI.isPOD(ResilienceScope::Local)) {
|
if (onHeap || !objectTI.isPOD(ResilienceScope::Local)) {
|
||||||
@@ -78,24 +78,24 @@ void Initialization::registerObject(IRGenFunction &IGF, Object object,
|
|||||||
objectTI);
|
objectTI);
|
||||||
destroy = IGF.getCleanupsDepth();
|
destroy = IGF.getCleanupsDepth();
|
||||||
} else {
|
} else {
|
||||||
destroy = IRGenFunction::CleanupsDepth::invalid();
|
destroy = CleanupsDepth::invalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
registerObject(object, destroy);
|
registerObject(object, destroy);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Initialization::registerObjectWithoutDestroy(Object object) {
|
void Initialization::registerObjectWithoutDestroy(Object object) {
|
||||||
registerObject(object, IRGenFunction::CleanupsDepth::invalid());
|
registerObject(object, CleanupsDepth::invalid());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register an object with the initialization process.
|
/// Register an object with the initialization process.
|
||||||
void Initialization::registerObject(Object object,
|
void Initialization::registerObject(Object object,
|
||||||
IRGenFunction::CleanupsDepth destroy) {
|
CleanupsDepth destroy) {
|
||||||
// The invariant is that the cleanup has to be an
|
// The invariant is that the cleanup has to be an
|
||||||
// UnboundDestroy if it's valid.
|
// UnboundDestroy if it's valid.
|
||||||
|
|
||||||
ValueRecord record = {
|
ValueRecord record = {
|
||||||
IRGenFunction::CleanupsDepth::invalid(), destroy
|
CleanupsDepth::invalid(), destroy
|
||||||
};
|
};
|
||||||
Records.insert(std::make_pair(object.Opaque, record));
|
Records.insert(std::make_pair(object.Opaque, record));
|
||||||
}
|
}
|
||||||
@@ -103,7 +103,7 @@ void Initialization::registerObject(Object object,
|
|||||||
/// Mark that an object has been allocated.
|
/// Mark that an object has been allocated.
|
||||||
void Initialization::markAllocated(IRGenFunction &IGF, Object object,
|
void Initialization::markAllocated(IRGenFunction &IGF, Object object,
|
||||||
OwnedAddress address,
|
OwnedAddress address,
|
||||||
IRGenFunction::CleanupsDepth dealloc) {
|
CleanupsDepth dealloc) {
|
||||||
ValueRecord &record = Records.find(object.Opaque)->second;
|
ValueRecord &record = Records.find(object.Opaque)->second;
|
||||||
record.DeallocCleanup = dealloc;
|
record.DeallocCleanup = dealloc;
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ Initialization::emitLocalAllocation(IRGenFunction &IGF, Object object,
|
|||||||
// If the type is known to be empty, don't actually allocate anything.
|
// If the type is known to be empty, don't actually allocate anything.
|
||||||
if (type.isEmpty(ResilienceScope::Local)) {
|
if (type.isEmpty(ResilienceScope::Local)) {
|
||||||
OwnedAddress addr = createEmptyAlloca(IGF.IGM, type);
|
OwnedAddress addr = createEmptyAlloca(IGF.IGM, type);
|
||||||
markAllocated(IGF, object, addr, IRGenFunction::CleanupsDepth::invalid());
|
markAllocated(IGF, object, addr, CleanupsDepth::invalid());
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,7 +173,7 @@ Initialization::emitLocalAllocation(IRGenFunction &IGF, Object object,
|
|||||||
// TODO: lifetime intrinsics?
|
// TODO: lifetime intrinsics?
|
||||||
|
|
||||||
OwnedAddress addr(rawAddr, IGF.IGM.RefCountedNull);
|
OwnedAddress addr(rawAddr, IGF.IGM.RefCountedNull);
|
||||||
markAllocated(IGF, object, addr, IRGenFunction::CleanupsDepth::invalid());
|
markAllocated(IGF, object, addr, CleanupsDepth::invalid());
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +192,7 @@ Initialization::emitLocalAllocation(IRGenFunction &IGF, Object object,
|
|||||||
|
|
||||||
// Push a cleanup to dealloc the allocation.
|
// Push a cleanup to dealloc the allocation.
|
||||||
// FIXME: don't emit the size twice!
|
// FIXME: don't emit the size twice!
|
||||||
IRGenFunction::CleanupsDepth deallocCleanup
|
CleanupsDepth deallocCleanup
|
||||||
= IGF.pushDeallocCleanup(allocation, layout.emitSize(IGF));
|
= IGF.pushDeallocCleanup(allocation, layout.emitSize(IGF));
|
||||||
|
|
||||||
OwnedAddress addr(rawAddr, allocation);
|
OwnedAddress addr(rawAddr, allocation);
|
||||||
@@ -201,7 +201,7 @@ Initialization::emitLocalAllocation(IRGenFunction &IGF, Object object,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void maybeSetCleanupState(IRGenFunction &IGF,
|
static void maybeSetCleanupState(IRGenFunction &IGF,
|
||||||
IRGenFunction::CleanupsDepth maybeCleanup,
|
CleanupsDepth maybeCleanup,
|
||||||
CleanupState newState) {
|
CleanupState newState) {
|
||||||
if (maybeCleanup.isValid())
|
if (maybeCleanup.isValid())
|
||||||
IGF.setCleanupState(maybeCleanup, newState);
|
IGF.setCleanupState(maybeCleanup, newState);
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ namespace irgen {
|
|||||||
/// variable initialization.
|
/// variable initialization.
|
||||||
class Initialization {
|
class Initialization {
|
||||||
struct ValueRecord {
|
struct ValueRecord {
|
||||||
IRGenFunction::CleanupsDepth DeallocCleanup;
|
CleanupsDepth DeallocCleanup;
|
||||||
IRGenFunction::CleanupsDepth DestroyCleanup;
|
CleanupsDepth DestroyCleanup;
|
||||||
};
|
};
|
||||||
|
|
||||||
llvm::DenseMap<void *, ValueRecord> Records;
|
llvm::DenseMap<void *, ValueRecord> Records;
|
||||||
@@ -108,14 +108,14 @@ public:
|
|||||||
/// trivial and there isn't a dealloc cleanup.
|
/// trivial and there isn't a dealloc cleanup.
|
||||||
void markAllocated(IRGenFunction &IGF, Object object,
|
void markAllocated(IRGenFunction &IGF, Object object,
|
||||||
OwnedAddress address,
|
OwnedAddress address,
|
||||||
IRGenFunction::CleanupsDepth dealloc);
|
CleanupsDepth dealloc);
|
||||||
|
|
||||||
/// Mark that the value has reached its instant of initialization.
|
/// Mark that the value has reached its instant of initialization.
|
||||||
void markInitialized(IRGenFunction &IGF, Object object);
|
void markInitialized(IRGenFunction &IGF, Object object);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Add an object that is going to be initialized.
|
/// Add an object that is going to be initialized.
|
||||||
void registerObject(Object object, IRGenFunction::CleanupsDepth destroy);
|
void registerObject(Object object, CleanupsDepth destroy);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace irgen
|
} // end namespace irgen
|
||||||
|
|||||||
@@ -1828,8 +1828,7 @@ namespace {
|
|||||||
|
|
||||||
// Pull off the outer result.
|
// Pull off the outer result.
|
||||||
FixedPacking innerResultPacking;
|
FixedPacking innerResultPacking;
|
||||||
IRGenFunction::CleanupsDepth outerResultCleanup
|
CleanupsDepth outerResultCleanup = CleanupsDepth::invalid();
|
||||||
= IRGenFunction::CleanupsDepth::invalid();
|
|
||||||
if (HasAbstractedResult) {
|
if (HasAbstractedResult) {
|
||||||
outerResult = Address(outerArgs.claimUnmanagedNext(),
|
outerResult = Address(outerArgs.claimUnmanagedNext(),
|
||||||
getFixedBufferAlignment(IGM));
|
getFixedBufferAlignment(IGM));
|
||||||
@@ -2182,7 +2181,7 @@ void irgen::emitErasureAsInit(IRGenFunction &IGF, ErasureExpr *E,
|
|||||||
Address object = emitAllocateBuffer(IGF, buffer, packing, concreteTI);
|
Address object = emitAllocateBuffer(IGF, buffer, packing, concreteTI);
|
||||||
|
|
||||||
// Push a cleanup to destroy that.
|
// Push a cleanup to destroy that.
|
||||||
IRGenFunction::CleanupsDepth deallocCleanup;
|
CleanupsDepth deallocCleanup;
|
||||||
bool needsDeallocCleanup = !isNeverAllocated(packing);
|
bool needsDeallocCleanup = !isNeverAllocated(packing);
|
||||||
if (needsDeallocCleanup) {
|
if (needsDeallocCleanup) {
|
||||||
IGF.pushFullExprCleanup<DeallocateBuffer>(buffer, packing, concreteTI);
|
IGF.pushFullExprCleanup<DeallocateBuffer>(buffer, packing, concreteTI);
|
||||||
|
|||||||
@@ -57,12 +57,10 @@ void IRGenFunction::emitStmt(Stmt *S) {
|
|||||||
return emitForEachStmt(cast<ForEachStmt>(S));
|
return emitForEachStmt(cast<ForEachStmt>(S));
|
||||||
|
|
||||||
case StmtKind::Break:
|
case StmtKind::Break:
|
||||||
unimplemented(cast<BreakStmt>(S)->getLoc(), "break statement");
|
return emitBreakStmt(cast<BreakStmt>(S));
|
||||||
return;
|
|
||||||
|
|
||||||
case StmtKind::Continue:
|
case StmtKind::Continue:
|
||||||
unimplemented(cast<ContinueStmt>(S)->getLoc(), "continue statement");
|
return emitContinueStmt(cast<ContinueStmt>(S));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
llvm_unreachable("bad statement kind!");
|
llvm_unreachable("bad statement kind!");
|
||||||
}
|
}
|
||||||
@@ -136,12 +134,29 @@ void IRGenFunction::emitReturnStmt(ReturnStmt *S) {
|
|||||||
Builder.ClearInsertionPoint();
|
Builder.ClearInsertionPoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void emitOrDeleteBlock(IRGenFunction &IGF, llvm::BasicBlock *BB) {
|
||||||
|
if (BB->use_empty()) {
|
||||||
|
// If the block is unused, we don't need it; just delete it.
|
||||||
|
delete BB;
|
||||||
|
} else {
|
||||||
|
// Otherwise, continue emitting code in BB.
|
||||||
|
if (IGF.Builder.hasValidIP())
|
||||||
|
IGF.Builder.CreateBr(BB);
|
||||||
|
IGF.Builder.emitBlockAnywhere(BB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void IRGenFunction::emitWhileStmt(WhileStmt *S) {
|
void IRGenFunction::emitWhileStmt(WhileStmt *S) {
|
||||||
// Create a new basic block and jump into it.
|
// Create a new basic block and jump into it.
|
||||||
llvm::BasicBlock *loopBB = createBasicBlock("while");
|
llvm::BasicBlock *loopBB = createBasicBlock("while");
|
||||||
Builder.CreateBr(loopBB);
|
Builder.CreateBr(loopBB);
|
||||||
Builder.emitBlock(loopBB);
|
Builder.emitBlock(loopBB);
|
||||||
|
|
||||||
|
// Set the destinations for 'break' and 'continue'
|
||||||
|
llvm::BasicBlock *endBB = createBasicBlock("while.end");
|
||||||
|
BreakDestStack.emplace_back(endBB, getCleanupsDepth());
|
||||||
|
ContinueDestStack.emplace_back(loopBB, getCleanupsDepth());
|
||||||
|
|
||||||
// Evaluate the condition with the false edge leading directly
|
// Evaluate the condition with the false edge leading directly
|
||||||
// to the continuation block.
|
// to the continuation block.
|
||||||
Condition cond = emitCondition(S->getCond(), /*hasFalseCode*/ false);
|
Condition cond = emitCondition(S->getCond(), /*hasFalseCode*/ false);
|
||||||
@@ -159,6 +174,10 @@ void IRGenFunction::emitWhileStmt(WhileStmt *S) {
|
|||||||
|
|
||||||
// Complete the conditional execution.
|
// Complete the conditional execution.
|
||||||
cond.complete(*this);
|
cond.complete(*this);
|
||||||
|
|
||||||
|
emitOrDeleteBlock(*this, endBB);
|
||||||
|
BreakDestStack.pop_back();
|
||||||
|
ContinueDestStack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRGenFunction::emitForStmt(ForStmt *S) {
|
void IRGenFunction::emitForStmt(ForStmt *S) {
|
||||||
@@ -184,7 +203,13 @@ void IRGenFunction::emitForStmt(ForStmt *S) {
|
|||||||
llvm::BasicBlock *loopBB = createBasicBlock("for.condition");
|
llvm::BasicBlock *loopBB = createBasicBlock("for.condition");
|
||||||
Builder.CreateBr(loopBB);
|
Builder.CreateBr(loopBB);
|
||||||
Builder.emitBlock(loopBB);
|
Builder.emitBlock(loopBB);
|
||||||
|
|
||||||
|
// Set the destinations for 'break' and 'continue'
|
||||||
|
llvm::BasicBlock *incBB = createBasicBlock("for.inc");
|
||||||
|
llvm::BasicBlock *endBB = createBasicBlock("for.end");
|
||||||
|
BreakDestStack.emplace_back(endBB, getCleanupsDepth());
|
||||||
|
ContinueDestStack.emplace_back(incBB, getCleanupsDepth());
|
||||||
|
|
||||||
// Evaluate the condition with the false edge leading directly
|
// Evaluate the condition with the false edge leading directly
|
||||||
// to the continuation block.
|
// to the continuation block.
|
||||||
Condition cond = S->getCond().isNonNull() ?
|
Condition cond = S->getCond().isNonNull() ?
|
||||||
@@ -195,7 +220,9 @@ void IRGenFunction::emitForStmt(ForStmt *S) {
|
|||||||
if (cond.hasTrue()) {
|
if (cond.hasTrue()) {
|
||||||
cond.enterTrue(*this);
|
cond.enterTrue(*this);
|
||||||
emitStmt(S->getBody());
|
emitStmt(S->getBody());
|
||||||
|
|
||||||
|
emitOrDeleteBlock(*this, incBB);
|
||||||
|
|
||||||
if (Builder.hasValidIP() && !S->getIncrement().isNull()) {
|
if (Builder.hasValidIP() && !S->getIncrement().isNull()) {
|
||||||
if (Expr *E = S->getIncrement().dyn_cast<Expr*>()) {
|
if (Expr *E = S->getIncrement().dyn_cast<Expr*>()) {
|
||||||
FullExpr scope(*this);
|
FullExpr scope(*this);
|
||||||
@@ -215,6 +242,9 @@ void IRGenFunction::emitForStmt(ForStmt *S) {
|
|||||||
// Complete the conditional execution.
|
// Complete the conditional execution.
|
||||||
cond.complete(*this);
|
cond.complete(*this);
|
||||||
|
|
||||||
|
emitOrDeleteBlock(*this, endBB);
|
||||||
|
BreakDestStack.pop_back();
|
||||||
|
ContinueDestStack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRGenFunction::emitForEachStmt(ForEachStmt *S) {
|
void IRGenFunction::emitForEachStmt(ForEachStmt *S) {
|
||||||
@@ -227,9 +257,14 @@ void IRGenFunction::emitForEachStmt(ForEachStmt *S) {
|
|||||||
if (!Builder.hasValidIP()) return;
|
if (!Builder.hasValidIP()) return;
|
||||||
|
|
||||||
// Create a new basic block and jump into it.
|
// Create a new basic block and jump into it.
|
||||||
llvm::BasicBlock *LoopBB = createBasicBlock("foreach.cond");
|
llvm::BasicBlock *loopBB = createBasicBlock("foreach.cond");
|
||||||
Builder.CreateBr(LoopBB);
|
Builder.CreateBr(loopBB);
|
||||||
Builder.emitBlock(LoopBB);
|
Builder.emitBlock(loopBB);
|
||||||
|
|
||||||
|
// Set the destinations for 'break' and 'continue'
|
||||||
|
llvm::BasicBlock *endBB = createBasicBlock("foreach.end");
|
||||||
|
BreakDestStack.emplace_back(endBB, getCleanupsDepth());
|
||||||
|
ContinueDestStack.emplace_back(loopBB, getCleanupsDepth());
|
||||||
|
|
||||||
Condition Cond = emitCondition(S->getRangeEmpty(), /*hasFalseCode=*/false,
|
Condition Cond = emitCondition(S->getRangeEmpty(), /*hasFalseCode=*/false,
|
||||||
/*invertValue=*/true);
|
/*invertValue=*/true);
|
||||||
@@ -247,13 +282,26 @@ void IRGenFunction::emitForEachStmt(ForEachStmt *S) {
|
|||||||
|
|
||||||
// Loop back to the header.
|
// Loop back to the header.
|
||||||
if (Builder.hasValidIP()) {
|
if (Builder.hasValidIP()) {
|
||||||
Builder.CreateBr(LoopBB);
|
Builder.CreateBr(loopBB);
|
||||||
Builder.ClearInsertionPoint();
|
Builder.ClearInsertionPoint();
|
||||||
}
|
}
|
||||||
Cond.exitTrue(*this);
|
Cond.exitTrue(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Complete the conditional execution.
|
// Complete the conditional execution.
|
||||||
Cond.complete(*this);
|
Cond.complete(*this);
|
||||||
|
|
||||||
|
emitOrDeleteBlock(*this, endBB);
|
||||||
|
BreakDestStack.pop_back();
|
||||||
|
ContinueDestStack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IRGenFunction::emitBreakStmt(BreakStmt *S) {
|
||||||
|
emitBranch(BreakDestStack.back());
|
||||||
|
Builder.ClearInsertionPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRGenFunction::emitContinueStmt(ContinueStmt *S) {
|
||||||
|
emitBranch(ContinueDestStack.back());
|
||||||
|
Builder.ClearInsertionPoint();
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "DiverseStack.h"
|
#include "DiverseStack.h"
|
||||||
#include "IRBuilder.h"
|
#include "IRBuilder.h"
|
||||||
|
#include "JumpDest.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class AllocaInst;
|
class AllocaInst;
|
||||||
@@ -33,7 +34,9 @@ namespace llvm {
|
|||||||
namespace swift {
|
namespace swift {
|
||||||
class AssignStmt;
|
class AssignStmt;
|
||||||
class BraceStmt;
|
class BraceStmt;
|
||||||
|
class BreakStmt;
|
||||||
class ClassType;
|
class ClassType;
|
||||||
|
class ContinueStmt;
|
||||||
class Decl;
|
class Decl;
|
||||||
class Expr;
|
class Expr;
|
||||||
class ExtensionDecl;
|
class ExtensionDecl;
|
||||||
@@ -56,13 +59,11 @@ namespace swift {
|
|||||||
class WhileStmt;
|
class WhileStmt;
|
||||||
|
|
||||||
namespace irgen {
|
namespace irgen {
|
||||||
class Cleanup;
|
|
||||||
class Condition;
|
class Condition;
|
||||||
class Explosion;
|
class Explosion;
|
||||||
enum class ExplosionKind : unsigned;
|
enum class ExplosionKind : unsigned;
|
||||||
class HeapLayout;
|
class HeapLayout;
|
||||||
class IRGenModule;
|
class IRGenModule;
|
||||||
class JumpDest;
|
|
||||||
class LinkEntity;
|
class LinkEntity;
|
||||||
class LValue;
|
class LValue;
|
||||||
class ManagedValue;
|
class ManagedValue;
|
||||||
@@ -175,8 +176,6 @@ public:
|
|||||||
return pushCleanupInState<T, A...>(state, ::std::forward<A>(args)...);
|
return pushCleanupInState<T, A...>(state, ::std::forward<A>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef DiverseStackImpl<Cleanup>::stable_iterator CleanupsDepth;
|
|
||||||
|
|
||||||
/// Retun a stable reference to the current cleanup.
|
/// Retun a stable reference to the current cleanup.
|
||||||
CleanupsDepth getCleanupsDepth() const {
|
CleanupsDepth getCleanupsDepth() const {
|
||||||
return Cleanups.stable_begin();
|
return Cleanups.stable_begin();
|
||||||
@@ -208,6 +207,8 @@ private:
|
|||||||
llvm::BasicBlock *UnreachableBB;
|
llvm::BasicBlock *UnreachableBB;
|
||||||
llvm::Instruction *JumpDestSlot;
|
llvm::Instruction *JumpDestSlot;
|
||||||
CleanupsDepth InnermostScope;
|
CleanupsDepth InnermostScope;
|
||||||
|
std::vector<JumpDest> BreakDestStack;
|
||||||
|
std::vector<JumpDest> ContinueDestStack;
|
||||||
|
|
||||||
friend class Scope;
|
friend class Scope;
|
||||||
Cleanup &initCleanup(Cleanup &cleanup, size_t allocSize, CleanupState state);
|
Cleanup &initCleanup(Cleanup &cleanup, size_t allocSize, CleanupState state);
|
||||||
@@ -276,6 +277,8 @@ private:
|
|||||||
void emitWhileStmt(WhileStmt *S);
|
void emitWhileStmt(WhileStmt *S);
|
||||||
void emitForStmt(ForStmt *S);
|
void emitForStmt(ForStmt *S);
|
||||||
void emitForEachStmt(ForEachStmt *S);
|
void emitForEachStmt(ForEachStmt *S);
|
||||||
|
void emitBreakStmt(BreakStmt *S);
|
||||||
|
void emitContinueStmt(ContinueStmt *S);
|
||||||
|
|
||||||
//--- Expression emission ------------------------------------------------------
|
//--- Expression emission ------------------------------------------------------
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
#ifndef SWIFT_IRGEN_JUMPDEST_H
|
#ifndef SWIFT_IRGEN_JUMPDEST_H
|
||||||
#define SWIFT_IRGEN_JUMPDEST_H
|
#define SWIFT_IRGEN_JUMPDEST_H
|
||||||
|
|
||||||
#include "IRGenFunction.h"
|
#include "DiverseStack.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class BasicBlock;
|
class BasicBlock;
|
||||||
@@ -26,18 +26,21 @@ namespace llvm {
|
|||||||
namespace swift {
|
namespace swift {
|
||||||
namespace irgen {
|
namespace irgen {
|
||||||
|
|
||||||
|
class Cleanup;
|
||||||
|
typedef DiverseStackImpl<Cleanup>::stable_iterator CleanupsDepth;
|
||||||
|
|
||||||
/// The destination of a direct jump. Swift currently does not
|
/// The destination of a direct jump. Swift currently does not
|
||||||
/// support indirect branches or goto, so the jump mechanism only
|
/// support indirect branches or goto, so the jump mechanism only
|
||||||
/// needs to worry about branches into scopes, not out of them.
|
/// needs to worry about branches into scopes, not out of them.
|
||||||
class JumpDest {
|
class JumpDest {
|
||||||
llvm::BasicBlock *Block;
|
llvm::BasicBlock *Block;
|
||||||
IRGenFunction::CleanupsDepth Depth;
|
CleanupsDepth Depth;
|
||||||
public:
|
public:
|
||||||
JumpDest(llvm::BasicBlock *block, IRGenFunction::CleanupsDepth depth)
|
JumpDest(llvm::BasicBlock *block, CleanupsDepth depth)
|
||||||
: Block(block), Depth(depth) {}
|
: Block(block), Depth(depth) {}
|
||||||
|
|
||||||
llvm::BasicBlock *getBlock() const { return Block; }
|
llvm::BasicBlock *getBlock() const { return Block; }
|
||||||
IRGenFunction::CleanupsDepth getDepth() const { return Depth; }
|
CleanupsDepth getDepth() const { return Depth; }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace irgen
|
} // end namespace irgen
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ namespace irgen {
|
|||||||
/// statement) has been entered.
|
/// statement) has been entered.
|
||||||
class Scope {
|
class Scope {
|
||||||
IRGenFunction &IGF;
|
IRGenFunction &IGF;
|
||||||
IRGenFunction::CleanupsDepth Depth;
|
CleanupsDepth Depth;
|
||||||
IRGenFunction::CleanupsDepth SavedInnermostScope;
|
CleanupsDepth SavedInnermostScope;
|
||||||
|
|
||||||
void popImpl() {
|
void popImpl() {
|
||||||
IGF.Cleanups.checkIterator(Depth);
|
IGF.Cleanups.checkIterator(Depth);
|
||||||
@@ -51,7 +51,7 @@ public:
|
|||||||
void pop() {
|
void pop() {
|
||||||
assert(Depth.isValid() && "popping a scope twice!");
|
assert(Depth.isValid() && "popping a scope twice!");
|
||||||
popImpl();
|
popImpl();
|
||||||
Depth = IRGenFunction::CleanupsDepth::invalid();
|
Depth = CleanupsDepth::invalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
~Scope() {
|
~Scope() {
|
||||||
|
|||||||
134
test/Interpreter/break_continue.swift
Normal file
134
test/Interpreter/break_continue.swift
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
// RUN: %swift -i %s | FileCheck %s
|
||||||
|
|
||||||
|
func test1() {
|
||||||
|
println("test1")
|
||||||
|
var i : Int
|
||||||
|
for i=0;;++i {
|
||||||
|
if i > 2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
println(i)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func test2() {
|
||||||
|
println("test2")
|
||||||
|
var i : Int
|
||||||
|
for i=0;i<10;++i {
|
||||||
|
if i > 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
println(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func test3() {
|
||||||
|
println("test3")
|
||||||
|
var i : Int
|
||||||
|
for i=0;i<10;++i {
|
||||||
|
if i > 2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
println(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func test4() {
|
||||||
|
println("test4")
|
||||||
|
for i in 0..10 {
|
||||||
|
if i > 2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
println(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func test5() {
|
||||||
|
println("test5")
|
||||||
|
for i in 0..10 {
|
||||||
|
if i < 2 {
|
||||||
|
println(i)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func test6() {
|
||||||
|
println("test6")
|
||||||
|
var i = 0
|
||||||
|
while (i < 10) {
|
||||||
|
if i < 2 {
|
||||||
|
println(i)
|
||||||
|
++i
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func test7() {
|
||||||
|
println("test7")
|
||||||
|
var i = 0
|
||||||
|
while (i < 10) {
|
||||||
|
if i < 2 {
|
||||||
|
println(i)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
println("foo")
|
||||||
|
}
|
||||||
|
func test8() {
|
||||||
|
println("test8")
|
||||||
|
var i : Int
|
||||||
|
for i=0;;++i {
|
||||||
|
for j in 0..10 {
|
||||||
|
if j > 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
println(j)
|
||||||
|
}
|
||||||
|
if i > 2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
println(i)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println("start")
|
||||||
|
test1()
|
||||||
|
// CHECK: test1
|
||||||
|
// CHECK-NEXT: 0
|
||||||
|
// CHECK-NEXT: 1
|
||||||
|
// CHECK-NEXT: 2
|
||||||
|
test2()
|
||||||
|
// CHECK: test2
|
||||||
|
// CHECK-NEXT: 0
|
||||||
|
// CHECK-NEXT: 1
|
||||||
|
// CHECK-NEXT: 2
|
||||||
|
test3()
|
||||||
|
// CHECK: test3
|
||||||
|
// CHECK-NEXT: 0
|
||||||
|
// CHECK-NEXT: 1
|
||||||
|
// CHECK-NEXT: 2
|
||||||
|
test4()
|
||||||
|
// CHECK: test4
|
||||||
|
// CHECK-NEXT: 0
|
||||||
|
// CHECK-NEXT: 1
|
||||||
|
// CHECK-NEXT: 2
|
||||||
|
test5()
|
||||||
|
// CHECK: test5
|
||||||
|
// CHECK-NEXT: 0
|
||||||
|
// CHECK-NEXT: 1
|
||||||
|
test6()
|
||||||
|
// CHECK: test6
|
||||||
|
// CHECK-NEXT: 0
|
||||||
|
// CHECK-NEXT: 1
|
||||||
|
test7()
|
||||||
|
// CHECK: test7
|
||||||
|
// CHECK-NEXT: 0
|
||||||
|
// CHECK-NEXT: foo
|
||||||
|
test8()
|
||||||
|
// CHECK: test8
|
||||||
|
// CHECK-NEXT: 0
|
||||||
|
// CHECK-NEXT: 1
|
||||||
|
// CHECK-NEXT: 0
|
||||||
|
// CHECK-NEXT: 0
|
||||||
|
// CHECK-NEXT: 1
|
||||||
|
// CHECK-NEXT: 1
|
||||||
Reference in New Issue
Block a user