@@ -10,6 +10,8 @@ using namespace libscratchcpp;
1010static const std::unordered_set<LLVMInstruction::Type>
1111 BEGIN_LOOP_INSTRUCTIONS = { LLVMInstruction::Type::BeginRepeatLoop, LLVMInstruction::Type::BeginWhileLoop, LLVMInstruction::Type::BeginRepeatUntilLoop };
1212
13+ static const std::unordered_set<LLVMInstruction::Type> LIST_WRITE_INSTRUCTIONS = { LLVMInstruction::Type::AppendToList, LLVMInstruction::Type::InsertToList, LLVMInstruction::Type::ListReplace };
14+
1315void LLVMCodeAnalyzer::analyzeScript (const LLVMInstructionList &script) const
1416{
1517 std::unordered_set<LLVMInstruction *> typeAssignedInstructions;
@@ -28,6 +30,7 @@ void LLVMCodeAnalyzer::analyzeScript(const LLVMInstructionList &script) const
2830 auto branch = std::make_unique<Branch>();
2931 branch->start = ins;
3032 branch->variableTypes = currentBranch->variableTypes ;
33+ branch->listTypes = currentBranch->listTypes ;
3134 currentBranch = branch.get ();
3235 branches.push_back (std::move (branch));
3336 } else if (isElse (ins)) {
@@ -39,6 +42,7 @@ void LLVMCodeAnalyzer::analyzeScript(const LLVMInstructionList &script) const
3942 currentBranch = currentBranch->elseBranch .get ();
4043 currentBranch->start = ins;
4144 currentBranch->variableTypes = previousBranch->variableTypes ;
45+ currentBranch->listTypes = previousBranch->listTypes ;
4246 } else if (isIfEnd (ins) || isLoopEnd (ins)) {
4347 if (isLoopEnd (ins) && currentBranch->typeChanges ) {
4448 // Next iteration
@@ -52,11 +56,16 @@ void LLVMCodeAnalyzer::analyzeScript(const LLVMInstructionList &script) const
5256 assert (primaryBranch);
5357
5458 if (primaryBranch && primaryBranch->elseBranch ) {
55- // The previous types can be ignored in if/else statements
56- overrideBranchTypes (primaryBranch, previousBranch);
57- mergeBranchTypes (primaryBranch->elseBranch .get (), previousBranch);
58- } else
59- mergeBranchTypes (primaryBranch, previousBranch);
59+ // The previous variable types can be ignored in if/else statements
60+ overrideVariableTypes (primaryBranch, previousBranch);
61+ mergeListTypes (primaryBranch, previousBranch);
62+
63+ mergeVariableTypes (primaryBranch->elseBranch .get (), previousBranch);
64+ mergeListTypes (primaryBranch->elseBranch .get (), previousBranch);
65+ } else {
66+ mergeVariableTypes (primaryBranch, previousBranch);
67+ mergeListTypes (primaryBranch, previousBranch);
68+ }
6069
6170 // Remove the branch
6271 branches.pop_back ();
@@ -72,6 +81,24 @@ void LLVMCodeAnalyzer::analyzeScript(const LLVMInstructionList &script) const
7281 // Type before the read
7382 updateVariableType (currentBranch, ins, typeAssignedInstructions, false );
7483
84+ // Store the type in the return register
85+ ins->functionReturnReg ->setType (ins->targetType );
86+ } else if (isListClear (ins)) {
87+ // Type before the read
88+ updateListType (currentBranch, ins, typeAssignedInstructions, true );
89+
90+ // Clear the list type
91+ currentBranch->listTypes [ins->targetList ] = Compiler::StaticType::Void;
92+ } else if (isListWrite (ins)) {
93+ // Type before the write
94+ updateListType (currentBranch, ins, typeAssignedInstructions, true );
95+
96+ // Type after the write
97+ currentBranch->listTypes [ins->targetList ] |= writeType (ins);
98+ } else if (isListRead (ins)) {
99+ // Type before the read
100+ updateListType (currentBranch, ins, typeAssignedInstructions, false );
101+
75102 // Store the type in the return register
76103 ins->functionReturnReg ->setType (ins->targetType );
77104 }
@@ -110,9 +137,37 @@ void LLVMCodeAnalyzer::updateVariableType(Branch *branch, LLVMInstruction *ins,
110137 }
111138}
112139
113- void LLVMCodeAnalyzer::mergeBranchTypes (Branch *branch, Branch *previousBranch) const
140+ void LLVMCodeAnalyzer::updateListType (Branch *branch, LLVMInstruction *ins, std::unordered_set<LLVMInstruction *> &typeAssignedInstructions, bool isWrite) const
141+ {
142+ auto it = branch->listTypes .find (ins->targetList );
143+
144+ if (it == branch->listTypes .cend ()) {
145+ if (typeAssignedInstructions.find (ins) == typeAssignedInstructions.cend ()) {
146+ if (isWrite)
147+ branch->typeChanges = true ;
148+
149+ typeAssignedInstructions.insert (ins);
150+ ins->targetType = Compiler::StaticType::Unknown;
151+ branch->listTypes [ins->targetList ] = ins->targetType ;
152+ }
153+ } else {
154+ if (typeAssignedInstructions.find (ins) == typeAssignedInstructions.cend ()) {
155+ if (isWrite)
156+ branch->typeChanges = true ;
157+
158+ ins->targetType = it->second ;
159+ typeAssignedInstructions.insert (ins);
160+ } else {
161+ if (isWrite && ((ins->targetType | it->second ) != ins->targetType ))
162+ branch->typeChanges = true ;
163+
164+ ins->targetType |= it->second ;
165+ }
166+ }
167+ }
168+
169+ void LLVMCodeAnalyzer::mergeVariableTypes (Branch *branch, Branch *previousBranch) const
114170{
115- // Variables
116171 for (const auto &[var, type] : branch->variableTypes ) {
117172 auto it = previousBranch->variableTypes .find (var);
118173
@@ -123,13 +178,24 @@ void LLVMCodeAnalyzer::mergeBranchTypes(Branch *branch, Branch *previousBranch)
123178 }
124179}
125180
126- void LLVMCodeAnalyzer::overrideBranchTypes (Branch *branch, Branch *previousBranch) const
181+ void LLVMCodeAnalyzer::overrideVariableTypes (Branch *branch, Branch *previousBranch) const
127182{
128- // Variables
129183 for (const auto &[var, type] : branch->variableTypes )
130184 previousBranch->variableTypes [var] = type;
131185}
132186
187+ void LLVMCodeAnalyzer::mergeListTypes (Branch *branch, Branch *previousBranch) const
188+ {
189+ for (const auto &[list, type] : branch->listTypes ) {
190+ auto it = previousBranch->listTypes .find (list);
191+
192+ if (it == previousBranch->listTypes .cend ())
193+ previousBranch->listTypes [list] = type;
194+ else
195+ it->second |= type;
196+ }
197+ }
198+
133199bool LLVMCodeAnalyzer::isLoopStart (const LLVMInstruction *ins) const
134200{
135201 return (BEGIN_LOOP_INSTRUCTIONS.find (ins->type ) != BEGIN_LOOP_INSTRUCTIONS.cend ());
@@ -165,6 +231,21 @@ bool LLVMCodeAnalyzer::isVariableWrite(const LLVMInstruction *ins) const
165231 return (ins->type == LLVMInstruction::Type::WriteVariable);
166232}
167233
234+ bool LLVMCodeAnalyzer::isListRead (const LLVMInstruction *ins) const
235+ {
236+ return (ins->type == LLVMInstruction::Type::GetListItem);
237+ }
238+
239+ bool LLVMCodeAnalyzer::isListWrite (const LLVMInstruction *ins) const
240+ {
241+ return (LIST_WRITE_INSTRUCTIONS.find (ins->type ) != LIST_WRITE_INSTRUCTIONS.cend ());
242+ }
243+
244+ bool LLVMCodeAnalyzer::isListClear (const LLVMInstruction *ins) const
245+ {
246+ return (ins->type == LLVMInstruction::Type::ClearList);
247+ }
248+
168249Compiler::StaticType LLVMCodeAnalyzer::writeType (LLVMInstruction *ins) const
169250{
170251 assert (ins);
@@ -173,9 +254,8 @@ Compiler::StaticType LLVMCodeAnalyzer::writeType(LLVMInstruction *ins) const
173254 const LLVMRegister *argReg = arg.second ;
174255
175256 if (argReg->instruction ) {
176- // TODO: Handle list item
177- if (isVariableRead (argReg->instruction .get ())) {
178- // Store the variable type in the value argument
257+ if (isVariableRead (argReg->instruction .get ()) || isListRead (argReg->instruction .get ())) {
258+ // Store the variable/list type in the value argument
179259 arg.first = argReg->instruction ->functionReturnReg ->type ();
180260 }
181261 }
0 commit comments