【Bp2Lua】常量折叠和变量折叠
谈一下编译器折叠优化算法
动机
变量折叠是 bp2lua 早期确定的两个技术卡点之一
bp2lua 做尽可能保守和必要的优化,提升生成代码的可读性,方便在生成代码上进行二次开发
常量折叠
常量折叠 - 维基百科,自由的百科全书
基本上大部分编译器,包括 Lua,都会进行编译时的常量折叠,算法核心是在 AST 上算常量表达式的可达性
变量折叠
变量折叠是我在开发 bp2lua 时临时想的一个算法,灵感基础是常量折叠+Pycharm的 inline refactor
在 a
上进行 inline refactor,点击 OK
a
被干掉
现在 a
被引用 2 次,注意 foo 调用有副作用,修改了状态
这时干掉 a
,就是错的
案例分析:S_LootItem_RPC
蓝图
-- before var fold
function M:S_LootItem_RPC(ItemRowName, MyInventory)
K2Node_CustomEvent_ItemRowName = ItemRowName
K2Node_CustomEvent_MyInventory = MyInventory
_getInventoryQuantity_Quantity = self.AC_Inventory:getInventoryQuantity(K2Node_CustomEvent_ItemRowName)
_Greater_IntInt_ReturnValue = (_getInventoryQuantity_Quantity > 0)
if _Greater_IntInt_ReturnValue then
self.AC_Inventory:RemoveInventory(K2Node_CustomEvent_ItemRowName, _getInventoryQuantity_Quantity)
K2Node_CustomEvent_MyInventory:AddInventory(K2Node_CustomEvent_ItemRowName, _getInventoryQuantity_Quantity)
end
end
-- after var fold
function M:S_LootItem_RPC(ItemRowName, MyInventory)
local K2Node_CustomEvent_ItemRowName
local _getInventoryQuantity_Quantity
K2Node_CustomEvent_ItemRowName = ItemRowName
_getInventoryQuantity_Quantity = self.AC_Inventory:getInventoryQuantity(K2Node_CustomEvent_ItemRowName)
if _getInventoryQuantity_Quantity > 0 then
self.AC_Inventory:RemoveInventory(K2Node_CustomEvent_ItemRowName, _getInventoryQuantity_Quantity)
MyInventory:AddInventory(K2Node_CustomEvent_ItemRowName, _getInventoryQuantity_Quantity)
end
end
后续问题
前面讨论的不能折叠的原因,看起来如果函数是 const 的,就可以了,可惜脚本并没有 const 机制,蓝图搞了个 pure,也只是 meta 标记罢了,没法保证计算结果真的正确
举个例子,比如下面这个 条件表达式 是 pure 的,可以干掉整个 if 语句,但是这种优化有额外的开发成本,权衡后留空,不实现
if
UE.UKismetMathLibrary.GreaterEqual_DoubleDouble(
_GetAnimationCurrentTime_ReturnValue,
0.47999998927116394
) and (_GetAnimationCurrentTime_ReturnValue < 0.5199999809265137)
then
end