Skip to content

Commit 6d5f67c

Browse files
committed
Implement IR generation for the 'foreach' loop and convert our fractal
examples over to using the 'foreach' loop. Addresses <rdar://problem/11259997>. Swift SVN r1606
1 parent bf1392c commit 6d5f67c

File tree

5 files changed

+98
-26
lines changed

5 files changed

+98
-26
lines changed

lib/IRGen/GenControl.cpp

+13-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "IRGenFunction.h"
2323
#include "IRGenModule.h"
2424
#include "JumpDest.h"
25+
#include "Scope.h"
2526

2627
using namespace swift;
2728
using namespace irgen;
@@ -99,11 +100,15 @@ IRGenFunction::createBasicBlock(const llvm::Twine &Name) {
99100
///
100101
/// \param hasFalseCode - true if the false branch doesn't just lead
101102
/// to the fallthrough.
102-
Condition IRGenFunction::emitCondition(Expr *E, bool hasFalseCode) {
103+
/// \param invertValue - true if this routine should invert the value before
104+
/// testing true/false.
105+
Condition IRGenFunction::emitCondition(Expr *E, bool hasFalseCode,
106+
bool invertValue) {
103107
assert(Builder.hasValidIP() && "emitting condition at unreachable point");
104108

105109
// Sema forces conditions to have Builtin.i1 type, which guarantees this.
106110
// TODO: special-case interesting condition expressions.
111+
FullExpr Scope(*this);
107112
llvm::Value *V = emitAsPrimitiveScalar(E);
108113
assert(V->getType()->isIntegerTy(1));
109114

@@ -113,7 +118,7 @@ Condition IRGenFunction::emitCondition(Expr *E, bool hasFalseCode) {
113118
if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(V)) {
114119
// If the condition is constant false, ignore the true branch. We
115120
// will fall into the false branch unless there is none.
116-
if (C->isZero()) {
121+
if (C->isZero() == !invertValue) {
117122
trueBB = nullptr;
118123
falseBB = (hasFalseCode ? Builder.GetInsertBlock() : nullptr);
119124

@@ -129,6 +134,12 @@ Condition IRGenFunction::emitCondition(Expr *E, bool hasFalseCode) {
129134

130135
// Otherwise, the condition requires a conditional branch.
131136
} else {
137+
// If requested, invert the value.
138+
if (invertValue)
139+
V = Builder.CreateXor(V,
140+
llvm::Constant::getIntegerValue(IGM.Int1Ty,
141+
llvm::APInt(1, 1)));
142+
132143
contBB = createBasicBlock("condition.cont");
133144
trueBB = createBasicBlock("if.true");
134145

lib/IRGen/GenStmt.cpp

+43-5
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@
2525
#include "JumpDest.h"
2626
#include "LValue.h"
2727

28-
// FIXME: Temporary
29-
#include "IRGenModule.h"
30-
3128
using namespace swift;
3229
using namespace irgen;
3330

@@ -57,8 +54,7 @@ void IRGenFunction::emitStmt(Stmt *S) {
5754
return emitForStmt(cast<ForStmt>(S));
5855

5956
case StmtKind::ForEach:
60-
IGM.unimplemented(S->getStartLoc(), "foreach loop");
61-
return;
57+
return emitForEachStmt(cast<ForEachStmt>(S));
6258
}
6359
llvm_unreachable("bad statement kind!");
6460
}
@@ -205,4 +201,46 @@ void IRGenFunction::emitForStmt(ForStmt *S) {
205201

206202
}
207203

204+
void IRGenFunction::emitForEachStmt(ForEachStmt *S) {
205+
FullExpr Scope(*this);
206+
207+
// Emit the 'range' variable that we'll be using for iteration.
208+
emitPatternBindingDecl(S->getRange());
209+
210+
// If we ever reach an unreachable point, stop emitting statements.
211+
// This will need revision if we ever add goto.
212+
if (!Builder.hasValidIP()) return;
213+
214+
// Create a new basic block and jump into it.
215+
llvm::BasicBlock *LoopBB = createBasicBlock("foreach.cond");
216+
Builder.CreateBr(LoopBB);
217+
Builder.emitBlock(LoopBB);
218+
219+
Condition Cond = emitCondition(S->getRangeEmpty(), /*hasFalseCode=*/false,
220+
/*invertValue=*/true);
221+
if (Cond.hasTrue()) {
222+
Cond.enterTrue(*this);
223+
224+
// Emit the loop body.
225+
FullExpr Scope(*this);
226+
emitPatternBindingDecl(S->getElementInit());
227+
emitStmt(S->getBody());
228+
229+
// Drop the first element in the range
230+
if (Builder.hasValidIP()) {
231+
FullExpr Scope(*this);
232+
emitIgnored(S->getRangeDropFirst());
233+
}
234+
235+
// Loop back to the header.
236+
if (Builder.hasValidIP()) {
237+
Builder.CreateBr(LoopBB);
238+
Builder.ClearInsertionPoint();
239+
}
240+
Cond.exitTrue(*this);
241+
}
242+
243+
// Complete the conditional execution.
244+
Cond.complete(*this);
245+
}
208246

lib/IRGen/IRGenFunction.h

+1-4
Original file line numberDiff line numberDiff line change
@@ -286,15 +286,12 @@ class IRGenFunction {
286286
const TypeInfo &type);
287287
void emitAssign(Expr *E, const LValue &lvalue, const TypeInfo &type);
288288

289-
void emitPatternBindingInit(Pattern *P, Expr *E, bool isGlobal);
290-
void emitPatternBindingInit(Pattern *P, Explosion &E, bool isGlobal);
291-
292289
OwnedAddress getAddrForParameter(VarDecl *param, Explosion &paramValues);
293290

294291
void emitNullaryCall(llvm::Value *fn, Type resultType, Explosion &result);
295292

296293
private:
297-
Condition emitCondition(Expr *E, bool hasFalseCode);
294+
Condition emitCondition(Expr *E, bool hasFalseCode, bool invertValue = false);
298295

299296
//--- Declaration emission -----------------------------------------------------
300297
public:

lib/Sema/TypeCheckStmt.cpp

+18-15
Original file line numberDiff line numberDiff line change
@@ -256,22 +256,24 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
256256

257257
// Compute the expression that determines whether the range is empty.
258258
Expr *Empty
259-
= callNullaryMethodOf(new (TC.Context) DeclRefExpr(Range, S->getInLoc(),
260-
RangeTy),
261-
TC.Context.getIdentifier("empty"),
262-
S->getInLoc(), diag::foreach_range_empty,
263-
diag::foreach_nonfunc_range_empty);
259+
= callNullaryMethodOf(
260+
new (TC.Context) DeclRefExpr(Range, S->getInLoc(),
261+
Range->getTypeOfReference()),
262+
TC.Context.getIdentifier("empty"),
263+
S->getInLoc(), diag::foreach_range_empty,
264+
diag::foreach_nonfunc_range_empty);
264265
if (!Empty) return nullptr;
265266
if (TC.typeCheckCondition(Empty)) return nullptr;
266267
S->setRangeEmpty(Empty);
267268

268269
// Compute the expression that extracts a value from the range.
269270
Expr *GetFirst
270-
= callNullaryMethodOf(new (TC.Context) DeclRefExpr(Range, S->getInLoc(),
271-
RangeTy),
272-
TC.Context.getIdentifier("getFirst"),
273-
S->getInLoc(), diag::foreach_range_getfirst,
274-
diag::foreach_nonfunc_range_getfirst);
271+
= callNullaryMethodOf(
272+
new (TC.Context) DeclRefExpr(Range, S->getInLoc(),
273+
Range->getTypeOfReference()),
274+
TC.Context.getIdentifier("getFirst"),
275+
S->getInLoc(), diag::foreach_range_getfirst,
276+
diag::foreach_nonfunc_range_getfirst);
275277
if (!GetFirst) return nullptr;
276278

277279
// Make sure our element type is materializable.
@@ -293,11 +295,12 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
293295

294296
// Compute the expression that drops the first value from the range.
295297
Expr *DropFirst
296-
= callNullaryMethodOf(new (TC.Context) DeclRefExpr(Range, S->getInLoc(),
297-
RangeTy),
298-
TC.Context.getIdentifier("dropFirst"),
299-
S->getInLoc(), diag::foreach_range_dropfirst,
300-
diag::foreach_nonfunc_range_dropfirst);
298+
= callNullaryMethodOf(
299+
new (TC.Context) DeclRefExpr(Range, S->getInLoc(),
300+
Range->getTypeOfReference()),
301+
TC.Context.getIdentifier("dropFirst"),
302+
S->getInLoc(), diag::foreach_range_dropfirst,
303+
diag::foreach_nonfunc_range_dropfirst);
301304
if (!DropFirst) return nullptr;
302305
S->setRangeDropFirst(DropFirst);
303306

test/IRGen/foreach.swift

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %swift -triple x86_64-apple-darwin10 -I %S/.. %s -emit-llvm | FileCheck %s
2+
3+
import swift
4+
5+
// CHECK: define void @_T7foreach12foreach_testFT1rNSs5Range_T_(
6+
func foreach_test(r : Range) {
7+
var sum : Int = 0
8+
// CHECK: call { i64, i64 } @_TNSs5Range11getElementsfRS_FT_S_
9+
// CHECK: br label
10+
// CHECK: call i1 @_TNSs5Range5emptyfRS_FT_NSs4Bool
11+
// CHECK: call i1 @_TNSs4Bool13getLogicValuefRS_FT_i1
12+
// CHECK-NEXT: [[RESULT:%[A-Za-z0-9.]+]] = xor
13+
// CHECK: br i1 [[RESULT]], label
14+
foreach i in r {
15+
// CHECK: call i64 @_TNSs5Range8getFirstfRS_FT_NSs5Int64
16+
// CHECK: call i64 @_TSsop1pFT3lhsNSs5Int643rhsS__S_
17+
sum = sum + i
18+
// CHECK: call void @_TNSs5Range9dropFirstfRS_FT_T_
19+
// CHECK-NEXT: br label
20+
}
21+
22+
// CHECK: ret void
23+
}

0 commit comments

Comments
 (0)