From 7f18cfc1c2c245a2936d8a9703f94d77703cd61b Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Tue, 26 Aug 2025 15:11:16 +0200 Subject: [PATCH] Improved performance of bitwise operations with constants --- src/asm/Instructions.go | 2 ++ src/asm/compilerARM.go | 9 +++++++++ src/asm/compilerX86.go | 12 ++++++++++++ src/codegen/canEncodeNumber.go | 14 +++++++++++++- src/codegen/exec.go | 21 +++++++++++++++++++++ src/verbose/ASM.go | 14 ++++++++++++++ 6 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/asm/Instructions.go b/src/asm/Instructions.go index 8e2bd41..04db644 100644 --- a/src/asm/Instructions.go +++ b/src/asm/Instructions.go @@ -44,6 +44,7 @@ type ( Multiply rrr Negate rr Or rrr + OrNumber rrn Pop struct{ Registers []cpu.Register } Push struct{ Registers []cpu.Register } Return struct{} @@ -72,4 +73,5 @@ type ( StackFrameEnd struct{ FramePointer bool } Syscall struct{} Xor rrr + XorNumber rrn ) \ No newline at end of file diff --git a/src/asm/compilerARM.go b/src/asm/compilerARM.go index 118162c..4be8ede 100644 --- a/src/asm/compilerARM.go +++ b/src/asm/compilerARM.go @@ -26,6 +26,9 @@ func (c *compilerARM) Compile(instr Instruction) { c.append(code) case *And: c.append(arm.AndRegisterRegister(instr.Destination, instr.Source, instr.Operand)) + case *AndNumber: + code, _ := arm.AndRegisterNumber(instr.Destination, instr.Source, instr.Number) + c.append(code) case *Call: c.append(arm.Call(0)) patch := c.PatchLast4Bytes() @@ -153,6 +156,9 @@ func (c *compilerARM) Compile(instr Instruction) { c.append(arm.NegateRegister(instr.Destination, instr.Source)) case *Or: c.append(arm.OrRegisterRegister(instr.Destination, instr.Source, instr.Operand)) + case *OrNumber: + code, _ := arm.OrRegisterNumber(instr.Destination, instr.Source, instr.Number) + c.append(code) case *Pop: registers := instr.Registers count := len(registers) @@ -205,6 +211,9 @@ func (c *compilerARM) Compile(instr Instruction) { } case *Xor: c.append(arm.XorRegisterRegister(instr.Destination, instr.Source, instr.Operand)) + case *XorNumber: + code, _ := arm.XorRegisterNumber(instr.Destination, instr.Source, instr.Number) + c.append(code) default: panic("unknown instruction") } diff --git a/src/asm/compilerX86.go b/src/asm/compilerX86.go index df3c07a..596dd1f 100644 --- a/src/asm/compilerX86.go +++ b/src/asm/compilerX86.go @@ -230,6 +230,12 @@ func (c *compilerX86) Compile(instr Instruction) { } c.code = x86.OrRegisterRegister(c.code, instr.Destination, instr.Operand) + case *OrNumber: + if instr.Destination != instr.Source { + c.code = x86.MoveRegisterRegister(c.code, instr.Destination, instr.Source) + } + + c.code = x86.OrRegisterNumber(c.code, instr.Destination, instr.Number) case *Pop: for _, register := range slices.Backward(instr.Registers) { c.code = x86.PopRegister(c.code, register) @@ -318,6 +324,12 @@ func (c *compilerX86) Compile(instr Instruction) { } c.code = x86.XorRegisterRegister(c.code, instr.Destination, instr.Operand) + case *XorNumber: + if instr.Destination != instr.Source { + c.code = x86.MoveRegisterRegister(c.code, instr.Destination, instr.Source) + } + + c.code = x86.XorRegisterNumber(c.code, instr.Destination, instr.Number) default: panic("unknown instruction") } diff --git a/src/codegen/canEncodeNumber.go b/src/codegen/canEncodeNumber.go index 778ffe5..5f99887 100644 --- a/src/codegen/canEncodeNumber.go +++ b/src/codegen/canEncodeNumber.go @@ -28,12 +28,24 @@ func (f *Function) canEncodeNumber(instr ssa.Value, number *ssa.Int) bool { _, encodable := arm.AddRegisterNumber(0, 0, number.Int) return encodable + case token.And: + _, encodable := arm.AndRegisterNumber(0, 0, number.Int) + return encodable + + case token.Or: + _, encodable := arm.OrRegisterNumber(0, 0, number.Int) + return encodable + case token.Shl, token.Shr: return number.Int >= 0 && number.Int <= 63 case token.Sub: _, encodable := arm.SubRegisterNumber(0, 0, number.Int) return encodable + + case token.Xor: + _, encodable := arm.XorRegisterNumber(0, 0, number.Int) + return encodable } case config.X86: @@ -42,7 +54,7 @@ func (f *Function) canEncodeNumber(instr ssa.Value, number *ssa.Int) bool { } switch instr.Op { - case token.Add, token.Sub: + case token.Add, token.And, token.Or, token.Sub, token.Xor: return sizeof.Signed(number.Int) <= 4 case token.Shl, token.Shr: diff --git a/src/codegen/exec.go b/src/codegen/exec.go index 1ec54db..69a1c74 100644 --- a/src/codegen/exec.go +++ b/src/codegen/exec.go @@ -53,6 +53,20 @@ func (f *Function) exec(step *Step) { Number: number.Int, }) + case token.And: + f.Assembler.Append(&asm.AndNumber{ + Destination: step.Register, + Source: left.Register, + Number: number.Int, + }) + + case token.Or: + f.Assembler.Append(&asm.OrNumber{ + Destination: step.Register, + Source: left.Register, + Number: number.Int, + }) + case token.Shl: f.Assembler.Append(&asm.ShiftLeftNumber{ Destination: step.Register, @@ -74,6 +88,13 @@ func (f *Function) exec(step *Step) { Number: number.Int, }) + case token.Xor: + f.Assembler.Append(&asm.XorNumber{ + Destination: step.Register, + Source: left.Register, + Number: number.Int, + }) + default: panic("not implemented: " + instr.String()) } diff --git a/src/verbose/ASM.go b/src/verbose/ASM.go index ecd6143..47c8f19 100644 --- a/src/verbose/ASM.go +++ b/src/verbose/ASM.go @@ -164,6 +164,13 @@ func printAssembly(f *core.Function) { register.Print(instr.Source) other.Print(", ") register.Print(instr.Operand) + case *asm.OrNumber: + mnemonic.Print(" or ") + register.Print(instr.Destination) + other.Print(", ") + register.Print(instr.Source) + other.Print(", ") + imm.Print(instr.Number) case *asm.Pop: mnemonic.Print(" pop ") register.Print(instr.Registers) @@ -241,6 +248,13 @@ func printAssembly(f *core.Function) { register.Print(instr.Source) other.Print(", ") register.Print(instr.Operand) + case *asm.XorNumber: + mnemonic.Print(" xor ") + register.Print(instr.Destination) + other.Print(", ") + register.Print(instr.Source) + other.Print(", ") + imm.Print(instr.Number) default: ansi.Red.Print(" unknown: " + reflect.TypeOf(instr).String()) } -- 2.54.0