From 704ae267e6fd2153fab96f1ee48fae2b5adf21b8 Mon Sep 17 00:00:00 2001 From: DerelictDrone Date: Tue, 14 Nov 2023 03:42:32 -0600 Subject: [PATCH] Easily copy and pass structs into and out of funcs --- lua/wire/client/hlzasm/hc_codetree.lua | 7 +- lua/wire/client/hlzasm/hc_compiler.lua | 3 +- lua/wire/client/hlzasm/hc_expression.lua | 115 +++++++++++++++++++++-- lua/wire/client/hlzasm/hc_output.lua | 27 +++++- lua/wire/client/hlzasm/hc_syntax.lua | 43 ++++++++- 5 files changed, 179 insertions(+), 16 deletions(-) diff --git a/lua/wire/client/hlzasm/hc_codetree.lua b/lua/wire/client/hlzasm/hc_codetree.lua index 6f28460..ca64b55 100644 --- a/lua/wire/client/hlzasm/hc_codetree.lua +++ b/lua/wire/client/hlzasm/hc_codetree.lua @@ -397,7 +397,12 @@ function HCOMP:GenerateLeaf(leaf,needResult) -- Make register operand temporary if requested if genOperands[i].ForceTemporary then - local initReg = genOperands[i].Register + local initReg + if genOperands[i].Register then + initReg = genOperands[i].Register + elseif genOperands[i].MemoryRegister then + initReg = genOperands[i].MemoryRegister + end genOperands[i].ForceTemporary = false if self.RegisterBusy[initReg] then diff --git a/lua/wire/client/hlzasm/hc_compiler.lua b/lua/wire/client/hlzasm/hc_compiler.lua index b1336fe..2d6fab3 100644 --- a/lua/wire/client/hlzasm/hc_compiler.lua +++ b/lua/wire/client/hlzasm/hc_compiler.lua @@ -241,7 +241,8 @@ function HCOMP:StartCompile(sourceCode,fileName,writeByteCallback,writeByteCalle -- All functions defined so far self.Functions = {} - + -- Details about the current function that we're building + self.CurFunction = {} -- All macros defined so far self.Defines = {} self.Defines["__LINE__"] = 0 diff --git a/lua/wire/client/hlzasm/hc_expression.lua b/lua/wire/client/hlzasm/hc_expression.lua index a6b0773..23c22ba 100644 --- a/lua/wire/client/hlzasm/hc_expression.lua +++ b/lua/wire/client/hlzasm/hc_expression.lua @@ -81,10 +81,33 @@ function HCOMP:Expression_FunctionCall(label) local TOKEN = self.TOKEN -- Push arguments to stack in reverse order for argNo = #argumentExpression,1,-1 do - local pushLeaf = self:NewLeaf() - pushLeaf.Opcode = "push" - pushLeaf.Operands[1] = argumentExpression[argNo] - table.insert(genLeaves,pushLeaf) + local pushLeaf + if argumentExpression[argNo].Memory then + if argumentExpression[argNo].Memory.CopySize then + for i=argumentExpression[argNo].Memory.CopySize-1,0,-1 do + pushLeaf = self:NewLeaf() + pushLeaf.Comment = " passing large variable, byte "..i + pushLeaf.Opcode = "push" + local a = argumentExpression[argNo] + local copiedArg = { + CurrentPosition = argumentExpression[argNo].CurrentPosition, + Memory = a.Memory, + MemAddrOffset = i + } + -- Memory will update globally when it receives the final value + -- so we wrap it into a new copy of the table with a constant num + -- because setting the const in memory would update the same table multiple times + pushLeaf.Operands[1] = copiedArg + table.insert(genLeaves,pushLeaf) + end + argumentCount = argumentCount + argumentExpression[argNo].Memory.CopySize-1 + end + else + pushLeaf = self:NewLeaf() + pushLeaf.Opcode = "push" + pushLeaf.Operands[1] = argumentExpression[argNo] + table.insert(genLeaves,pushLeaf) + end if functionEntry then if functionEntry.Parameters[argNo] then @@ -145,6 +168,18 @@ function HCOMP:Expression_FunctionCall(label) local TOKEN = self.TOKEN end -- Return EAX as the return value + if self.Functions[label] then + if self.StructSize[self.Functions[label].ReturnType] then + -- Return as memory register that requests copy of x size + return { MemoryRegister = 1, ForceTemporary = true, CopySize = self.StructSize[self.Functions[label].ReturnType], PreviousLeaf = genLeaves[#genLeaves]} + end + elseif self.CurFunction then + if self.CurFunction.ReturnType then + if self.StructSize[self.CurFunction.ReturnType] then + return { MemoryRegister = 1, ForceTemporary = true, CopySize = self.StructSize[self.CurFunction.ReturnType], PreviousLeaf = genLeaves[#genLeaves]} + end + end + end return { Register = 1, ForceTemporary = true, PreviousLeaf = genLeaves[#genLeaves] } end @@ -332,7 +367,7 @@ function HCOMP:Expression_Level3() local TOKEN = self.TOKEN addressLeaf.Operands[2] = { Constant = structData[memberName].Offset } operationLeaf = { MemoryPointer = addressLeaf } else - operationLeaf = { Stack = structLabel.StackOffset+structData[memberName].Offset } + operationLeaf = { Stack = structLabel.StackOffset+structData[memberName].Offset-1 } end elseif structLabel.Type == "Variable" then if structLabel.PointerToStruct then @@ -373,7 +408,12 @@ function HCOMP:Expression_Level3() local TOKEN = self.TOKEN else -- Parse variable access if label.Type == "Variable" then -- Read from a variable -- Array variables are resolved as pointers at constant expression stage - operationLeaf = { Memory = label, ForceType = forceType } + if label.Struct then + operationLeaf = { Memory = label, ForceType = forceType } + operationLeaf.Memory.CopySize = self.StructSize[label.Struct] + else + operationLeaf = { Memory = label, ForceType = forceType } + end elseif label.Type == "Unknown" then -- Read from an unknown variable operationLeaf = { UnknownOperationByLabel = label, ForceType = forceType } elseif label.Type == "Stack" then -- Read from stack @@ -485,7 +525,68 @@ function HCOMP:Expression_Level0() if self:MatchToken(self.TOKEN.EQUAL) then -- = local rightLeaf = self:Expression_LevelLeaf(0) - + if leftLeaf.Memory then + if rightLeaf.Memory then + if leftLeaf.Memory.CopySize and rightLeaf.Memory.CopySize then + local topLeaf = self:NewOpcode("mov",leftLeaf,rightLeaf) + local curLeaf = topLeaf + local tempLeftLeaf,tempRightLeaf + for i=1,math.min(leftLeaf.Memory.CopySize,rightLeaf.Memory.CopySize)-1 do + tempLeftLeaf = { + CurrentPosition = leftLeaf.CurrentPosition, + Memory = leftLeaf.Memory, + MemAddrOffset = i + } + tempRightLeaf = { + CurrentPosition = rightLeaf.CurrentPosition, + Memory = rightLeaf.Memory, + MemAddrOffset = i + } + curLeaf.PreviousLeaf = self:NewOpcode("mov",tempLeftLeaf,tempRightLeaf) + curLeaf = curLeaf.PreviousLeaf + end + -- example of generated output (because previousleaf is parsed before the leaf containing previousleaf) + -- MOV #0+2,#3+2 + -- MOV #0+1,#3+1 + -- MOV #0,#3 + -- * Mark these both with an offset so they won't warn + leftLeaf.MemAddrOffset = 0 + rightLeaf.MemAddrOffset = 0 + curLeaf.Comment = topLeaf.Comment + topLeaf.Comment = nil + return topLeaf + end + elseif rightLeaf.MemoryRegister then + if leftLeaf.Memory.CopySize and rightLeaf.CopySize then + local topLeaf = self:NewOpcode("mov",leftLeaf,rightLeaf) + local curLeaf = topLeaf + local tempLeftLeaf + for i=1,math.min(leftLeaf.Memory.CopySize,rightLeaf.CopySize)-1 do + tempLeftLeaf = { + CurrentPosition = leftLeaf.CurrentPosition, + Memory = leftLeaf.Memory, + MemAddrOffset = i + } + curLeaf.PreviousLeaf = self:NewOpcode("inc",{Register = rightLeaf.MemoryRegister}) + curLeaf = curLeaf.PreviousLeaf + curLeaf.PreviousLeaf = self:NewOpcode("mov",tempLeftLeaf,rightLeaf) + curLeaf = curLeaf.PreviousLeaf + end + -- example of generated output (because previousleaf is parsed before the leaf containing previousleaf) + -- MOV #0+2,#R0 + -- INC R0 + -- MOV #0+1,#R0 + -- INC R0 + -- MOV #0,#R0 + -- * Mark these both with an offset so they won't warn + leftLeaf.MemAddrOffset = 0 + rightLeaf.MemAddrOffset = 0 + curLeaf.Comment = topLeaf.Comment + topLeaf.Comment = nil + return topLeaf + end + end + end -- Mark this leaf as an explict assign operation local operationLeaf = self:NewOpcode("mov",leftLeaf,rightLeaf) operationLeaf.ExplictAssign = true diff --git a/lua/wire/client/hlzasm/hc_output.lua b/lua/wire/client/hlzasm/hc_output.lua index 0e9cbba..3fd4ca9 100644 --- a/lua/wire/client/hlzasm/hc_output.lua +++ b/lua/wire/client/hlzasm/hc_output.lua @@ -363,9 +363,28 @@ function HCOMP:PrintBlock(block,file,isLibrary) printText = printText .. "#" .. block.Operands[i].MemoryPointer end elseif block.Operands[i].Memory then + if not block.Operands[i].MemAddrOffset then + if block.Operands[i].Memory.CopySize then + if block.Operands[1].Memory and i ~= 1 then + if block.Operands[i].Memory.CopySize then + self:Warning("Operation will only use first byte of large variables on left and right, use &varname to get a pointer instead") + end + else + if not block.Operands[i].MemAddrOffset then + PrintTable(block.Operands[i]) + self:Warning("Operation will only use first byte of large variable on right, use &varname to get a pointer instead") + end + end + end + end if istable(block.Operands[i].Memory) then if block.Operands[i].Memory.Value - then printText = printText .. "#" .. block.Operands[i].Memory.Value + then + if block.Operands[i].MemAddrOffset then + printText = printText .. "#" .. block.Operands[i].Memory.Value + block.Operands[i].MemAddrOffset + else + printText = printText .. "#" .. block.Operands[i].Memory.Value + end else printText = printText .. "#" .. block.Operands[i].Memory.Name end else @@ -530,7 +549,11 @@ function HCOMP:OperandRM(operand,block) end elseif operand.Memory then if istable(operand.Memory) then -- label - operand.Value = operand.Memory.Value + if operand.MemAddrOffset then + operand.Value = operand.Memory.Value + operand.MemAddrOffset + else + operand.Value = operand.Memory.Value + end else -- constant operand.Value = operand.Memory end diff --git a/lua/wire/client/hlzasm/hc_syntax.lua b/lua/wire/client/hlzasm/hc_syntax.lua index 44ac905..da428a8 100644 --- a/lua/wire/client/hlzasm/hc_syntax.lua +++ b/lua/wire/client/hlzasm/hc_syntax.lua @@ -513,7 +513,15 @@ function HCOMP:DefineVariable(isFunctionParam,isForwardDecl,isRegisterDecl,isStr -- Create function entrypoint local label label = self:DefineLabel(varName) - + self:PreviousToken() -- LPAREN + self:PreviousToken() -- Func Name + self:PreviousToken() -- Type Name + self:MatchToken(TOKEN.IDENT) -- Type Name + local returnType = self.TokenData + self:MatchToken(TOKEN.IDENT) + local funcName = self.TokenData + self.CurFunction = {Name = funcName, ReturnType = returnType} + self:NextToken() label.Type = "Pointer" label.Defined = true @@ -1134,12 +1142,37 @@ function HCOMP:Statement() local TOKEN = self.TOKEN if self:MatchToken(TOKEN.RETURN) and self.HeadLeaf then if not self:MatchToken(TOKEN.COLON) then local returnExpression = self:Expression() + local copyLargeVariable = false + if self.StructSize[self.CurFunction.ReturnType] then + copyLargeVariable = true -- Converts this to automatically return ptr to large variable + end local returnLeaf = self:NewLeaf() - returnLeaf.Opcode = "mov" - returnLeaf.Operands[1] = { Register = 1 } - returnLeaf.Operands[2] = returnExpression - returnLeaf.ExplictAssign = true + local preReturnLeaf,postReturnLeaf + if copyLargeVariable then + local finalReturnExpression = returnExpression + returnLeaf.Opcode = "mov" + returnLeaf.Operands[1] = { Register = 1 } + if returnExpression.Stack then + finalReturnExpression = { Register = 8 } -- EBP, the stack frame register, where the stack ptr is local to + postReturnLeaf = self:NewOpcode("add",returnLeaf.Operands[1],{Constant = returnExpression.Stack}) + -- MOV EAX,EBP + -- ADD EAX,(stack-pos) + end + returnLeaf.Operands[2] = finalReturnExpression + returnLeaf.ExplictAssign = true + else + returnLeaf.Opcode = "mov" + returnLeaf.Operands[1] = { Register = 1 } + returnLeaf.Operands[2] = returnExpression + returnLeaf.ExplictAssign = true + end + if preReturnLeaf then + self:AddLeafToTail(preReturnLeaf) + end self:AddLeafToTail(returnLeaf) + if postReturnLeaf then + self:AddLeafToTail(postReturnLeaf) + end end self:MatchToken(TOKEN.COLON)