From 09a4c50cb76479ad6ce31725c7a4fe5ffe990f28 Mon Sep 17 00:00:00 2001 From: DerelictDrone Date: Thu, 9 Nov 2023 00:37:29 -0600 Subject: [PATCH 1/5] Major zap/preserve changes Zap/Preserve entire ranges, global preserve or zap via pragma, zap generic registers, and zap register variables --- lua/wire/client/hlzasm/hc_codetree.lua | 6 ++- lua/wire/client/hlzasm/hc_compiler.lua | 2 + lua/wire/client/hlzasm/hc_expression.lua | 25 ++++++++++ lua/wire/client/hlzasm/hc_output.lua | 4 +- lua/wire/client/hlzasm/hc_preprocess.lua | 48 +++++++++++++++++++ lua/wire/client/hlzasm/hc_syntax.lua | 59 +++++++++++++++++++++++- 6 files changed, 139 insertions(+), 5 deletions(-) diff --git a/lua/wire/client/hlzasm/hc_codetree.lua b/lua/wire/client/hlzasm/hc_codetree.lua index 6f28460..4875cdb 100644 --- a/lua/wire/client/hlzasm/hc_codetree.lua +++ b/lua/wire/client/hlzasm/hc_codetree.lua @@ -90,7 +90,11 @@ end -- Returns free (non-busy) register. Does not check EBP and ESP function HCOMP:FreeRegister() -- Try to find a free register - for i=1,6 do + for i=1,#self.RegisterBusy do + if not self.RegisterBusy[i] then return i end + end + + for i=1,6 do if not self.RegisterBusy[i] then return i end end diff --git a/lua/wire/client/hlzasm/hc_compiler.lua b/lua/wire/client/hlzasm/hc_compiler.lua index b1336fe..289c2a5 100644 --- a/lua/wire/client/hlzasm/hc_compiler.lua +++ b/lua/wire/client/hlzasm/hc_compiler.lua @@ -206,6 +206,8 @@ function HCOMP:StartCompile(sourceCode,fileName,writeByteCallback,writeByteCalle self.Settings.GenerateComments = true -- Generates comments in output listing -- Code generation settings + self.Settings.AutoBusyRegisters = false -- Automatically preserves or zaps a range of registers for all code leaves that are generated while this is enabled. + self.Settings.AutoBusyRegisterRanges = {} self.Settings.FixedSizeOutput = false -- Output fixed-size instructions self.Settings.SeparateDataSegment = false -- Puts all variables into separate data segment self.Settings.GenerateLibrary = false -- Generate precompiled library diff --git a/lua/wire/client/hlzasm/hc_expression.lua b/lua/wire/client/hlzasm/hc_expression.lua index a6b0773..87795b4 100644 --- a/lua/wire/client/hlzasm/hc_expression.lua +++ b/lua/wire/client/hlzasm/hc_expression.lua @@ -45,6 +45,11 @@ function HCOMP:Expression_ExplictIncDec(opcode,label,returnAfter) elseif label.Type == "Stack" then operationLeaf.Operands[1] = { Stack = label.StackOffset } elseif label.Type == "Register" then + if self.RegisterIdentities[label.Name] ~= nil then + if self.RegisterIdentities[label.Name] == -1 then + self:Error("Attempting to use register variable after zapping it") + end + end operationLeaf.Operands[1] = { Register = label.Value } end end @@ -193,6 +198,11 @@ function HCOMP:Expression_ArrayAccess(label) local TOKEN = self.TOKEN addressLeaf.Operands[2] = { Constant = {{ Type = TOKEN.IDENT, Data = label.Name, Position = self:CurrentSourcePosition() }} } operationLeaf = { MemoryPointer = addressLeaf } elseif label.Type == "Register" then + if self.RegisterIdentities[label.Name] ~= nil then + if self.RegisterIdentities[label.Name] == -1 then + self:Error("Attempting to use register variable after zapping it") + end + end addressLeaf.Opcode = "add" addressLeaf.Operands[1] = arrayOffsetLeaf addressLeaf.Operands[2] = { Register = label.Value } @@ -389,6 +399,11 @@ function HCOMP:Expression_Level3() local TOKEN = self.TOKEN end elseif label.Type == "Register" then -- Register variable + if self.RegisterIdentities[label.Name] ~= nil then + if self.RegisterIdentities[label.Name] == -1 then + self:Error("Attempting to use register variable after zapping it") + end + end operationLeaf = { Register = label.Value } end end @@ -655,6 +670,11 @@ function HCOMP:ConstantExpression_Level3() -- Pointer to stack value is not a constant return false elseif label.Type == "Register" then + if self.RegisterIdentities[label.Name] ~= nil then + if self.RegisterIdentities[label.Name] == -1 then + self:Error("Attempting to use register variable after zapping it") + end + end -- Register variable is not a constant return false elseif label.Type == "Unknown" then @@ -736,6 +756,11 @@ function HCOMP:ConstantExpression_Level3() -- Stack variables are not constant return false elseif label.Type == "Register" then + if self.RegisterIdentities[label.Name] ~= nil then + if self.RegisterIdentities[label.Name] == -1 then + self:Error("Attempting to use register variable after zapping it") + end + end -- Register variable is not a constant return false elseif label.Type == "Unknown" then diff --git a/lua/wire/client/hlzasm/hc_output.lua b/lua/wire/client/hlzasm/hc_output.lua index 0e9cbba..8b42a01 100644 --- a/lua/wire/client/hlzasm/hc_output.lua +++ b/lua/wire/client/hlzasm/hc_output.lua @@ -296,7 +296,7 @@ RegisterName[22] = "KS" RegisterName[23] = "LS" for port=0,1023 do RegisterName[1024+port] = "port"..port end for reg=0,31 do RegisterName[96+reg] = "R"..reg end - +HCOMP.RegisterName = RegisterName local SegmentRegisterName = {} SegmentRegisterName[01] = "CS" @@ -316,7 +316,7 @@ SegmentRegisterName[14] = "EDI" SegmentRegisterName[15] = "ESP" SegmentRegisterName[16] = "EBP" for reg=0,31 do SegmentRegisterName[17+reg] = "R"..reg end - +HCOMP.SegmentRegisterName = RegisterName diff --git a/lua/wire/client/hlzasm/hc_preprocess.lua b/lua/wire/client/hlzasm/hc_preprocess.lua index 9d6d951..74fd420 100644 --- a/lua/wire/client/hlzasm/hc_preprocess.lua +++ b/lua/wire/client/hlzasm/hc_preprocess.lua @@ -70,6 +70,54 @@ function HCOMP:ParsePreprocessMacro(lineText,macroPosition) CPULib.CPUName = pragmaCommand elseif pragmaName == "searchpath" then table.insert(self.SearchPaths,pragmaCommand) + elseif pragmaName == "allow" or pragmaName == "zap" then + if not self.Settings.AutoBusyRegisters then + self.Settings.AutoBusyRegisters = true + end + local Arguments = string.gmatch(macroParameters,'[^, ]+') -- comma separate the two registers + Arguments() -- drop first space + local StartRegister = trimString(Arguments()) + local EndRegister = trimString(Arguments()) + local StartInd,EndInd = -1,-1 + for ind,reg in ipairs(self.RegisterName) do + if reg == StartRegister then + StartInd = ind + end + if reg == EndRegister then + EndInd = ind + break + end + end + if StartInd ~= -1 and EndInd ~= -1 then + table.insert(self.Settings.AutoBusyRegisterRanges,{false,StartInd,EndInd}) + else + self:Error(StartRegister .. " to " .. EndRegister .. " is an invalid range!", + macroPosition.Line,macroPosition.Col,macroPosition.File) + end + elseif pragmaName == "disallow" or pragmaName == "preserve" then + if not self.Settings.AutoBusyRegisters then + self.Settings.AutoBusyRegisters = true + end + local Arguments = string.gmatch(macroParameters,'[^, ]+') -- comma separate the two registers + Arguments() -- drop first space + local StartRegister = trimString(Arguments()) + local EndRegister = trimString(Arguments()) + local StartInd,EndInd = -1,-1 + for ind,reg in ipairs(self.RegisterName) do + if reg == StartRegister then + StartInd = ind + end + if reg == EndRegister then + EndInd = ind + break + end + end + if StartInd ~= -1 and EndInd ~= -1 then + table.insert(self.Settings.AutoPreserveRegisterRanges,{StartInd,EndInd}) + else + self:Error(StartRegister .. " to " .. EndRegister .. " is an invalid range!", + macroPosition.Line,macroPosition.Col,macroPosition.File) + end end elseif macroName == "define" then -- #define local defineName = trimString(string.sub(macroParameters,1,(string.find(macroParameters," ") or 0)-1)) diff --git a/lua/wire/client/hlzasm/hc_syntax.lua b/lua/wire/client/hlzasm/hc_syntax.lua index 44ac905..a3cf5d5 100644 --- a/lua/wire/client/hlzasm/hc_syntax.lua +++ b/lua/wire/client/hlzasm/hc_syntax.lua @@ -228,6 +228,19 @@ function HCOMP:BlockStart(blockType) -- Create busy registers list self.BusyRegisters = { false,false,false,false,false,false,true,true } + self.RegisterIdentities = {} -- holds register vars with the identity as key and value as index in busyregisters + for i=#self.BusyRegisters,128 do -- Allows R0-R31 and segment registers to be used, but only if ZAPPED beforehand + self.BusyRegisters[i] = true + end + if self.Settings.AutoBusyRegisters then + for _,range in ipairs(self.Settings.AutoBusyRegisterRanges) do + for i=range[2],range[3] do + if self.RegisterName[i] ~= 'N/A' then + self.BusyRegisters[i] = range[1] + end + end + end + end end -- Create a leaf that corresponds to label for BREAK @@ -428,7 +441,7 @@ end -------------------------------------------------------------------------------- function HCOMP:DeclareRegisterVariable() if self.BlockDepth > 0 then - for reg=1,6 do + for reg=1,#self.BusyRegisters do if not self.BusyRegisters[reg] then self.BusyRegisters[reg] = true return reg @@ -614,6 +627,7 @@ function HCOMP:DefineVariable(isFunctionParam,isForwardDecl,isRegisterDecl,isStr if isRegisterDecl then label.Type = "Register" label.Value = self:DeclareRegisterVariable() + self.RegisterIdentities[varName] = label.Value if isStruct then self:Error("Cannot hold structure variables in registers - yet") end else label.Type = "Stack" @@ -675,6 +689,7 @@ function HCOMP:DefineVariable(isFunctionParam,isForwardDecl,isRegisterDecl,isStr if isRegisterDecl then label.Type = "Register" label.Value = self:DeclareRegisterVariable() + self.RegisterIdentities[varName] = label.Value else label.Type = "Variable" if isStruct and (pointerLevel > 0) then label.PointerToStruct = true end @@ -810,8 +825,48 @@ function HCOMP:Statement() local TOKEN = self.TOKEN if self:MatchToken(TOKEN.PRESERVE) or self:MatchToken(TOKEN.ZAP) then local tokenType = self.TokenType if self.BlockDepth > 0 then - while self:MatchToken(TOKEN.REGISTER) do + while self:MatchToken(TOKEN.REGISTER) or self:MatchToken(TOKEN.IDENT) do + if self.TokenType == TOKEN.IDENT then + if self.RegisterIdentities[self.TokenData] then + if tokenType == TOKEN.PRESERVE then + self:Error("Trying to preserve a register variable") + end + if self.RegisterIdentities[self.TokenData] == -1 then + self:Error("Trying to zap variable twice") + end + self.BusyRegisters[self.RegisterIdentities[self.TokenData]] = tokenType == TOKEN.PRESERVE + self.RegisterIdentities[self.TokenData] = -1 -- so we can error on attempted use after zap + if self:MatchToken(TOKEN.MINUS) then + self:Error("Cannot zap ranges using register variables") + end + else + if tokenType == TOKEN.PRESERVE then + self:Error("Trying to preserve a variable") + end + self:Error("Trying to zap a non register variable") + end + end + if self.TokenType == TOKEN.REGISTER then + local prevTokenData = self.TokenData self.BusyRegisters[self.TokenData] = tokenType == TOKEN.PRESERVE + if self:MatchToken(TOKEN.MINUS) then -- match range of registers + if self:MatchToken(TOKEN.REGISTER) or self:MatchToken(TOKEN.IDENT) then + if self.TokenType == TOKEN.IDENT then + self:Error("Cannot zap ranges using register variables") + end + if prevTokenData > self.TokenData then + self:Error("Start of register range is greater than end of register range") + end + for i=prevTokenData,self.TokenData do + if self.RegisterName[i] ~= "N/A" then + self.BusyRegisters[i] = tokenType == TOKEN.PRESERVE + end + end + else + self:Error("Invalid register range") + end + end + end self:MatchToken(TOKEN.COMMA) end self:MatchToken(TOKEN.COLON) From 5f436df3ab769677dd2ebcafe831df9eea73fda0 Mon Sep 17 00:00:00 2001 From: DerelictDrone Date: Thu, 9 Nov 2023 03:04:41 -0600 Subject: [PATCH 2/5] Delete remnant for loop for busy register checking --- lua/wire/client/hlzasm/hc_codetree.lua | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lua/wire/client/hlzasm/hc_codetree.lua b/lua/wire/client/hlzasm/hc_codetree.lua index 4875cdb..3d69fd5 100644 --- a/lua/wire/client/hlzasm/hc_codetree.lua +++ b/lua/wire/client/hlzasm/hc_codetree.lua @@ -94,10 +94,6 @@ function HCOMP:FreeRegister() if not self.RegisterBusy[i] then return i end end - for i=1,6 do - if not self.RegisterBusy[i] then return i end - end - -- Try to find a register that wasnt pushed to stack yet -- for i=1,6 do -- if not self.RegisterStackOffset[i] then From 7d3d2c5dfb218ddb1694189990d44383d28fa229 Mon Sep 17 00:00:00 2001 From: DerelictDrone Date: Thu, 9 Nov 2023 03:17:21 -0600 Subject: [PATCH 3/5] Removes not nil checks for RegisterIdentities --- lua/wire/client/hlzasm/hc_expression.lua | 30 ++++++++---------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/lua/wire/client/hlzasm/hc_expression.lua b/lua/wire/client/hlzasm/hc_expression.lua index 87795b4..ad26b2b 100644 --- a/lua/wire/client/hlzasm/hc_expression.lua +++ b/lua/wire/client/hlzasm/hc_expression.lua @@ -45,10 +45,8 @@ function HCOMP:Expression_ExplictIncDec(opcode,label,returnAfter) elseif label.Type == "Stack" then operationLeaf.Operands[1] = { Stack = label.StackOffset } elseif label.Type == "Register" then - if self.RegisterIdentities[label.Name] ~= nil then - if self.RegisterIdentities[label.Name] == -1 then - self:Error("Attempting to use register variable after zapping it") - end + if self.RegisterIdentities[label.Name] == -1 then + self:Error("Attempting to use register variable after zapping it") end operationLeaf.Operands[1] = { Register = label.Value } end @@ -198,10 +196,8 @@ function HCOMP:Expression_ArrayAccess(label) local TOKEN = self.TOKEN addressLeaf.Operands[2] = { Constant = {{ Type = TOKEN.IDENT, Data = label.Name, Position = self:CurrentSourcePosition() }} } operationLeaf = { MemoryPointer = addressLeaf } elseif label.Type == "Register" then - if self.RegisterIdentities[label.Name] ~= nil then - if self.RegisterIdentities[label.Name] == -1 then - self:Error("Attempting to use register variable after zapping it") - end + if self.RegisterIdentities[label.Name] == -1 then + self:Error("Attempting to use register variable after zapping it") end addressLeaf.Opcode = "add" addressLeaf.Operands[1] = arrayOffsetLeaf @@ -399,10 +395,8 @@ function HCOMP:Expression_Level3() local TOKEN = self.TOKEN end elseif label.Type == "Register" then -- Register variable - if self.RegisterIdentities[label.Name] ~= nil then - if self.RegisterIdentities[label.Name] == -1 then - self:Error("Attempting to use register variable after zapping it") - end + if self.RegisterIdentities[label.Name] == -1 then + self:Error("Attempting to use register variable after zapping it") end operationLeaf = { Register = label.Value } end @@ -670,10 +664,8 @@ function HCOMP:ConstantExpression_Level3() -- Pointer to stack value is not a constant return false elseif label.Type == "Register" then - if self.RegisterIdentities[label.Name] ~= nil then - if self.RegisterIdentities[label.Name] == -1 then - self:Error("Attempting to use register variable after zapping it") - end + if self.RegisterIdentities[label.Name] == -1 then + self:Error("Attempting to use register variable after zapping it") end -- Register variable is not a constant return false @@ -756,10 +748,8 @@ function HCOMP:ConstantExpression_Level3() -- Stack variables are not constant return false elseif label.Type == "Register" then - if self.RegisterIdentities[label.Name] ~= nil then - if self.RegisterIdentities[label.Name] == -1 then - self:Error("Attempting to use register variable after zapping it") - end + if self.RegisterIdentities[label.Name] == -1 then + self:Error("Attempting to use register variable after zapping it") end -- Register variable is not a constant return false From e37ba0604fa86aa31a45391d858f838fba338574 Mon Sep 17 00:00:00 2001 From: DerelictDrone Date: Thu, 9 Nov 2023 03:17:56 -0600 Subject: [PATCH 4/5] Fixes pragma preserve register --- lua/wire/client/hlzasm/hc_preprocess.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/wire/client/hlzasm/hc_preprocess.lua b/lua/wire/client/hlzasm/hc_preprocess.lua index 74fd420..662bab6 100644 --- a/lua/wire/client/hlzasm/hc_preprocess.lua +++ b/lua/wire/client/hlzasm/hc_preprocess.lua @@ -113,7 +113,7 @@ function HCOMP:ParsePreprocessMacro(lineText,macroPosition) end end if StartInd ~= -1 and EndInd ~= -1 then - table.insert(self.Settings.AutoPreserveRegisterRanges,{StartInd,EndInd}) + table.insert(self.Settings.AutoBusyRegisterRanges,{true,StartInd,EndInd}) else self:Error(StartRegister .. " to " .. EndRegister .. " is an invalid range!", macroPosition.Line,macroPosition.Col,macroPosition.File) From 64dc21dafae13050b826a03b2fde4fb61089bc9e Mon Sep 17 00:00:00 2001 From: DerelictDrone Date: Thu, 9 Nov 2023 14:12:50 -0600 Subject: [PATCH 5/5] Replace gmatch with match for args, remove duplicate comments --- lua/wire/client/hlzasm/hc_preprocess.lua | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lua/wire/client/hlzasm/hc_preprocess.lua b/lua/wire/client/hlzasm/hc_preprocess.lua index 662bab6..41837cc 100644 --- a/lua/wire/client/hlzasm/hc_preprocess.lua +++ b/lua/wire/client/hlzasm/hc_preprocess.lua @@ -74,10 +74,11 @@ function HCOMP:ParsePreprocessMacro(lineText,macroPosition) if not self.Settings.AutoBusyRegisters then self.Settings.AutoBusyRegisters = true end - local Arguments = string.gmatch(macroParameters,'[^, ]+') -- comma separate the two registers - Arguments() -- drop first space - local StartRegister = trimString(Arguments()) - local EndRegister = trimString(Arguments()) + local StartRegister, EndRegister = string.match(macroParameters, "([^,%s]+)%s*,%s*([^,%s]+)") + if StartRegister == nil then + self:Error("Missing register range argument", + macroPosition.Line,macroPosition.Col,macroPosition.File) + end local StartInd,EndInd = -1,-1 for ind,reg in ipairs(self.RegisterName) do if reg == StartRegister then @@ -98,10 +99,11 @@ function HCOMP:ParsePreprocessMacro(lineText,macroPosition) if not self.Settings.AutoBusyRegisters then self.Settings.AutoBusyRegisters = true end - local Arguments = string.gmatch(macroParameters,'[^, ]+') -- comma separate the two registers - Arguments() -- drop first space - local StartRegister = trimString(Arguments()) - local EndRegister = trimString(Arguments()) + local StartRegister, EndRegister = string.match(macroParameters, "([^,%s]+)%s*,%s*([^,%s]+)") + if StartRegister == nil then + self:Error("Missing register range argument", + macroPosition.Line,macroPosition.Col,macroPosition.File) + end local StartInd,EndInd = -1,-1 for ind,reg in ipairs(self.RegisterName) do if reg == StartRegister then