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 {
|
func (c *ShiftLCommand) generateByteShiftConst(amount uint16) []string {
|
||||||
var asm []string
|
var asm []string
|
||||||
|
|
||||||
// Copy source to destination if needed
|
// Check if same variable
|
||||||
copyAsm := c.generateByteCopy()
|
if c.sourceIsVar && c.sourceVarName == c.destVarName {
|
||||||
asm = append(asm, copyAsm...)
|
// Same variable: load to accumulator, shift, store back (faster)
|
||||||
|
asm = append(asm, fmt.Sprintf("\tlda %s", c.sourceVarName))
|
||||||
// Apply shift
|
// Shift in accumulator (faster: 2 cycles vs 5 for memory)
|
||||||
for i := uint16(0); i < amount; i++ {
|
for i := uint16(0); i < amount; i++ {
|
||||||
asm = append(asm, fmt.Sprintf("\tasl %s", c.destVarName))
|
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
|
return asm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -267,24 +288,61 @@ func (c *ShiftLCommand) generateByteShiftConst(amount uint16) []string {
|
||||||
func (c *ShiftLCommand) generateByteShiftVar(ctx *compiler.CompilerContext) ([]string, error) {
|
func (c *ShiftLCommand) generateByteShiftVar(ctx *compiler.CompilerContext) ([]string, error) {
|
||||||
var asm []string
|
var asm []string
|
||||||
|
|
||||||
// Copy source to destination if needed
|
// Check if same variable
|
||||||
copyAsm := c.generateByteCopy()
|
if c.sourceIsVar && c.sourceVarName == c.destVarName {
|
||||||
asm = append(asm, copyAsm...)
|
// 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
|
// Generate labels
|
||||||
loopLabel := ctx.GeneralStack.Push()
|
loopLabel := ctx.GeneralStack.Push()
|
||||||
ctx.GeneralStack.Pop()
|
ctx.GeneralStack.Pop()
|
||||||
doneLabel := ctx.GeneralStack.Push()
|
doneLabel := ctx.GeneralStack.Push()
|
||||||
ctx.GeneralStack.Pop()
|
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("\tldx %s", c.amountVarName))
|
||||||
asm = append(asm, fmt.Sprintf("\tbeq %s", doneLabel))
|
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, loopLabel)
|
||||||
asm = append(asm, fmt.Sprintf("\tasl %s", c.destVarName))
|
asm = append(asm, "\tasl")
|
||||||
asm = append(asm, "\tdex")
|
asm = append(asm, "\tdex")
|
||||||
asm = append(asm, fmt.Sprintf("\tbne %s", loopLabel))
|
asm = append(asm, fmt.Sprintf("\tbne %s", loopLabel))
|
||||||
|
|
||||||
|
// Store result
|
||||||
asm = append(asm, doneLabel)
|
asm = append(asm, doneLabel)
|
||||||
|
asm = append(asm, fmt.Sprintf("\tsta %s", c.destVarName))
|
||||||
|
|
||||||
return asm, nil
|
return asm, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -366,10 +366,10 @@ func TestShiftLCommand_Generate(t *testing.T) {
|
||||||
},
|
},
|
||||||
wantLines: []string{
|
wantLines: []string{
|
||||||
"\tlda #$01",
|
"\tlda #$01",
|
||||||
|
"\tasl",
|
||||||
|
"\tasl",
|
||||||
|
"\tasl",
|
||||||
"\tsta result",
|
"\tsta result",
|
||||||
"\tasl result",
|
|
||||||
"\tasl result",
|
|
||||||
"\tasl result",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -450,14 +450,14 @@ func TestShiftLCommand_Generate(t *testing.T) {
|
||||||
},
|
},
|
||||||
wantLines: []string{
|
wantLines: []string{
|
||||||
"\tlda value",
|
"\tlda value",
|
||||||
"\tsta result",
|
|
||||||
"\tldx shift",
|
"\tldx shift",
|
||||||
"\tbeq _L2",
|
"\tbeq _L2",
|
||||||
"_L1",
|
"_L1",
|
||||||
"\tasl result",
|
"\tasl",
|
||||||
"\tdex",
|
"\tdex",
|
||||||
"\tbne _L1",
|
"\tbne _L1",
|
||||||
"_L2",
|
"_L2",
|
||||||
|
"\tsta result",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -509,13 +509,15 @@ func TestShiftLCommand_Generate(t *testing.T) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
wantLines: []string{
|
wantLines: []string{
|
||||||
|
"\tlda value",
|
||||||
"\tldx shift",
|
"\tldx shift",
|
||||||
"\tbeq _L2",
|
"\tbeq _L2",
|
||||||
"_L1",
|
"_L1",
|
||||||
"\tasl value",
|
"\tasl",
|
||||||
"\tdex",
|
"\tdex",
|
||||||
"\tbne _L1",
|
"\tbne _L1",
|
||||||
"_L2",
|
"_L2",
|
||||||
|
"\tsta value",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -609,11 +611,11 @@ func TestShiftLCommand_Generate(t *testing.T) {
|
||||||
},
|
},
|
||||||
wantLines: []string{
|
wantLines: []string{
|
||||||
"\tlda wordval",
|
"\tlda wordval",
|
||||||
|
"\tasl",
|
||||||
|
"\tasl",
|
||||||
|
"\tasl",
|
||||||
|
"\tasl",
|
||||||
"\tsta result",
|
"\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 {
|
func (c *ShiftRCommand) generateByteShiftConst(amount uint16) []string {
|
||||||
var asm []string
|
var asm []string
|
||||||
|
|
||||||
// Copy source to destination if needed
|
// Check if same variable
|
||||||
copyAsm := c.generateByteCopy()
|
if c.sourceIsVar && c.sourceVarName == c.destVarName {
|
||||||
asm = append(asm, copyAsm...)
|
// Same variable: load to accumulator, shift, store back (faster)
|
||||||
|
asm = append(asm, fmt.Sprintf("\tlda %s", c.sourceVarName))
|
||||||
// Apply shift (right shift uses LSR)
|
// Shift in accumulator (faster: 2 cycles vs 5 for memory)
|
||||||
for i := uint16(0); i < amount; i++ {
|
for i := uint16(0); i < amount; i++ {
|
||||||
asm = append(asm, fmt.Sprintf("\tlsr %s", c.destVarName))
|
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
|
return asm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -279,24 +300,61 @@ func (c *ShiftRCommand) generateByteShiftConst(amount uint16) []string {
|
||||||
func (c *ShiftRCommand) generateByteShiftVar(ctx *compiler.CompilerContext) ([]string, error) {
|
func (c *ShiftRCommand) generateByteShiftVar(ctx *compiler.CompilerContext) ([]string, error) {
|
||||||
var asm []string
|
var asm []string
|
||||||
|
|
||||||
// Copy source to destination if needed
|
// Check if same variable
|
||||||
copyAsm := c.generateByteCopy()
|
if c.sourceIsVar && c.sourceVarName == c.destVarName {
|
||||||
asm = append(asm, copyAsm...)
|
// 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
|
// Generate labels
|
||||||
loopLabel := ctx.GeneralStack.Push()
|
loopLabel := ctx.GeneralStack.Push()
|
||||||
ctx.GeneralStack.Pop()
|
ctx.GeneralStack.Pop()
|
||||||
doneLabel := ctx.GeneralStack.Push()
|
doneLabel := ctx.GeneralStack.Push()
|
||||||
ctx.GeneralStack.Pop()
|
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("\tldx %s", c.amountVarName))
|
||||||
asm = append(asm, fmt.Sprintf("\tbeq %s", doneLabel))
|
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, loopLabel)
|
||||||
asm = append(asm, fmt.Sprintf("\tlsr %s", c.destVarName))
|
asm = append(asm, "\tlsr")
|
||||||
asm = append(asm, "\tdex")
|
asm = append(asm, "\tdex")
|
||||||
asm = append(asm, fmt.Sprintf("\tbne %s", loopLabel))
|
asm = append(asm, fmt.Sprintf("\tbne %s", loopLabel))
|
||||||
|
|
||||||
|
// Store result
|
||||||
asm = append(asm, doneLabel)
|
asm = append(asm, doneLabel)
|
||||||
|
asm = append(asm, fmt.Sprintf("\tsta %s", c.destVarName))
|
||||||
|
|
||||||
return asm, nil
|
return asm, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -366,10 +366,10 @@ func TestShiftRCommand_Generate(t *testing.T) {
|
||||||
},
|
},
|
||||||
wantLines: []string{
|
wantLines: []string{
|
||||||
"\tlda #$08",
|
"\tlda #$08",
|
||||||
|
"\tlsr",
|
||||||
|
"\tlsr",
|
||||||
|
"\tlsr",
|
||||||
"\tsta result",
|
"\tsta result",
|
||||||
"\tlsr result",
|
|
||||||
"\tlsr result",
|
|
||||||
"\tlsr result",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -450,14 +450,14 @@ func TestShiftRCommand_Generate(t *testing.T) {
|
||||||
},
|
},
|
||||||
wantLines: []string{
|
wantLines: []string{
|
||||||
"\tlda value",
|
"\tlda value",
|
||||||
"\tsta result",
|
|
||||||
"\tldx shift",
|
"\tldx shift",
|
||||||
"\tbeq _L2",
|
"\tbeq _L2",
|
||||||
"_L1",
|
"_L1",
|
||||||
"\tlsr result",
|
"\tlsr",
|
||||||
"\tdex",
|
"\tdex",
|
||||||
"\tbne _L1",
|
"\tbne _L1",
|
||||||
"_L2",
|
"_L2",
|
||||||
|
"\tsta result",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -509,13 +509,15 @@ func TestShiftRCommand_Generate(t *testing.T) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
wantLines: []string{
|
wantLines: []string{
|
||||||
|
"\tlda value",
|
||||||
"\tldx shift",
|
"\tldx shift",
|
||||||
"\tbeq _L2",
|
"\tbeq _L2",
|
||||||
"_L1",
|
"_L1",
|
||||||
"\tlsr value",
|
"\tlsr",
|
||||||
"\tdex",
|
"\tdex",
|
||||||
"\tbne _L1",
|
"\tbne _L1",
|
||||||
"_L2",
|
"_L2",
|
||||||
|
"\tsta value",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue