diff --git a/lua/wire/client/hlzasm/hc_codetree.lua b/lua/wire/client/hlzasm/hc_codetree.lua index 2c03e24..15b8382 100644 --- a/lua/wire/client/hlzasm/hc_codetree.lua +++ b/lua/wire/client/hlzasm/hc_codetree.lua @@ -90,7 +90,7 @@ 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 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..ad26b2b 100644 --- a/lua/wire/client/hlzasm/hc_expression.lua +++ b/lua/wire/client/hlzasm/hc_expression.lua @@ -45,6 +45,9 @@ 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] == -1 then + self:Error("Attempting to use register variable after zapping it") + end operationLeaf.Operands[1] = { Register = label.Value } end end @@ -193,6 +196,9 @@ 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] == -1 then + self:Error("Attempting to use register variable after zapping it") + end addressLeaf.Opcode = "add" addressLeaf.Operands[1] = arrayOffsetLeaf addressLeaf.Operands[2] = { Register = label.Value } @@ -389,6 +395,9 @@ function HCOMP:Expression_Level3() local TOKEN = self.TOKEN end elseif label.Type == "Register" then -- Register variable + if self.RegisterIdentities[label.Name] == -1 then + self:Error("Attempting to use register variable after zapping it") + end operationLeaf = { Register = label.Value } end end @@ -655,6 +664,9 @@ function HCOMP:ConstantExpression_Level3() -- Pointer to stack value is not a constant return false elseif label.Type == "Register" then + 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 elseif label.Type == "Unknown" then @@ -736,6 +748,9 @@ function HCOMP:ConstantExpression_Level3() -- Stack variables are not constant return false elseif label.Type == "Register" then + 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 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..41837cc 100644 --- a/lua/wire/client/hlzasm/hc_preprocess.lua +++ b/lua/wire/client/hlzasm/hc_preprocess.lua @@ -70,6 +70,56 @@ 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 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 + 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 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 + StartInd = ind + end + if reg == EndRegister then + EndInd = ind + break + end + end + if StartInd ~= -1 and EndInd ~= -1 then + table.insert(self.Settings.AutoBusyRegisterRanges,{true,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)