Optimized equality and non equality tests with zero in comparison.go

This commit is contained in:
Mattias Hansson 2025-11-06 07:09:19 +01:00
parent af315647bd
commit 2dc591f40d

View file

@ -180,6 +180,21 @@ func (cg *comparisonGenerator) tempLabel() string {
return label
}
// isZeroLiteral checks if operand is literal 0
func (cg *comparisonGenerator) isZeroLiteral(op *operandInfo) bool {
return !op.isVar && op.value == 0
}
// genLoadAndTest generates load with optional compare for zero optimization
func (cg *comparisonGenerator) genLoadAndTest(loadOp *operandInfo, cmpOp *operandInfo, offset int) []string {
code := []string{cg.loadOperand(loadOp, offset)}
// Skip CMP when comparing with zero - Z flag already set by LDA
if !cg.isZeroLiteral(cmpOp) {
code = append(code, cg.cmpOperand(cmpOp, offset))
}
return code
}
// extractByteWord separates byte and word operands
func (cg *comparisonGenerator) extractByteWord() (byte, word *operandInfo) {
if cg.kind1 == compiler.KindByte {
@ -205,76 +220,69 @@ func (cg *comparisonGenerator) genEqual() ([]string, error) {
}
func (cg *comparisonGenerator) genByteEqual() ([]string, error) {
code := cg.genLoadAndTest(cg.param1, cg.param2, 0)
if !cg.useLongJump {
return []string{
cg.loadOperand(cg.param1, 0),
cg.cmpOperand(cg.param2, 0),
fmt.Sprintf("\tbne %s", cg.skipLabel),
}, nil
code = append(code, fmt.Sprintf("\tbne %s", cg.skipLabel))
return code, nil
}
success := cg.tempLabel()
return []string{
cg.loadOperand(cg.param1, 0),
cg.cmpOperand(cg.param2, 0),
code = append(code,
fmt.Sprintf("\tbeq %s", success),
fmt.Sprintf("\tjmp %s", cg.skipLabel),
success,
}, nil
)
return code, nil
}
func (cg *comparisonGenerator) genWordEqual() ([]string, error) {
code := cg.genLoadAndTest(cg.param1, cg.param2, 0)
if !cg.useLongJump {
return []string{
cg.loadOperand(cg.param1, 0),
cg.cmpOperand(cg.param2, 0),
fmt.Sprintf("\tbne %s", cg.skipLabel),
cg.loadOperand(cg.param1, 1),
cg.cmpOperand(cg.param2, 1),
fmt.Sprintf("\tbne %s", cg.skipLabel),
}, nil
code = append(code, fmt.Sprintf("\tbne %s", cg.skipLabel))
code = append(code, cg.genLoadAndTest(cg.param1, cg.param2, 1)...)
code = append(code, fmt.Sprintf("\tbne %s", cg.skipLabel))
return code, nil
}
success := cg.tempLabel()
fail := cg.tempLabel()
return []string{
cg.loadOperand(cg.param1, 0),
cg.cmpOperand(cg.param2, 0),
fmt.Sprintf("\tbne %s", fail),
cg.loadOperand(cg.param1, 1),
cg.cmpOperand(cg.param2, 1),
code = append(code, fmt.Sprintf("\tbne %s", fail))
code = append(code, cg.genLoadAndTest(cg.param1, cg.param2, 1)...)
code = append(code,
fmt.Sprintf("\tbeq %s", success),
fail,
fmt.Sprintf("\tjmp %s", cg.skipLabel),
success,
}, nil
)
return code, nil
}
func (cg *comparisonGenerator) genMixedEqual() ([]string, error) {
byteOp, wordOp := cg.extractByteWord()
// Check if word high byte != 0 (means can't be equal)
code := []string{cg.loadOperand(wordOp, 1)}
code = append(code, fmt.Sprintf("\tbne %s", cg.skipLabel))
// High byte is 0, compare low bytes
code = append(code, cg.genLoadAndTest(wordOp, byteOp, 0)...)
if !cg.useLongJump {
return []string{
cg.loadOperand(wordOp, 1),
fmt.Sprintf("\tbne %s", cg.skipLabel),
cg.loadOperand(byteOp, 0),
cg.cmpOperand(wordOp, 0),
fmt.Sprintf("\tbne %s", cg.skipLabel),
}, nil
code = append(code, fmt.Sprintf("\tbne %s", cg.skipLabel))
return code, nil
}
success := cg.tempLabel()
fail := cg.tempLabel()
return []string{
cg.loadOperand(wordOp, 1),
fmt.Sprintf("\tbne %s", fail),
cg.loadOperand(byteOp, 0),
cg.cmpOperand(wordOp, 0),
code = append(code,
fmt.Sprintf("\tbeq %s", success),
fail,
fmt.Sprintf("\tjmp %s", cg.skipLabel),
success,
}, nil
)
return code, nil
}
// != operator
@ -291,76 +299,72 @@ func (cg *comparisonGenerator) genNotEqual() ([]string, error) {
}
func (cg *comparisonGenerator) genByteNotEqual() ([]string, error) {
code := cg.genLoadAndTest(cg.param1, cg.param2, 0)
if !cg.useLongJump {
return []string{
cg.loadOperand(cg.param1, 0),
cg.cmpOperand(cg.param2, 0),
fmt.Sprintf("\tbeq %s", cg.skipLabel),
}, nil
code = append(code, fmt.Sprintf("\tbeq %s", cg.skipLabel))
return code, nil
}
success := cg.tempLabel()
return []string{
cg.loadOperand(cg.param1, 0),
cg.cmpOperand(cg.param2, 0),
code = append(code,
fmt.Sprintf("\tbne %s", success),
fmt.Sprintf("\tjmp %s", cg.skipLabel),
success,
}, nil
)
return code, nil
}
func (cg *comparisonGenerator) genWordNotEqual() ([]string, error) {
success := cg.tempLabel()
code := cg.genLoadAndTest(cg.param1, cg.param2, 0)
if !cg.useLongJump {
return []string{
cg.loadOperand(cg.param1, 0),
cg.cmpOperand(cg.param2, 0),
fmt.Sprintf("\tbne %s", success),
cg.loadOperand(cg.param1, 1),
cg.cmpOperand(cg.param2, 1),
code = append(code, fmt.Sprintf("\tbne %s", success))
code = append(code, cg.genLoadAndTest(cg.param1, cg.param2, 1)...)
code = append(code,
fmt.Sprintf("\tbne %s", success),
fmt.Sprintf("\tjmp %s", cg.skipLabel),
success,
}, nil
)
return code, nil
}
return []string{
cg.loadOperand(cg.param1, 0),
cg.cmpOperand(cg.param2, 0),
fmt.Sprintf("\tbne %s", success),
cg.loadOperand(cg.param1, 1),
cg.cmpOperand(cg.param2, 1),
code = append(code, fmt.Sprintf("\tbne %s", success))
code = append(code, cg.genLoadAndTest(cg.param1, cg.param2, 1)...)
code = append(code,
fmt.Sprintf("\tbne %s", success),
fmt.Sprintf("\tjmp %s", cg.skipLabel),
success,
}, nil
)
return code, nil
}
func (cg *comparisonGenerator) genMixedNotEqual() ([]string, error) {
byteOp, wordOp := cg.extractByteWord()
success := cg.tempLabel()
// Check if word high byte != 0 (means values definitely not equal)
code := []string{cg.loadOperand(wordOp, 1)}
code = append(code, fmt.Sprintf("\tbne %s", success))
// High byte is 0, compare low bytes
code = append(code, cg.genLoadAndTest(wordOp, byteOp, 0)...)
if !cg.useLongJump {
return []string{
cg.loadOperand(wordOp, 1),
fmt.Sprintf("\tbne %s", success),
cg.loadOperand(byteOp, 0),
cg.cmpOperand(wordOp, 0),
code = append(code,
fmt.Sprintf("\tbeq %s", cg.skipLabel),
success,
}, nil
)
return code, nil
}
return []string{
cg.loadOperand(wordOp, 1),
fmt.Sprintf("\tbne %s", success),
cg.loadOperand(byteOp, 0),
cg.cmpOperand(wordOp, 0),
code = append(code,
fmt.Sprintf("\tbne %s", success),
fmt.Sprintf("\tjmp %s", cg.skipLabel),
success,
}, nil
)
return code, nil
}
// > operator (unsigned)