Skip to content

Commit d42fa41

Browse files
committed
Fixes #18
1 parent cb6115a commit d42fa41

3 files changed

Lines changed: 175 additions & 15 deletions

File tree

include/PulseGenerator.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "clang/AST/DeclBase.h"
88
#include "clang/AST/Expr.h"
99
#include "clang/AST/RecursiveASTVisitor.h"
10+
#include "clang/AST/Stmt.h"
1011
#include "clang/AST/Type.h"
1112
#include "clang/Analysis/Analyses/ExprMutationAnalyzer.h"
1213
#include "clang/Basic/SourceManager.h"
@@ -31,7 +32,9 @@ class PulseVisitor : public clang::RecursiveASTVisitor<PulseVisitor> {
3132
bool VisitTypedefDecl(clang::TypedefDecl *TypeDefDec);
3233

3334
PulseStmt *pulseFromCompoundStmt(clang::Stmt *S, clang::ExprMutationAnalyzer *A, PulseModul *Module);
34-
PulseStmt *pulseFromStmt(clang::Stmt *S, clang::ExprMutationAnalyzer *A, clang::Stmt *Parent, PulseModul *Module);
35+
PulseStmt *pulseFromStmt(clang::Stmt *S, clang::ExprMutationAnalyzer *A,
36+
clang::Stmt *Parent, PulseModul *Module,
37+
clang::CompoundStmt *CS);
3538
FStarType *getPulseTyFromCTy(clang::QualType CType);
3639
Term *getTermFromCExpr(clang::Expr *E, clang::ExprMutationAnalyzer *A, llvm::SmallVector<PulseStmt*> &ExprsBef,
3740
clang::Stmt *Parent, clang::QualType ParentType, PulseModul *Module, bool isWrite = false);

src/PulseGenerator.cpp

Lines changed: 122 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,73 @@ std::map<Decl *, QualType> PulseVisitor::inferArrayTypes(FunctionDecl *FD) {
7676
return DeclToPulseSymbol;
7777
}
7878

79+
bool checkIsSameStructInstance(Expr *A, Expr *B, ASTContext &Context) {
80+
A = A->IgnoreImpCasts();
81+
B = B->IgnoreImpCasts();
82+
83+
DeclRefExpr *DeclRefA = dyn_cast<DeclRefExpr>(A);
84+
if (!DeclRefA)
85+
return false;
86+
87+
DeclRefExpr *DeclRefB = dyn_cast<DeclRefExpr>(B);
88+
if (!DeclRefB)
89+
return false;
90+
91+
if (DeclRefA && DeclRefB) {
92+
return DeclRefA->getDecl() == DeclRefB->getDecl();
93+
}
94+
95+
MemberExpr *MemA = dyn_cast<MemberExpr>(A);
96+
MemberExpr *MemB = dyn_cast<MemberExpr>(B);
97+
98+
if (MemA && MemB) {
99+
return checkIsSameStructInstance(MemA->getBase(), MemB->getBase(), Context);
100+
}
101+
102+
// Also check recursively pointer derefernces and array access.
103+
UnaryOperator *UOA = dyn_cast<UnaryOperator>(A);
104+
UnaryOperator *UOB = dyn_cast<UnaryOperator>(B);
105+
106+
if (UOA && UOB && UOA->getOpcode() == UOB->getOpcode()) {
107+
return checkIsSameStructInstance(UOA->getSubExpr(), UOB->getSubExpr(),
108+
Context);
109+
}
110+
111+
return false;
112+
}
113+
114+
bool checkIfLastStructAccess(MemberExpr *ToCheck, CompoundStmt *CS,
115+
ASTContext &Context) {
116+
Expr *ToCheckBase = ToCheck->getBase()->IgnoreImpCasts();
117+
SourceManager &SM = Context.getSourceManager();
118+
SourceLocation ToCheckLoc = ToCheck->getExprLoc();
119+
SourceLocation LastLoc = ToCheckLoc;
120+
121+
for (const Stmt *S : CS->body()) {
122+
// Traverse the compound statement and visit it recursively.
123+
// We store the last accessed member in LastLoc.
124+
// When we encounter a member expr, we check if this is the same instance as
125+
// the ToBeChecked member expression.
126+
// We also check if the member expression comes after the to be checked
127+
// member,
128+
// if so we update Last loc.
129+
for (const Stmt *Child : S->children()) {
130+
if (auto *ME = dyn_cast<MemberExpr>(Child)) {
131+
Expr *Base = ME->getBase()->IgnoreImpCasts();
132+
if (Context.getParents(*Base).size() > 0 &&
133+
SM.isBeforeInTranslationUnit(ToCheckLoc, ME->getExprLoc()) &&
134+
checkIsSameStructInstance(Base, ToCheckBase, Context)) {
135+
LastLoc = ME->getExprLoc();
136+
}
137+
}
138+
}
139+
}
140+
141+
// If the location of the member to be checked is the same as the last loc
142+
// This is indeed the last access to the member.
143+
return ToCheckLoc == LastLoc;
144+
}
145+
79146
bool PulseVisitor::checkIsRecursiveFunction(FunctionDecl *FD) {
80147

81148
bool result = false;
@@ -852,6 +919,8 @@ bool PulseVisitor::VisitFunctionDecl(FunctionDecl *FD) {
852919
auto *PulseBody = pulseFromCompoundStmt(CS, &Analyzer, Module);
853920

854921
// Release declarations that are function parameters.
922+
//TODO: Vidush Eventually we should get rid of these.
923+
//This is just in case there are release expressions left and we need to release them.
855924
PulseSequence *NewSeq = nullptr;
856925
PulseSequence *Head = nullptr;
857926
for (auto It = TrackStructExplodeAndRecover.begin(); It != TrackStructExplodeAndRecover.end();) {
@@ -975,7 +1044,8 @@ PulseStmt *PulseVisitor::pulseFromCompoundStmt(Stmt *S,
9751044

9761045
for (auto *InnerStmt : CS->body()) {
9771046

978-
auto *NextPulseStmt = pulseFromStmt(InnerStmt, Analyzer, nullptr, Modul);
1047+
auto *NextPulseStmt =
1048+
pulseFromStmt(InnerStmt, Analyzer, nullptr, Modul, CS);
9791049
if (NextPulseStmt == nullptr)
9801050
continue;
9811051

@@ -998,7 +1068,8 @@ PulseStmt *PulseVisitor::pulseFromCompoundStmt(Stmt *S,
9981068
}
9991069

10001070
PulseStmt *PulseVisitor::pulseFromStmt(Stmt *S, ExprMutationAnalyzer *Analyzer,
1001-
Stmt *Parent, PulseModul *Module) {
1071+
Stmt *Parent, PulseModul *Module,
1072+
CompoundStmt *CS) {
10021073

10031074
if (!S)
10041075
return nullptr;
@@ -1243,8 +1314,6 @@ PulseStmt *PulseVisitor::pulseFromStmt(Stmt *S, ExprMutationAnalyzer *Analyzer,
12431314
PulseCall->pushArg(ParenthesisDeref);
12441315
Assignment->Lhs = PulseCall;
12451316

1246-
assert(ExprsBef.empty() && "Expected ExprsBefore to be empty!\n");
1247-
12481317
auto It = TrackStructExplodeAndRecover.find(VD);
12491318
if (It == TrackStructExplodeAndRecover.end()){
12501319
auto *NewSeq = new PulseSequence();
@@ -1256,6 +1325,47 @@ PulseStmt *PulseVisitor::pulseFromStmt(Stmt *S, ExprMutationAnalyzer *Analyzer,
12561325
return NewSeq;
12571326
}
12581327

1328+
auto *RetSeq = releaseExprs(ExprsBef);
1329+
1330+
assert(ExprsBef.empty() && "Expected ExprsBefore to be empty!\n");
1331+
1332+
if (checkIfLastStructAccess(ME, CS, Ctx)) {
1333+
1334+
It = TrackStructExplodeAndRecover.find(VD);
1335+
auto ItElem = *It;
1336+
auto &Decl = ItElem.first;
1337+
auto &Info = ItElem.second;
1338+
// recover not released.
1339+
// In fact assert that a recover should not be released before.
1340+
assert(!Info.second && "A recover was released for the struct when "
1341+
"there are accesses remaining!\n");
1342+
if (auto *ParamD = dyn_cast<ParmVarDecl>(Decl)) {
1343+
1344+
auto StructName =
1345+
ParamD->getType()->getPointeeType().getAsString();
1346+
1347+
auto *RecoverStatememt = new GenericStmt();
1348+
RecoverStatememt->body =
1349+
StructName + "_recover " + ParamD->getNameAsString() + ";";
1350+
TrackStructExplodeAndRecover.erase(It);
1351+
1352+
auto *NewSeq = new PulseSequence();
1353+
NewSeq->assignS1(Assignment);
1354+
NewSeq->assignS2(RecoverStatememt);
1355+
if (RetSeq) {
1356+
RetSeq->assignS2(NewSeq);
1357+
return RetSeq;
1358+
}
1359+
1360+
return NewSeq;
1361+
}
1362+
}
1363+
1364+
if (RetSeq) {
1365+
RetSeq->assignS2(Assignment);
1366+
return RetSeq;
1367+
}
1368+
12591369
return Assignment;
12601370
}
12611371

@@ -1432,8 +1542,8 @@ PulseStmt *PulseVisitor::pulseFromStmt(Stmt *S, ExprMutationAnalyzer *Analyzer,
14321542

14331543
auto PulseCond =
14341544
getTermFromCExpr(Cond, Analyzer, ExprsBefore, Parent, Cond->getType(), Module);
1435-
auto *PulseElse = pulseFromStmt(Else, Analyzer, Parent, Module);
1436-
auto *PulseThen = pulseFromStmt(Then, Analyzer, Parent, Module);
1545+
auto *PulseElse = pulseFromStmt(Else, Analyzer, Parent, Module, CS);
1546+
auto *PulseThen = pulseFromStmt(Then, Analyzer, Parent, Module, CS);
14371547

14381548
auto PulseIfStmt = new PulseIf();
14391549
PulseIfStmt->setTag(PulseStmtTag::If);
@@ -1551,7 +1661,8 @@ PulseStmt *PulseVisitor::pulseFromStmt(Stmt *S, ExprMutationAnalyzer *Analyzer,
15511661
}
15521662

15531663
PulseWhile->setTag(PulseStmtTag::WhileStmt);
1554-
PulseWhile->Guard = pulseFromStmt(WhileCond, Analyzer, Parent, Module);
1664+
PulseWhile->Guard =
1665+
pulseFromStmt(WhileCond, Analyzer, Parent, Module, CS);
15551666
PulseWhile->Body = pulseFromCompoundStmt(CompundBody, Analyzer, Module);
15561667

15571668
return PulseWhile;
@@ -1560,7 +1671,8 @@ PulseStmt *PulseVisitor::pulseFromStmt(Stmt *S, ExprMutationAnalyzer *Analyzer,
15601671
auto *PulseWhile = new PulseWhileStmt();
15611672
PulseWhile->setTag(PulseStmtTag::WhileStmt);
15621673

1563-
PulseWhile->Guard = pulseFromStmt(WhileCond, Analyzer, Parent, Module);
1674+
PulseWhile->Guard =
1675+
pulseFromStmt(WhileCond, Analyzer, Parent, Module, CS);
15641676
PulseWhile->Body = pulseFromCompoundStmt(WhileBody, Analyzer, Module);
15651677

15661678
return PulseWhile;
@@ -1605,7 +1717,7 @@ PulseStmt *PulseVisitor::pulseFromStmt(Stmt *S, ExprMutationAnalyzer *Analyzer,
16051717
}
16061718
}
16071719
}
1608-
NewSequence->assignS2(pulseFromStmt(SubStmt, Analyzer, Parent, Module));
1720+
NewSequence->assignS2(pulseFromStmt(SubStmt, Analyzer, Parent, Module, CS));
16091721
return NewSequence;
16101722
} else {
16111723
llvm::outs() << "\n\nPrint in pulseFromStmt\n";
@@ -1715,9 +1827,6 @@ PulseVisitor::getTermFromCExpr(Expr *E, ExprMutationAnalyzer *MutAnalyzer,
17151827
// Wrap Call Expr into a Paren to be safe.
17161828
auto *NewParen = new Paren();
17171829
NewParen->setInnerExpr(NewAppENode);
1718-
1719-
assert(ExprsBefore.empty() && "Unreleased expressions!\n");
1720-
17211830
return NewParen;
17221831

17231832
llvm::outs() << "\n\nPrint Expresion in PulseVisitor::getTermFromCExpr "
@@ -2049,8 +2158,7 @@ PulseVisitor::getTermFromCExpr(Expr *E, ExprMutationAnalyzer *MutAnalyzer,
20492158
assert(false && "Should not reach here!");
20502159
return nullptr;
20512160
} else if (auto *ME = dyn_cast<MemberExpr>(E)) {
2052-
2053-
2161+
20542162
auto *MemberExprDecl = ME->getMemberDecl();
20552163

20562164
auto *BaseExpr = ME->getBase()->IgnoreParens()->IgnoreImpCasts();

test-transpiler/c/issues/issue18.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#include <stdint.h>
2+
#include <stdlib.h>
3+
#include "../../../include/PulseMacros.h"
4+
5+
REQUIRES(emp)
6+
RETURNS(i:int32)
7+
ENSURES(emp)
8+
int test(void)
9+
{
10+
return 0;
11+
}
12+
13+
typedef struct _point {
14+
int px;
15+
int py;
16+
} point;
17+
18+
19+
INCLUDE (
20+
let is_diag_point (p:ref point) (v:int32)
21+
: slprop
22+
= point_pred p {px=v; py=v}
23+
24+
let is_point (p:ref point) (xy : (int & int))
25+
: slprop
26+
= exists* v. point_pred p v ** pure (as_int v.px == fst xy) ** pure (as_int v.py == snd xy)
27+
28+
ghost
29+
fn fold_is_point (p:ref point) (#s:point_spec)
30+
requires point_pred p s
31+
ensures exists* v. is_point p v ** pure (v == (as_int s.px, as_int s.py))
32+
{
33+
fold (is_point p (as_int s.px, as_int s.py));
34+
}
35+
36+
)
37+
38+
ERASED_ARG(#v:erased _)
39+
REQUIRES(is_point p v)
40+
REQUIRES(pure <| fits (+) (fst v) (as_int dx))
41+
REQUIRES(pure <| fits (+) (snd v) (as_int dy))
42+
ENSURES(is_point p (fst v + as_int dx, snd v + as_int dy))
43+
void move(point *p, int dx, int dy)
44+
{
45+
LEMMA(unfold(is_point));
46+
p->px = p->px + dx;
47+
p->py = p->py + dy;
48+
LEMMA(fold_is_point p);
49+
}

0 commit comments

Comments
 (0)