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 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 // extractByteWord separates byte and word operands
func (cg *comparisonGenerator) extractByteWord() (byte, word *operandInfo) { func (cg *comparisonGenerator) extractByteWord() (byte, word *operandInfo) {
if cg.kind1 == compiler.KindByte { if cg.kind1 == compiler.KindByte {
@ -205,76 +220,69 @@ func (cg *comparisonGenerator) genEqual() ([]string, error) {
} }
func (cg *comparisonGenerator) genByteEqual() ([]string, error) { func (cg *comparisonGenerator) genByteEqual() ([]string, error) {
code := cg.genLoadAndTest(cg.param1, cg.param2, 0)
if !cg.useLongJump { if !cg.useLongJump {
return []string{ code = append(code, fmt.Sprintf("\tbne %s", cg.skipLabel))
cg.loadOperand(cg.param1, 0), return code, nil
cg.cmpOperand(cg.param2, 0),
fmt.Sprintf("\tbne %s", cg.skipLabel),
}, nil
} }
success := cg.tempLabel() success := cg.tempLabel()
return []string{ code = append(code,
cg.loadOperand(cg.param1, 0),
cg.cmpOperand(cg.param2, 0),
fmt.Sprintf("\tbeq %s", success), fmt.Sprintf("\tbeq %s", success),
fmt.Sprintf("\tjmp %s", cg.skipLabel), fmt.Sprintf("\tjmp %s", cg.skipLabel),
success, success,
}, nil )
return code, nil
} }
func (cg *comparisonGenerator) genWordEqual() ([]string, error) { func (cg *comparisonGenerator) genWordEqual() ([]string, error) {
code := cg.genLoadAndTest(cg.param1, cg.param2, 0)
if !cg.useLongJump { if !cg.useLongJump {
return []string{ code = append(code, fmt.Sprintf("\tbne %s", cg.skipLabel))
cg.loadOperand(cg.param1, 0), code = append(code, cg.genLoadAndTest(cg.param1, cg.param2, 1)...)
cg.cmpOperand(cg.param2, 0), code = append(code, fmt.Sprintf("\tbne %s", cg.skipLabel))
fmt.Sprintf("\tbne %s", cg.skipLabel), return code, nil
cg.loadOperand(cg.param1, 1),
cg.cmpOperand(cg.param2, 1),
fmt.Sprintf("\tbne %s", cg.skipLabel),
}, nil
} }
success := cg.tempLabel() success := cg.tempLabel()
fail := cg.tempLabel() fail := cg.tempLabel()
return []string{ code = append(code, fmt.Sprintf("\tbne %s", fail))
cg.loadOperand(cg.param1, 0), code = append(code, cg.genLoadAndTest(cg.param1, cg.param2, 1)...)
cg.cmpOperand(cg.param2, 0), code = append(code,
fmt.Sprintf("\tbne %s", fail),
cg.loadOperand(cg.param1, 1),
cg.cmpOperand(cg.param2, 1),
fmt.Sprintf("\tbeq %s", success), fmt.Sprintf("\tbeq %s", success),
fail, fail,
fmt.Sprintf("\tjmp %s", cg.skipLabel), fmt.Sprintf("\tjmp %s", cg.skipLabel),
success, success,
}, nil )
return code, nil
} }
func (cg *comparisonGenerator) genMixedEqual() ([]string, error) { func (cg *comparisonGenerator) genMixedEqual() ([]string, error) {
byteOp, wordOp := cg.extractByteWord() 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 { if !cg.useLongJump {
return []string{ code = append(code, fmt.Sprintf("\tbne %s", cg.skipLabel))
cg.loadOperand(wordOp, 1), return code, nil
fmt.Sprintf("\tbne %s", cg.skipLabel),
cg.loadOperand(byteOp, 0),
cg.cmpOperand(wordOp, 0),
fmt.Sprintf("\tbne %s", cg.skipLabel),
}, nil
} }
success := cg.tempLabel() success := cg.tempLabel()
fail := cg.tempLabel() fail := cg.tempLabel()
return []string{ code = append(code,
cg.loadOperand(wordOp, 1),
fmt.Sprintf("\tbne %s", fail),
cg.loadOperand(byteOp, 0),
cg.cmpOperand(wordOp, 0),
fmt.Sprintf("\tbeq %s", success), fmt.Sprintf("\tbeq %s", success),
fail, fail,
fmt.Sprintf("\tjmp %s", cg.skipLabel), fmt.Sprintf("\tjmp %s", cg.skipLabel),
success, success,
}, nil )
return code, nil
} }
// != operator // != operator
@ -291,76 +299,72 @@ func (cg *comparisonGenerator) genNotEqual() ([]string, error) {
} }
func (cg *comparisonGenerator) genByteNotEqual() ([]string, error) { func (cg *comparisonGenerator) genByteNotEqual() ([]string, error) {
code := cg.genLoadAndTest(cg.param1, cg.param2, 0)
if !cg.useLongJump { if !cg.useLongJump {
return []string{ code = append(code, fmt.Sprintf("\tbeq %s", cg.skipLabel))
cg.loadOperand(cg.param1, 0), return code, nil
cg.cmpOperand(cg.param2, 0),
fmt.Sprintf("\tbeq %s", cg.skipLabel),
}, nil
} }
success := cg.tempLabel() success := cg.tempLabel()
return []string{ code = append(code,
cg.loadOperand(cg.param1, 0),
cg.cmpOperand(cg.param2, 0),
fmt.Sprintf("\tbne %s", success), fmt.Sprintf("\tbne %s", success),
fmt.Sprintf("\tjmp %s", cg.skipLabel), fmt.Sprintf("\tjmp %s", cg.skipLabel),
success, success,
}, nil )
return code, nil
} }
func (cg *comparisonGenerator) genWordNotEqual() ([]string, error) { func (cg *comparisonGenerator) genWordNotEqual() ([]string, error) {
success := cg.tempLabel() success := cg.tempLabel()
code := cg.genLoadAndTest(cg.param1, cg.param2, 0)
if !cg.useLongJump { if !cg.useLongJump {
return []string{ code = append(code, fmt.Sprintf("\tbne %s", success))
cg.loadOperand(cg.param1, 0), code = append(code, cg.genLoadAndTest(cg.param1, cg.param2, 1)...)
cg.cmpOperand(cg.param2, 0), code = append(code,
fmt.Sprintf("\tbne %s", success),
cg.loadOperand(cg.param1, 1),
cg.cmpOperand(cg.param2, 1),
fmt.Sprintf("\tbne %s", success), fmt.Sprintf("\tbne %s", success),
fmt.Sprintf("\tjmp %s", cg.skipLabel), fmt.Sprintf("\tjmp %s", cg.skipLabel),
success, success,
}, nil )
return code, nil
} }
return []string{ code = append(code, fmt.Sprintf("\tbne %s", success))
cg.loadOperand(cg.param1, 0), code = append(code, cg.genLoadAndTest(cg.param1, cg.param2, 1)...)
cg.cmpOperand(cg.param2, 0), code = append(code,
fmt.Sprintf("\tbne %s", success),
cg.loadOperand(cg.param1, 1),
cg.cmpOperand(cg.param2, 1),
fmt.Sprintf("\tbne %s", success), fmt.Sprintf("\tbne %s", success),
fmt.Sprintf("\tjmp %s", cg.skipLabel), fmt.Sprintf("\tjmp %s", cg.skipLabel),
success, success,
}, nil )
return code, nil
} }
func (cg *comparisonGenerator) genMixedNotEqual() ([]string, error) { func (cg *comparisonGenerator) genMixedNotEqual() ([]string, error) {
byteOp, wordOp := cg.extractByteWord() byteOp, wordOp := cg.extractByteWord()
success := cg.tempLabel() 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 { if !cg.useLongJump {
return []string{ code = append(code,
cg.loadOperand(wordOp, 1),
fmt.Sprintf("\tbne %s", success),
cg.loadOperand(byteOp, 0),
cg.cmpOperand(wordOp, 0),
fmt.Sprintf("\tbeq %s", cg.skipLabel), fmt.Sprintf("\tbeq %s", cg.skipLabel),
success, success,
}, nil )
return code, nil
} }
return []string{ code = append(code,
cg.loadOperand(wordOp, 1),
fmt.Sprintf("\tbne %s", success),
cg.loadOperand(byteOp, 0),
cg.cmpOperand(wordOp, 0),
fmt.Sprintf("\tbne %s", success), fmt.Sprintf("\tbne %s", success),
fmt.Sprintf("\tjmp %s", cg.skipLabel), fmt.Sprintf("\tjmp %s", cg.skipLabel),
success, success,
}, nil )
return code, nil
} }
// > operator (unsigned) // > operator (unsigned)