package org.reasm.m68k.assembly.internal; import javax.annotation.Nonnull; import org.reasm.Function; import org.reasm.ValueVisitor; import org.reasm.commons.messages.RelativeBranchTargetOutOfRangeErrorMessage; import org.reasm.m68k.messages.LabelExpectedErrorMessage; final class BranchLabelValueVisitor implements ValueVisitor<Void> { @Nonnull private final M68KAssemblyContext context; @Nonnull private InstructionSize size = InstructionSize.DEFAULT; @Nonnull InstructionSize outputSize = InstructionSize.DEFAULT; int distance; BranchLabelValueVisitor(@Nonnull M68KAssemblyContext context) { this.context = context; } @Override public Void visitFloat(double value) { this.context.addTentativeMessage(new LabelExpectedErrorMessage()); return null; } @Override public Void visitFunction(Function value) { this.context.addTentativeMessage(new LabelExpectedErrorMessage()); return null; } @Override public Void visitSignedInt(long value) { value -= this.context.programCounter + 2; switch (this.size) { case BYTE: if (!(value >= -0x80 && value <= 0x7F)) { this.context.addTentativeMessage(new RelativeBranchTargetOutOfRangeErrorMessage(value)); } break; case DEFAULT: default: if (this.context.optimizeUnsizedBranches) { final InstructionSize outputSize; if (value >= -0x80 && value <= 0x7F && value != 0 && value != -1) { // byte size outputSize = InstructionSize.BYTE; } else { final boolean fitsInWord = value >= -0x8000 && value <= 0x7FFF; if (!InstructionSetCheck.MC68020_OR_LATER.isSupported(this.context.instructionSet) || fitsInWord) { if (!fitsInWord) { this.context.addTentativeMessage(new RelativeBranchTargetOutOfRangeErrorMessage(value)); } // word size outputSize = InstructionSize.WORD; } else { if (!(value >= -0x80000000 && value <= 0x7FFFFFFF)) { this.context.addTentativeMessage(new RelativeBranchTargetOutOfRangeErrorMessage(value)); } // long size outputSize = InstructionSize.LONG; } } this.outputSize = outputSize; break; } // fall-through case WORD: if (!(value >= -0x8000 && value <= 0x7FFF)) { this.context.addTentativeMessage(new RelativeBranchTargetOutOfRangeErrorMessage(value)); } break; case LONG: if (!(value >= -0x80000000 && value <= 0x7FFFFFFF)) { this.context.addTentativeMessage(new RelativeBranchTargetOutOfRangeErrorMessage(value)); } break; } this.distance = (int) value; return null; } @Override public Void visitString(String value) { this.context.addTentativeMessage(new LabelExpectedErrorMessage()); return null; } @Override public Void visitUndetermined() { return null; } @Override public Void visitUnsignedInt(long value) { return this.visitSignedInt(value); } void reset(@Nonnull InstructionSize size) { this.size = size; } }