if (tdb)
MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
- if ((v == 0) && CHECK_OPTS(OPT_INDIRECT_DISP) && !movep)
+ if ((v == 0) && CHECK_OPTS(OPT_OUTER_DISP) && !movep)
{
// If expr is 0, size optimise the opcode. Generally the lower
// 6 bits of the opcode for expr(ax) are 101rrr where rrr=the
chptr_opcode[1] |= 0x0080 & 255; // slap in 010 bits
}
- if (sbra_flag)
+ if (optim_warn_flag)
warn("0(An) converted to (An)");
return OK;
case ABSL:
if (w) // Defined
{
- if (optim_pc)
+ if (CHECK_OPTS(OPT_PC_RELATIVE))
if (aNexattr&(DEFINED | REFERENCED | EQUATED) == DEFINED | REFERENCED)
return error("relocation not allowed");
{
inst = B16(01010000, 01001000) | (((uint16_t)a0exval & 7) << 9) | (a0reg);
D_word(inst);
- warn("lea size(An),An converted to addq #size,An");
+ if (optim_warn_flag)
+ warn("lea size(An),An converted to addq #size,An");
return OK;
}
//
int m_adda(WORD inst, WORD siz)
{
- if (a0exattr & DEFINED)
+ if ((a0exattr & DEFINED) && (am0 == IMMED))
{
- if (CHECK_OPTS(OPT_ADDA_ADDQ))
+ if (CHECK_OPTS(OPT_ADDA_ADDQ))
if (a0exval > 1 && a0exval <= 8)
+ {
// Immediate is between 1 and 8 so let's convert to addq
return m_addq(B16(01010000, 00000000), siz);
- if (CHECK_OPTS(OPT_ADDA_LEA))
- if (a0exval > 8 && (a0exval+0x8000)<0x10000)
- {
- // Immediate is larger than 8 and word size so let's convert to lea
- am0 = ADISP; // Change addressing mode
- a0reg = a1reg; // In ADISP a0reg is used instead of a1reg!
- if (!(inst & (1 << 14)))
+ if (optim_warn_flag)
+ warn("adda/suba size(An),An converted to addq/subq #size,An");
+ }
+ if (CHECK_OPTS(OPT_ADDA_LEA))
+ if (a0exval > 8 && (a0exval + 0x8000) < 0x10000)
{
- // We have a suba #x,AREG so let's negate the value
- a0exval = -a0exval;
+ // Immediate is larger than 8 and word size so let's convert to lea
+ am0 = ADISP; // Change addressing mode
+ a0reg = a1reg; // In ADISP a0reg is used instead of a1reg!
+ if (!(inst & (1 << 14)))
+ {
+ // We have a suba #x,AREG so let's negate the value
+ a0exval = -a0exval;
+ }
+
+ // We're going to rely on +o4 for this, so let's ensure that it's on,
+ // even just for this instruction
+ int return_value;
+ int temp_flag = optim_flags[OPT_LEA_ADDQ];
+ optim_flags[OPT_LEA_ADDQ] = 1; // Temporarily save switch state
+ return_value = m_lea(B16(01000001, 11011000), SIZW);
+ optim_flags[OPT_LEA_ADDQ] = temp_flag; // Restore switch state
+ return return_value;
}
- return m_lea(B16(01000001, 11011000), SIZW);
- }
}
inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
{
m_moveq((WORD)0x7000, (WORD)0);
- if (sbra_flag)
+ if (optim_warn_flag)
warn("move.l #size,dx converted to moveq");
}
else
inst |= v & 0xFF;
D_word(inst);
- if (sbra_flag)
+ if (optim_warn_flag)
warn("Bcc.w/BSR.w converted to .s");
return OK;
{
// .B
AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
- D_word(inst);
+ // So here we have a small issue: this bra.s could be zero offset, but we can never know.
+ // Because unless we know beforehand that the offset will be zero (i.e. "bra.s +0"), it's
+ // going to be a label below this instruction! We do have an optimisation flag that can
+ // check against this during fixups, but we cannot rely on the state of the flag after
+ // all the file(s) have been processed because its state might have changed multiple times
+ // during file parsing. (Yes, there's a very low chance that this will ever happen but
+ // it's not zero!). So, we can use the byte that is going to be filled during fixups
+ // to store the state of the optimisation flag and read it during that stage so each bra.s
+ // will have its state stored neatly. Sleazy? Eh, who cares, like this will ever happen ;)
+ // One final note: we'd better be damn sure that the flag's value is less than 256 or
+ // magical stuff will happen!
+ D_word(inst|optim_flags[OPT_NULL_BRA]);
return OK;
}
else
{
expr(AnBEXPR, &AnBEXVAL, &AnBEXATTR, &AnESYM);
- if (CHECK_OPTS(OPT_BASE_DISP) && AnBEXVAL == 0 && AnEXATTR != 0)
+ if (CHECK_OPTS(OPT_020_DISP) && AnBEXVAL == 0 && AnEXATTR != 0)
{
// bd=0 so let's optimise it out
AnEXTEN|=EXT_BDSIZE0;
{
// Defined, absolute values from $FFFF8000..$00007FFF
// get optimized to absolute short
- if (CHECK_OPTS(OPT_ABS_SHORT)
+ if (CHECK_OPTS(OPT_020_DISP)
&& ((AnBEXATTR & (TDB | DEFINED)) == DEFINED)
&& (((uint32_t)AnBEXVAL + 0x8000) < 0x10000))
{
AnEXTEN |= EXT_BDSIZEW;
- warn("absolute value in base displacement ranging $FFFF8000..$00007FFF optimised to absolute short");
+ if (optim_warn_flag)
+ warn("absolute value in base displacement ranging $FFFF8000..$00007FFF optimised to absolute short");
}
else
{
else if (*tok == ']')
{
// PC and Xn is suppressed
- AnREG = 6 << 3; // stuff 110 to mode field
- //AnEXTEN|=EXT_BS|EXT_IS;
+ AnREG = 6 << 3; // stuff 110b to mode field
AnEXTEN |= EXT_BS;
}
else
// At a crossroads here. We can accept either ([bd,An/PC],... or ([bd,An/PC,Xn*scale],...
if (*tok == ']')
{
- //([bd,An/PC],Xn,od)
+ // ([bd,An/PC],Xn,od)
// Check for Xn
tok++;
if (*tok == ')')
{
- //Xn and od are non existent, get out of jail free card
+ // Xn and od are non existent, get out of jail free card
tok++;
AMn = MEMPRE; // ([bc,An,Xn],od) with no Xn and od
- AnEXTEN |= EXT_IS | EXT_IISPREN; //Suppress Xn and od
+ AnEXTEN |= EXT_IS | EXT_IISPREN; // Suppress Xn and od
goto AnOK;
}
else if (*tok != ',')
}
else
{
- //No index found, suppress it
+ // No index found, suppress it
AnEXTEN |= EXT_IS;
tok--; // Rewind tok to point to the comma
goto IS_SUPPRESSEDn; // https://xkcd.com/292/ - what does he know anyway?
if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
goto badmode;
- if (CHECK_OPTS(OPT_BASE_DISP) && (AnEXATTR & DEFINED) && (AnEXVAL == 0))
+ if (CHECK_OPTS(OPT_020_DISP) && (AnEXATTR & DEFINED) && (AnEXVAL == 0))
{
// od=0 so optimise it out
AMn = MEMPOST; // let's say it's ([bd,An],Xn,od) with od=0 then
// Defined, absolute values from $FFFF8000..$00007FFF get
// optimized to absolute short
- if (CHECK_OPTS(OPT_ABS_SHORT)
+ if (CHECK_OPTS(OPT_020_DISP)
&& ((AnEXATTR & (TDB | DEFINED)) == DEFINED)
&& (((uint32_t)AnEXVAL + 0x8000) < 0x10000))
{
AnEXTEN |= EXT_IISPOSW; // Word outer displacement
AMn = MEMPOST;
- warn("outer displacement absolute value from $FFFF8000..$00007FFF optimised to absolute short");
+ if (optim_warn_flag)
+ warn("absolute value in outer displacement ranging $FFFF8000..$00007FFF optimised to absolute short");
}
}
expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM);
- if (CHECK_OPTS(OPT_BASE_DISP) && (AnEXVAL == 0))
+ if (CHECK_OPTS(OPT_020_DISP) && (AnEXVAL == 0))
{
// od=0 so optimise it out
AMn = MEMPOST; // let's say it's ([bd,An],Xn,od) with od=0 then
}
// Defined, absolute values from $FFFF8000..$00007FFF get
// optimized to absolute short
- else if (CHECK_OPTS(OPT_BASE_DISP)
+ else if (CHECK_OPTS(OPT_020_DISP)
&& ((AnEXATTR & (TDB | DEFINED)) == DEFINED)
&& (((uint32_t)AnEXVAL + 0x8000) < 0x10000))
{
//AnEXTEN|=EXT_IISNOIW; // Word outer displacement with IS suppressed
- warn("outer displacement absolute value from $FFFF8000..$00007FFF optimised to absolute short");
+ if (optim_warn_flag)
+ warn("outer displacement absolute value from $FFFF8000..$00007FFF optimised to absolute short");
}
}
if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
goto badmode;
- if (CHECK_OPTS(OPT_BASE_DISP) && (AnEXVAL == 0) && (AnEXATTR & DEFINED))
+ if (CHECK_OPTS(OPT_020_DISP) && (AnEXVAL == 0) && (AnEXATTR & DEFINED))
{
// od=0 so optimise it out
AMn = MEMPRE; // let's say it's ([bd,An],Xn,od) with od=0 then
// Defined, absolute values from $FFFF8000..$00007FFF
// get optimized to absolute short
- if (CHECK_OPTS(OPT_BASE_DISP)
+ if (CHECK_OPTS(OPT_020_DISP)
&& ((AnEXATTR & (TDB | DEFINED)) == DEFINED)
&& (((uint32_t)AnEXVAL + 0x8000) < 0x10000))
{
expr_size = EXT_IISPREW;
- warn("outer displacement absolute value from $FFFF8000..$00007FFF optimised to absolute short");
+ if (optim_warn_flag)
+ warn("outer displacement absolute value from $FFFF8000..$00007FFF optimised to absolute short");
}
}
// When PC relative is enforced, check for any symbols that aren't
// EQU'd, in this case it's an illegal mode
- if (optim_pc)
+ if (CHECK_OPTS(OPT_PC_RELATIVE))
if (AnEXATTR & REFERENCED)
if (AnEXATTR & DEFINED)
if (!(AnEXATTR & EQUATED))
{
AMn = ABSW;
- if (sbra_flag)
+ if (optim_warn_flag)
warn("absolute value from $FFFF8000..$00007FFF optimised to absolute short");
}
}
int as68_flag; // as68 kludge mode
int glob_flag; // Assume undefined symbols are global
int lsym_flag; // Include local symbols in object file
-int sbra_flag; // Warn about possible short branches
+int optim_warn_flag; // Warn about possible short branches
int prg_flag; // !=0, produce .PRG executable (2=symbols)
int prg_extend; // !=0, output extended .PRG symbols
int legacy_flag; // Do stuff like insert code in RISC assembler
char * searchpath = NULL; // Search path for include files
char defname[] = "noname.o"; // Default output filename
int optim_flags[OPT_COUNT]; // Specific optimisations on/off matrix
-int optim_pc = 0; // Enforce PC relative
int activecpu = CPU_68000; // Active 68k CPU (68000 by default)
int activefpu = FPU_NONE; // Active FPU (none by default)
int org68k_active = 0; // .org switch for 68k (only with RAW output format)
" -o file Output file name\n"
" +o[value] Turn a specific optimisation on\n"
" Available optimisation values and default settings:\n"
- " o0: Absolute long adddresses to word (on)\n"
- " o1: move.l #x,dn/an to moveq (on)\n"
- " o2: Word branches to short (on)\n"
- " o3: Outer displacement 0(an) to (an) (off)\n"
- " o4: lea size(An),An to addq #size,An (off)\n"
- " o5: Absolute long base displacement to word (off)\n"
- " o6: Null branches to NOP (off)\n"
- " o7: clr.l Dx to moveq #0,Dx (off)\n"
- " o8: adda.w/l #x,Dy to addq.w/l #x,Dy (off)\n"
- " o9: adda.w/l #x,Dy to lea x(Dy),Dy (off)\n"
- " op: Enforce PC relative (off)\n"
+ " o0: Absolute long addresses to word (on)\n"
+ " o1: move.l #x,dn/an to moveq (on)\n"
+ " o2: Word branches to short (on)\n"
+ " o3: Outer displacement 0(an) to (an) (off)\n"
+ " o4: lea size(An),An to addq #size,An (off)\n"
+ " o5: 68020+ Absolute long base/outer displacement to word (off)\n"
+ " o6: Null branches to NOP (off)\n"
+ " o7: clr.l Dx to moveq #0,Dx (off)\n"
+ " o8: adda.w/l #x,Dy to addq.w/l #x,Dy (off)\n"
+ " o9: adda.w/l #x,Dy to lea x(Dy),Dy (off)\n"
+ " op: Enforce PC relative (off)\n"
" ~o[value] Turn a specific optimisation off\n"
" +oall Turn all optimisations on\n"
" ~oall Turn all optimisations off\n"
{
int onoff = 0;
- if (*optstring == '+')
- onoff = 1;
- else if (*optstring != '~')
- return ERROR;
-
- if ((optstring[2] == 'a' || optstring[2] == 'A')
- && (optstring[3] == 'l' || optstring[3] == 'L')
- && (optstring[4] == 'l' || optstring[4] == 'L'))
- {
- memset(optim_flags, onoff, OPT_COUNT * sizeof(int));
- return OK;
- }
- else if (optstring[1] == 'o' || optstring[1] == 'O') // Turn on specific optimisation
+ while (*optstring)
{
- if (optstring[2] == 'p' || optstring[2] == 'P')
+ if (*optstring == '+')
+ onoff = 1;
+ else if (*optstring != '~')
+ return ERROR;
+
+ if ((optstring[2] == 'a' || optstring[2] == 'A')
+ && (optstring[3] == 'l' || optstring[3] == 'L')
+ && (optstring[4] == 'l' || optstring[4] == 'L'))
{
- optim_pc = 1;
- return OK;
+ memset(optim_flags, onoff, OPT_COUNT * sizeof(int));
+ optstring += 5;
}
-
- int opt_no = atoi(&optstring[2]);
-
- if ((opt_no >= 0) && (opt_no < OPT_COUNT))
+ else if (optstring[1] == 'o' || optstring[1] == 'O') // Turn on specific optimisation
{
- optim_flags[opt_no] = onoff;
- return OK;
+ if (optstring[2] == 'p' || optstring[2] == 'P')
+ {
+ optim_flags[OPT_PC_RELATIVE] = onoff;
+ optstring += 3;
+ }
+ else
+ {
+ int opt_no = atoi(&optstring[2]);
+ if ((opt_no >= 0) && (opt_no < OPT_COUNT))
+ {
+ optim_flags[opt_no] = onoff;
+ optstring += 3;
+ // If opt_no is 2 digits then consume an extra character.
+ // Sounds a bit sleazy but we know we're not going to hit
+ // more than 100 optimisation switches so this should be fine.
+ // If we do hit that number then it'll probably be time to burn
+ // the whole codebase and start from scratch.
+ if (opt_no > 9)
+ optstring++;
+ }
+ else
+ return ERROR;
+ }
}
else
+ {
return ERROR;
+ }
+ if (*optstring == ',')
+ optstring++;
}
- else
- {
- return ERROR;
- }
+ return OK;
}
verb_flag = perm_verb_flag; // Initialize verbose flag
as68_flag = 0; // Initialize as68 kludge mode
glob_flag = 0; // Initialize .globl flag
- sbra_flag = 0; // Initialize short branch flag
+ optim_warn_flag = 0; // Initialize short branch flag
debug = 0; // Initialize debug flag
searchpath = NULL; // Initialize search path
objfname = NULL; // Initialize object filename
default: segpadsize = 2; break; // Effective autoeven();
}
break;
- case 's': // Warn about possible short branches
+ case 's': // Warn about possible short branches and applied optimisations
case 'S':
- sbra_flag = 1;
+ optim_warn_flag = 1;
break;
case 'u': // Make undefined symbols .globl
case 'U':
OPT_ABS_SHORT = 0,
OPT_MOVEL_MOVEQ = 1,
OPT_BSR_BCC_S = 2,
- OPT_INDIRECT_DISP = 3,
+ OPT_OUTER_DISP = 3,
OPT_LEA_ADDQ = 4,
- OPT_BASE_DISP = 5,
+ OPT_020_DISP = 5, // 020+ base and outer displacements (bd, od) absolute long to short
OPT_NULL_BRA = 6,
OPT_CLR_DX = 7,
OPT_ADDA_ADDQ = 8,
OPT_ADDA_LEA = 9,
+ OPT_PC_RELATIVE = 10, // Enforce PC relative
OPT_COUNT // Dummy, used to count number of optimisation switches
};
extern int list_flag;
extern int glob_flag;
extern int lsym_flag;
-extern int sbra_flag;
+extern int optim_warn_flag;
extern int obj_format;
extern int legacy_flag;
extern int prg_flag; // 1 = write ".PRG" relocatable executable
extern LONG PRGFLAGS;
extern int optim_flags[OPT_COUNT];
-extern int optim_pc;
extern int activecpu;
extern int activefpu;
extern uint32_t org68k_address;
if (evexpr(fup->expr, &eval, &eattr, &esym) != OK)
continue;
- if (optim_pc)
+ if (CHECK_OPTS(OPT_PC_RELATIVE))
if (eattr & REFERENCED)
if (eattr & DEFINED)
if (!(eattr & EQUATED))
SYM * sy = fup->symbol;
eattr = sy->sattr;
- if (optim_pc)
+ if (CHECK_OPTS(OPT_PC_RELATIVE))
if (eattr & REFERENCED)
if (eattr & DEFINED)
if (!(eattr & EQUATED))
}
}
- if (sbra_flag && (dw & FU_LBRA) && (eval + 0x80 < 0x100))
+ if (optim_warn_flag && (dw & FU_LBRA) && (eval + 0x80 < 0x100))
warn("unoptimized short branch");
}
if (eval == 0)
{
- if (CHECK_OPTS(OPT_NULL_BRA))
+ if (*locp) // optim_flags[OPT_NULL_BRA] is stored there, check the comment in mach.s under m_br
{
// Just output a NOP
*locp++ = 0x4E;
*locp = 0x71;
+ if (optim_warn_flag)
+ warn("bra.s with zero offset converted to NOP");
continue;
}
else