Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
Pyston
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
Pyston
Commits
0999d34a
Commit
0999d34a
authored
Jun 27, 2016
by
Kevin Modzelewski
Committed by
Kevin Modzelewski
Jul 06, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move is_defined names out of the symbol table
parent
061e994b
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
313 additions
and
195 deletions
+313
-195
src/analysis/function_analysis.h
src/analysis/function_analysis.h
+20
-0
src/codegen/compvars.cpp
src/codegen/compvars.cpp
+15
-1
src/codegen/compvars.h
src/codegen/compvars.h
+2
-0
src/codegen/irgen.cpp
src/codegen/irgen.cpp
+138
-76
src/codegen/irgen/irgenerator.cpp
src/codegen/irgen/irgenerator.cpp
+98
-104
src/codegen/irgen/irgenerator.h
src/codegen/irgen/irgenerator.h
+13
-4
src/core/util.h
src/core/util.h
+10
-10
test/tests/undefined_passing.py
test/tests/undefined_passing.py
+17
-0
No files found.
src/analysis/function_analysis.h
View file @
0999d34a
...
...
@@ -51,12 +51,30 @@ public:
return
v
[
vreg
];
}
void
clear
()
{
int
n
=
v
.
size
();
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
v
[
i
]
=
T
();
}
}
int
numSet
()
{
int
n
=
v
.
size
();
int
r
=
0
;
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
if
(
v
[
i
]
!=
T
())
r
++
;
}
return
r
;
}
class
iterator
{
public:
const
VRegMap
<
T
>&
map
;
int
i
;
iterator
(
const
VRegMap
<
T
>&
map
,
int
i
)
:
map
(
map
),
i
(
i
)
{}
// TODO: make this skip unset values?
iterator
&
operator
++
()
{
i
++
;
return
*
this
;
...
...
@@ -66,6 +84,8 @@ public:
bool
operator
!=
(
const
iterator
&
rhs
)
const
{
return
!
(
*
this
==
rhs
);
}
std
::
pair
<
int
,
const
T
&>
operator
*
()
{
return
std
::
pair
<
int
,
const
T
&>
(
i
,
map
[
i
]);
}
int
first
()
const
{
return
i
;
}
const
T
&
second
()
const
{
return
map
[
i
];
}
};
int
numVregs
()
const
{
return
v
.
size
();
}
...
...
src/codegen/compvars.cpp
View file @
0999d34a
...
...
@@ -2429,8 +2429,11 @@ public:
}
};
ConcreteCompilerType
*
BOOL
=
new
BoolType
();
llvm
::
Value
*
makeLLVMBool
(
bool
b
)
{
return
llvm
::
ConstantInt
::
get
(
BOOL
->
llvmType
(),
b
,
false
);
}
ConcreteCompilerVariable
*
makeBool
(
bool
b
)
{
return
new
ConcreteCompilerVariable
(
BOOL
,
llvm
::
ConstantInt
::
get
(
BOOL
->
llvmType
(),
b
,
false
));
return
new
ConcreteCompilerVariable
(
BOOL
,
makeLLVMBool
(
b
));
}
ConcreteCompilerVariable
*
doIs
(
IREmitter
&
emitter
,
CompilerVariable
*
lhs
,
CompilerVariable
*
rhs
,
bool
negate
)
{
...
...
@@ -2858,6 +2861,17 @@ llvm::Value* i1FromBool(IREmitter& emitter, ConcreteCompilerVariable* v) {
}
}
llvm
::
Value
*
i1FromLLVMBool
(
IREmitter
&
emitter
,
llvm
::
Value
*
v
)
{
if
(
BOOLS_AS_I64
)
{
assert
(
v
->
getType
()
==
BOOL
->
llvmType
());
assert
(
BOOL
->
llvmType
()
==
g
.
i64
);
llvm
::
Value
*
v2
=
emitter
.
getBuilder
()
->
CreateTrunc
(
v
,
g
.
i1
);
return
v2
;
}
else
{
return
v
;
}
}
ConcreteCompilerType
*
LIST
,
*
SLICE
,
*
MODULE
,
*
DICT
,
*
SET
,
*
FROZENSET
,
*
LONG
,
*
BOXED_COMPLEX
;
...
...
src/codegen/compvars.h
View file @
0999d34a
...
...
@@ -346,6 +346,7 @@ CompilerVariable* makeFloat(double);
CompilerVariable
*
makeUnboxedFloat
(
IREmitter
&
,
ConcreteCompilerVariable
*
);
CompilerVariable
*
makeUnboxedFloat
(
IREmitter
&
,
llvm
::
Value
*
);
llvm
::
Value
*
makeLLVMBool
(
bool
b
);
ConcreteCompilerVariable
*
makeBool
(
bool
);
ConcreteCompilerVariable
*
makeLong
(
IREmitter
&
,
Box
*
);
ConcreteCompilerVariable
*
makePureImaginary
(
IREmitter
&
,
Box
*
);
...
...
@@ -372,6 +373,7 @@ CompilerType* makeFuncType(ConcreteCompilerType* rtn_type, const std::vector<Con
ConcreteCompilerVariable
*
boolFromI1
(
IREmitter
&
,
llvm
::
Value
*
);
llvm
::
Value
*
i1FromBool
(
IREmitter
&
,
ConcreteCompilerVariable
*
);
llvm
::
Value
*
i1FromLLVMBool
(
IREmitter
&
,
llvm
::
Value
*
);
template
<
typename
V
>
CompilerVariable
*
_ValuedCompilerType
<
V
>::
getPystonIter
(
IREmitter
&
emitter
,
const
OpInfo
&
info
,
VAR
*
var
)
{
...
...
src/codegen/irgen.cpp
View file @
0999d34a
...
...
@@ -297,13 +297,6 @@ static ConcreteCompilerType* getTypeAtBlockStart(TypeAnalysis* types, InternedSt
}
}
static
bool
shouldPhisOwnThisSym
(
llvm
::
StringRef
name
)
{
// generating unnecessary increfs to the passed generator would introduce cycles inside the generator
if
(
name
==
PASSED_GENERATOR_NAME
)
assert
(
0
);
return
true
;
}
llvm
::
Value
*
handlePotentiallyUndefined
(
ConcreteCompilerVariable
*
is_defined_var
,
llvm
::
Type
*
rtn_type
,
llvm
::
BasicBlock
*&
cur_block
,
IREmitter
&
emitter
,
bool
speculate_undefined
,
std
::
function
<
llvm
::
Value
*
(
IREmitter
&
)
>
when_defined
,
...
...
@@ -361,6 +354,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
CFG
*
cfg
=
source
->
cfg
;
auto
&&
vreg_info
=
cfg
->
getVRegInfo
();
int
num_vregs
=
vreg_info
.
getTotalNumOfVRegs
();
if
(
entry_descriptor
!=
NULL
)
assert
(
blocks
.
count
(
cfg
->
getStartingBlock
())
==
0
);
...
...
@@ -383,7 +377,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
// the function entry block, where we add the type guards [no guards anymore]
llvm
::
BasicBlock
*
osr_entry_block
=
NULL
;
llvm
::
BasicBlock
*
osr_unbox_block_end
=
NULL
;
// the block after type guards where we up/down-convert things
ConcreteSymbolTable
*
osr_syms
=
NULL
;
// syms after conversion
std
::
unordered_map
<
InternedString
,
ConcreteCompilerVariable
*>*
osr_syms
=
NULL
;
// syms after conversion
if
(
entry_descriptor
!=
NULL
)
{
llvm
::
BasicBlock
*
osr_unbox_block
=
llvm
::
BasicBlock
::
Create
(
g
.
context
,
"osr_unbox"
,
irstate
->
getLLVMFunction
(),
&
irstate
->
getLLVMFunction
()
->
getEntryBlock
());
...
...
@@ -391,8 +385,8 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
&
irstate
->
getLLVMFunction
()
->
getEntryBlock
());
assert
(
&
irstate
->
getLLVMFunction
()
->
getEntryBlock
()
==
osr_entry_block
);
osr_syms
=
new
ConcreteSymbolTable
();
SymbolTable
*
initial_syms
=
new
SymbolTable
();
osr_syms
=
new
std
::
unordered_map
<
InternedString
,
ConcreteCompilerVariable
*>
();
auto
initial_syms
=
new
std
::
unordered_map
<
InternedString
,
CompilerVariable
*>
();
// llvm::BranchInst::Create(llvm_entry_blocks[entry_descriptor->backedge->target->idx], entry_block);
llvm
::
BasicBlock
*
osr_entry_block_end
=
osr_entry_block
;
...
...
@@ -499,10 +493,14 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
////
// Main ir generation: go through each basic block in the CFG and emit the code
// TODO: switch these to unique_ptr
std
::
unordered_map
<
CFGBlock
*
,
SymbolTable
*>
ending_symbol_tables
;
std
::
unordered_map
<
CFGBlock
*
,
ConcreteSymbolTable
*>
phi_ending_symbol_tables
;
typedef
std
::
map
<
InternedString
,
std
::
pair
<
ConcreteCompilerType
*
,
llvm
::
PHINode
*>>
PHITable
;
std
::
unordered_map
<
CFGBlock
*
,
DefinednessTable
*>
definedness_tables
;
typedef
VRegMap
<
std
::
pair
<
ConcreteCompilerType
*
,
llvm
::
PHINode
*>>
PHITable
;
typedef
VRegMap
<
llvm
::
PHINode
*>
DefinednessPHITable
;
std
::
unordered_map
<
CFGBlock
*
,
PHITable
*>
created_phis
;
std
::
unordered_map
<
CFGBlock
*
,
DefinednessPHITable
*>
created_definedness_phis
;
std
::
unordered_map
<
CFGBlock
*
,
llvm
::
SmallVector
<
IRGenerator
::
ExceptionState
,
2
>>
incoming_exception_state
;
CFGBlock
*
initial_block
=
NULL
;
...
...
@@ -536,8 +534,10 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
llvm
::
BasicBlock
*
entry_block_end
=
llvm_entry_blocks
[
block
];
std
::
unique_ptr
<
IREmitter
>
emitter
(
createIREmitter
(
irstate
,
entry_block_end
));
PHITable
*
phis
=
new
PHITable
();
PHITable
*
phis
=
new
PHITable
(
num_vregs
);
created_phis
[
block
]
=
phis
;
DefinednessPHITable
*
definedness_phis
=
new
DefinednessPHITable
(
num_vregs
);
created_definedness_phis
[
block
]
=
definedness_phis
;
// Set initial symbol table:
// If we're in the starting block, no phis or symbol table changes for us.
...
...
@@ -612,25 +612,40 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
irstate
->
setupFrameInfoVarOSR
(
osr_frame_info_arg
);
for
(
const
auto
&
p
:
entry_descriptor
->
args
)
{
// Don't add the frame info to the symbol table since we will store it separately
// (we manually added it during the calculation of osr_syms):
if
(
p
.
first
.
s
()
==
FRAME_INFO_PTR_NAME
)
continue
;
ConcreteCompilerType
*
analyzed_type
=
getTypeAtBlockStart
(
types
,
p
.
first
,
vreg_info
,
block
);
// printf("For %s, given %s, analyzed for %s\n", p.first.c_str(), p.second->debugName().c_str(),
// analyzed_type->debugName().c_str());
assert
(
p
.
first
.
s
()
!=
FRAME_INFO_PTR_NAME
);
assert
(
p
.
first
.
s
()
!=
PASSED_CLOSURE_NAME
);
assert
(
p
.
first
.
s
()
!=
CREATED_CLOSURE_NAME
);
assert
(
p
.
first
.
s
()
!=
PASSED_GENERATOR_NAME
);
if
(
p
.
first
.
s
()[
0
]
==
'!'
)
{
assert
(
startswith
(
p
.
first
.
s
(),
"!is_defined_"
));
assert
(
p
.
second
==
BOOL
);
auto
base_name
=
source
->
getInternedStrings
().
get
(
p
.
first
.
s
().
substr
(
12
));
llvm
::
PHINode
*
phi
=
emitter
->
getBuilder
()
->
CreatePHI
(
BOOL
->
llvmType
(),
block
->
predecessors
.
size
()
+
1
,
p
.
first
.
s
());
int
vreg
=
vreg_info
.
getVReg
(
base_name
);
generator
->
giveDefinednessVar
(
vreg
,
phi
);
(
*
definedness_phis
)[
vreg
]
=
phi
;
}
else
{
int
vreg
=
vreg_info
.
getVReg
(
p
.
first
);
ConcreteCompilerType
*
analyzed_type
=
getTypeAtBlockStart
(
types
,
p
.
first
,
vreg_info
,
block
);
// printf("For %s, given %s, analyzed for %s\n", p.first.c_str(), p.second->debugName().c_str(),
// analyzed_type->debugName().c_str());
llvm
::
PHINode
*
phi
=
emitter
->
getBuilder
()
->
CreatePHI
(
analyzed_type
->
llvmType
(),
block
->
predecessors
.
size
()
+
1
,
p
.
first
.
s
());
if
(
analyzed_type
->
getBoxType
()
==
analyzed_type
)
{
irstate
->
getRefcounts
()
->
setType
(
phi
,
RefType
::
OWNED
);
}
llvm
::
PHINode
*
phi
=
emitter
->
getBuilder
()
->
CreatePHI
(
analyzed_type
->
llvmType
(),
block
->
predecessors
.
size
()
+
1
,
p
.
first
.
s
());
if
(
analyzed_type
->
getBoxType
()
==
analyzed_type
)
{
RefType
type
=
shouldPhisOwnThisSym
(
p
.
first
.
s
())
?
RefType
::
OWNED
:
RefType
::
BORROWED
;
irstate
->
getRefcounts
()
->
setType
(
phi
,
type
);
ConcreteCompilerVariable
*
var
=
new
ConcreteCompilerVariable
(
analyzed_type
,
phi
);
generator
->
giveLocalSymbol
(
vreg
,
var
);
(
*
phis
)[
vreg
]
=
std
::
make_pair
(
analyzed_type
,
phi
);
}
ConcreteCompilerVariable
*
var
=
new
ConcreteCompilerVariable
(
analyzed_type
,
phi
);
generator
->
giveLocalSymbol
(
p
.
first
,
var
);
(
*
phis
)[
p
.
first
]
=
std
::
make_pair
(
analyzed_type
,
phi
);
}
}
else
if
(
pred
==
NULL
)
{
assert
(
traversal_order
.
size
()
<
cfg
->
blocks
.
size
());
...
...
@@ -643,11 +658,15 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
}
RELEASE_ASSERT
(
0
,
"Rotted code"
);
#if 0
std::set<InternedString> names;
for (const int vreg : phi_analysis->getAllRequiredFor(block)) {
auto s = cfg->getVRegInfo().getName(vreg);
names.insert(s);
if (phi_analysis->isPotentiallyUndefinedAfter(vreg, block->predecessors[0])) {
assert(0 && "this should go in definedness_names or some such");
names.insert(getIsDefinedName(s, source->getInternedStrings()));
}
}
...
...
@@ -664,8 +683,11 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
ConcreteCompilerVariable* var = new ConcreteCompilerVariable(type, phi);
generator->giveLocalSymbol(s, var);
assert(s.s()[0] != '!' && "implement me");
(*phis)[s] = std::make_pair(type, phi);
}
#endif
}
else
{
assert
(
pred
);
assert
(
blocks
.
count
(
pred
));
...
...
@@ -673,7 +695,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
if
(
block
->
predecessors
.
size
()
==
1
)
{
// If this block has only one predecessor, it by definition doesn't need any phi nodes.
// Assert that the phi_st is empty, and just create the symbol table from the non-phi st:
ASSERT
(
phi_ending_symbol_tables
[
pred
]
->
size
()
==
0
,
"%d %d"
,
block
->
idx
,
pred
->
idx
);
ASSERT
(
phi_ending_symbol_tables
[
pred
]
->
numSet
()
==
0
,
"%d %d"
,
block
->
idx
,
pred
->
idx
);
assert
(
ending_symbol_tables
.
count
(
pred
));
// Filter out any names set by an invoke statement at the end of the previous block, if we're in the
...
...
@@ -716,6 +738,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
assert
(
asgn
->
targets
.
size
()
==
1
);
if
(
asgn
->
targets
[
0
]
->
type
==
AST_TYPE
::
Name
)
{
InternedString
name
=
ast_cast
<
AST_Name
>
(
asgn
->
targets
[
0
])
->
id
;
int
vreg
=
ast_cast
<
AST_Name
>
(
asgn
->
targets
[
0
])
->
vreg
;
assert
(
name
.
c_str
()[
0
]
==
'#'
);
// it must be a temporary
// You might think I need to check whether `name' is being assigned globally or locally,
// since a global assign doesn't affect the symbol table. However, the CFG pass only
...
...
@@ -724,14 +747,19 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
// TODO: inefficient
sym_table
=
new
SymbolTable
(
*
sym_table
);
ASSERT
(
sym_table
->
count
(
name
)
,
"%d %s
\n
"
,
block
->
idx
,
name
.
c_str
());
sym_table
->
erase
(
name
)
;
ASSERT
(
(
*
sym_table
)[
vreg
]
!=
NULL
,
"%d %s
\n
"
,
block
->
idx
,
name
.
c_str
());
(
*
sym_table
)[
vreg
]
=
NULL
;
created_new_sym_table
=
true
;
}
}
}
generator
->
copySymbolsFrom
(
sym_table
);
for
(
auto
&&
p
:
*
definedness_tables
[
pred
])
{
if
(
!
p
.
second
)
continue
;
generator
->
giveDefinednessVar
(
p
.
first
,
p
.
second
);
}
if
(
created_new_sym_table
)
delete
sym_table
;
}
else
{
...
...
@@ -747,28 +775,34 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
// And go through and add phi nodes:
ConcreteSymbolTable
*
pred_st
=
phi_ending_symbol_tables
[
pred
];
// We have to sort the phi table by name in order to a get a deterministic ordering for the JIT object
// cache.
typedef
std
::
pair
<
InternedString
,
ConcreteCompilerVariable
*>
Entry
;
std
::
vector
<
Entry
>
sorted_pred_st
(
pred_st
->
begin
(),
pred_st
->
end
());
std
::
sort
(
sorted_pred_st
.
begin
(),
sorted_pred_st
.
end
(),
[](
const
Entry
&
lhs
,
const
Entry
&
rhs
)
{
return
lhs
.
first
<
rhs
.
first
;
});
for
(
auto
&
entry
:
sorted_pred_st
)
{
InternedString
name
=
entry
.
first
;
ConcreteCompilerVariable
*
cv
=
entry
.
second
;
// incoming CCV from predecessor block
// printf("block %d: adding phi for %s from pred %d\n", block->idx, name.c_str(), pred->idx);
llvm
::
PHINode
*
phi
=
emitter
->
getBuilder
()
->
CreatePHI
(
cv
->
getType
()
->
llvmType
(),
block
->
predecessors
.
size
(),
name
.
s
());
for
(
int
vreg
=
0
;
vreg
<
num_vregs
;
vreg
++
)
{
ConcreteCompilerVariable
*
cv
=
(
*
pred_st
)[
vreg
];
if
(
!
cv
)
continue
;
llvm
::
PHINode
*
phi
=
emitter
->
getBuilder
()
->
CreatePHI
(
cv
->
getType
()
->
llvmType
(),
block
->
predecessors
.
size
());
if
(
VERBOSITY
(
"irgen"
))
phi
->
setName
(
vreg_info
.
getName
(
vreg
).
s
());
if
(
cv
->
getType
()
->
getBoxType
()
==
cv
->
getType
())
{
RefType
type
=
shouldPhisOwnThisSym
(
name
.
s
())
?
RefType
::
OWNED
:
RefType
::
BORROWED
;
irstate
->
getRefcounts
()
->
setType
(
phi
,
type
);
irstate
->
getRefcounts
()
->
setType
(
phi
,
RefType
::
OWNED
);
}
// emitter->getBuilder()->CreateCall(g.funcs.dump, phi);
ConcreteCompilerVariable
*
var
=
new
ConcreteCompilerVariable
(
cv
->
getType
(),
phi
);
generator
->
giveLocalSymbol
(
name
,
var
);
generator
->
giveLocalSymbol
(
vreg
,
var
);
(
*
phis
)[
vreg
]
=
std
::
make_pair
(
cv
->
getType
(),
phi
);
}
(
*
phis
)[
name
]
=
std
::
make_pair
(
cv
->
getType
(),
phi
);
for
(
auto
&&
p
:
*
definedness_tables
[
pred
])
{
if
(
!
p
.
second
)
continue
;
llvm
::
PHINode
*
phi
=
emitter
->
getBuilder
()
->
CreatePHI
(
BOOL
->
llvmType
(),
block
->
predecessors
.
size
());
if
(
VERBOSITY
(
"irgen"
))
phi
->
setName
(
"!is_defined_"
+
vreg_info
.
getName
(
p
.
first
).
s
());
generator
->
giveDefinednessVar
(
p
.
first
,
phi
);
(
*
definedness_phis
)[
p
.
first
]
=
phi
;
}
}
}
...
...
@@ -794,6 +828,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
const
IRGenerator
::
EndingState
&
ending_st
=
generator
->
getEndingSymbolTable
();
ending_symbol_tables
[
block
]
=
ending_st
.
symbol_table
;
phi_ending_symbol_tables
[
block
]
=
ending_st
.
phi_symbol_table
;
definedness_tables
[
block
]
=
ending_st
.
definedness_vars
;
llvm_exit_blocks
[
block
]
=
ending_st
.
ending_block
;
if
(
ending_st
.
exception_state
.
size
())
{
...
...
@@ -806,7 +841,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
}
if
(
into_hax
.
count
(
block
))
ASSERT
(
ending_st
.
symbol_table
->
size
()
==
0
,
"%d"
,
block
->
idx
);
ASSERT
(
ending_st
.
symbol_table
->
numSet
()
==
0
,
"%d"
,
block
->
idx
);
}
////
...
...
@@ -836,22 +871,20 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
// printf("(%d %ld) -> (%d %ld)\n", bpred->idx, phi_ending_symbol_tables[bpred]->size(), b->idx,
// phis->size());
ASSERT
(
sameKeyset
(
phi_ending_symbol_tables
[
bpred
],
phis
),
"%d->%d"
,
bpred
->
idx
,
b
->
idx
);
assert
(
phi_ending_symbol_tables
[
bpred
]
->
size
()
==
phis
->
size
());
assert
(
phi_ending_symbol_tables
[
bpred
]
->
numSet
()
==
phis
->
numSet
());
}
if
(
this_is_osr_entry
)
{
assert
(
sameKeyset
(
osr_syms
,
phis
));
int
nondefined_syms
=
0
;
for
(
auto
&&
p
:
*
osr_syms
)
{
if
(
p
.
first
.
s
()[
0
]
!=
'!'
)
nondefined_syms
++
;
}
assert
(
nondefined_syms
==
phis
->
numSet
());
}
#endif // end checking phi agreement.
// Can't always add the phi incoming value right away, since we may have to create more
// basic blocks as part of type coercion.
// Instead, just make a record of the phi node, value, and the location of the from-BB,
// which we won't read until after all new BBs have been added.
std
::
vector
<
std
::
tuple
<
llvm
::
PHINode
*
,
llvm
::
Value
*
,
llvm
::
BasicBlock
*&>>
phi_args
;
for
(
auto
it
=
phis
->
begin
();
it
!=
phis
->
end
();
++
it
)
{
llvm
::
PHINode
*
llvm_phi
=
it
->
second
.
second
;
auto
handle_phi
=
[
&
](
llvm
::
PHINode
*
llvm_phi
,
int
vreg
,
CompilerType
*
phi_type
,
bool
is_defined_name
)
{
for
(
int
j
=
0
;
j
<
b
->
predecessors
.
size
();
j
++
)
{
CFGBlock
*
bpred
=
b
->
predecessors
[
j
];
if
(
blocks
.
count
(
bpred
)
==
0
)
...
...
@@ -861,34 +894,59 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
if
(
llvm
::
isa
<
llvm
::
UnreachableInst
>
(
terminator
))
continue
;
ConcreteCompilerVariable
*
v
=
(
*
phi_ending_symbol_tables
[
bpred
])[
it
->
first
];
assert
(
v
);
// Make sure they all prepared for the same type:
ASSERT
(
it
->
second
.
first
==
v
->
getType
(),
"%d %d: %s %s %s"
,
b
->
idx
,
bpred
->
idx
,
it
->
first
.
c_str
(),
it
->
second
.
first
->
debugName
().
c_str
(),
v
->
getType
()
->
debugName
().
c_str
());
llvm
::
Value
*
val
=
v
->
getValue
();
llvm_phi
->
addIncoming
(
v
->
getValue
(),
llvm_exit_blocks
[
b
->
predecessors
[
j
]]);
llvm
::
Value
*
val
;
CompilerType
*
this_type
;
if
(
!
is_defined_name
)
{
ConcreteCompilerVariable
*
v
=
(
*
phi_ending_symbol_tables
[
bpred
])[
vreg
];
assert
(
v
);
// Make sure they all prepared for the same type:
ASSERT
(
phi_type
==
v
->
getType
(),
"%d %d: %d %s %s"
,
b
->
idx
,
bpred
->
idx
,
vreg
,
phi_type
->
debugName
().
c_str
(),
v
->
getType
()
->
debugName
().
c_str
());
val
=
v
->
getValue
();
this_type
=
v
->
getType
();
}
else
{
val
=
(
*
definedness_tables
[
bpred
])[
vreg
];
this_type
=
BOOL
;
}
assert
(
val
);
llvm_phi
->
addIncoming
(
val
,
llvm_exit_blocks
[
b
->
predecessors
[
j
]]);
if
(
v
->
getType
()
->
getBoxType
()
==
v
->
getType
()
&&
shouldPhisOwnThisSym
(
it
->
first
.
s
())
)
{
if
(
this_type
->
getBoxType
()
==
this_type
)
{
// llvm::outs() << *v->getValue() << " is getting consumed by phi " << *llvm_phi << '\n';
assert
(
llvm
::
isa
<
llvm
::
BranchInst
>
(
terminator
));
irstate
->
getRefcounts
()
->
refConsumed
(
v
->
getValue
()
,
terminator
);
irstate
->
getRefcounts
()
->
refConsumed
(
v
al
,
terminator
);
}
}
if
(
this_is_osr_entry
)
{
ConcreteCompilerVariable
*
v
=
(
*
osr_syms
)[
it
->
first
];
ConcreteCompilerVariable
*
v
;
if
(
!
is_defined_name
)
v
=
(
*
osr_syms
)[
vreg_info
.
getName
(
vreg
)];
else
v
=
(
*
osr_syms
)[
getIsDefinedName
(
vreg_info
.
getName
(
vreg
),
source
->
getInternedStrings
())];
assert
(
v
);
ASSERT
(
it
->
second
.
first
==
v
->
getType
()
,
""
);
ASSERT
(
phi_type
==
phi_type
,
""
);
llvm_phi
->
addIncoming
(
v
->
getValue
(),
osr_unbox_block_end
);
}
};
for
(
auto
it
=
phis
->
begin
();
it
!=
phis
->
end
();
++
it
)
{
llvm
::
PHINode
*
llvm_phi
=
it
.
second
().
second
;
if
(
!
llvm_phi
)
continue
;
handle_phi
(
llvm_phi
,
it
.
first
(),
it
.
second
().
first
,
false
);
}
for
(
auto
t
:
phi_args
)
{
RELEASE_ASSERT
(
0
,
"this hasn't been hit in a very long time -- check refcounting"
);
std
::
get
<
0
>
(
t
)
->
addIncoming
(
std
::
get
<
1
>
(
t
),
std
::
get
<
2
>
(
t
));
auto
definedness_phis
=
created_definedness_phis
[
b
];
for
(
auto
it
=
definedness_phis
->
begin
();
it
!=
definedness_phis
->
end
();
++
it
)
{
llvm
::
PHINode
*
llvm_phi
=
it
.
second
();
if
(
!
llvm_phi
)
continue
;
handle_phi
(
llvm_phi
,
it
.
first
(),
BOOL
,
true
);
}
}
...
...
@@ -898,7 +956,9 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
continue
;
delete
ending_symbol_tables
[
b
];
delete
phi_ending_symbol_tables
[
b
];
delete
created_phis
[
b
];
delete
definedness_tables
[
b
];
}
if
(
entry_descriptor
)
{
...
...
@@ -1101,8 +1161,10 @@ CompiledFunction* doCompile(FunctionMetadata* md, SourceInfo* source, ParamNames
IRGenState
irstate
(
md
,
cf
,
source
,
std
::
move
(
phis
),
param_names
,
getGCBuilder
(),
dbg_funcinfo
,
&
refcounter
);
emitBBs
(
&
irstate
,
types
,
entry_descriptor
,
blocks
);
assert
(
!
llvm
::
verifyFunction
(
*
f
,
&
llvm
::
errs
()));
RefcountTracker
::
addRefcounts
(
&
irstate
);
assert
(
!
llvm
::
verifyFunction
(
*
f
,
&
llvm
::
errs
()));
int
num_instructions
=
std
::
distance
(
llvm
::
inst_begin
(
f
),
llvm
::
inst_end
(
f
));
static
StatCounter
num_llvm_insts
(
"num_llvm_insts"
);
...
...
src/codegen/irgen/irgenerator.cpp
View file @
0999d34a
...
...
@@ -797,6 +797,8 @@ private:
IREmitterImpl
emitter
;
// symbol_table tracks which (non-global) python variables are bound to which CompilerVariables
SymbolTable
symbol_table
;
DefinednessTable
definedness_vars
;
std
::
unordered_map
<
CFGBlock
*
,
llvm
::
BasicBlock
*>&
entry_blocks
;
CFGBlock
*
myblock
;
TypeAnalysis
*
types
;
...
...
@@ -825,6 +827,8 @@ public:
:
irstate
(
irstate
),
curblock
(
entry_blocks
[
myblock
]),
emitter
(
irstate
,
curblock
,
this
),
symbol_table
(
myblock
->
cfg
->
getVRegInfo
().
getTotalNumOfVRegs
()),
definedness_vars
(
myblock
->
cfg
->
getVRegInfo
().
getTotalNumOfVRegs
()),
entry_blocks
(
entry_blocks
),
myblock
(
myblock
),
types
(
types
),
...
...
@@ -889,9 +893,9 @@ private:
return
irstate
->
getSourceInfo
()
->
getInternedStrings
().
get
(
std
::
forward
<
T
>
(
s
));
}
InternedString
getIsDefinedName
(
InternedString
name
)
{
return
pyston
::
getIsDefinedName
(
name
,
irstate
->
getSourceInfo
()
->
getInternedStrings
());
}
//
InternedString getIsDefinedName(InternedString name) {
//
return pyston::getIsDefinedName(name, irstate->getSourceInfo()->getInternedStrings());
//
}
CompilerVariable
*
evalAttribute
(
AST_Attribute
*
node
,
const
UnwindInfo
&
unw_info
)
{
CompilerVariable
*
value
=
evalExpr
(
node
->
value
,
unw_info
);
...
...
@@ -1417,7 +1421,7 @@ private:
return
new
ConcreteCompilerVariable
(
UNKNOWN
,
r
);
}
else
{
// vst is one of {FAST, CLOSURE}
if
(
symbol_table
.
find
(
node
->
id
)
==
symbol_table
.
end
()
)
{
if
(
!
symbol_table
[
node
->
vreg
]
)
{
// TODO should mark as DEAD here, though we won't end up setting all the names appropriately
// state = DEAD;
llvm
::
CallSite
call
=
emitter
.
createCall
(
...
...
@@ -1429,24 +1433,22 @@ private:
return
undefVariable
();
}
InternedString
defined_name
=
getIsDefinedName
(
node
->
id
);
ConcreteCompilerVariable
*
is_defined_var
=
static_cast
<
ConcreteCompilerVariable
*>
(
_getFake
(
defined_name
,
true
));
auto
is_defined_var
=
getDefinedVar
(
node
->
vreg
,
true
);
if
(
is_defined_var
)
{
emitter
.
createCall
(
unw_info
,
g
.
funcs
.
assertNameDefined
,
{
i1FromBool
(
emitter
,
is_defined_var
),
embedRelocatablePtr
(
node
->
id
.
c_str
(),
g
.
i8_ptr
),
{
i1From
LLVM
Bool
(
emitter
,
is_defined_var
),
embedRelocatablePtr
(
node
->
id
.
c_str
(),
g
.
i8_ptr
),
emitter
.
setType
(
embedRelocatablePtr
(
UnboundLocalError
,
g
.
llvm_class_type_ptr
),
RefType
::
BORROWED
),
getConstantInt
(
true
,
g
.
i1
)
});
// At this point we know the name must be defined (otherwise the assert would have fired):
_popFake
(
defined_name
);
popDefinedVar
(
node
->
vreg
);
}
CompilerVariable
*
rtn
=
symbol_table
[
node
->
id
];
CompilerVariable
*
rtn
=
symbol_table
[
node
->
vreg
];
if
(
is_kill
)
symbol_table
.
erase
(
node
->
id
)
;
symbol_table
[
node
->
vreg
]
=
NULL
;
return
rtn
;
}
}
...
...
@@ -1893,32 +1895,24 @@ private:
return
evalSliceExprPost
(
node
,
unw_info
,
rtn
);
}
void
_setFake
(
InternedString
name
,
CompilerVariable
*
val
)
{
assert
(
name
.
s
()[
0
]
==
'!'
);
CompilerVariable
*&
cur
=
symbol_table
[
name
];
void
setDefinedVar
(
int
vreg
,
llvm
::
Value
*
val
)
{
// printf("Setting definedness var for %s\n", name.c_str());
assert
(
val
->
getType
()
==
BOOL
->
llvmType
());
llvm
::
Value
*&
cur
=
definedness_vars
[
vreg
];
assert
(
cur
==
NULL
);
cur
=
val
;
}
// whether a Python variable FOO might be undefined or not is determined by whether the corresponding is_defined_FOO
// variable is present in our symbol table. If it is, then it *might* be undefined. If it isn't, then it either is
// definitely defined, or definitely isn't.
//
// to check whether a variable is in our symbol table, call _getFake with allow_missing = true and check whether the
// result is NULL.
CompilerVariable
*
_getFake
(
InternedString
name
,
bool
allow_missing
=
false
)
{
assert
(
name
.
s
()[
0
]
==
'!'
);
auto
it
=
symbol_table
.
find
(
name
);
if
(
it
==
symbol_table
.
end
())
{
llvm
::
Value
*
getDefinedVar
(
int
vreg
,
bool
allow_missing
=
false
)
{
auto
r
=
definedness_vars
[
vreg
];
if
(
!
r
)
assert
(
allow_missing
);
return
NULL
;
}
return
it
->
second
;
return
r
;
}
CompilerVariable
*
_popFake
(
InternedString
name
,
bool
allow_missing
=
false
)
{
CompilerVariable
*
rtn
=
_getFake
(
name
,
allow_missing
);
symbol_table
.
erase
(
name
)
;
llvm
::
Value
*
popDefinedVar
(
int
vreg
,
bool
allow_missing
=
false
)
{
llvm
::
Value
*
rtn
=
getDefinedVar
(
vreg
,
allow_missing
);
definedness_vars
[
vreg
]
=
NULL
;
if
(
!
allow_missing
)
assert
(
rtn
!=
NULL
);
return
rtn
;
...
...
@@ -1979,13 +1973,12 @@ private:
}
else
{
// FAST or CLOSURE
CompilerVariable
*
prev
=
symbol_table
[
name
];
symbol_table
[
name
]
=
val
;
CompilerVariable
*
prev
=
symbol_table
[
vreg
];
symbol_table
[
vreg
]
=
val
;
// Clear out the is_defined name since it is now definitely defined:
assert
(
!
isIsDefinedName
(
name
.
s
()));
InternedString
defined_name
=
getIsDefinedName
(
name
);
bool
maybe_was_undefined
=
_popFake
(
defined_name
,
true
);
bool
maybe_was_undefined
=
popDefinedVar
(
vreg
,
true
);
if
(
vst
==
ScopeInfo
::
VarScopeType
::
CLOSURE
)
{
size_t
offset
=
irstate
->
getScopeInfo
()
->
getClosureOffset
(
name
);
...
...
@@ -2205,15 +2198,14 @@ private:
// SyntaxError: can not delete variable 'x' referenced in nested scope
assert
(
vst
==
ScopeInfo
::
VarScopeType
::
FAST
);
CompilerVariable
*
prev
=
symbol_table
.
count
(
target
->
id
)
?
symbol_table
[
target
->
id
]
:
NULL
;
CompilerVariable
*
prev
=
symbol_table
[
target
->
vreg
]
;
InternedString
defined_name
=
getIsDefinedName
(
target
->
id
);
ConcreteCompilerVariable
*
is_defined_var
=
static_cast
<
ConcreteCompilerVariable
*>
(
_getFake
(
defined_name
,
true
));
llvm
::
Value
*
is_defined_var
=
getDefinedVar
(
target
->
vreg
,
true
);
_setVRegIfUserVisible
(
target
->
vreg
,
[]()
{
return
getNullPtr
(
g
.
llvm_value_type_ptr
);
},
prev
,
(
bool
)
is_defined_var
);
if
(
symbol_table
.
count
(
target
->
id
)
==
0
)
{
if
(
!
symbol_table
[
target
->
vreg
]
)
{
llvm
::
CallSite
call
=
emitter
.
createCall
(
unw_info
,
g
.
funcs
.
assertNameDefined
,
{
getConstantInt
(
0
,
g
.
i1
),
embedConstantPtr
(
target
->
id
.
c_str
(),
g
.
i8_ptr
),
...
...
@@ -2226,13 +2218,13 @@ private:
if
(
is_defined_var
)
{
emitter
.
createCall
(
unw_info
,
g
.
funcs
.
assertNameDefined
,
{
i1FromBool
(
emitter
,
is_defined_var
),
embedConstantPtr
(
target
->
id
.
c_str
(),
g
.
i8_ptr
),
{
i1From
LLVM
Bool
(
emitter
,
is_defined_var
),
embedConstantPtr
(
target
->
id
.
c_str
(),
g
.
i8_ptr
),
emitter
.
setType
(
embedRelocatablePtr
(
NameError
,
g
.
llvm_class_type_ptr
),
RefType
::
BORROWED
),
getConstantInt
(
true
/*local_error_msg*/
,
g
.
i1
)
});
_popFake
(
defined_name
);
popDefinedVar
(
target
->
vreg
);
}
symbol_table
.
erase
(
target
->
id
)
;
symbol_table
[
target
->
vreg
]
=
NULL
;
}
void
doExec
(
AST_Exec
*
node
,
const
UnwindInfo
&
unw_info
)
{
...
...
@@ -2664,7 +2656,7 @@ private:
_doSet
(
name
,
var
,
unw_info
);
}
bool
allowableFakeEndingSymbol
(
InternedString
name
)
{
return
isIsDefinedName
(
name
.
s
());
}
//
bool allowableFakeEndingSymbol(InternedString name) { return isIsDefinedName(name.s()); }
void
endBlock
(
State
new_state
)
{
assert
(
state
==
RUNNING
);
...
...
@@ -2675,40 +2667,37 @@ private:
auto
cfg
=
source
->
cfg
;
ScopeInfo
*
scope_info
=
irstate
->
getScopeInfo
();
// Sort the names here to make the process deterministic:
std
::
map
<
InternedString
,
CompilerVariable
*>
sorted_symbol_table
(
symbol_table
.
begin
(),
symbol_table
.
end
());
for
(
const
auto
&
p
:
sorted_symbol_table
)
{
assert
(
p
.
first
.
s
()
!=
FRAME_INFO_PTR_NAME
);
assert
(
p
.
second
->
getType
()
->
isUsable
());
if
(
allowableFakeEndingSymbol
(
p
.
first
))
int
num_vregs
=
symbol_table
.
numVregs
();
for
(
int
vreg
=
0
;
vreg
<
num_vregs
;
vreg
++
)
{
if
(
!
symbol_table
[
vreg
])
continue
;
// ASSERT(p.first[0] != '!' || isIsDefinedName(p.first), "left a fake variable in the real
// symbol table? '%s'", p.first.c_str
());
auto
val
=
symbol_table
[
vreg
];
assert
(
val
->
getType
()
->
isUsable
());
int
vreg
=
cfg
->
getVRegInfo
().
getVReg
(
p
.
first
);
if
(
!
irstate
->
getLiveness
()
->
isLiveAtEnd
(
vreg
,
myblock
))
{
symbol_table
.
erase
(
getIsDefinedName
(
p
.
first
)
);
symbol_table
.
erase
(
p
.
first
)
;
popDefinedVar
(
vreg
,
true
);
symbol_table
[
vreg
]
=
NULL
;
}
else
if
(
irstate
->
getPhis
()
->
isRequiredAfter
(
vreg
,
myblock
))
{
assert
(
scope_info
->
getScopeTypeOfName
(
p
.
first
)
!=
ScopeInfo
::
VarScopeType
::
GLOBAL
);
assert
(
scope_info
->
getScopeTypeOfName
(
cfg
->
getVRegInfo
().
getName
(
vreg
))
!=
ScopeInfo
::
VarScopeType
::
GLOBAL
);
ConcreteCompilerType
*
phi_type
=
types
->
getTypeAtBlockEnd
(
vreg
,
myblock
);
assert
(
phi_type
->
isUsable
());
// printf("Converting %s from %s to %s\n", p.first.c_str(),
// p.second->getType()->debugName().c_str(), phi_type->debugName().c_str());
// printf("have to convert %s from %s to %s\n", p.first.c_str(),
// p.second->getType()->debugName().c_str(), phi_type->debugName().c_str());
ConcreteCompilerVariable
*
v
=
p
.
second
->
makeConverted
(
emitter
,
phi_type
);
symbol_table
[
p
.
first
]
=
v
;
ConcreteCompilerVariable
*
v
=
val
->
makeConverted
(
emitter
,
phi_type
);
symbol_table
[
vreg
]
=
v
;
}
else
{
if
(
myblock
->
successors
.
size
())
{
// TODO getTypeAtBlockEnd will automatically convert up to the concrete type, which we don't
// want
// here, but this is just for debugging so I guess let it happen for now:
ConcreteCompilerType
*
ending_type
=
types
->
getTypeAtBlockEnd
(
vreg
,
myblock
);
RELEASE_ASSERT
(
p
.
second
->
canConvertTo
(
ending_type
),
"%s is supposed to be %s, but somehow is %s"
,
p
.
first
.
c_str
(),
ending_type
->
debugName
().
c_str
(),
p
.
second
->
getType
()
->
debugName
().
c_str
());
RELEASE_ASSERT
(
val
->
canConvertTo
(
ending_type
),
"%s is supposed to be %s, but somehow is %s"
,
cfg
->
getVRegInfo
().
getName
(
vreg
)
.
c_str
(),
ending_type
->
debugName
().
c_str
(),
val
->
getType
()
->
debugName
().
c_str
());
}
}
}
...
...
@@ -2718,22 +2707,19 @@ private:
if
(
VERBOSITY
()
>=
3
)
printf
(
"phi will be required for %s
\n
"
,
name
.
c_str
());
assert
(
scope_info
->
getScopeTypeOfName
(
name
)
!=
ScopeInfo
::
VarScopeType
::
GLOBAL
);
CompilerVariable
*&
cur
=
symbol_table
[
name
];
InternedString
defined_name
=
getIsDefinedName
(
name
);
CompilerVariable
*&
cur
=
symbol_table
[
vreg
];
if
(
cur
!=
NULL
)
{
// printf("defined on this path; ");
ConcreteCompilerVariable
*
is_defined
=
static_cast
<
ConcreteCompilerVariable
*>
(
_popFake
(
defined_name
,
true
));
llvm
::
Value
*
is_defined
=
popDefinedVar
(
vreg
,
true
);
if
(
irstate
->
getPhis
()
->
isPotentiallyUndefinedAfter
(
vreg
,
myblock
))
{
// printf("is potentially undefined later, so marking it defined\n");
if
(
is_defined
)
{
_setFake
(
defined_name
,
is_defined
);
setDefinedVar
(
vreg
,
is_defined
);
}
else
{
_setFake
(
defined_name
,
make
Bool
(
1
));
setDefinedVar
(
vreg
,
makeLLVM
Bool
(
1
));
}
}
else
{
// printf("is defined in all later paths, so not marking\n");
...
...
@@ -2755,7 +2741,7 @@ private:
}
cur
=
new
ConcreteCompilerVariable
(
phi_type
,
v
);
_setFake
(
defined_name
,
make
Bool
(
0
));
setDefinedVar
(
vreg
,
makeLLVM
Bool
(
0
));
}
}
...
...
@@ -2766,12 +2752,18 @@ public:
void
addFrameStackmapArgs
(
PatchpointInfo
*
pp
,
std
::
vector
<
llvm
::
Value
*>&
stackmap_args
)
override
{
int
initial_args
=
stackmap_args
.
size
();
auto
&&
vregs
=
irstate
->
getSourceInfo
()
->
cfg
->
getVRegInfo
();
// For deopts we need to add the compiler created names to the stackmap
if
(
ENABLE_FRAME_INTROSPECTION
&&
pp
->
isDeopt
())
{
// TODO: don't need to use a sorted symbol table if we're explicitly recording the names!
// nice for debugging though.
typedef
std
::
pair
<
InternedString
,
CompilerVariable
*>
Entry
;
std
::
vector
<
Entry
>
sorted_symbol_table
(
symbol_table
.
begin
(),
symbol_table
.
end
());
std
::
vector
<
Entry
>
sorted_symbol_table
;
for
(
auto
&&
p
:
symbol_table
)
{
if
(
p
.
second
)
sorted_symbol_table
.
push_back
(
Entry
(
vregs
.
getName
(
p
.
first
),
p
.
second
));
}
// TODO: at some point it would be nice to pass these separately
auto
source
=
irstate
->
getSourceInfo
();
...
...
@@ -2814,7 +2806,8 @@ public:
SourceInfo
*
source
=
irstate
->
getSourceInfo
();
SymbolTable
*
st
=
new
SymbolTable
(
symbol_table
);
ConcreteSymbolTable
*
phi_st
=
new
ConcreteSymbolTable
();
ConcreteSymbolTable
*
phi_st
=
new
ConcreteSymbolTable
(
symbol_table
.
numVregs
());
DefinednessTable
*
def_vars
=
new
DefinednessTable
(
definedness_vars
);
auto
cfg
=
source
->
cfg
;
auto
&&
vreg_info
=
cfg
->
getVRegInfo
();
...
...
@@ -2823,17 +2816,19 @@ public:
assert
(
incoming_exc_state
.
empty
());
for
(
auto
&&
p
:
symbol_table
)
{
ASSERT
(
p
.
second
->
getType
()
->
isUsable
(),
"%s"
,
p
.
first
.
c_str
());
if
(
!
p
.
second
)
continue
;
ASSERT
(
p
.
second
->
getType
()
->
isUsable
(),
"%d"
,
p
.
first
);
}
if
(
myblock
->
successors
.
size
()
==
0
)
{
st
->
clear
();
symbol_table
.
clear
();
return
EndingState
(
st
,
phi_st
,
curblock
,
outgoing_exc_state
);
return
EndingState
(
st
,
phi_st
,
def_vars
,
curblock
,
outgoing_exc_state
);
}
else
if
(
myblock
->
successors
.
size
()
>
1
)
{
// Since there are no critical edges, all successors come directly from this node,
// so there won't be any required phis.
return
EndingState
(
st
,
phi_st
,
curblock
,
outgoing_exc_state
);
return
EndingState
(
st
,
phi_st
,
def_vars
,
curblock
,
outgoing_exc_state
);
}
assert
(
myblock
->
successors
.
size
()
==
1
);
// other cases should have been handled
...
...
@@ -2843,39 +2838,29 @@ public:
// If the next block has a single predecessor, don't have to
// emit any phis.
// Should probably not emit no-op jumps like this though.
return
EndingState
(
st
,
phi_st
,
curblock
,
outgoing_exc_state
);
return
EndingState
(
st
,
phi_st
,
def_vars
,
curblock
,
outgoing_exc_state
);
}
// We have one successor, but they have more than one predecessor.
// We're going to sort out which symbols need to go in phi_st and which belong inst.
for
(
SymbolTable
::
iterator
it
=
st
->
begin
();
it
!=
st
->
end
();)
{
if
(
allowableFakeEndingSymbol
(
it
->
first
)
||
irstate
->
getPhis
()
->
isRequiredAfter
(
cfg
->
getVRegInfo
().
getVReg
(
it
->
first
),
myblock
))
{
// this conversion should have already happened... should refactor this.
ConcreteCompilerType
*
ending_type
;
if
(
isIsDefinedName
(
it
->
first
.
s
()))
{
assert
(
it
->
second
->
getType
()
==
BOOL
);
ending_type
=
BOOL
;
}
else
if
(
it
->
first
.
s
()
==
PASSED_CLOSURE_NAME
)
{
RELEASE_ASSERT
(
0
,
""
);
}
else
if
(
it
->
first
.
s
()
==
CREATED_CLOSURE_NAME
)
{
RELEASE_ASSERT
(
0
,
""
);
}
else
if
(
it
->
first
.
s
()
==
PASSED_GENERATOR_NAME
)
{
RELEASE_ASSERT
(
0
,
""
);
}
else
if
(
it
->
first
.
s
()
==
FRAME_INFO_PTR_NAME
)
{
RELEASE_ASSERT
(
0
,
""
);
}
else
{
ending_type
=
types
->
getTypeAtBlockEnd
(
vreg_info
.
getVReg
(
it
->
first
),
myblock
);
}
for
(
auto
&&
p
:
*
st
)
{
if
(
!
p
.
second
)
continue
;
if
(
/*allowableFakeEndingSymbol(it->first)
||*/
irstate
->
getPhis
()
->
isRequiredAfter
(
p
.
first
,
myblock
))
{
ConcreteCompilerType
*
ending_type
=
types
->
getTypeAtBlockEnd
(
p
.
first
,
myblock
);
assert
(
ending_type
->
isUsable
());
//(*phi_st)[it->first] = it->second->makeConverted(emitter, it->second->getConcreteType());
(
*
phi_st
)[
it
->
first
]
=
it
->
second
->
makeConverted
(
emitter
,
ending_type
);
it
=
st
->
erase
(
it
);
}
else
{
++
it
;
//(*phi_st)[p->first] = p->second->makeConverted(emp, p->second->getConcreteType());
(
*
phi_st
)[
p
.
first
]
=
p
.
second
->
makeConverted
(
emitter
,
ending_type
);
(
*
st
)[
p
.
first
]
=
NULL
;
}
}
return
EndingState
(
st
,
phi_st
,
curblock
,
outgoing_exc_state
);
return
EndingState
(
st
,
phi_st
,
def_vars
,
curblock
,
outgoing_exc_state
);
}
void
giveDefinednessVar
(
int
vreg
,
llvm
::
Value
*
val
)
override
{
// printf("Giving definedness var %s\n", irstate->getSourceInfo()->cfg->getVRegInfo().getName(vreg).c_str());
setDefinedVar
(
vreg
,
val
);
}
void
giveLocalSymbol
(
InternedString
name
,
CompilerVariable
*
var
)
override
{
...
...
@@ -2884,12 +2869,18 @@ public:
assert
(
name
.
s
()
!=
CREATED_CLOSURE_NAME
);
assert
(
name
.
s
()
!=
PASSED_CLOSURE_NAME
);
assert
(
name
.
s
()
!=
PASSED_GENERATOR_NAME
);
assert
(
name
.
s
()[
0
]
!=
'!'
);
ASSERT
(
irstate
->
getScopeInfo
()
->
getScopeTypeOfName
(
name
)
!=
ScopeInfo
::
VarScopeType
::
GLOBAL
,
"%s"
,
name
.
c_str
());
ASSERT
(
var
->
getType
()
->
isUsable
(),
"%s"
,
name
.
c_str
());
int
vreg
=
irstate
->
getSourceInfo
()
->
cfg
->
getVRegInfo
().
getVReg
(
name
);
giveLocalSymbol
(
vreg
,
var
);
}
void
giveLocalSymbol
(
int
vreg
,
CompilerVariable
*
var
)
override
{
assert
(
var
->
getType
()
->
isUsable
());
CompilerVariable
*&
cur
=
symbol_table
[
name
];
CompilerVariable
*&
cur
=
symbol_table
[
vreg
];
assert
(
cur
==
NULL
);
cur
=
var
;
}
...
...
@@ -2898,9 +2889,11 @@ public:
assert
(
st
);
DupCache
cache
;
for
(
SymbolTable
::
iterator
it
=
st
->
begin
();
it
!=
st
->
end
();
++
it
)
{
if
(
!
it
.
second
())
continue
;
// printf("Copying in %s, a %s\n", it->first.c_str(), it->second->getType()->debugName().c_str());
symbol_table
[
it
->
first
]
=
it
->
second
->
dup
(
cache
);
assert
(
symbol_table
[
it
->
first
]
->
getType
()
->
isUsable
());
symbol_table
[
it
.
first
()]
=
it
.
second
()
->
dup
(
cache
);
assert
(
symbol_table
[
it
.
first
()
]
->
getType
()
->
isUsable
());
}
}
...
...
@@ -3028,10 +3021,11 @@ public:
}
void
run
(
const
CFGBlock
*
block
)
override
{
auto
&&
vregs
=
block
->
cfg
->
getVRegInfo
();
if
(
VERBOSITY
(
"irgenerator"
)
>=
2
)
{
// print starting symbol table
printf
(
" %d init:"
,
block
->
idx
);
for
(
auto
it
=
symbol_table
.
begin
();
it
!=
symbol_table
.
end
();
++
it
)
printf
(
" %s"
,
it
->
first
.
c_str
());
printf
(
" %s"
,
vregs
.
getName
(
it
.
first
())
.
c_str
());
printf
(
"
\n
"
);
}
for
(
int
i
=
0
;
i
<
block
->
body
.
size
();
i
++
)
{
...
...
@@ -3050,7 +3044,7 @@ public:
if
(
VERBOSITY
(
"irgenerator"
)
>=
2
)
{
// print ending symbol table
printf
(
" %d fini:"
,
block
->
idx
);
for
(
auto
it
=
symbol_table
.
begin
();
it
!=
symbol_table
.
end
();
++
it
)
printf
(
" %s"
,
it
->
first
.
c_str
());
printf
(
" %s"
,
vregs
.
getName
(
it
.
first
())
.
c_str
());
printf
(
"
\n
"
);
}
}
...
...
src/codegen/irgen/irgenerator.h
View file @
0999d34a
...
...
@@ -21,6 +21,7 @@
#include "llvm/ADT/iterator_range.h"
#include "llvm/IR/Instructions.h"
#include "analysis/function_analysis.h"
#include "core/stringpool.h"
#include "core/types.h"
...
...
@@ -43,9 +44,10 @@ class TypeAnalysis;
class
RefcountTracker
;
class
UnwindInfo
;
typedef
std
::
unordered_map
<
InternedString
,
CompilerVariable
*>
SymbolTable
;
typedef
std
::
map
<
InternedString
,
CompilerVariable
*>
SortedSymbolTable
;
typedef
std
::
unordered_map
<
InternedString
,
ConcreteCompilerVariable
*>
ConcreteSymbolTable
;
typedef
VRegMap
<
CompilerVariable
*>
SymbolTable
;
typedef
VRegMap
<
llvm
::
Value
*>
DefinednessTable
;
typedef
VRegMap
<
CompilerVariable
*>
SortedSymbolTable
;
typedef
VRegMap
<
ConcreteCompilerVariable
*>
ConcreteSymbolTable
;
extern
const
std
::
string
CREATED_CLOSURE_NAME
;
extern
const
std
::
string
PASSED_CLOSURE_NAME
;
...
...
@@ -153,15 +155,20 @@ public:
// symbol_table records which Python variables are bound to what CompilerVariables at the end of this block.
// phi_symbol_table records the ones that will need to be `phi'd.
// both only record non-globals.
// TODO: switch these to unique_ptr's
SymbolTable
*
symbol_table
;
ConcreteSymbolTable
*
phi_symbol_table
;
DefinednessTable
*
definedness_vars
;
llvm
::
BasicBlock
*
ending_block
;
llvm
::
SmallVector
<
ExceptionState
,
2
>
exception_state
;
EndingState
(
SymbolTable
*
symbol_table
,
ConcreteSymbolTable
*
phi_symbol_table
,
llvm
::
BasicBlock
*
ending_block
,
EndingState
(
SymbolTable
*
symbol_table
,
ConcreteSymbolTable
*
phi_symbol_table
,
DefinednessTable
*
definedness_vars
,
llvm
::
BasicBlock
*
ending_block
,
llvm
::
ArrayRef
<
ExceptionState
>
exception_state
)
:
symbol_table
(
symbol_table
),
phi_symbol_table
(
phi_symbol_table
),
definedness_vars
(
definedness_vars
),
ending_block
(
ending_block
),
exception_state
(
exception_state
.
begin
(),
exception_state
.
end
())
{}
};
...
...
@@ -172,6 +179,8 @@ public:
=
0
;
virtual
void
giveLocalSymbol
(
InternedString
name
,
CompilerVariable
*
var
)
=
0
;
virtual
void
giveLocalSymbol
(
int
vreg
,
CompilerVariable
*
var
)
=
0
;
virtual
void
giveDefinednessVar
(
int
vreg
,
llvm
::
Value
*
val
)
=
0
;
virtual
void
copySymbolsFrom
(
SymbolTable
*
st
)
=
0
;
virtual
void
run
(
const
CFGBlock
*
block
)
=
0
;
// primary entry point
virtual
EndingState
getEndingSymbolTable
()
=
0
;
...
...
src/core/util.h
View file @
0999d34a
...
...
@@ -95,19 +95,19 @@ void removeDirectoryIfExists(const std::string& path);
// Checks that lhs and rhs, which are iterables of InternedStrings, have the
// same set of names in them.
template
<
class
T1
,
class
T2
>
bool
sameKeyset
(
T1
*
lhs
,
T2
*
rhs
)
{
std
::
vector
<
InternedString
>
lv
,
rv
;
for
(
typename
T1
::
iterator
it
=
lhs
->
begin
();
it
!=
lhs
->
end
();
it
++
)
{
lv
.
push_back
(
it
->
first
);
std
::
vector
<
int
>
lv
,
rv
;
for
(
typename
T1
::
iterator
it
=
lhs
->
begin
();
it
!=
lhs
->
end
();
++
it
)
{
lv
.
push_back
(
(
*
it
).
first
);
}
for
(
typename
T2
::
iterator
it
=
rhs
->
begin
();
it
!=
rhs
->
end
();
it
++
)
{
rv
.
push_back
(
it
->
first
);
for
(
typename
T2
::
iterator
it
=
rhs
->
begin
();
it
!=
rhs
->
end
();
++
it
)
{
rv
.
push_back
(
(
*
it
).
first
);
}
std
::
sort
(
lv
.
begin
(),
lv
.
end
());
std
::
sort
(
rv
.
begin
(),
rv
.
end
());
std
::
vector
<
InternedString
>
lextra
(
lv
.
size
());
std
::
vector
<
InternedString
>::
iterator
diffend
std
::
vector
<
int
>
lextra
(
lv
.
size
());
std
::
vector
<
int
>::
iterator
diffend
=
std
::
set_difference
(
lv
.
begin
(),
lv
.
end
(),
rv
.
begin
(),
rv
.
end
(),
lextra
.
begin
());
lextra
.
resize
(
diffend
-
lextra
.
begin
());
...
...
@@ -115,19 +115,19 @@ template <class T1, class T2> bool sameKeyset(T1* lhs, T2* rhs) {
if
(
lextra
.
size
())
{
printf
(
"Only in lhs:
\n
"
);
for
(
int
i
=
0
;
i
<
lextra
.
size
();
i
++
)
{
printf
(
"%
s
\n
"
,
lextra
[
i
].
c_str
()
);
printf
(
"%
d
\n
"
,
lextra
[
i
]
);
}
good
=
false
;
}
std
::
vector
<
InternedString
>
rextra
(
rv
.
size
());
std
::
vector
<
int
>
rextra
(
rv
.
size
());
diffend
=
std
::
set_difference
(
rv
.
begin
(),
rv
.
end
(),
lv
.
begin
(),
lv
.
end
(),
rextra
.
begin
());
rextra
.
resize
(
diffend
-
rextra
.
begin
());
if
(
rextra
.
size
())
{
printf
(
"Only in rhs:
\n
"
);
for
(
int
i
=
0
;
i
<
rextra
.
size
();
i
++
)
{
printf
(
"%
s
\n
"
,
rextra
[
i
].
c_str
()
);
printf
(
"%
d
\n
"
,
rextra
[
i
]
);
}
good
=
false
;
}
...
...
test/tests/undefined_passing.py
0 → 100644
View file @
0999d34a
# I think we have some other similar tests to this, but it's hard to find them.
def
f
(
x
):
if
x
:
y
=
1
if
''
:
pass
print
y
for
i
in
xrange
(
10000
):
f
(
1
)
try
:
f
(
0
)
assert
0
except
UnboundLocalError
:
pass
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