Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
latte
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
zygzagZ
latte
Commits
1bed5bf5
Commit
1bed5bf5
authored
Jan 15, 2021
by
zygzagZ
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor arrays
parent
75ea8c19
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
124 additions
and
81 deletions
+124
-81
runtime.c
lib/runtime.c
+6
-11
Absyn.cpp
src/Absyn.cpp
+2
-2
Absyn.h
src/Absyn.h
+3
-1
Compiler.cpp
src/Compiler.cpp
+10
-13
Compiler.h
src/Compiler.h
+1
-8
TypeCheck.cpp
src/TypeCheck.cpp
+4
-2
BasicBlock.h
src/codeGen/BasicBlock.h
+1
-0
QuadrupleGenerator.cpp
src/codeGen/QuadrupleGenerator.cpp
+97
-44
No files found.
lib/runtime.c
View file @
1bed5bf5
...
...
@@ -6,6 +6,11 @@
#include <string.h>
#include <stdint.h>
void
error
()
{
puts
(
"runtime error"
);
exit
(
1
);
}
int
printInt
(
int
a
)
{
printf
(
"%d
\n
"
,
a
);
}
...
...
@@ -47,28 +52,18 @@ int readInt () {
return
result
;
}
void
error
()
{
puts
(
"runtime error"
);
exit
(
1
);
}
char
*
__latte_mem_init
(
size_t
size
,
void
*
virtTab
)
{
char
*
buf
=
calloc
(
1
,
size
);
if
(
!
buf
)
error
();
*
((
void
**
)
buf
)
=
virtTab
;
return
buf
;
}
char
*
__latte_mem_init_array
(
int
len
,
size_t
size
,
void
*
virtTab
)
{
char
*
__latte_mem_init_array
(
size_t
size
,
int
len
)
{
if
(
len
<
0
)
error
();
if
(
len
>
(
SIZE_MAX
-
4
)
/
size
)
error
();
char
*
buf
=
calloc
(
1
,
4
+
len
*
size
);
if
(
!
buf
)
error
();
*
((
int
*
)
buf
)
=
len
;
// store length
if
(
virtTab
)
{
for
(
size_t
i
=
0
;
i
<
len
;
i
++
)
{
*
((
void
**
)(
buf
+
4
+
i
*
size
))
=
virtTab
;
}
}
return
buf
;
}
...
...
src/Absyn.cpp
View file @
1bed5bf5
...
...
@@ -2909,7 +2909,7 @@ bool Fun::isEqual(Type const *other, bool sub) const {
bool
ClassT
::
isEqual
(
Type
const
*
other
,
bool
sub
)
const
{
if
(
const
ClassT
*
casted
=
dynamic_cast
<
const
ClassT
*>
(
other
))
{
auto
v1
=
pident_
->
var
.
lock
(),
v2
=
casted
->
pident_
->
var
.
lock
();
auto
v1
=
pident_
->
getVar
(),
v2
=
casted
->
pident_
->
getVar
();
if
(
!
v1
||
!
v2
)
return
false
;
if
(
v1
==
v2
)
return
true
;
if
(
!
sub
)
return
false
;
...
...
@@ -2922,5 +2922,5 @@ bool ClassT::isEqual(Type const *other, bool sub) const {
}
ClassInfoPtr
ClassT
::
getClass
()
const
{
return
dynamic_pointer_cast
<
ClassInfo
>
(
pident_
->
var
.
lock
());
return
dynamic_pointer_cast
<
ClassInfo
>
(
pident_
->
getVar
());
}
\ No newline at end of file
src/Absyn.h
View file @
1bed5bf5
...
...
@@ -273,7 +273,9 @@ class PIdent : public Visitable
{
public:
String
string_
;
std
::
weak_ptr
<
VarInfo
>
var
;
shared_ptr
<
VarInfo
>
var
;
shared_ptr
<
VarInfo
>
getVar
()
{
return
var
;
}
PIdent
(
const
PIdent
&
);
PIdent
&
operator
=
(
const
PIdent
&
);
...
...
src/Compiler.cpp
View file @
1bed5bf5
...
...
@@ -78,8 +78,7 @@ void Compiler::compileFunction(const FunctionInfoPtr& f) {
RegisterAllocator
regGen
((
quadEnv
));
regGen
.
allocate
();
}
catch
(
const
ParseError
&
e
)
{
printFunction
(
quadEnv
,
f
);
throw
ParseError
(
buf
.
str
()
+
e
.
what
());
std
::
cerr
<<
"Register Allocator error: "
<<
e
.
what
()
<<
endl
;
}
printFunction
(
quadEnv
,
f
);
...
...
@@ -251,19 +250,16 @@ void Compiler::generateQAlloc(QAlloc &q) {
if
(
r
!=
Register
(
q
.
loc
))
append
(
"PUSHL"
,
r
);
}
assert
(
q
.
virtSymbol
.
empty
()
||
!
q
.
count
);
if
(
q
.
virtSymbol
.
empty
()
)
{
append
(
"PUSHL"
,
"$0"
);
if
(
q
.
count
)
{
append
(
"PUSHL"
,
getRef
(
q
.
count
)
);
}
else
{
append
(
"PUSHL"
,
"$"
+
quote
(
q
.
virtSymbol
));
}
append
(
"PUSHL"
,
"$"
+
to_string
(
q
.
size
));
if
(
q
.
count
)
{
append
(
"PUSHL"
,
getRef
(
q
.
count
));
}
append
(
"CALL"
,
q
.
count
?
"__latte_mem_init_array"
:
"__latte_mem_init"
);
append
(
"ADDL"
,
"$"
+
to_string
(
q
.
count
?
12
:
8
),
"%esp"
);
...
...
@@ -319,7 +315,7 @@ void Compiler::generateQCall(QCall &q) {
}
else
{
append
(
"CALL"
,
quote
(
mangleFunctionName
(
q
.
fn
)));
}
if
(
q
.
params
)
{
if
(
q
.
params
||
q
.
self
)
{
append
(
"ADDL"
,
"$"
+
to_string
(
q
.
params
*
4
+
(
q
.
self
?
4
:
0
)),
"%esp"
);
}
auto
popRegs
=
registersToSave
(
q
);
...
...
@@ -335,7 +331,7 @@ void Compiler::generateQCall(QCall &q) {
void
Compiler
::
generateQParam
(
QParam
&
q
)
{
if
(
q
.
call
)
{
assert
(
q
.
num
>=
0
);
if
(
q
.
num
==
1
)
{
if
(
q
.
num
==
(
q
.
call
->
params
?
1
:
0
)
)
{
// first argument, need to save registers
for
(
auto
r
:
registersToSave
(
*
q
.
call
))
{
if
(
r
!=
Register
(
q
.
call
->
loc
))
...
...
@@ -438,12 +434,13 @@ Op Compiler::generateCmp(const VariablePtr& l, Op op, const VariablePtr &r) {
void
Compiler
::
generateQJumpCond
(
QJumpCond
&
q
)
{
auto
thisBlock
=
q
.
block
;
auto
tgBlock
=
q
.
target
->
block
;
assert
(
thisBlock
&&
tgBlock
);
const
auto
&
map
=
tgBlock
->
getPhiMapping
(
thisBlock
);
for
(
const
auto
&
phiVars
:
map
)
{
if
((
phiVars
.
first
->
info
&&
phiVars
.
second
->
info
&&
phiVars
.
first
->
info
!=
phiVars
.
second
->
info
)
||
(
phiVars
.
first
->
localOffset
&&
phiVars
.
second
->
localOffset
&&
phiVars
.
first
->
localOffset
!=
phiVars
.
second
->
localOffset
)
||
(
phiVars
.
first
->
registerColor
&&
phiVars
.
second
->
registerColor
&&
phiVars
.
first
->
registerColor
!=
phiVars
.
second
->
registerColor
)
)
{
(
phiVars
.
first
->
localOffset
&&
phiVars
.
second
->
localOffset
&&
phiVars
.
first
->
localOffset
!=
phiVars
.
second
->
localOffset
)
||
(
phiVars
.
first
->
registerColor
&&
phiVars
.
second
->
registerColor
&&
phiVars
.
first
->
registerColor
!=
phiVars
.
second
->
registerColor
)
)
{
buf
<<
(
"// Unimplemented phi CondJump register XCHG
\n
"
);
}
}
...
...
src/Compiler.h
View file @
1bed5bf5
...
...
@@ -85,10 +85,7 @@ public:
}
auto
unused
(
const
QuadruplePtr
&
q
)
const
{
auto
ret
=
to_set
(
::
aliveAfter
(
q
,
Register
::
assignable
));
ret
.
emplace
(
0
);
ret
-=
to_set
(
locks
);
return
ret
;
return
available
()
-
to_set
(
::
aliveAfter
(
q
,
Register
::
assignable
));
}
void
lock
(
Register
i
)
{
...
...
@@ -220,10 +217,6 @@ protected:
}
void
moveTo
(
VariablePtr
&
v
,
Register
tg
)
{
if
(
v
->
constExpr
)
{
append
(
"MOVL"
,
"$"
+
to_string
(
v
->
val
),
tg
);
return
;
}
auto
reg
=
Register
(
v
);
if
(
reg
==
0
)
{
append
(
"MOVL"
,
getRef
(
v
),
tg
);
...
...
src/TypeCheck.cpp
View file @
1bed5bf5
...
...
@@ -31,7 +31,7 @@ void TypeCheck::visitPIdent(PIdent *p_ident)
p_ident
->
var
=
var
;
lastType
=
var
->
type
;
if
(
auto
ptr
=
dynamic_pointer_cast
<
ClassT
>
(
lastType
))
{
if
(
!
ptr
->
pident_
||
!
ptr
->
pident_
->
var
.
lock
())
if
(
!
ptr
->
pident_
||
!
ptr
->
pident_
->
getVar
())
throw
runtime_error
(
"either no pident or no var assigned found"
);
}
}
...
...
@@ -247,6 +247,7 @@ void TypeCheck::visitForEach(ForEach *for_each)
VarInfoPtr
var
=
make_shared
<
VarInfo
>
(
for_each
->
pident_
,
for_each
->
type_
->
clone
());
binding
->
variables
<<
var
;
for_each
->
pident_
->
var
=
var
;
scope
->
currentBinding
=
binding
;
for_each
->
stmt_
->
accept
(
this
);
...
...
@@ -319,7 +320,7 @@ void TypeCheck::visitEClsMmbr(EClsMmbr *e_cls_mmbr)
throw
ParseError
(
"Class expected"
,
e_cls_mmbr
->
expr_
);
}
ClassInfoPtr
klass
=
scope
->
classes
[
type
->
pident_
];
assert
(
klass
==
type
->
pident_
->
var
.
lock
());
assert
(
klass
==
type
->
pident_
->
getVar
());
VarInfoPtr
var
=
klass
->
variables
[
e_cls_mmbr
->
pident_
];
if
(
!
var
||
var
==
scope
->
variables
.
local
(
e_cls_mmbr
->
pident_
->
string_
))
{
throw
UndefinedError
(
e_cls_mmbr
->
pident_
);
...
...
@@ -662,6 +663,7 @@ void TypeCheck::checkFunction(FunctionInfoPtr f)
f
->
binding
=
binding
;
if
(
scope
->
currentClass
)
{
f
->
self
=
make_shared
<
VarInfo
>
(
"self"
,
scope
->
currentClass
->
type
);
f
->
self
->
lineLocation
=
f
->
lineLocation
;
binding
->
variables
<<
f
->
self
;
}
...
...
src/codeGen/BasicBlock.h
View file @
1bed5bf5
...
...
@@ -73,6 +73,7 @@ public:
[[
nodiscard
]]
set
<
VariablePtr
>
inForBlock
(
const
BasicBlockPtr
&
q
)
const
{
set
<
VariablePtr
>
ret
;
for
(
const
auto
&
var
:
b
->
findPhi
(
q
))
{
if
(
var
.
second
->
constExpr
)
continue
;
ret
.
emplace
(
var
.
second
);
}
return
in
+
ret
;
...
...
src/codeGen/QuadrupleGenerator.cpp
View file @
1bed5bf5
...
...
@@ -107,7 +107,7 @@ VariableLayout QuadrupleGenerator::captureEnv() {
/// expressions
void
QuadrupleGenerator
::
visitEVar
(
EVar
*
p
)
{
auto
var
=
p
->
pident_
->
var
.
lock
();
auto
var
=
p
->
pident_
->
getVar
();
lastVar
=
alloc
(
var
);
if
(
var
->
isInstanceVariable
())
{
auto
fn
=
scope
->
currentFunction
;
...
...
@@ -281,13 +281,14 @@ void QuadrupleGenerator::visitEOr(EOr *p) {
leftValBlock
->
append
(
block
);
auto
r
=
evalJump
(
p
->
expr_2
,
labelTrue
,
labelFalse
);
if
(
!
r
)
return
;
if
(
r
->
constExpr
)
{
if
(
!
r
||
r
->
constExpr
)
{
assert
(
leftValBlock
->
quads
.
back
()
==
llq
);
leftValBlock
->
quads
.
pop_back
();
// could merge basic blocks now, but why bother
lastVar
=
r
->
val
?
r
:
l
;
if
(
r
)
{
lastVar
=
r
->
val
?
r
:
l
;
}
}
else
{
auto
rightValBlock
=
block
;
flushBasicBlock
();
...
...
@@ -321,17 +322,8 @@ void QuadrupleGenerator::visitEIndexAcc(EIndexAcc *p) {
}
lastVar
=
alloc
(
type
->
type_
->
clone
());
lastVar
->
memory
=
true
;
if
(
type
->
type_
->
size
()
>
4
)
{
// calculate quantifier, we multiply index because size is larger than 4
auto
q
=
alloc
(
type
->
type_
->
size
());
auto
newIndex
=
alloc
();
// calculate var = index * quantifier
addQuad
<
QAssign
>
(
newIndex
,
index
,
Op
::
Mul
,
q
);
addQuad
<
QAccess
>
(
lastVar
,
lhs
,
newIndex
,
1
,
4
);
// 4 accounts for table length entry
}
else
{
addQuad
<
QAccess
>
(
lastVar
,
lhs
,
index
,
type
->
type_
->
size
(),
4
);
// 4 accounts for table length entry
}
assert
(
type
->
type_
->
size
()
<=
4
);
addQuad
<
QAccess
>
(
lastVar
,
lhs
,
index
,
type
->
type_
->
size
(),
4
);
// 4 accounts for table length entry
Bool
b
;
if
(
type
->
type_
->
isEqual
(
&
b
))
{
addLastVarCondJump
(
nullptr
,
Op
::
Copy
,
lastVar
);
...
...
@@ -340,23 +332,13 @@ void QuadrupleGenerator::visitEIndexAcc(EIndexAcc *p) {
void
QuadrupleGenerator
::
visitEClsMmbr
(
EClsMmbr
*
p
)
{
auto
l
=
evalJump
(
p
->
expr_
,
labelTrue
,
labelFalse
);
auto
var
=
p
->
pident_
->
var
.
lock
();
auto
var
=
p
->
pident_
->
getVar
();
assert
(
var
);
// it cannot be function, as function might only be used in EApp and are handled directly there
assert
(
!
var
->
toFunction
());
// Array length calculation works because of arrayLengthVar that has offset 0
size_t
offset
=
var
->
offset
;
if
(
dynamic_cast
<
EIndexAcc
*>
(
p
->
expr_
))
{
// opt if EIndexAcc is used inside visitEClsMmbr
auto
access
=
dynamic_pointer_cast
<
QAccess
>
(
lastQuad
);
access
->
access
.
offset
+=
offset
;
l
->
info
=
var
;
lastVar
=
l
;
}
else
{
lastVar
=
alloc
(
var
);
auto
quad
=
make_shared
<
QAccess
>
(
lastVar
,
l
,
nullptr
,
0
,
offset
);
addQuad
(
quad
);
}
lastVar
=
alloc
(
var
);
addQuad
<
QAccess
>
(
lastVar
,
l
,
nullptr
,
0
,
var
->
offset
);
Bool
b
;
if
(
var
->
type
->
isEqual
(
&
b
))
{
addLastVarCondJump
(
nullptr
,
Op
::
Copy
,
lastVar
);
...
...
@@ -371,10 +353,10 @@ void QuadrupleGenerator::visitEApp(EApp *p) {
// call tab[i].fun()
// call obj.fun()
self
=
evalExpr
(
mem
->
expr_
);
info
=
static_pointer_cast
<
FunctionInfo
>
(
mem
->
pident_
->
var
.
lock
());
info
=
static_pointer_cast
<
FunctionInfo
>
(
mem
->
pident_
->
getVar
());
}
else
if
(
auto
ident
=
dynamic_cast
<
EVar
*>
(
p
->
expr_
))
{
auto
klass
=
scope
->
currentFunction
->
klass
.
lock
();
info
=
static_pointer_cast
<
FunctionInfo
>
(
ident
->
pident_
->
var
.
lock
());
info
=
static_pointer_cast
<
FunctionInfo
>
(
ident
->
pident_
->
getVar
());
auto
otherClass
=
info
->
klass
.
lock
();
if
(
otherClass
)
{
// call fun() = self.fun()
...
...
@@ -416,20 +398,14 @@ void QuadrupleGenerator::visitENewArray(ENewArray *p) {
// allocate enough memory with calloc, if it is class then init each entry...
auto
type
=
p
->
type_
;
size_t
size
=
type
->
size
();
string
virtSymbol
;
if
(
auto
klass
=
dynamic_cast
<
ClassT
*>
(
type
))
{
auto
info
=
klass
->
pident_
->
var
.
lock
()
->
toClass
();
size
=
info
->
size
;
virtSymbol
=
Compiler
::
getVirtName
(
info
);
}
auto
count
=
evalExpr
(
p
->
expr_
);
lastVar
=
alloc
(
new
Array
(
type
->
clone
()));
addQuad
<
QAlloc
>
(
lastVar
,
size
,
virtSymbol
,
count
);
addQuad
<
QAlloc
>
(
lastVar
,
size
,
""
,
count
);
}
void
QuadrupleGenerator
::
visitENewClass
(
ENewClass
*
p
)
{
// allocate enough memory with calloc, setup virt table pointer.
auto
info
=
p
->
pident_
->
var
.
lock
()
->
toClass
();
auto
info
=
p
->
pident_
->
getVar
()
->
toClass
();
size_t
size
=
info
->
size
;
string
virtSymbol
=
Compiler
::
getVirtName
(
info
);
lastVar
=
alloc
();
...
...
@@ -439,7 +415,7 @@ void QuadrupleGenerator::visitENewClass(ENewClass *p) {
/// statements
void
QuadrupleGenerator
::
visitInit
(
Init
*
p
)
{
auto
info
=
p
->
pident_
->
var
.
lock
();
auto
info
=
p
->
pident_
->
getVar
();
assert
(
info
);
auto
var
=
evalExpr
(
p
->
expr_
);
auto
loc
=
alloc
(
info
);
...
...
@@ -449,7 +425,7 @@ void QuadrupleGenerator::visitInit(Init *p) {
}
void
QuadrupleGenerator
::
visitNoInit
(
Init
*
p
)
{
auto
info
=
p
->
pident_
->
var
.
lock
();
auto
info
=
p
->
pident_
->
getVar
();
assert
(
info
);
auto
loc
=
alloc
(
info
);
addQuad
<
QAssign
>
(
loc
,
Op
::
Copy
,
alloc
(
0
));
...
...
@@ -531,8 +507,10 @@ void QuadrupleGenerator::compileCond(Expr *expr_, Stmt *stmt_1, Stmt *stmt_2) {
if
(
condVar
->
constExpr
)
{
assert
(
!
dynamic_pointer_cast
<
QJump
>
(
lastQuad
));
if
(
condVar
->
val
)
{
addQuad
(
ifBranch
);
stmt_1
->
accept
(
this
);
}
else
if
(
stmt_2
)
{
addQuad
(
elseBranch
);
stmt_2
->
accept
(
this
);
}
return
;
...
...
@@ -647,8 +625,83 @@ void QuadrupleGenerator::visitSExp(SExp *p) {
evalExpr
(
p
->
expr_
);
}
void
QuadrupleGenerator
::
visitForEach
(
ForEach
*
p
)
{
auto
tab
=
evalExpr
(
p
->
expr_
);
// throw ParseError("ForEach is yet unimplemented!", p);
// TODO: implement
void
QuadrupleGenerator
::
visitForEach
(
ForEach
*
expr
)
{
auto
cond
=
make_shared
<
QLabel
>
(
"for_cond"
);
auto
arr
=
evalExpr
(
expr
->
expr_
);
addQuad
<
QJump
>
(
cond
);
auto
beforeBlock
=
flushBasicBlock
();
// jump <- loop -> cond
auto
loop
=
make_shared
<
QLabel
>
(
"for_loop"
);
addQuad
(
loop
);
// jump <- loop
// hook env
auto
env1
=
captureEnv
();
// produce all variables hooks
for
(
const
auto
&
change
:
env1
.
changes
)
{
if
(
!
change
.
second
.
first
)
continue
;
auto
info
=
change
.
first
;
info
->
loc
=
nullptr
;
alloc
(
info
);
}
VarInfoPtr
iter
=
make_shared
<
VarInfo
>
(
"_it"
,
make_shared
<
Int
>
());
auto
iter1
=
alloc
(
iter
);
// save hooks for later
env1
.
capture
();
// env2 starts with hooked variables
auto
env2
=
captureEnv
();
auto
loopFirstBlock
=
block
;
auto
iterInfo
=
expr
->
pident_
->
getVar
();
assert
(
iterInfo
);
auto
iterVar
=
alloc
(
iterInfo
);
addQuad
<
QAccess
>
(
iterVar
,
arr
,
iter1
,
4
,
4
);
expr
->
stmt_
->
accept
(
this
);
iter
->
loc
=
nullptr
;
auto
iter2
=
alloc
(
iter
);
addQuad
<
QAssign
>
(
iter2
,
iter1
,
Op
::
Plus
,
alloc
(
1
));
auto
loopLastBlock
=
flushBasicBlock
(
true
);
// jump <- cond
auto
condFirstBlock
=
block
;
addQuad
(
cond
);
// env2 contains changed hooks
env2
.
capture
();
// restore env1 pre-hook variables
env1
.
revert
();
beforeBlock
->
append
(
condFirstBlock
);
for
(
const
auto
&
p
:
env2
.
changes
)
{
auto
info
=
p
.
first
;
auto
hooked
=
p
.
second
.
first
;
auto
looped
=
p
.
second
.
second
;
if
(
!
hooked
)
continue
;
auto
orig
=
env1
.
changes
[
info
].
first
;
// save hooks if used
info
->
loc
=
hooked
;
// transition from pre-hook to hooked var [before -> cond]
condFirstBlock
->
addPhi
(
beforeBlock
,
hooked
,
orig
);
// transition from hooked var
condFirstBlock
->
addPhi
(
loopLastBlock
,
hooked
,
looped
);
// loopLastBlock doesn't need phi, it has only one incoming block
}
condFirstBlock
->
addPhi
(
beforeBlock
,
iter1
,
alloc
(
0
));
condFirstBlock
->
addPhi
(
loopLastBlock
,
iter1
,
iter2
);
auto
len
=
alloc
();
addQuad
<
QAccess
>
(
len
,
arr
,
nullptr
,
0
,
0
);
addQuad
<
QJumpCond
>
(
loop
,
iter1
,
Op
::
LT
,
len
);
auto
condLastBlock
=
flushBasicBlock
(
true
);
// jump -> loop
condLastBlock
->
append
(
loopFirstBlock
);
// next block is ready to use updated variables
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment