Skip to content

Commit 6412e2c

Browse files
committed
Added lua config optimizer support
1 parent 0851d89 commit 6412e2c

File tree

10 files changed

+228
-19
lines changed

10 files changed

+228
-19
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ else()
160160
"$<$<CONFIG:Release>:/GL>"
161161
"/F4194304" #Stack size
162162
"/FS"
163+
"/bigobj"
163164
)
164165

165166
target_compile_options(

sqfc.lua

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
---@diagnostic disable: lowercase-global
12
local inspect = require 'inspect' -- https://github.com/kikito/inspect.lua
23
print("Config loading")
34

@@ -95,7 +96,72 @@ compiler:AddMacro(Macro.new("MY_MACRO_CUSTOM_ARGS", {"arg1", "arg2"},
9596
end
9697
));
9798

98-
print("Preprocessed Script: \n", compiler:PreprocessFile(path.new("P:/test/test.sqf")));
99+
print("Preprocessed Script: \n", compiler:PreprocessFile(path.new("P:/test.sqf")));
100+
101+
102+
function optimizerNodeHandler(node)
103+
104+
105+
print("node meta:", inspect(getmetatable(node)))
106+
print("node:", inspect(node))
107+
print("nodef:", node.file)
108+
print("nodel:", node.line)
109+
print("nodet:", node.type)
110+
print("nodec:", node.constant)
111+
print("nodev:", node.value)
112+
113+
if node.type == InstructionType.callUnary and node:areChildrenConstant() and node.value=="params" then
114+
print("Params!")
115+
-- We are calling params script command and the array argument consists of only constants, we can safely optimize the array to a push instruction
116+
117+
function resolveMakeArray(node)
118+
print("resolve", node.type)
119+
if (node.type ~= InstructionType.makeArray) then return end
120+
121+
for i,v in ipairs(node.children) do
122+
resolveMakeArray(v)
123+
end
124+
node.value = ScriptConstantArray.new(); --dummy. Children are the contents
125+
node.type = InstructionType.push;
126+
end
127+
128+
129+
print("preresolve", #node.children, resolveMakeArray)
130+
resolveMakeArray(node.children[1])
131+
132+
--#TODO verify again that they are all push or makeArray instructions
133+
134+
node.children[1].value = ScriptConstantArray.new() --dummy. Children are the contents
135+
node.children[1].type = InstructionType.push
136+
print("Params optimized!")
137+
end
138+
139+
140+
-- We need to figure out what things we consider as constants
141+
-- Push and end statement are always constants
142+
if node.type == InstructionType.push or node.type == InstructionType.endStatement then
143+
node.constant = true
144+
end
145+
146+
147+
function isArrayConst(node)
148+
for i,v in ipairs(node.children) do
149+
if not v.constant or v.type ~= InstructionType.push then
150+
return false
151+
end
152+
end
153+
return true
154+
end
155+
156+
-- makeArray is only const if all children are makeArray or push
157+
if node.type == InstructionType.makeArray then
158+
node.constant = isArrayConst(node);
159+
end
160+
161+
end
162+
163+
local optimizer = OptimizerModuleLua.new(optimizerNodeHandler)
99164

100165

166+
compiler:CompileScriptToFile(path.new("P:/test.sqf"), path.new("P:/test.asm"), optimizer)
101167

src/luaHandler.cpp

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ namespace sol {
4545

4646
template <>
4747
struct is_automagical<std::filesystem::path> : std::false_type {};
48+
49+
template <>
50+
struct is_automagical<OptimizerModuleLua> : std::false_type {};
51+
52+
template <>
53+
struct is_automagical<OptimizerModuleBase::Node> : std::false_type {};
4854
}
4955

5056

@@ -237,10 +243,24 @@ LuaHandler::LuaHandler() {
237243

238244
auto result = comp.preprocessScript(path.generic_string(), ("\\" / pathRelative).generic_string());
239245
return result;
240-
}
246+
},
247+
248+
"CompileScriptToFile", [](ScriptCompiler& comp, const std::filesystem::path& path, const std::filesystem::path& outputFile, OptimizerModuleLua& luaOptimizer) {
249+
auto rootDir = path.root_path();
250+
auto pathRelative = path.lexically_relative(rootDir);
241251

252+
comp.compileScriptLua(path.generic_string(), ("\\" / pathRelative).generic_string(), luaOptimizer, outputFile);
253+
}
242254
);
243255

256+
lua.new_usertype<OptimizerModuleLua>(
257+
"OptimizerModuleLua", sol::no_constructor,
258+
"new", [](sol::protected_function func) {
259+
OptimizerModuleLua opt;
260+
opt.nodeHandler = func;
261+
return opt;
262+
}
263+
);
244264

