bit shift operators prefer shifting in ACC if possible
This commit is contained in:
parent
822326f993
commit
5f25d66aeb
4 changed files with 160 additions and 40 deletions
|
|
@ -251,15 +251,36 @@ func (c *ShiftLCommand) generateByteCopy() []string {
|
|||
func (c *ShiftLCommand) generateByteShiftConst(amount uint16) []string {
|
||||
var asm []string
|
||||
|
||||
// Copy source to destination if needed
|
||||
copyAsm := c.generateByteCopy()
|
||||
asm = append(asm, copyAsm...)
|
||||
|
||||
// Apply shift
|
||||
for i := uint16(0); i < amount; i++ {
|
||||
asm = append(asm, fmt.Sprintf("\tasl %s", c.destVarName))
|
||||
// Check if same variable
|
||||
if c.sourceIsVar && c.sourceVarName == c.destVarName {
|
||||
// Same variable: load to accumulator, shift, store back (faster)
|
||||
asm = append(asm, fmt.Sprintf("\tlda %s", c.sourceVarName))
|
||||
// Shift in accumulator (faster: 2 cycles vs 5 for memory)
|
||||
for i := uint16(0); i < amount; i++ {
|
||||
asm = append(asm, "\tasl")
|
||||
}
|
||||
asm = append(asm, fmt.Sprintf("\tsta %s", c.destVarName))
|
||||
return asm
|
||||
}
|
||||
|
||||
// Different variables or literal source: shift in accumulator
|
||||
if c.sourceIsVar {
|
||||
// Variable source
|
||||
asm = append(asm, fmt.Sprintf("\tlda %s", c.sourceVarName))
|
||||
} else {
|
||||
// Literal source
|
||||
val := uint8(c.sourceValue & 0xFF)
|
||||
asm = append(asm, fmt.Sprintf("\tlda #$%02x", val))
|
||||
}
|
||||
|
||||
// Shift in accumulator (faster: 2 cycles vs 5 for memory)
|
||||
for i := uint16(0); i < amount; i++ {
|
||||
asm = append(asm, "\tasl")
|
||||
}
|
||||
|
||||
// Store result
|
||||
asm = append(asm, fmt.Sprintf("\tsta %s", c.destVarName))
|
||||
|
||||
return asm
|
||||
}
|
||||
|
||||
|
|
@ -267,24 +288,61 @@ func (c *ShiftLCommand) generateByteShiftConst(amount uint16) []string {
|
|||
func (c *ShiftLCommand) generateByteShiftVar(ctx *compiler.CompilerContext) ([]string, error) {
|
||||
var asm []string
|
||||
|
||||
// Copy source to destination if needed
|
||||
copyAsm := c.generateByteCopy()
|
||||
asm = append(asm, copyAsm...)
|
||||
// Check if same variable
|
||||
if c.sourceIsVar && c.sourceVarName == c.destVarName {
|
||||
// Same variable: load to accumulator, shift loop, store back (faster)
|
||||
// Generate labels
|
||||
loopLabel := ctx.GeneralStack.Push()
|
||||
ctx.GeneralStack.Pop()
|
||||
doneLabel := ctx.GeneralStack.Push()
|
||||
ctx.GeneralStack.Pop()
|
||||
|
||||
// Load value to accumulator
|
||||
asm = append(asm, fmt.Sprintf("\tlda %s", c.sourceVarName))
|
||||
|
||||
// Variable shift loop (in accumulator, 2 cycles vs 5 for memory)
|
||||
asm = append(asm, fmt.Sprintf("\tldx %s", c.amountVarName))
|
||||
asm = append(asm, fmt.Sprintf("\tbeq %s", doneLabel))
|
||||
asm = append(asm, loopLabel)
|
||||
asm = append(asm, "\tasl")
|
||||
asm = append(asm, "\tdex")
|
||||
asm = append(asm, fmt.Sprintf("\tbne %s", loopLabel))
|
||||
asm = append(asm, doneLabel)
|
||||
|
||||
// Store result back
|
||||
asm = append(asm, fmt.Sprintf("\tsta %s", c.destVarName))
|
||||
|
||||
return asm, nil
|
||||
}
|
||||
|
||||
// Different variables or literal: shift in accumulator (faster)
|
||||
// Generate labels
|
||||
loopLabel := ctx.GeneralStack.Push()
|
||||
ctx.GeneralStack.Pop()
|
||||
doneLabel := ctx.GeneralStack.Push()
|
||||
ctx.GeneralStack.Pop()
|
||||
|
||||
// Variable shift loop
|
||||
// Load source to accumulator
|
||||
if c.sourceIsVar {
|
||||
asm = append(asm, fmt.Sprintf("\tlda %s", c.sourceVarName))
|
||||
} else {
|
||||
val := uint8(c.sourceValue & 0xFF)
|
||||
asm = append(asm, fmt.Sprintf("\tlda #$%02x", val))
|
||||
}
|
||||
|
||||
// Load shift amount to X
|
||||
asm = append(asm, fmt.Sprintf("\tldx %s", c.amountVarName))
|
||||
asm = append(asm, fmt.Sprintf("\tbeq %s", doneLabel))
|
||||
|
||||
// Shift loop (in accumulator, 2 cycles vs 5 for memory)
|
||||
asm = append(asm, loopLabel)
|
||||
asm = append(asm, fmt.Sprintf("\tasl %s", c.destVarName))
|
||||
asm = append(asm, "\tasl")
|
||||
asm = append(asm, "\tdex")
|
||||
asm = append(asm, fmt.Sprintf("\tbne %s", loopLabel))
|
||||
|
||||
// Store result
|
||||
asm = append(asm, doneLabel)
|
||||
asm = append(asm, fmt.Sprintf("\tsta %s", c.destVarName))
|
||||
|
||||
return asm, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -366,10 +366,10 @@ func TestShiftLCommand_Generate(t *testing.T) {
|
|||
},
|
||||
wantLines: []string{
|
||||
"\tlda #$01",
|
||||
"\tasl",
|
||||
"\tasl",
|
||||
"\tasl",
|
||||
"\tsta result",
|
||||
"\tasl result",
|
||||
"\tasl result",
|
||||
"\tasl result",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -450,14 +450,14 @@ func TestShiftLCommand_Generate(t *testing.T) {
|
|||
},
|
||||
wantLines: []string{
|
||||
"\tlda value",
|
||||
"\tsta result",
|
||||
"\tldx shift",
|
||||
"\tbeq _L2",
|
||||
"_L1",
|
||||
"\tasl result",
|
||||
"\tasl",
|
||||
"\tdex",
|
||||
"\tbne _L1",
|
||||
"_L2",
|
||||
"\tsta result",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -509,13 +509,15 @@ func TestShiftLCommand_Generate(t *testing.T) {
|
|||
}
|
||||
},
|
||||
wantLines: []string{
|
||||
"\tlda value",
|
||||
"\tldx shift",
|
||||
"\tbeq _L2",
|
||||
"_L1",
|
||||
"\tasl value",
|
||||
"\tasl",
|
||||
"\tdex",
|
||||
"\tbne _L1",
|
||||
"_L2",
|
||||
"\tsta value",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -609,11 +611,11 @@ func TestShiftLCommand_Generate(t *testing.T) {
|
|||
},
|
||||
wantLines: []string{
|
||||
"\tlda wordval",
|
||||
"\tasl",
|
||||
"\tasl",
|
||||
"\tasl",
|
||||
"\tasl",
|
||||
"\tsta result",
|
||||
"\tasl result",
|
||||
"\tasl result",
|
||||
"\tasl result",
|
||||
"\tasl result",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -263,15 +263,36 @@ func (c *ShiftRCommand) generateByteCopy() []string {
|
|||
func (c *ShiftRCommand) generateByteShiftConst(amount uint16) []string {
|
||||
var asm []string
|
||||
|
||||
// Copy source to destination if needed
|
||||
copyAsm := c.generateByteCopy()
|
||||
asm = append(asm, copyAsm...)
|
||||
|
||||
// Apply shift (right shift uses LSR)
|
||||
for i := uint16(0); i < amount; i++ {
|
||||
asm = append(asm, fmt.Sprintf("\tlsr %s", c.destVarName))
|
||||
// Check if same variable
|
||||
if c.sourceIsVar && c.sourceVarName == c.destVarName {
|
||||
// Same variable: load to accumulator, shift, store back (faster)
|
||||
asm = append(asm, fmt.Sprintf("\tlda %s", c.sourceVarName))
|
||||
// Shift in accumulator (faster: 2 cycles vs 5 for memory)
|
||||
for i := uint16(0); i < amount; i++ {
|
||||
asm = append(asm, "\tlsr")
|
||||
}
|
||||
asm = append(asm, fmt.Sprintf("\tsta %s", c.destVarName))
|
||||
return asm
|
||||
}
|
||||
|
||||
// Different variables or literal source: shift in accumulator
|
||||
if c.sourceIsVar {
|
||||
// Variable source
|
||||
asm = append(asm, fmt.Sprintf("\tlda %s", c.sourceVarName))
|
||||
} else {
|
||||
// Literal source
|
||||
val := uint8(c.sourceValue & 0xFF)
|
||||
asm = append(asm, fmt.Sprintf("\tlda #$%02x", val))
|
||||
}
|
||||
|
||||
// Shift in accumulator (faster: 2 cycles vs 5 for memory)
|
||||
for i := uint16(0); i < amount; i++ {
|
||||
asm = append(asm, "\tlsr")
|
||||
}
|
||||
|
||||
// Store result
|
||||
asm = append(asm, fmt.Sprintf("\tsta %s", c.destVarName))
|
||||
|
||||
return asm
|
||||
}
|
||||
|
||||
|
|
@ -279,24 +300,61 @@ func (c *ShiftRCommand) generateByteShiftConst(amount uint16) []string {
|
|||
func (c *ShiftRCommand) generateByteShiftVar(ctx *compiler.CompilerContext) ([]string, error) {
|
||||
var asm []string
|
||||
|
||||
// Copy source to destination if needed
|
||||
copyAsm := c.generateByteCopy()
|
||||
asm = append(asm, copyAsm...)
|
||||
// Check if same variable
|
||||
if c.sourceIsVar && c.sourceVarName == c.destVarName {
|
||||
// Same variable: load to accumulator, shift loop, store back (faster)
|
||||
// Generate labels
|
||||
loopLabel := ctx.GeneralStack.Push()
|
||||
ctx.GeneralStack.Pop()
|
||||
doneLabel := ctx.GeneralStack.Push()
|
||||
ctx.GeneralStack.Pop()
|
||||
|
||||
// Load value to accumulator
|
||||
asm = append(asm, fmt.Sprintf("\tlda %s", c.sourceVarName))
|
||||
|
||||
// Variable shift loop (in accumulator, 2 cycles vs 5 for memory)
|
||||
asm = append(asm, fmt.Sprintf("\tldx %s", c.amountVarName))
|
||||
asm = append(asm, fmt.Sprintf("\tbeq %s", doneLabel))
|
||||
asm = append(asm, loopLabel)
|
||||
asm = append(asm, "\tlsr")
|
||||
asm = append(asm, "\tdex")
|
||||
asm = append(asm, fmt.Sprintf("\tbne %s", loopLabel))
|
||||
asm = append(asm, doneLabel)
|
||||
|
||||
// Store result back
|
||||
asm = append(asm, fmt.Sprintf("\tsta %s", c.destVarName))
|
||||
|
||||
return asm, nil
|
||||
}
|
||||
|
||||
// Different variables or literal: shift in accumulator (faster)
|
||||
// Generate labels
|
||||
loopLabel := ctx.GeneralStack.Push()
|
||||
ctx.GeneralStack.Pop()
|
||||
doneLabel := ctx.GeneralStack.Push()
|
||||
ctx.GeneralStack.Pop()
|
||||
|
||||
// Variable shift loop (right shift uses LSR)
|
||||
// Load source to accumulator
|
||||
if c.sourceIsVar {
|
||||
asm = append(asm, fmt.Sprintf("\tlda %s", c.sourceVarName))
|
||||
} else {
|
||||
val := uint8(c.sourceValue & 0xFF)
|
||||
asm = append(asm, fmt.Sprintf("\tlda #$%02x", val))
|
||||
}
|
||||
|
||||
// Load shift amount to X
|
||||
asm = append(asm, fmt.Sprintf("\tldx %s", c.amountVarName))
|
||||
asm = append(asm, fmt.Sprintf("\tbeq %s", doneLabel))
|
||||
|
||||
// Shift loop (in accumulator, 2 cycles vs 5 for memory)
|
||||
asm = append(asm, loopLabel)
|
||||
asm = append(asm, fmt.Sprintf("\tlsr %s", c.destVarName))
|
||||
asm = append(asm, "\tlsr")
|
||||
asm = append(asm, "\tdex")
|
||||
asm = append(asm, fmt.Sprintf("\tbne %s", loopLabel))
|
||||
|
||||
// Store result
|
||||
asm = append(asm, doneLabel)
|
||||
asm = append(asm, fmt.Sprintf("\tsta %s", c.destVarName))
|
||||
|
||||
return asm, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -366,10 +366,10 @@ func TestShiftRCommand_Generate(t *testing.T) {
|
|||
},
|
||||
wantLines: []string{
|
||||
"\tlda #$08",
|
||||
"\tlsr",
|
||||
"\tlsr",
|
||||
"\tlsr",
|
||||
"\tsta result",
|
||||
"\tlsr result",
|
||||
"\tlsr result",
|
||||
"\tlsr result",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -450,14 +450,14 @@ func TestShiftRCommand_Generate(t *testing.T) {
|
|||
},
|
||||
wantLines: []string{
|
||||
"\tlda value",
|
||||
"\tsta result",
|
||||
"\tldx shift",
|
||||
"\tbeq _L2",
|
||||
"_L1",
|
||||
"\tlsr result",
|
||||
"\tlsr",
|
||||
"\tdex",
|
||||
"\tbne _L1",
|
||||
"_L2",
|
||||
"\tsta result",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -509,13 +509,15 @@ func TestShiftRCommand_Generate(t *testing.T) {
|
|||
}
|
||||
},
|
||||
wantLines: []string{
|
||||
"\tlda value",
|
||||
"\tldx shift",
|
||||
"\tbeq _L2",
|
||||
"_L1",
|
||||
"\tlsr value",
|
||||
"\tlsr",
|
||||
"\tdex",
|
||||
"\tbne _L1",
|
||||
"_L2",
|
||||
"\tsta value",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue