Fix carry usage check in inline assembler, add optional volatile to __asm

This commit is contained in:
drmortalwombat 2025-03-12 08:11:23 +01:00
parent 1c7d71cadb
commit c98e0751b0
5 changed files with 71 additions and 22 deletions

View File

@ -935,6 +935,11 @@ The compiler provides two levels of interrupt safe functions. The specifier __i
return 0
}
### Assembler optimizer
The compiler uses various optimizations on inline assembler that may not have the expected result in all cases. The optimizer can be disabled for a range of code with e.g. #pragma optimize(noasm) or for an individual __asm statement by using __asm volatile {}.
The assembler optimizer is enabled with optimization levels O2 and up.
# Helping the compiler optimizing
The compiler does various optimization when compiling the code, but there are some rules to follow, things to avoid and hints to place to help the compiler to generate optimal code.

View File

@ -4335,6 +4335,9 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
jins->mDst.mTemp = proc->AddTemporary(IT_INT32);
jins->mDst.mType = IT_INT32;
if (dec->mFlags & DTF_VOLATILE)
jins->mVolatile = true;
jins->mSrc[0].mType = IT_POINTER;
jins->mSrc[0].mTemp = ins->mDst.mTemp;
jins->mNumOperands = 1;

View File

@ -642,6 +642,8 @@ bool NativeCodeInstruction::IsUsedResultInstructions(NumberSet& requiredTemps)
requiredTemps += CPU_REG_X;
if (mFlags & NCIF_USE_CPU_REG_Y)
requiredTemps += CPU_REG_Y;
if (mFlags & NCIF_USE_CPU_REG_C)
requiredTemps += CPU_REG_C;
if (mFlags & NCIF_RUNTIME)
{
@ -1611,9 +1613,17 @@ bool NativeCodeInstruction::ChangesGlobalMemory(void) const
bool NativeCodeInstruction::RequiresCarry(void) const
{
return
mType == ASMIT_ADC || mType == ASMIT_SBC ||
mType == ASMIT_ROL || mType == ASMIT_ROR;
if (mType == ASMIT_ADC || mType == ASMIT_SBC ||
mType == ASMIT_ROL || mType == ASMIT_ROR)
{
return true;
}
else if (mType == ASMIT_JSR)
{
return mFlags & NCIF_USE_CPU_REG_C;
}
else
return false;
}
bool NativeCodeInstruction::ChangesZFlag(void) const
@ -4706,6 +4716,11 @@ void NativeCodeInstruction::FilterRegUsage(NumberSet& requiredTemps, NumberSet&
if (!providedTemps[CPU_REG_Y])
requiredTemps += CPU_REG_Y;
}
if (mFlags & NCIF_USE_CPU_REG_C)
{
if (!providedTemps[CPU_REG_C])
requiredTemps += CPU_REG_C;
}
if (mFlags & NCIF_RUNTIME)
{
@ -14297,7 +14312,7 @@ void NativeCodeBasicBlock::CallAssembler(InterCodeProcedure* proc, NativeCodePro
assert(ins->mSrc[0].mLinkerObject);
if (ins->mCode == IC_ASSEMBLER && (proc->mCompilerOptions & COPT_OPTIMIZE_ASSEMBLER) && ins->mSrc[0].mLinkerObject->mSection == proc->mLinkerObject->mSection)
if (ins->mCode == IC_ASSEMBLER && (proc->mCompilerOptions & COPT_OPTIMIZE_ASSEMBLER) && ins->mSrc[0].mLinkerObject->mSection == proc->mLinkerObject->mSection && !ins->mVolatile)
{
ExpandingArray<NativeCodeInstruction> tains;
@ -14339,6 +14354,8 @@ void NativeCodeBasicBlock::CallAssembler(InterCodeProcedure* proc, NativeCodePro
uflags |= NCIF_USE_CPU_REG_X;
if (dins.ChangesYReg())
uflags |= NCIF_USE_CPU_REG_Y;
if (dins.ChangesCarry())
uflags |= NCIF_USE_CPU_REG_C;
tains.Push(dins);
}

View File

@ -133,13 +133,14 @@ static const uint32 NCIF_ALIASING = 0x00000800;
static const uint32 NCIF_USE_CPU_REG_A = 0x00001000;
static const uint32 NCIF_USE_CPU_REG_X = 0x00002000;
static const uint32 NCIF_USE_CPU_REG_Y = 0x00004000;
static const uint32 NCIF_USE_CPU_REG_C = 0x00008000;
// use a 32bit zero page register indexed by X for JSR
static const uint32 NCIF_USE_ZP_32_X = 0x00008000;
static const uint32 NICF_USE_ZP_ADDR = 0x00010000;
static const uint32 NICF_USE_WORKREGS = 0x00020000;
static const uint32 NCIF_USE_ZP_32_X = 0x00010000;
static const uint32 NICF_USE_ZP_ADDR = 0x00020000;
static const uint32 NICF_USE_WORKREGS = 0x00040000;
static const uint32 NCIF_BREAKPOINT = 0x00040000;
static const uint32 NCIF_BREAKPOINT = 0x00080000;
class NativeCodeInstruction
{

View File

@ -6866,11 +6866,18 @@ Expression* Parser::ParseSimpleExpression(bool lhs, bool tid)
}
break;
case TK_ASM:
{
mScanner->NextToken();
bool vol = ConsumeTokenIf(TK_VOLATILE);
if (mScanner->mToken == TK_OPEN_BRACE)
{
mScanner->NextToken();
exp = ParseAssembler();
if (vol)
exp->mDecValue->mFlags |= DTF_VOLATILE;
exp->mDecType = TheSignedLongTypeDeclaration;
if (mScanner->mToken == TK_CLOSE_BRACE)
mScanner->NextToken();
@ -6882,7 +6889,7 @@ Expression* Parser::ParseSimpleExpression(bool lhs, bool tid)
mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "'{' expected");
exp = new Expression(mScanner->mLocation, EX_VOID);
}
break;
} break;
default:
mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Term starts with invalid token", TokenNames[mScanner->mToken]);
mScanner->NextToken();
@ -9885,6 +9892,8 @@ Expression* Parser::ParseStatement(void)
{
mScanner->NextToken();
ParsePragma();
if (mScanner->mToken == TK_CLOSE_BRACE)
return nullptr;
}
if (mScanner->mToken == TK_OPEN_BRACE)
@ -9901,21 +9910,24 @@ Expression* Parser::ParseStatement(void)
do
{
Expression* nexp = ParseStatement();
if (exp)
if (nexp)
{
if (!pexp)
if (exp)
{
pexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
pexp->mLeft = exp;
exp = pexp;
if (!pexp)
{
pexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
pexp->mLeft = exp;
exp = pexp;
}
pexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE);
pexp = pexp->mRight;
pexp->mLeft = nexp;
}
pexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE);
pexp = pexp->mRight;
pexp->mLeft = nexp;
else
exp = nexp;
}
else
exp = nexp;
} while (mScanner->mToken != TK_CLOSE_BRACE && mScanner->mToken != TK_EOF);
@ -10488,11 +10500,16 @@ Expression* Parser::ParseStatement(void)
mScanner->NextToken();
break;
case TK_ASM:
{
mScanner->NextToken();
bool vol = ConsumeTokenIf(TK_VOLATILE);
if (mScanner->mToken == TK_OPEN_BRACE)
{
mScanner->NextToken();
exp = ParseAssembler();
if (vol)
exp->mDecValue->mFlags |= DTF_VOLATILE;
if (mScanner->mToken == TK_CLOSE_BRACE)
mScanner->NextToken();
else
@ -10503,7 +10520,7 @@ Expression* Parser::ParseStatement(void)
mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "'{' expected");
exp = new Expression(mScanner->mLocation, EX_VOID);
}
break;
} break;
case TK_ASSUME:
mScanner->NextToken();
exp = new Expression(mScanner->mLocation, EX_ASSUME);
@ -12241,6 +12258,9 @@ Expression* Parser::ParseAssembler(Declaration* vdasm)
else
dasm = vdasm->mBase;
if (!(mCompilerOptions & COPT_OPTIMIZE_ASSEMBLER))
vdasm->mFlags |= DTF_VOLATILE;
DeclarationScope* scope = dasm->mScope;
mScope = scope;
@ -13482,7 +13502,7 @@ void Parser::ParsePragma(void)
else if (ConsumeIdentIf("pop"))
{
if (mCompilerOptionSP > 0)
mCompilerOptions = mCompilerOptionStack[--mCompilerOptionSP] = mCompilerOptions;
mCompilerOptions = mCompilerOptionStack[--mCompilerOptionSP];
else
mErrors->Error(mScanner->mLocation, ERRR_STACK_OVERFLOW, "Stack underflow");
}
@ -13688,6 +13708,9 @@ void Parser::Parse(void)
mScope->Insert(ident, vdasm);
}
if (ConsumeTokenIf(TK_VOLATILE))
vdasm->mFlags |= DTF_VOLATILE;
if (mScanner->mToken == TK_OPEN_BRACE)
{
mScanner->NextToken();