245265

246266
lua.new_usertype<sqf::runtime::parser::macro>(
@@ -337,17 +357,17 @@ LuaHandler::LuaHandler() {
337357

338358
lua.new_usertype<OptimizerModuleBase::Node>(
339359
"OptimizerNode", sol::no_constructor,
340-
"type", sol::var(&OptimizerModuleBase::Node::type),
341-
"file", sol::var(&OptimizerModuleBase::Node::file),
342-
"line", sol::var(&OptimizerModuleBase::Node::line),
343-
"offset", sol::var(&OptimizerModuleBase::Node::offset),
344-
"children", sol::var(&OptimizerModuleBase::Node::children),
345-
"constant", sol::var(&OptimizerModuleBase::Node::constant),
360+
"type", &OptimizerModuleBase::Node::type,
361+
"file", &OptimizerModuleBase::Node::file,
362+
"line", &OptimizerModuleBase::Node::line,
363+
"offset", &OptimizerModuleBase::Node::offset,
364+
"children", &OptimizerModuleBase::Node::children,
365+
"constant", &OptimizerModuleBase::Node::constant,
366+
"value", &OptimizerModuleBase::Node::value,
346367
"areChildrenConstant", &OptimizerModuleBase::Node::areChildrenConstant
347368
);
348369

349-
lua.new_enum("InstructionType"
350-
"OptimizerNode", sol::no_constructor,
370+
lua.new_enum("InstructionType",
351371
"endStatement", InstructionType::endStatement,
352372
"push", InstructionType::push,
353373
"callUnary", InstructionType::callUnary,
@@ -359,6 +379,11 @@ LuaHandler::LuaHandler() {
359379
"makeArray" , InstructionType::makeArray
360380
);
361381

382+
lua.new_usertype<ScriptConstantArray>(
383+
"ScriptConstantArray", sol::default_constructor
384+
);
385+
386+
362387
lua["ASC"] = LuaASC{};
363388
}
364389

src/optimizer/optimizerModuleBase.hpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ class OptimizerModuleBase {
4848
class Node {
4949
public:
5050
Node() {}
51-
Node(Node&& mv) noexcept {
52-
type = mv.type;
53-
file = std::move(mv.file);
54-
line = mv.line;
55-
offset = mv.offset;
56-
value = std::move(mv.value);
57-
children = std::move(mv.children);
58-
}
51+
//Node(Node&& mv) noexcept {
52+
// type = mv.type;
53+
// file = std::move(mv.file);
54+
// line = mv.line;
55+
// offset = mv.offset;
56+
// value = std::move(mv.value);
57+
// children = std::move(mv.children);
58+
//}
5959

6060
InstructionType type;
6161

src/optimizer/optimizerModuleConstantFold.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,8 @@ void OptimizerModuleConstantFold::processNode(Node& node) {
313313
case InstructionType::makeArray: {
314314

315315
if (node.areChildrenConstant()) {//#TODO when converting to ASM check again if all elements are push
316+
317+
//#TODO they could also be nested arrays, so makeArray with constants in it
316318
bool allPush = std::all_of(node.children.begin(), node.children.end(), [](const Node & it)
317319
{
318320
return it.type == InstructionType::push;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include "optimizerModuleLua.hpp"
2+
#include <algorithm>
3+
#include <intrin.h>
4+
#include <sstream>
5+
#include <unordered_set>
6+
7+
constexpr auto NularPushConstNularCommand(std::string_view name) {
8+
return [name](OptimizerModuleBase::Node& node) -> void {
9+
node.type = InstructionType::push;
10+
if (!node.children.empty())
11+
__debugbreak();
12+
node.children.clear();
13+
node.constant = true;
14+
node.value = ScriptConstantNularCommand(std::string(name));
15+
};
16+
}
17+
18+
19+
20+
void OptimizerModuleLua::optimizeLua(Node& node) {
21+
auto worklist = node.bottomUpFlatten();
22+
23+
for (auto& it : worklist) {
24+
processNode(*it);
25+
}
26+
}
27+
28+
void OptimizerModuleLua::processNode(Node& node) {
29+
nodeHandler(node);
30+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#pragma once
2+
#include "optimizerModuleBase.hpp"
3+
4+
#include "sol/sol.hpp"
5+
6+
7+
8+
class OptimizerModuleLua : public virtual OptimizerModuleBase {
9+
public:
10+
void optimizeLua(Node& node);
11+
12+
sol::protected_function nodeHandler;
13+
14+
15+
private:
16+
void processNode(Node& node);
17+
};

src/scriptCompiler.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,70 @@ void ScriptCompiler::ASTToInstructions(CompiledCodeData& output, CompileTempData
553553
}
554554
}
555555

556+
CompiledCodeData ScriptCompiler::compileScriptLua(std::filesystem::path physicalPath, std::filesystem::path virtualPath, OptimizerModuleLua& optimizer, const std::filesystem::path& outputFile)
557+
{
558+
std::ifstream inputFile(physicalPath);
559+
560+
auto filesize = std::filesystem::file_size(physicalPath);
561+
if (filesize == 0) // uh. oki
562+
return CompiledCodeData();
563+
564+
std::string scriptCode;
565+
scriptCode.resize(filesize);
566+
inputFile.read(scriptCode.data(), filesize);
567+
568+
if (
569+
static_cast<unsigned char>(scriptCode[0]) == 0xef &&
570+
static_cast<unsigned char>(scriptCode[1]) == 0xbb &&
571+
static_cast<unsigned char>(scriptCode[2]) == 0xbf
572+
) {
573+
scriptCode.erase(0, 3);
574+
}
575+
576+
auto preprocessedScript = vm->parser_preprocessor().preprocess(*vm, scriptCode, sqf::runtime::fileio::pathinfo(physicalPath.string(), virtualPath.string()));
577+
if (!preprocessedScript) {
578+
//__debugbreak();
579+
return CompiledCodeData();
580+
}
581+
bool errorflag = false;
582+
583+
584+
sqf::parser::sqf::parser sqfParser(vmlogger);
585+
sqf::parser::sqf::bison::astnode ast;
586+
sqf::parser::sqf::tokenizer tokenizer(preprocessedScript->begin(), preprocessedScript->end(), virtualPath.string());
587+
auto errflag = !sqfParser.get_tree(*vm, tokenizer, &ast);
588+
if (errflag || ast.children.empty()) {
589+
//__debugbreak();
590+
return CompiledCodeData();
591+
}
592+
593+
//print_navigate_ast(&std::cout, ast, sqf::parse::sqf::astkindname);
594+
595+
CompiledCodeData stuff;
596+
CompileTempData temp;
597+
ScriptCodePiece mainCode;
598+
599+
600+
auto& statementsNode = ast.children[0];
601+
if (statementsNode.kind != sqf::parser::sqf::bison::astkind::STATEMENTS)
602+
__debugbreak();
603+
604+
auto node = OptimizerModuleBase::nodeFromAST(statementsNode);
605+
606+
Optimizer opt;
607+
optimizer.optimizeLua(node);
608+
609+
ASTToInstructions(stuff, temp, mainCode.code, node);
610+
mainCode.contentString = stuff.AddConstant(std::move(*preprocessedScript));
611+
stuff.codeIndex = stuff.AddConstant(std::move(mainCode));
612+
613+
std::ofstream output2(outputFile, std::ofstream::binary);
614+
ScriptSerializer::compiledToHumanReadable(stuff, output2);
615+
output2.flush();
616+
617+
return stuff;
618+
}
619+
556620
void ScriptCompiler::initIncludePaths(const std::vector<std::filesystem::path>& paths) {
557621
for (auto& includefolder : paths) {
558622

src/scriptCompiler.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <runtime/parser/preprocessor.h>
1111
#include <runtime/parser/sqf.h>
1212
#include <parser/sqf/sqf_parser.hpp>
13+
#include <src\optimizer\optimizerModuleLua.hpp>
1314
using astnode = sqf::parser::sqf::bison::astnode;
1415

1516
class ScriptCompiler {
@@ -19,6 +20,8 @@ class ScriptCompiler {
1920

2021

2122
CompiledCodeData compileScript(std::filesystem::path physicalPath, std::filesystem::path virtualPath);
23+
24+
CompiledCodeData compileScriptLua(std::filesystem::path physicalPath, std::filesystem::path virtualPath, OptimizerModuleLua& optimizer, const std::filesystem::path& outputFile);
2225
void initIncludePaths(const std::vector<std::filesystem::path>&);
2326
void addMacro(sqf::runtime::parser::macro macro);
2427
void addPragma(sqf::runtime::parser::pragma pragma);

src/scriptSerializer.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,12 @@ void blaBLaConstant(const CompiledCodeData& code, const ScriptConstant& constant
3737
break;
3838
case ConstantType::array:
3939
if (!inArray)
40-
output << "push ARRAY [\n";
40+
output << "push ARRAY [";
4141
else
4242
output << "[\n";
4343
for (auto& it : std::get<4>(constant).content)
4444
blaBLaConstant(code, it, output, true);
45+
output.seekp(-2, SEEK_CUR);
4546
output << "]\n";
4647
break;
4748
default:;

0 commit comments

Comments
 (0)