From c1ecf1c2811a3dd50756cfd674766bd2ef7c6f06 Mon Sep 17 00:00:00 2001 From: drmortalwombat <90205530+drmortalwombat@users.noreply.github.com> Date: Mon, 11 Sep 2023 08:04:09 +0200 Subject: [PATCH] Added bitfields --- autotest/autotest.bat | 3 + autotest/bitfields.cpp | 248 ++++++++++++++++++++++++++++ oscar64/ByteCodeGenerator.cpp | 13 +- oscar64/Compiler.cpp | 6 +- oscar64/Compiler.h | 2 +- oscar64/Declaration.cpp | 9 +- oscar64/Declaration.h | 4 +- oscar64/Emulator.cpp | 2 +- oscar64/Errors.h | 1 + oscar64/InterCode.cpp | 182 +++++++++++++++++++-- oscar64/InterCode.h | 1 + oscar64/InterCodeGenerator.cpp | 275 +++++++++++++++++++++++++++++--- oscar64/InterCodeGenerator.h | 6 +- oscar64/NativeCodeGenerator.cpp | 272 +++++++++++++++++++++++++++++-- oscar64/NativeCodeGenerator.h | 4 + oscar64/Parser.cpp | 116 +++++++++++++- oscar64/oscar64.cpp | 7 +- 17 files changed, 1083 insertions(+), 68 deletions(-) create mode 100644 autotest/bitfields.cpp diff --git a/autotest/autotest.bat b/autotest/autotest.bat index 9d5a926..b5ed668 100644 --- a/autotest/autotest.bat +++ b/autotest/autotest.bat @@ -1,5 +1,8 @@ rem @echo off +@call :test bitfields.cpp +@if %errorlevel% neq 0 goto :error + @call :test opp_string.cpp @if %errorlevel% neq 0 goto :error diff --git a/autotest/bitfields.cpp b/autotest/bitfields.cpp new file mode 100644 index 0000000..3e7cd44 --- /dev/null +++ b/autotest/bitfields.cpp @@ -0,0 +1,248 @@ +#include + +struct A +{ + char x : 4; + char y : 1; + char z : 3; +}; + +A a = {7, 1, 2}; + +void test_char_fit(void) +{ + assert(a.x == 7); + assert(a.y == 1); + assert(a.z == 2); + assert(sizeof(A) == 1); + + for(int i=0; i<16; i++) + { + a.x = i; + a.y = 0; + a.z = 3; + assert(a.x == i); + assert(a.y == 0); + assert(a.z == 3); + } +} + +struct B +{ + char x : 6; + char y : 6; + char z : 6; + char w : 6; +}; + +B b = {11, 22, 33, 44}; + +void test_char_cross(void) +{ + assert(b.x == 11); + assert(b.y == 22); + assert(b.z == 33); + assert(b.w == 44); + assert(sizeof(B) == 3); + + for(int i=0; i<64; i++) + { + b.x = i * 1; + b.y = i * 3; + b.z = i * 5; + b.w = i * 7; + assert(b.x == ((i * 1) & 0x3f)); + assert(b.y == ((i * 3) & 0x3f)); + assert(b.z == ((i * 5) & 0x3f)); + assert(b.w == ((i * 7) & 0x3f)); + } +} + +struct C +{ + unsigned x : 4; + unsigned y : 1; + unsigned z : 3; +}; + +C c = {7, 1, 2}; + +void test_word_fit(void) +{ + assert(c.x == 7); + assert(c.y == 1); + assert(c.z == 2); + assert(sizeof(C) == 1); + + for(int i=0; i<16; i++) + { + c.x = i; + c.y = 0; + c.z = 3; + assert(c.x == i); + assert(c.y == 0); + assert(c.z == 3); + } +} + +struct D +{ + unsigned x : 10; + unsigned y : 10; + unsigned z : 10; + unsigned w : 10; +}; + +D d = {111, 222, 333, 444}; + +void test_word_cross(void) +{ + assert(d.x == 111); + assert(d.y == 222); + assert(d.z == 333); + assert(d.w == 444); + assert(sizeof(D) == 5); + + for(int i=0; i<1024; i++) + { + d.x = i * 1; + d.y = i * 3; + d.z = i * 5; + d.w = i * 7; + assert(d.x == ((i * 1) & 0x3ff)); + assert(d.y == ((i * 3) & 0x3ff)); + assert(d.z == ((i * 5) & 0x3ff)); + assert(d.w == ((i * 7) & 0x3ff)); + } +} + +struct E +{ + unsigned long x : 4; + unsigned long y : 1; + unsigned long z : 3; +}; + +E e = {7, 1, 2}; + +void test_dword_fit(void) +{ + assert(e.x == 7); + assert(e.y == 1); + assert(e.z == 2); + assert(sizeof(E) == 1); + + for(int i=0; i<16; i++) + { + e.x = i; + e.y = 0; + e.z = 3; + assert(e.x == i); + assert(e.y == 0); + assert(e.z == 3); + } +} + +struct F +{ + unsigned long x : 20; + unsigned long y : 20; + unsigned long z : 20; + unsigned long w : 20; +}; + +F f = {111111UL, 222222UL, 333333UL, 444444UL}; + +void test_dword_cross(void) +{ + assert(f.x == 111111UL); + assert(f.y == 222222UL); + assert(f.z == 333333UL); + assert(f.w == 444444UL); + assert(sizeof(F) == 10); + + for(int i=0; i<1024; i++) + { + f.x = i * 11UL; + f.y = i * 33UL; + f.z = i * 55UL; + f.w = i * 77UL; + assert(f.x == ((i * 11UL) & 0xfffffUL)); + assert(f.y == ((i * 33UL) & 0xfffffUL)); + assert(f.z == ((i * 55UL) & 0xfffffUL)); + assert(f.w == ((i * 77UL) & 0xfffffUL)); + } +} + +struct G +{ + signed char x : 1; + signed char y : 5; + signed char z : 2; +}; + +G g = {0, -1, -2}; + +void test_char_signed(void) +{ + assert(g.x == 0); + assert(g.y == -1); + assert(g.z == -2); + assert(sizeof(G) == 1); + + for(int i=-16; i<16; i++) + { + g.x = -1; + g.y = i; + g.z = 1; + assert(g.x == -1); + assert(g.y == i); + assert(g.z == 1); + } +} + +struct H +{ + int x : 10; + int y : 10; + int z : 10; + int w : 10; +}; + +H h = {111, -222, -333, 444}; + +void test_word_signed(void) +{ + assert(h.x == 111); + assert(h.y == -222); + assert(h.z == -333); + assert(h.w == 444); + assert(sizeof(H) == 5); + + for(int i=-32; i<32; i++) + { + h.x = i * 1; + h.y = i * 3; + h.z = i * 5; + h.w = i * 7; + assert(h.x == i * 1); + assert(h.y == i * 3); + assert(h.z == i * 5); + assert(h.w == i * 7); + } +} + + +int main(void) +{ + test_char_fit(); + test_char_cross(); + test_word_fit(); + test_word_cross(); + test_dword_fit(); + test_dword_cross(); + test_char_signed(); + test_word_signed(); + + return 0; +} diff --git a/oscar64/ByteCodeGenerator.cpp b/oscar64/ByteCodeGenerator.cpp index 5707d8a..c3c9b03 100644 --- a/oscar64/ByteCodeGenerator.cpp +++ b/oscar64/ByteCodeGenerator.cpp @@ -4246,8 +4246,8 @@ void ByteCodeBasicBlock::BinaryOperator(InterCodeProcedure* proc, const InterIns case IA_SAR: { ByteCode rbc = ByteCodeBinRegOperator(ins); - ByteCode ibc = ByteCodeBinImmOperator(ins); + if (ins->mSrc[1].mTemp < 0) { IntConstToAccu(ins->mSrc[1].mIntConst); @@ -4259,18 +4259,25 @@ void ByteCodeBasicBlock::BinaryOperator(InterCodeProcedure* proc, const InterIns } else if (ins->mSrc[0].mTemp < 0) { - ByteCodeInstruction lins(BC_LOAD_REG_16); + ByteCodeInstruction lins(InterTypeSize[ins->mSrc[1].mType] == 1 ? BC_LOAD_REG_8 : BC_LOAD_REG_16); lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]; lins.mRegisterFinal = ins->mSrc[1].mFinal; mIns.Push(lins); + if (ins->mOperator == IA_SAR && InterTypeSize[ins->mSrc[1].mType] == 1) + { + ByteCodeInstruction xins(BC_CONV_I8_I16); + xins.mRegister = BC_REG_ACCU; + mIns.Push(xins); + } + ByteCodeInstruction bins(ibc); bins.mValue = int(ins->mSrc[0].mIntConst); mIns.Push(bins); } else { - ByteCodeInstruction lins(BC_LOAD_REG_16); + ByteCodeInstruction lins(InterTypeSize[ins->mSrc[1].mType] == 1 ? BC_LOAD_REG_8 : BC_LOAD_REG_16); lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]; lins.mRegisterFinal = ins->mSrc[1].mFinal && (ins->mSrc[1].mTemp != ins->mSrc[0].mTemp);; mIns.Push(lins); diff --git a/oscar64/Compiler.cpp b/oscar64/Compiler.cpp index 7a2a995..518da0d 100644 --- a/oscar64/Compiler.cpp +++ b/oscar64/Compiler.cpp @@ -1236,7 +1236,7 @@ bool Compiler::WriteOutputFile(const char* targetPath, DiskImage * d64) return true; } -int Compiler::ExecuteCode(bool profile, bool trace) +int Compiler::ExecuteCode(bool profile, int trace) { Location loc; @@ -1249,12 +1249,12 @@ int Compiler::ExecuteCode(bool profile, bool trace) memcpy(emu->mMemory + mLinker->mProgramStart, mLinker->mMemory + mLinker->mProgramStart, mLinker->mProgramEnd - mLinker->mProgramStart); emu->mMemory[0x2d] = mLinker->mProgramEnd & 0xff; emu->mMemory[0x2e] = mLinker->mProgramEnd >> 8; - ecode = emu->Emulate(2061, trace ? 2 : 0); + ecode = emu->Emulate(2061, trace); } else if (mCompilerOptions & COPT_TARGET_CRT) { memcpy(emu->mMemory + 0x8000, mLinker->mMemory + 0x0800, 0x4000); - ecode = emu->Emulate(0x8009, trace ? 2 : 0); + ecode = emu->Emulate(0x8009, trace); } printf("Emulation result %d\n", ecode); diff --git a/oscar64/Compiler.h b/oscar64/Compiler.h index 67964b7..632b1fb 100644 --- a/oscar64/Compiler.h +++ b/oscar64/Compiler.h @@ -44,7 +44,7 @@ public: bool ParseSource(void); bool GenerateCode(void); bool WriteOutputFile(const char* targetPath, DiskImage * d64); - int ExecuteCode(bool profile, bool trace); + int ExecuteCode(bool profile, int trace); void AddDefine(const Ident* ident, const char* value); diff --git a/oscar64/Declaration.cpp b/oscar64/Declaration.cpp index f20327a..fa28538 100644 --- a/oscar64/Declaration.cpp +++ b/oscar64/Declaration.cpp @@ -819,6 +819,8 @@ Expression* Expression::ConstantFold(Errors * errors, LinkerSection * dataSectio dec->mBase = mLeft->mDecValue; dec->mOffset = mDecValue->mOffset; dec->mSize = mDecValue->mSize; + dec->mBits = mDecValue->mBits; + dec->mShift = mDecValue->mShift; ex->mDecValue = dec; ex->mDecType = mDecType; return ex; @@ -831,6 +833,8 @@ Expression* Expression::ConstantFold(Errors * errors, LinkerSection * dataSectio dec->mBase = mLeft->mDecValue->mBase; dec->mOffset = mLeft->mDecValue->mOffset + mDecValue->mOffset; dec->mSize = mDecValue->mSize; + dec->mBits = mDecValue->mBits; + dec->mShift = mDecValue->mShift; ex->mDecValue = dec; ex->mDecType = mDecType; return ex; @@ -880,14 +884,15 @@ Expression* Expression::ConstantFold(Errors * errors, LinkerSection * dataSectio Declaration::Declaration(const Location& loc, DecType type) : mLocation(loc), mEndLocation(loc), mType(type), mScope(nullptr), mData(nullptr), mIdent(nullptr), mQualIdent(nullptr), mSize(0), mOffset(0), mFlags(0), mComplexity(0), mLocalSize(0), - mBase(nullptr), mParams(nullptr), mValue(nullptr), mNext(nullptr), mPrev(nullptr), + mBase(nullptr), mParams(nullptr), mValue(nullptr), mNext(nullptr), mPrev(nullptr), mConst(nullptr), mMutable(nullptr), mDefaultConstructor(nullptr), mDestructor(nullptr), mCopyConstructor(nullptr), mCopyAssignment(nullptr), mMoveConstructor(nullptr), mMoveAssignment(nullptr), mVectorConstructor(nullptr), mVectorDestructor(nullptr), mVectorCopyConstructor(nullptr), mVectorCopyAssignment(nullptr), mVTable(nullptr), mTemplate(nullptr), mVarIndex(-1), mLinkerObject(nullptr), mCallers(nullptr), mCalled(nullptr), mAlignment(1), mFriends(nullptr), mInteger(0), mNumber(0), mMinValue(-0x80000000LL), mMaxValue(0x7fffffffLL), mFastCallBase(0), mFastCallSize(0), mStride(0), mStripe(1), - mCompilerOptions(0), mUseCount(0), mTokens(nullptr), mParser(nullptr) + mCompilerOptions(0), mUseCount(0), mTokens(nullptr), mParser(nullptr), + mShift(0), mBits(0) {} Declaration::~Declaration(void) diff --git a/oscar64/Declaration.h b/oscar64/Declaration.h index e98a54d..4b5e7bb 100644 --- a/oscar64/Declaration.h +++ b/oscar64/Declaration.h @@ -29,9 +29,6 @@ enum DecType DT_TYPE_ASSEMBLER, DT_TYPE_AUTO, - DT_TYPE_CONST, - DT_TYPE_VOLATILE, - DT_CONST_INTEGER, DT_CONST_FLOAT, DT_CONST_FUNCTION, @@ -264,6 +261,7 @@ public: Expression* mValue; DeclarationScope* mScope; int mOffset, mSize, mVarIndex, mNumVars, mComplexity, mLocalSize, mAlignment, mFastCallBase, mFastCallSize, mStride, mStripe; + uint8 mShift, mBits; int64 mInteger, mMinValue, mMaxValue; double mNumber; uint64 mFlags, mCompilerOptions; diff --git a/oscar64/Emulator.cpp b/oscar64/Emulator.cpp index 7bc4421..3f32dc2 100644 --- a/oscar64/Emulator.cpp +++ b/oscar64/Emulator.cpp @@ -649,7 +649,7 @@ int Emulator::Emulate(int startIP, int trace) break; } - if ((trace & 1) && ip == 0x0855) + if ((trace & 1) && ip == 0x0862) { unsigned accu = mMemory[BC_REG_ACCU] + (mMemory[BC_REG_ACCU + 1] << 8) + (mMemory[BC_REG_ACCU + 2] << 16) + (mMemory[BC_REG_ACCU + 3] << 24); int ptr = mMemory[BC_REG_ADDR] + 256 * mMemory[BC_REG_ADDR + 1]; diff --git a/oscar64/Errors.h b/oscar64/Errors.h index 5864598..c66d7c4 100644 --- a/oscar64/Errors.h +++ b/oscar64/Errors.h @@ -83,6 +83,7 @@ enum ErrorID EERR_NON_STATIC_MEMBER, EERR_TEMPLATE_PARAMS, EERR_FUNCTION_TEMPLATE, + EERR_INVALID_BITFIELD, EERR_INVALID_CONSTEXPR, EERR_DOUBLE_FREE, diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index 0ba2108..ae5f7bb 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -643,6 +643,16 @@ static bool SameMem(const InterOperand& op, const InterInstruction* ins) return false; } +static bool SameMemAndSize(const InterOperand& op, const InterInstruction* ins) +{ + if (ins->mCode == IC_LOAD) + return SameMemAndSize(op, ins->mSrc[0]); + else if (ins->mCode == IC_STORE) + return SameMemAndSize(op, ins->mSrc[1]); + else + return false; +} + static bool SameInstruction(const InterInstruction* ins1, const InterInstruction* ins2) { if (ins1->mCode == ins2->mCode && ins1->mNumOperands == ins2->mNumOperands) @@ -7252,11 +7262,36 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(const GrowingVariableArray case IA_SHL: if (ins->mSrc[0].mTemp < 0 && ins->mSrc[1].mTemp >= 0) { - if (vr.mMinState == IntegerValueRange::S_BOUND) - ins->mSrc[1].mRange.LimitMin(vr.mMinValue >> ins->mSrc[0].mIntConst); - if (vr.mMaxState == IntegerValueRange::S_BOUND) - ins->mSrc[1].mRange.LimitMax(vr.mMaxValue >> ins->mSrc[0].mIntConst); - mReverseValueRange[ins->mSrc[1].mTemp].Limit(ins->mSrc[1].mRange); + if (ins->mDst.mType == IT_INT16) + { + if (vr.mMinState == IntegerValueRange::S_BOUND && vr.mMinValue >= -0x4000 && + vr.mMaxState == IntegerValueRange::S_BOUND && vr.mMaxValue < 0x4000) + { + ins->mSrc[1].mRange.LimitMin(vr.mMinValue >> ins->mSrc[0].mIntConst); + ins->mSrc[1].mRange.LimitMax(vr.mMaxValue >> ins->mSrc[0].mIntConst); + mReverseValueRange[ins->mSrc[1].mTemp].Limit(ins->mSrc[1].mRange); + } + } + else if (ins->mDst.mType == IT_INT8) + { + if (vr.mMinState == IntegerValueRange::S_BOUND && vr.mMinValue >= -0x40 && + vr.mMaxState == IntegerValueRange::S_BOUND && vr.mMaxValue < 0x40) + { + ins->mSrc[1].mRange.LimitMin(vr.mMinValue >> ins->mSrc[0].mIntConst); + ins->mSrc[1].mRange.LimitMax(vr.mMaxValue >> ins->mSrc[0].mIntConst); + mReverseValueRange[ins->mSrc[1].mTemp].Limit(ins->mSrc[1].mRange); + } + } + else if (ins->mDst.mType == IT_INT32) + { + if (vr.mMinState == IntegerValueRange::S_BOUND && vr.mMinValue >= -0x40000000 && + vr.mMaxState == IntegerValueRange::S_BOUND && vr.mMaxValue < 0x40000000) + { + ins->mSrc[1].mRange.LimitMin(vr.mMinValue >> ins->mSrc[0].mIntConst); + ins->mSrc[1].mRange.LimitMax(vr.mMaxValue >> ins->mSrc[0].mIntConst); + mReverseValueRange[ins->mSrc[1].mTemp].Limit(ins->mSrc[1].mRange); + } + } } break; case IA_SUB: @@ -8559,6 +8594,72 @@ bool InterCodeBasicBlock::RemoveUnusedStoreInstructions(const GrowingVariableArr } +bool InterCodeBasicBlock::RemoveUnusedIndirectStoreInstructions(void) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + ExpandingArray stores; + + for (int i = mInstructions.Size() - 1; i >= 0; i--) + { + InterInstruction* ins = mInstructions[i]; + + if (ins->mCode == IC_STORE) + { + int j = 0; + while (j < stores.Size() && !SameMemAndSize(ins->mSrc[1], stores[j]->mSrc[1])) + j++; + + if (j < stores.Size()) + { + if (ins->mVolatile) + stores[j] = ins; + else + { + ins->mCode = IC_NONE; + ins->mNumOperands = 0; + } + } + else + { + j = 0; + while (j < stores.Size()) + { + if (CollidingMem(ins, stores[j])) + stores.Remove(j); + else + j++; + } + stores.Push(ins); + } + } + else + { + int j = 0; + while (j < stores.Size()) + { + if (CollidingMem(ins, stores[j]) || ins->mDst.mTemp >= 0 && ins->mDst.mTemp == stores[j]->mSrc[1].mTemp) + stores.Remove(j); + else + j++; + } + } + } + + if (mTrueJump && mTrueJump->RemoveUnusedIndirectStoreInstructions()) + changed = true; + if (mFalseJump && mFalseJump->RemoveUnusedIndirectStoreInstructions()) + changed = true; + } + + return changed; +} + + bool InterCodeBasicBlock::EliminateAliasValues(const GrowingInstructionPtrArray& tvalue, const GrowingInstructionPtrArray& avalue) { bool changed = false; @@ -9867,7 +9968,7 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray& if (ins->mCode == IC_LOAD) { j = 0; - while (j < tvalue.Size() && !SameMem(ins->mSrc[0], tvalue[j])) + while (j < tvalue.Size() && !SameMemAndSize(ins->mSrc[0], tvalue[j])) j++; if (j < tvalue.Size()) { @@ -9880,7 +9981,7 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray& else if (ins->mCode == IC_STORE) { j = 0; - while (j < tvalue.Size() && !SameMem(ins->mSrc[1], tvalue[j])) + while (j < tvalue.Size() && !SameMemAndSize(ins->mSrc[1], tvalue[j])) j++; if (j < tvalue.Size()) { @@ -9945,7 +10046,7 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray& if (!ins->mVolatile) { int j = 0; - while (j < mLoadStoreInstructions.Size() && !SameMem(ins->mSrc[0], mLoadStoreInstructions[j])) + while (j < mLoadStoreInstructions.Size() && !SameMemAndSize(ins->mSrc[0], mLoadStoreInstructions[j])) j++; if (j < mLoadStoreInstructions.Size()) { @@ -9986,7 +10087,7 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray& { int j = 0, k = 0; - while (j < mLoadStoreInstructions.Size() && !SameMem(ins->mSrc[1], mLoadStoreInstructions[j])) + while (j < mLoadStoreInstructions.Size() && !SameMemAndSize(ins->mSrc[1], mLoadStoreInstructions[j])) j++; if (!ins->mVolatile && j < mLoadStoreInstructions.Size() && mLoadStoreInstructions[j]->mCode == IC_LOAD && ins->mSrc[0].mTemp == mLoadStoreInstructions[j]->mDst.mTemp) @@ -14541,7 +14642,6 @@ bool InterCodeBasicBlock::PeepholeReplaceOptimization(const GrowingVariableArray int64 mshift = mInstructions[i + 1]->mSrc[0].mIntConst; mInstructions[i + 0]->mOperator = IA_AND; - mInstructions[i + 0]->mSrc[0].mType = IT_INT16; mInstructions[i + 0]->mSrc[0].mType = mInstructions[i + 1]->mSrc[0].mType; switch (mInstructions[i + 0]->mSrc[1].mType) @@ -14584,6 +14684,61 @@ bool InterCodeBasicBlock::PeepholeReplaceOptimization(const GrowingVariableArray } } #endif +#if 1 + else if ( + mInstructions[i + 0]->mCode == IC_BINARY_OPERATOR && mInstructions[i + 0]->mOperator == IA_SHL && mInstructions[i + 0]->mSrc[0].mTemp < 0 && + mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR && mInstructions[i + 1]->mOperator == IA_SHR && mInstructions[i + 1]->mSrc[0].mTemp < 0 && + mInstructions[i + 1]->mSrc[1].mTemp == mInstructions[i + 0]->mDst.mTemp && mInstructions[i + 1]->mSrc[1].mFinal) + { + + int64 shift = mInstructions[i + 0]->mSrc[0].mIntConst; + if (shift & 7) + { + int64 mshift = mInstructions[i + 1]->mSrc[0].mIntConst; + + mInstructions[i + 0]->mOperator = IA_AND; + mInstructions[i + 0]->mSrc[0].mType = mInstructions[i + 1]->mSrc[0].mType; + + switch (mInstructions[i + 0]->mSrc[1].mType) + { + case IT_INT8: + mInstructions[i + 0]->mSrc[0].mIntConst = 0xffu >> shift; + break; + case IT_INT16: + mInstructions[i + 0]->mSrc[0].mIntConst = 0xffffu >> shift; + break; + case IT_INT32: + mInstructions[i + 0]->mSrc[0].mIntConst = 0xffffffffu >> shift; + break; + } + + if (shift > mshift && mInstructions[i + 0]->mDst.mType > mInstructions[i + 1]->mSrc[1].mType) + { + mInstructions[i + 1]->mSrc[1].mType = mInstructions[i + 0]->mDst.mType; + mInstructions[i + 1]->mDst.mType = mInstructions[i + 0]->mDst.mType; + } + + if (shift > mshift) + { + mInstructions[i + 1]->mOperator = IA_SHL; + mInstructions[i + 1]->mSrc[0].mIntConst = shift - mshift; + } + else if (shift < mshift) + { + mInstructions[i + 1]->mOperator = IA_SHR; + mInstructions[i + 1]->mSrc[0].mIntConst = mshift - shift; + } + else + { + mInstructions[i + 0]->mDst = mInstructions[i + 1]->mDst; + mInstructions[i + 1]->mCode = IC_NONE; + mInstructions[i + 1]->mNumOperands = 0; + } + + changed = true; + } + } +#endif #if 1 else if ( mInstructions[i + 0]->mCode == IC_LOAD_TEMPORARY && @@ -16507,6 +16662,11 @@ void InterCodeProcedure::RemoveUnusedStoreInstructions(InterMemory paramMemory) DisassembleDebug("removed unused static stores"); } + + // Remove unused indirect stores + + ResetVisited(); + mEntryBlock->RemoveUnusedIndirectStoreInstructions(); } } @@ -16921,7 +17081,7 @@ void InterCodeProcedure::Close(void) { GrowingTypeArray tstack(IT_NONE); - CheckFunc = !strcmp(mIdent->mString, "main"); + CheckFunc = !strcmp(mIdent->mString, "test"); mEntryBlock = mBlocks[0]; diff --git a/oscar64/InterCode.h b/oscar64/InterCode.h index fbe4d86..c8435f1 100644 --- a/oscar64/InterCode.h +++ b/oscar64/InterCode.h @@ -428,6 +428,7 @@ public: void BuildGlobalProvidedVariableSet(const GrowingVariableArray& localVars, NumberSet fromProvidedVars, const GrowingVariableArray& params, NumberSet fromProvidedParams, InterMemory paramMemory); bool BuildGlobalRequiredVariableSet(const GrowingVariableArray& localVars, NumberSet& fromRequiredVars, const GrowingVariableArray& params, NumberSet& fromRequiredParams, InterMemory paramMemory); bool RemoveUnusedStoreInstructions(const GrowingVariableArray& localVars, const GrowingVariableArray& params, InterMemory paramMemory); + bool RemoveUnusedIndirectStoreInstructions(void); void BuildStaticVariableSet(const GrowingVariableArray& staticVars); void BuildGlobalProvidedStaticVariableSet(const GrowingVariableArray& staticVars, NumberSet fromProvidedVars); diff --git a/oscar64/InterCodeGenerator.cpp b/oscar64/InterCodeGenerator.cpp index e683d77..cfaceda 100644 --- a/oscar64/InterCodeGenerator.cpp +++ b/oscar64/InterCodeGenerator.cpp @@ -68,16 +68,220 @@ InterCodeGenerator::ExValue InterCodeGenerator::Dereference(InterCodeProcedure* ins->mDst.mRange.LimitMin(v.mType->mMinValue); ins->mDst.mRange.LimitMax(v.mType->mMaxValue); } + if (v.mType->mFlags & DTF_VOLATILE) ins->mVolatile = true; block->Append(ins); - v = ExValue(v.mType, ins->mDst.mTemp, v.mReference - 1); + if (v.mReference == 1 && v.mBits) + { + if (v.mBits + v.mShift <= 8) + ins->mDst.mType = IT_INT8; + else if (v.mBits + v.mShift <= 16) + ins->mDst.mType = IT_INT16; + else + ins->mDst.mType = IT_INT32; + + ins->mSrc[0].mOperandSize = InterTypeSize[ins->mDst.mType]; + int nbits = ins->mSrc[0].mOperandSize * 8; + + InterInstruction* clsins = new InterInstruction(exp->mLocation, IC_CONSTANT); + clsins->mDst.mType = IT_INT8; + clsins->mDst.mTemp = proc->AddTemporary(clsins->mDst.mType); + clsins->mConst.mType = IT_INT8; + clsins->mConst.mIntConst = nbits - v.mShift - v.mBits; + clsins->mNumOperands = 0; + block->Append(clsins); + + InterInstruction* crsins = new InterInstruction(exp->mLocation, IC_CONSTANT); + crsins->mDst.mType = IT_INT8; + crsins->mDst.mTemp = proc->AddTemporary(crsins->mDst.mType); + crsins->mConst.mType = IT_INT8; + crsins->mConst.mIntConst = nbits - v.mBits; + crsins->mNumOperands = 0; + block->Append(crsins); + + InterInstruction* slins = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR); + slins->mOperator = IA_SHL; + slins->mDst.mType = ins->mDst.mType; + slins->mDst.mTemp = proc->AddTemporary(slins->mDst.mType); + slins->mSrc[1] = ins->mDst; + slins->mSrc[0] = clsins->mDst; + slins->mNumOperands = 2; + block->Append(slins); + + InterInstruction* srins = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR); + srins->mOperator = (v.mType->mFlags & DTF_SIGNED) ? IA_SAR : IA_SHR; + srins->mDst.mType = ins->mDst.mType; + srins->mDst.mTemp = proc->AddTemporary(slins->mDst.mType); + srins->mSrc[1] = slins->mDst; + srins->mSrc[0] = crsins->mDst; + srins->mNumOperands = 2; + block->Append(srins); + + if (InterTypeSize[ins->mDst.mType] < v.mType->mSize) + { + InterInstruction* crins = new InterInstruction(exp->mLocation, IC_CONVERSION_OPERATOR); + crins->mDst.mType = InterTypeOf(v.mType); + crins->mDst.mTemp = proc->AddTemporary(crins->mDst.mType); + crins->mSrc[0] = srins->mDst; + crins->mNumOperands = 1; + if (ins->mDst.mType == IT_INT16) + crins->mOperator = (v.mType->mFlags & DTF_SIGNED) ? IA_EXT16TO32S : IA_EXT16TO32U; + else if (v.mType->mSize == 2) + crins->mOperator = (v.mType->mFlags & DTF_SIGNED) ? IA_EXT8TO16S : IA_EXT8TO16U; + else + crins->mOperator = (v.mType->mFlags & DTF_SIGNED) ? IA_EXT8TO32S : IA_EXT8TO32U; + block->Append(crins); + v = ExValue(v.mType, crins->mDst.mTemp, v.mReference - 1); + } + else + v = ExValue(v.mType, srins->mDst.mTemp, v.mReference - 1); + } + else + v = ExValue(v.mType, ins->mDst.mTemp, v.mReference - 1, v.mBits, v.mShift); } return v; } +void InterCodeGenerator::StoreValue(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock*& block, ExValue vl, ExValue vr) +{ + // Bitfield assignment + if (vl.mBits) + { + InterType itype; + + if (vl.mBits + vl.mShift <= 8) + itype = IT_INT8; + else if (vl.mBits + vl.mShift <= 16) + itype = IT_INT16; + else + itype = IT_INT32; + + int nbits = InterTypeSize[itype] * 8; + + InterInstruction* lins = new InterInstruction(exp->mLocation, IC_LOAD); + lins->mDst.mType = itype; + lins->mDst.mTemp = proc->AddTemporary(lins->mDst.mType); + lins->mSrc[0].mMemory = IM_INDIRECT; + lins->mSrc[0].mType = IT_POINTER; + lins->mSrc[0].mTemp = vl.mTemp; + lins->mSrc[0].mOperandSize = InterTypeSize[itype]; + lins->mVolatile = vl.mType->mFlags & DTF_VOLATILE; + lins->mNumOperands = 1; + block->Append(lins); + + InterInstruction* csins = new InterInstruction(exp->mLocation, IC_CONSTANT); + csins->mDst.mType = IT_INT8; + csins->mDst.mTemp = proc->AddTemporary(csins->mDst.mType); + csins->mConst.mType = IT_INT8; + csins->mConst.mIntConst = vl.mShift; + csins->mNumOperands = 0; + block->Append(csins); + + InterInstruction* cmsins = new InterInstruction(exp->mLocation, IC_CONSTANT); + cmsins->mDst.mType = itype; + cmsins->mDst.mTemp = proc->AddTemporary(cmsins->mDst.mType); + cmsins->mConst.mType = itype; + cmsins->mConst.mIntConst = ((1 << vl.mBits) - 1) << vl.mShift; + cmsins->mNumOperands = 0; + block->Append(cmsins); + + InterInstruction* cmlins = new InterInstruction(exp->mLocation, IC_CONSTANT); + cmlins->mDst.mType = itype; + cmlins->mDst.mTemp = proc->AddTemporary(cmlins->mDst.mType); + cmlins->mConst.mType = itype; + cmlins->mConst.mIntConst = ~cmsins->mConst.mIntConst; + cmlins->mNumOperands = 0; + block->Append(cmlins); + + int rtemp = vr.mTemp; + + if (InterTypeSize[itype] > vr.mType->mSize) + { + InterInstruction* cins = new InterInstruction(exp->mLocation, IC_CONVERSION_OPERATOR); + + if (InterTypeSize[itype] == 2) + cins->mOperator = IA_EXT8TO16U; + else if (vr.mType->mSize == 1) + cins->mOperator = IA_EXT8TO32U; + else + cins->mOperator = IA_EXT8TO16U; + + cins->mDst.mType = itype; + cins->mDst.mTemp = proc->AddTemporary(itype); + cins->mSrc[0].mTemp = rtemp; + cins->mSrc[0].mType = InterTypeOf(vr.mType); + block->Append(cins); + + rtemp = cins->mDst.mTemp; + } + + InterInstruction* sins = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR); + sins->mOperator = IA_SHL; + sins->mDst.mType = itype; + sins->mDst.mTemp = proc->AddTemporary(sins->mDst.mType); + sins->mSrc[1].mTemp = rtemp; + sins->mSrc[1].mType = itype; + sins->mSrc[0] = csins->mDst; + sins->mNumOperands = 2; + block->Append(sins); + + InterInstruction* msins = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR); + msins->mOperator = IA_AND; + msins->mDst.mType = itype; + msins->mDst.mTemp = proc->AddTemporary(msins->mDst.mType); + msins->mSrc[0] = sins->mDst; + msins->mSrc[1] = cmsins->mDst; + msins->mNumOperands = 2; + block->Append(msins); + + InterInstruction* mlins = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR); + mlins->mOperator = IA_AND; + mlins->mDst.mType = itype; + mlins->mDst.mTemp = proc->AddTemporary(mlins->mDst.mType); + mlins->mSrc[0] = lins->mDst; + mlins->mSrc[1] = cmlins->mDst; + mlins->mNumOperands = 2; + block->Append(mlins); + + InterInstruction* oins = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR); + oins->mOperator = IA_OR; + oins->mDst.mType = itype; + oins->mDst.mTemp = proc->AddTemporary(oins->mDst.mType); + oins->mSrc[0] = msins->mDst; + oins->mSrc[1] = mlins->mDst; + oins->mNumOperands = 2; + block->Append(oins); + + InterInstruction* ins = new InterInstruction(exp->mLocation, IC_STORE); + ins->mSrc[1].mMemory = IM_INDIRECT; + ins->mSrc[0] = oins->mDst; + ins->mSrc[1].mType = IT_POINTER; + ins->mSrc[1].mTemp = vl.mTemp; + ins->mSrc[1].mOperandSize = InterTypeSize[itype]; + ins->mVolatile = vl.mType->mFlags & DTF_VOLATILE; + ins->mNumOperands = 2; + block->Append(ins); + } + else + { + InterInstruction* ins = new InterInstruction(exp->mLocation, IC_STORE); + + ins->mSrc[1].mMemory = IM_INDIRECT; + ins->mSrc[0].mType = InterTypeOf(vr.mType); + ins->mSrc[0].mTemp = vr.mTemp; + ins->mSrc[1].mType = IT_POINTER; + ins->mSrc[1].mTemp = vl.mTemp; + ins->mSrc[1].mOperandSize = vl.mType->mSize; + ins->mSrc[1].mStride = vl.mType->mStripe; + ins->mVolatile = vl.mType->mFlags & DTF_VOLATILE; + ins->mNumOperands = 2; + block->Append(ins); + } +} + InterCodeGenerator::ExValue InterCodeGenerator::CoerceType(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock*& block, ExValue v, Declaration* type, bool checkTrunc) { int stemp = v.mTemp; @@ -1713,6 +1917,8 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* ins->mConst.mOperandSize = dec->mSize; ins->mConst.mIntConst = dec->mOffset; + int lbits = dec->mBits, lshift = dec->mShift; + if (dec->mType == DT_VARIABLE_REF) dec = dec->mBase; @@ -1779,13 +1985,13 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if (exp->mDecType->IsReference()) return ExValue(exp->mDecType->mBase, ins->mDst.mTemp, ref + 1); else - return ExValue(exp->mDecType, ins->mDst.mTemp, ref); + return ExValue(exp->mDecType, ins->mDst.mTemp, ref, lbits, lshift); } case EX_ASSIGNMENT: case EX_INITIALIZATION: - { + { if (exp->mLeft->mDecType && exp->mLeft->mDecType->mType == DT_TYPE_STRUCT) { vl = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); @@ -1902,8 +2108,6 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if (vl.mReference != 1) mErrors->Error(exp->mLeft->mLocation, EERR_NOT_AN_LVALUE, "Not a left hand expression"); - InterInstruction * ins = new InterInstruction(exp->mLocation, IC_STORE); - if (exp->mToken != TK_ASSIGN) { ExValue vll = Dereference(proc, exp, block, vl); @@ -2043,17 +2247,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* vr = CoerceType(proc, exp, block, vr, vl.mType); } - ins->mCode = IC_STORE; - ins->mSrc[1].mMemory = IM_INDIRECT; - ins->mSrc[0].mType = InterTypeOf(vr.mType); - ins->mSrc[0].mTemp = vr.mTemp; - ins->mSrc[1].mType = IT_POINTER; - ins->mSrc[1].mTemp = vl.mTemp; - ins->mSrc[1].mOperandSize = vl.mType->mSize; - ins->mSrc[1].mStride = vl.mType->mStripe; - ins->mVolatile = vl.mType->mFlags & DTF_VOLATILE; - ins->mNumOperands = 2; - block->Append(ins); + StoreValue(proc, exp, block, vl, vr); } } @@ -2151,7 +2345,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* ains->mDst.mTemp = proc->AddTemporary(ains->mDst.mType); block->Append(ains); - return ExValue(exp->mDecValue->mBase, ains->mDst.mTemp, 1); + return ExValue(exp->mDecValue->mBase, ains->mDst.mTemp, 1, exp->mDecValue->mBits, exp->mDecValue->mShift); } case EX_BINARY: @@ -2483,7 +2677,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if (vl.mType->mFlags & DTF_CONST) mErrors->Error(exp->mLocation, EERR_CONST_ASSIGN, "Cannot change const value"); - InterInstruction * cins = new InterInstruction(exp->mLocation, IC_CONSTANT), * ains = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR), * sins = new InterInstruction(exp->mLocation, IC_STORE); + InterInstruction* cins = new InterInstruction(exp->mLocation, IC_CONSTANT), * ains = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR);// , * sins = new InterInstruction(exp->mLocation, IC_STORE); ExValue vdl = Dereference(proc, exp, block, vl); @@ -2524,6 +2718,8 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* ains->mDst.mTemp = proc->AddTemporary(ains->mDst.mType); block->Append(ains); + StoreValue(proc, exp, block, vl, ExValue(vl.mType, ains->mDst.mTemp)); +#if 0 sins->mSrc[1].mMemory = IM_INDIRECT; sins->mSrc[0].mType = ains->mDst.mType; sins->mSrc[0].mTemp = ains->mDst.mTemp; @@ -2532,6 +2728,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* sins->mSrc[1].mOperandSize = vl.mType->mSize; sins->mVolatile = vl.mType->mFlags & DTF_VOLATILE; block->Append(sins); +#endif // Return reference to value return ExValue(vl.mType, vl.mTemp, 1); @@ -2550,7 +2747,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if (vl.mType->mFlags & DTF_CONST) mErrors->Error(exp->mLocation, EERR_CONST_ASSIGN, "Cannot change const value"); - InterInstruction * cins = new InterInstruction(exp->mLocation, IC_CONSTANT), * ains = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR), * sins = new InterInstruction(exp->mLocation, IC_STORE); + InterInstruction* cins = new InterInstruction(exp->mLocation, IC_CONSTANT), * ains = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR);// , * sins = new InterInstruction(exp->mLocation, IC_STORE); ExValue vdl = Dereference(proc, exp, block, vl); @@ -2590,6 +2787,8 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* ains->mDst.mTemp = proc->AddTemporary(ttype); block->Append(ains); + StoreValue(proc, exp, block, vl, ExValue(vl.mType, ains->mDst.mTemp)); +#if 0 sins->mSrc[1].mMemory = IM_INDIRECT; sins->mSrc[0].mType = ains->mDst.mType; sins->mSrc[0].mTemp = ains->mDst.mTemp; @@ -2598,7 +2797,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* sins->mSrc[1].mOperandSize = vl.mType->mSize; sins->mVolatile = vl.mType->mFlags & DTF_VOLATILE; block->Append(sins); - +#endif return ExValue(vdl.mType, vdl.mTemp); } break; @@ -2642,7 +2841,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* return ExValue(vl.mType->mBase, vl.mTemp, vl.mReference + 1); case TK_BINARY_AND: { - if (vl.mReference < 1) + if (vl.mReference < 1 || vl.mBits) mErrors->Error(exp->mLocation, EERR_NOT_AN_LVALUE, "Not an addressable value"); Declaration* dec = new Declaration(exp->mLocation, DT_TYPE_POINTER); @@ -4582,10 +4781,38 @@ void InterCodeGenerator::BuildInitializer(InterCodeModule * mod, uint8* dp, int else if (data->mType == DT_CONST_INTEGER) { int64 t = data->mInteger; - for (int i = 0; i < data->mBase->mSize; i++) + if (data->mBits) { - dp[offset + i * data->mBase->mStripe] = uint8(t & 0xff); - t >>= 8; + if (data->mBits + data->mShift <= 8) + { + uint8 mask = uint8(((1 << data->mBits) - 1) << data->mShift); + dp[offset] = (dp[offset] & ~mask) | (uint8(t << data->mShift) & mask); + } + else if (data->mBits + data->mShift <= 16) + { + uint16 mask = uint16(((1 << data->mBits) - 1) << data->mShift); + + dp[offset + 0] = (dp[offset + 0] & ~(mask & 0xff)) | (uint8(t << data->mShift) & (mask & 0xff)); + dp[offset + 1] = (dp[offset + 1] & ~(mask >> 8)) | (uint8(t >> (8 - data->mShift)) & (mask >> 8)); + } + else + { + uint32 mask = uint32(((1 << data->mBits) - 1) << data->mShift); + t = (t << data->mShift) & mask; + + dp[offset + 0] = (dp[offset + 0] & ~(mask & 0xff)) | (uint8(t )); + dp[offset + 1] = (dp[offset + 1] & ~(mask >> 8)) | (uint8(t >> 8)); + dp[offset + 2] = (dp[offset + 2] & ~(mask >> 16)) | (uint8(t >> 16)); + dp[offset + 3] = (dp[offset + 3] & ~(mask >> 24)) | (uint8(t >> 24)); + } + } + else + { + for (int i = 0; i < data->mBase->mSize; i++) + { + dp[offset + i * data->mBase->mStripe] = uint8(t & 0xff); + t >>= 8; + } } } else if (data->mType == DT_CONST_ADDRESS) diff --git a/oscar64/InterCodeGenerator.h b/oscar64/InterCodeGenerator.h index ac637a2..79f9bb0 100644 --- a/oscar64/InterCodeGenerator.h +++ b/oscar64/InterCodeGenerator.h @@ -21,9 +21,10 @@ public: { Declaration* mType; int mTemp, mReference; + int mBits, mShift; - ExValue(Declaration* type = nullptr, int temp = -1, int reference = 0) - : mType(type), mTemp(temp), mReference(reference) + ExValue(Declaration* type = nullptr, int temp = -1, int reference = 0, int bits = 0, int shift = 0) + : mType(type), mTemp(temp), mReference(reference), mBits(bits), mShift(shift) {} }; @@ -86,6 +87,7 @@ protected: void TranslateLogic(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock* block, InterCodeBasicBlock* tblock, InterCodeBasicBlock* fblock, Expression* exp, DestructStack*& destack, InlineMapper* inlineMapper); ExValue TranslateInline(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock*& block, Expression* exp, const BranchTarget& breakBlock, const BranchTarget& continueBlock, InlineMapper* inlineMapper, bool inlineConstexpr, ExValue* lrexp); void CopyStruct(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock*& block, ExValue vl, ExValue vr, InlineMapper* inlineMapper, bool moving); + void StoreValue(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock*& block, ExValue vl, ExValue vr); void UnwindDestructStack(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock*& block, DestructStack* stack, DestructStack * bottom, InlineMapper* inlineMapper); void BuildInitializer(InterCodeModule* mod, uint8 * dp, int offset, Declaration* data, InterVariable * variable); diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index 539d07a..4b11ac5 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -9788,7 +9788,7 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]; int shift = ins->mSrc[0].mIntConst & 15; - if (ins->mDst.IsUByte()) + if (ins->mDst.IsUByte() || InterTypeSize[ins->mDst.mType] == 1) { if (shift == 0) { @@ -9834,8 +9834,11 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg)); } - mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); - mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + if (InterTypeSize[ins->mDst.mType] > 1) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + } } else { @@ -10045,7 +10048,7 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p { int shift = ins->mSrc[0].mIntConst & 15; #if 1 - if (ins->mSrc[1].IsUByte()) + if (ins->mSrc[1].IsUByte() || InterTypeSize[ins->mSrc[1].mType] == 1) { if (shift == 0) { @@ -10053,8 +10056,11 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p { mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg)); - mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); - mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + if (InterTypeSize[ins->mDst.mType] > 1) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + } } } else if (shift == 7) @@ -10062,7 +10068,8 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); - mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + if (InterTypeSize[ins->mDst.mType] > 1) + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); } @@ -10074,14 +10081,18 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 3)); mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); - mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); - mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + if (InterTypeSize[ins->mDst.mType] > 1) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + } } else if (shift >= 8) { mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); - mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + if (InterTypeSize[ins->mDst.mType] > 1) + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else { @@ -10089,8 +10100,11 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p for (int i = 0; i < shift; i++) mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); - mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); - mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + if (InterTypeSize[ins->mDst.mType] > 1) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + } } } else @@ -10377,6 +10391,33 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } + else if (InterTypeSize[ins->mDst.mType] == 1) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); + + if (shift > 5) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED)); + for (int i = shift; i < 8; i++) + mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0xff >> shift)); + + mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80 >> shift)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0x80 >> shift)); + } + else if (shift > 0) + { + for (int i = 0; i < shift; i++) + mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED)); + + mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80 >> shift)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0x80 >> shift)); + } + + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); + } else if (ins->mSrc[1].IsSByte() && shift != 0 && shift < 5) { mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); @@ -18939,6 +18980,148 @@ bool NativeCodeBasicBlock::ShortcutPointerAddForward(void) return changed; } +bool NativeCodeBasicBlock::MoveIndirectLoadZeroStoreDown(int at) +{ + int yval = mIns[at].mAddress; + + for (int i = at + 3; i < mIns.Size(); i++) + { + if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at + 2].mAddress) + { + if (mIns[i].mLive & LIVE_CPU_REG_Y) + return false; + mIns.Insert(i, mIns[at]); + mIns.Insert(i + 1, mIns[at + 1]); + mIns[i + 2].mType = ASMIT_STA; + mIns[i].mLive |= mIns[i + 2].mLive; + mIns[i + 1].mLive |= mIns[i + 2].mLive; + mIns.Remove(at + 1, 2); + return true; + } + + if (mIns[i].ChangesZeroPage(mIns[at + 1].mAddress) || mIns[i].ChangesZeroPage(mIns[at + 1].mAddress + 1) || mIns[i].ReferencesZeroPage(mIns[at + 2].mAddress)) + return false; + + if (mIns[i].mType == ASMIT_JSR) + return false; + + if (mIns[i].ChangesAddress()) + { + if (mIns[i].mMode == ASMIM_INDIRECT_Y && mIns[i].mAddress == mIns[at + 1].mAddress) + { + if (yval == -1 || yval == mIns[at].mAddress) + return false; + } + else if (mIns[at + 1].MayBeChangedOnAddress(mIns[i])) + return false; + } + + if (mIns[i].ChangesYReg()) + { + if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_IMMEDIATE) + yval = mIns[i].mAddress; + else if (mIns[i].mType == ASMIT_INY && yval >= 0) + yval = (yval + 1) & 255; + else if (mIns[i].mType == ASMIT_DEY && yval >= 0) + yval = (yval - 1) & 255; + else + yval = -1; + } + + } + + return false; +} + +bool NativeCodeBasicBlock::MoveLoadZeroStoreIndirectUp(int at) +{ + int i = at - 1; + while (i >= 0 && !(mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress)) + i--; + + if (i >= 0 && mIns[i].mType == ASMIT_STA && !(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_Y))) + { + int yval = -1; + for (int j = i + 1; j < at; j++) + { + if (mIns[j].mType == ASMIT_JSR) + return false; + if (mIns[j].ChangesZeroPage(mIns[at + 2].mAddress) || mIns[j].ChangesZeroPage(mIns[at + 2].mAddress + 1)) + return false; + + if (mIns[j].mMode == ASMIM_INDIRECT_Y && mIns[j].mAddress == mIns[at + 2].mAddress) + { + if (yval == -1 || yval == mIns[at].mAddress) + return false; + } + else if (mIns[j].MayBeSameAddress(mIns[at + 2])) + return false; + + if (mIns[j].ChangesYReg()) + { + if (mIns[j].mType == ASMIT_LDY && mIns[j].mMode == ASMIM_IMMEDIATE) + yval = mIns[j].mAddress; + else if (mIns[j].mType == ASMIT_INY && yval >= 0) + yval = (yval + 1) & 255; + else if (mIns[j].mType == ASMIT_DEY && yval >= 0) + yval = (yval - 1) & 255; + else + yval = -1; + } + } + + NativeCodeInstruction i0 = mIns[at + 1], i1 = mIns[at + 2]; + mIns.Remove(at + 1, 2); + + mIns.Insert(i + 1, i0); + mIns.Insert(i + 2, i1); + mIns[i].mLive |= LIVE_CPU_REG_A; + mIns[i + 1].mLive |= mIns[i].mLive; + mIns[i + 2].mLive |= mIns[i].mLive; + + return true; + } + + return false; +} + + +bool NativeCodeBasicBlock::ShortcutIndirectLoadStore(void) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + for (int i = 0; i + 2 < mIns.Size(); i++) + { + if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && + mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y && + mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && + mIns[i + 2].mAddress != mIns[i + 1].mAddress && mIns[i + 2].mAddress != mIns[i + 1].mAddress + 1) + { + if (MoveIndirectLoadZeroStoreDown(i)) + changed = true; + } + else if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && + mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_IMMEDIATE && + mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) + { + if (MoveLoadZeroStoreIndirectUp(i)) + changed = true; + } + } + + if (mTrueJump && mTrueJump->ShortcutIndirectLoadStore()) + changed = true; + if (mFalseJump && mFalseJump->ShortcutIndirectLoadStore()) + changed = true; + } + + return changed; +} + #if 0 static int NativeCodeExpressionID; @@ -34683,6 +34866,39 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass #endif +#if 1 + for (int i = 0; i + 1 < mIns.Size(); i++) + { + if (mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_IMPLIED && + mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_C))) + { + int j = 1; + while (i >= j && i + j + 1 < mIns.Size() && + mIns[i - j].mType == ASMIT_ASL && mIns[i - j].mMode == ASMIM_IMPLIED && + mIns[i + 1 + j].mType == ASMIT_LSR && mIns[i + 1 + j].mMode == ASMIM_IMPLIED && !(mIns[i + 1 + j].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_C))) + j++; + mIns[i + 1 - j].mType = ASMIT_AND; + mIns[i + 1 - j].mMode = ASMIM_IMMEDIATE; + mIns[i + 1 - j].mAddress = 0xff >> j; + + while (j > 1) + { + mIns[i + j].mType = ASMIT_NOP; + mIns[i + j].mMode = ASMIM_IMPLIED; + j--; + mIns[i + 1 - j].mType = ASMIT_NOP; + mIns[i + 1 - j].mMode = ASMIM_IMPLIED; + } + mIns[i + 1].mType = ASMIT_NOP; + mIns[i + 1].mMode = ASMIM_IMPLIED; + changed = true; + } + } + + CheckLive(); + +#endif + #if 1 bool progress = false; do { @@ -36740,6 +36956,19 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; progress = true; } +#endif +#if 1 + else if ( + mIns[i + 0].mType == ASMIT_LSR && mIns[i + 0].mMode == ASMIM_IMPLIED && + mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && + mIns[i + 2].mType == ASMIT_ROL && mIns[i + 2].mMode == ASMIM_IMPLIED && !(mIns[i + 2].mLive & LIVE_CPU_REG_C)) + { + mIns[i + 1].mType = ASMIT_AND; mIns[i + 1].mAddress = 1; + mIns[i + 0].mAddress &= (mIns[i + 2].mAddress << 1) | 1; + mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED; + mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; + progress = true; + } #endif else if ( mIns[i + 0].IsShift() && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && @@ -36984,6 +37213,15 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass mIns.Remove(i + 2); progress = true; } + else if ( + mIns[i + 0].mType == ASMIT_LDA && + mIns[i + 1].mType == ASMIT_STA && + mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && + !(mIns[i + 0].mMode == ASMIM_INDIRECT_Y && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && (mIns[i + 1].mAddress == mIns[i + 0].mAddress || mIns[i + 1].mAddress + 1 == mIns[i + 0].mAddress))) + { + mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; + progress = true; + } if ( mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress <= 1 && @@ -40915,7 +41153,7 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) { mInterProc = proc; - CheckFunc = !strcmp(mInterProc->mIdent->mString, "main"); + CheckFunc = !strcmp(mInterProc->mIdent->mString, "test"); int nblocks = proc->mBlocks.Size(); tblocks = new NativeCodeBasicBlock * [nblocks]; @@ -41688,6 +41926,14 @@ void NativeCodeProcedure::Optimize(void) changed = true; #endif + + if (step == 2) + { + ResetVisited(); + if (mEntryBlock->ShortcutIndirectLoadStore()) + changed = true; + } + #if 1 if (step >= 3) { diff --git a/oscar64/NativeCodeGenerator.h b/oscar64/NativeCodeGenerator.h index 044061b..9f2b280 100644 --- a/oscar64/NativeCodeGenerator.h +++ b/oscar64/NativeCodeGenerator.h @@ -604,6 +604,10 @@ public: bool CheckShortcutPointerAddForward(int at); bool ShortcutPointerAddForward(void); + bool ShortcutIndirectLoadStore(void); + bool MoveIndirectLoadZeroStoreDown(int at); + bool MoveLoadZeroStoreIndirectUp(int at); + bool CommonSubExpressionElimination(void); bool CheckPatchFailReg(const NativeCodeBasicBlock* block, int reg); diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp index e6d845c..6c9a421 100644 --- a/oscar64/Parser.cpp +++ b/oscar64/Parser.cpp @@ -231,6 +231,8 @@ Declaration* Parser::ParseStructDeclaration(uint64 flags, DecType dt, Declaratio } else { + int bitsleft = 0; + Declaration* mlast = nullptr; for (;;) { @@ -334,7 +336,103 @@ Declaration* Parser::ParseStructDeclaration(uint64 flags, DecType dt, Declaratio mdec->mType = DT_ELEMENT; mdec->mOffset = offset; - offset += mdec->mBase->mSize; + if (mdec->mBits) + { + if (mdec->mBits <= 8) + { + if (bitsleft == 0) + { + bitsleft = 8 - mdec->mBits; + offset++; + } + else if (bitsleft >= mdec->mBits) + { + mdec->mOffset--; + mdec->mShift = 8 - bitsleft; + bitsleft -= mdec->mBits; + } + else + { + mdec->mOffset--; + mdec->mShift = 8 - bitsleft; + bitsleft = 8 + bitsleft - mdec->mBits; + offset++; + } + } + else if (mdec->mBits <= 16) + { + if (bitsleft == 0) + { + bitsleft = 16 - mdec->mBits; + offset += 2; + } + else if (bitsleft + 8 >= mdec->mBits) + { + mdec->mOffset--; + mdec->mShift = 8 - bitsleft; + bitsleft = bitsleft + 8 - mdec->mBits; + offset++; + } + else + { + mdec->mOffset -= 3; + mdec->mShift = 24 - bitsleft; + bitsleft = bitsleft + 16 - mdec->mBits; + offset += 2; + } + } + else if (mdec->mBits <= 24) + { + if (bitsleft == 0) + { + bitsleft = 24 - mdec->mBits; + offset += 3; + } + else if (bitsleft + 16 >= mdec->mBits) + { + mdec->mOffset -= 2; + mdec->mShift = 16 - bitsleft; + bitsleft = bitsleft + 16 - mdec->mBits; + offset += 2; + } + else + { + mdec->mOffset -= 1; + mdec->mShift = 8 - bitsleft; + bitsleft = bitsleft + 24 - mdec->mBits; + offset += 3; + } + } + else + { + if (bitsleft == 0) + { + bitsleft = 32 - mdec->mBits; + offset += 4; + } + else if (bitsleft + 24 >= mdec->mBits) + { + mdec->mOffset--; + mdec->mShift = 8 - bitsleft; + bitsleft = bitsleft + 24 - mdec->mBits; + offset+=2; + } + else + { + bitsleft = 32 - mdec->mBits; + offset += mdec->mBase->mSize; + } + } + + if (mdec->mShift == 0 && mdec->mBits == 8 * mdec->mSize) + mdec->mBits = 0; + } + else + { + bitsleft = 0; + offset += mdec->mBase->mSize; + } + if (offset > dec->mSize) dec->mSize = offset; @@ -1409,6 +1507,8 @@ Expression* Parser::ParseInitExpression(Declaration* dtype) Expression* texp = ParseInitExpression(mdec->mBase); Declaration* cdec = CopyConstantInitializer(mdec->mOffset, mdec->mBase, texp); + cdec->mBits = mdec->mBits; + cdec->mShift = mdec->mShift; if (last) last->mNext = cdec; @@ -4043,9 +4143,19 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex ldec = ndec; // ndec->mNext = nullptr; - if (mScanner->mToken == TK_ASSIGN) + if (ConsumeTokenIf(TK_COLON)) + { + Expression* exp = ParseRExpression(); + if (!ndec->mBase->IsIntegerType()) + mErrors->Error(exp->mLocation, EERR_INVALID_BITFIELD, "Invalid bitfíeld for non integer type"); + else if (exp->mType == EX_CONSTANT && exp->mDecType->IsIntegerType() && exp->mDecValue->mType == DT_CONST_INTEGER) + ndec->mBits = uint8(exp->mDecValue->mInteger); + else + mErrors->Error(exp->mLocation, EERR_CONSTANT_TYPE, "Constant integer expression expected"); + } + + if (ConsumeTokenIf(TK_ASSIGN)) { - mScanner->NextToken(); ndec->mValue = ParseInitExpression(ndec->mBase); if (ndec->mBase->mType == DT_TYPE_AUTO) { diff --git a/oscar64/oscar64.cpp b/oscar64/oscar64.cpp index 55b6271..53d3af2 100644 --- a/oscar64/oscar64.cpp +++ b/oscar64/oscar64.cpp @@ -116,7 +116,8 @@ int main2(int argc, const char** argv) strcpy_s(crtPath, includePath); strcat_s(crtPath, "crt.c"); - bool emulate = false, profile = false, trace = false; + bool emulate = false, profile = false; + int trace = 0; targetPath[0] = 0; diskPath[0] = 0; @@ -211,7 +212,9 @@ int main2(int argc, const char** argv) if (arg[2] == 'p') profile = true; else if (arg[2] == 't') - trace = true; + trace = 2; + else if (arg[2] == 'b') + trace = 1; } else if (arg[1] == 'd') {