diff --git a/internal/commands/comparison.go b/internal/commands/comparison.go index 0b82765..4e3572c 100644 --- a/internal/commands/comparison.go +++ b/internal/commands/comparison.go @@ -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)