Add malloc/free as intrinsic

This commit is contained in:
drmortalwombat 2023-07-02 12:00:53 +02:00
parent 08adc7f1bd
commit 7858c2135b
19 changed files with 891 additions and 32 deletions

View File

@ -51,16 +51,15 @@ void heapcheck(void)
for(i=0; i<s; i++) for(i=0; i<s; i++)
{ {
if (p[i] != n) if (p[i] != n)
{
printf("MemError %d at %d:%d != %d\n", k, i, n, p[i]);
exit(-2); exit(-2);
}
} }
free(memp[n]); free(memp[n]);
s = rand() % 100 + 3; s = rand() % 100 + 3;
mems[n] = s; mems[n] = s;
memp[n] = malloc(s); memp[n] = malloc(s);
if (!memp[n])
exit(-3);
memset(memp[n], n, s); memset(memp[n], n, s);
} }
} }

View File

@ -4112,3 +4112,472 @@ cmpne:
} }
#pragma bytecode(BC_BINOP_CMP_S32, inp_op_cmp_s32) #pragma bytecode(BC_BINOP_CMP_S32, inp_op_cmp_s32)
void HeapStart, HeapEnd;
bool HeapInit;
struct Heap {
Heap * next;
unsigned size;
} HeapNode;
#pragma section(heap, 0x0000, HeapStart, HeapEnd)
__asm malloc
{
// round size to be a multiple of four
// and make room for two additional bytes
// to store size of memory node
clc
lda accu + 0
sta tmp + 4
adc #$05
and #$fc
sta tmp
lda accu + 1
sta tmp + 5
adc #$00
sta tmp + 1
// check if heap is initialized
lda HeapInit
bne hasHeap
// initialize heap
lda #$ff
sta HeapInit
// set next pointer to null
lda #0
sta HeapStart + 0
sta HeapStart + 1
// set size of dummy node to null
sta HeapNode + 2
sta HeapNode + 3
// set next pointer of dummy node to first free heap block
lda #<HeapStart
sta HeapNode + 0
lda #>HeapStart
sta HeapNode + 1
// set size to size of heap
sec
lda #<HeapEnd
sbc #<HeapStart
sta HeapStart + 2
lda #>HeapEnd
sbc #>HeapStart
sta HeapStart + 3
hasHeap:
// remember address of pointer to this
// heap block, to correct if block is a
// perfect fit
lda #<HeapNode
sta accu + 2
lda #>HeapNode
sta accu + 3
// Now loop over free nodes, until we find a match
loop:
// next heap block
ldy #0
lda (accu + 2), y
sta accu
iny
lda (accu + 2), y
sta accu + 1
// exit if out of blocks
beq done
// calculate remaining size of heap block
ldy #2
sec
lda (accu), y
sbc tmp
sta tmp + 2
iny
lda (accu), y
sbc tmp + 1
sta tmp + 3
// will fit
bcs avail
// prev
lda accu
sta accu + 2
lda accu + 1
sta accu + 3
jmp loop
done:
// no more heap blocks
rts
avail:
// is it a perfect fit?
lda tmp + 2
ora tmp + 3
bne nofit
// so adjust previous pointer to point to
// next heap block
ldy #0
lda (accu), y
sta (accu + 2), y
iny
lda (accu), y
sta (accu + 2), y
jmp found
nofit:
// adjust size of remaining heapblock
ldy #2
lda tmp + 2
sta (accu), y
iny
lda tmp + 3
sta (accu), y
// advance address to start of next heap block
clc
lda accu
adc tmp + 2
sta accu
lda accu + 1
adc tmp + 3
sta accu + 1
found:
// remember size of heap block for free without size
ldy #0
lda tmp + 4
sta (accu), y
iny
lda tmp + 5
sta (accu), y
// advanve by two bytes to skip size
clc
lda accu
adc #2
sta accu
bcc page
inc accu + 1
page:
rts
}
__asm inp_malloc
{
sty tmpy
jsr malloc
ldy tmpy
jmp startup.exec
}
#pragma bytecode(BC_MALLOC, inp_malloc)
__asm free
{
// check nullptr free
lda accu
ora accu + 1
bne notnull
rts
notnull:
// two bytes back to fix size
sec
lda accu
sbc #2
sta accu
bcs page
dec accu + 1
page:
// cache size and end of block
clc
ldy #0
lda (accu), y
adc #5
and #$fc
sta tmp
iny
lda (accu), y
adc #0
sta tmp + 1
clc
lda tmp + 0
adc accu
sta accu + 2
lda tmp + 1
adc accu + 1
sta accu + 3
// pointer to heap block, starting with
// dummy block
lda #<HeapNode
sta tmp + 2
lda #>HeapNode
sta tmp + 3
loop:
// check if end of heap
ldy #1
lda (tmp + 2), y
beq noend
// Check if behind this block
cmp accu + 1
bcc before
bne after
dey
lda (tmp + 2), y
cmp accu + 0
bcs after
before:
ldy # 1
lda (tmp + 2), y
tax
dey
lda (tmp + 2), y
sta tmp + 2
stx tmp + 3
jmp loop
after:
// Merge with next block
ldy #1
lda accu + 3
cmp (tmp + 2), y
bne noend
dey
lda accu + 2
cmp (tmp + 2), y
bne noend
// Pointer to next next block
ldy #0
lda (accu + 2), y
sta (accu), y
iny
lda (accu + 2), y
sta (accu), y
// Add size of next block to this
iny
clc
lda tmp
adc (accu + 2), y
sta tmp
iny
lda tmp + 1
adc (accu + 2), y
sta tmp + 1
jmp start
noend:
// Link to next block
ldy #0
lda (tmp + 2), y
sta (accu), y
iny
lda (tmp + 2), y
sta (accu), y
start:
// Calculate end of free block
ldy #2
clc
lda tmp + 2
adc (tmp + 2), y
iny
tax
lda tmp + 3
adc (tmp + 2), y
// Matches start of new block
cmp accu + 1
bne nostart
cpx accu
bne nostart
// If so, increase the size and link
// to free block after
ldy #0
lda (accu), y
sta (tmp + 2), y
iny
lda (accu), y
sta (tmp + 2), y
iny
clc
lda (tmp + 2), y
adc tmp
sta (tmp + 2), y
iny
lda (tmp + 2), y
adc tmp + 1
sta (tmp + 2), y
rts
nostart:
// Link to new free block
ldy #0
lda accu
sta (tmp + 2), y
iny
lda accu + 1
sta (tmp + 2), y
iny
// Set size of free block
lda tmp
sta (accu), y
iny
lda tmp + 1
sta (accu), y
rts
}
__asm inp_free
{
sty tmpy
jsr free
ldy tmpy
jmp startup.exec
}
#pragma bytecode(BC_FREE, inp_free)
#pragma runtime(malloc, malloc)
#pragma runtime(free, free)
#if 0
void * malloc(unsigned int size)
{
size = (size + 7) & ~3;
if (!freeHeapInit)
{
freeHeap = (Heap *)&HeapStart;
freeHeap->next = nullptr;
freeHeap->size = (unsigned int)&HeapEnd - (unsigned int)&HeapStart;
freeHeapInit = true;
}
Heap * pheap = nullptr, * heap = freeHeap;
while (heap)
{
if (size <= heap->size)
{
if (size == heap->size)
{
if (pheap)
pheap->next = heap->next;
else
freeHeap = heap->next;
}
else
{
Heap * nheap = (Heap *)((int)heap + size);
nheap->size = heap->size - size;
nheap->next = heap->next;
if (pheap)
pheap->next = nheap;
else
freeHeap = nheap;
heap->size = size;
}
return (void *)((int)heap + 2);
}
pheap = heap;
heap = heap->next;
}
return nullptr;
}
void free(void * ptr)
{
if (!ptr)
return;
Heap * fheap = (Heap *)((int)ptr - 2);
Heap * eheap = (Heap *)((int)ptr - 2 + fheap->size);
if (freeHeap)
{
if (eheap == freeHeap)
{
fheap->size += freeHeap->size;
fheap->next = freeHeap->next;
freeHeap = fheap;
}
else if (eheap < freeHeap)
{
fheap->next = freeHeap;
freeHeap = fheap;
}
else
{
Heap * pheap = freeHeap;
while (pheap->next && pheap->next < fheap)
pheap = pheap->next;
Heap * nheap = (Heap *)((int)pheap + pheap->size);
if (nheap == fheap)
{
pheap->size += fheap->size;
if (pheap->next == eheap)
{
pheap->size += pheap->next->size;
pheap->next = pheap->next->next;
}
}
else if (pheap->next == eheap)
{
fheap->next = pheap->next->next;
fheap->size += pheap->next->size;
pheap->next = fheap;
}
else
{
fheap->next = pheap->next;
pheap->next = fheap;
}
}
}
else
{
freeHeap = fheap;
freeHeap->next = nullptr;
}
}
#endif

View File

@ -142,8 +142,8 @@ enum ByteCode
BC_BRANCHF_LE, BC_BRANCHF_LE,
BC_LOOP_U8, BC_LOOP_U8,
BC_UNUSED_2, BC_MALLOC,
BC_UNUSED_3, BC_FREE,
BC_UNUSED_4, BC_UNUSED_4,
BC_UNUSED_5, BC_UNUSED_5,
BC_UNUSED_6, BC_UNUSED_6,

View File

@ -524,6 +524,7 @@ void exit(int status)
} }
} }
#if 0
struct Heap { struct Heap {
unsigned int size; unsigned int size;
Heap * next; Heap * next;
@ -636,6 +637,7 @@ void free(void * ptr)
freeHeap->next = nullptr; freeHeap->next = nullptr;
} }
} }
#endif
void * calloc(int num, int size) void * calloc(int num, int size)
{ {

View File

@ -47,6 +47,10 @@ unsigned int rand(void);
void srand(unsigned int seed); void srand(unsigned int seed);
#pragma intrinsic(malloc)
#pragma intrinsic(free)
#pragma compile("stdlib.c") #pragma compile("stdlib.c")
#endif #endif

View File

@ -142,8 +142,8 @@ static const char* ByteCodeNames[] = {
"BRANCHF_LE", "BRANCHF_LE",
"LOOP_U8", "LOOP_U8",
nullptr, "MALLOC",
nullptr, "FREE",
nullptr, nullptr,
nullptr, nullptr,
nullptr, nullptr,
@ -565,6 +565,11 @@ bool ByteCodeInstruction::CheckAccuSize(uint32 & used)
used = 0; used = 0;
break; break;
case BC_MALLOC:
case BC_FREE:
used = 0x0000ffff;
break;
case BC_BINOP_ADDA_16: case BC_BINOP_ADDA_16:
used |= 0x0000ffff; used |= 0x0000ffff;
break; break;
@ -779,6 +784,8 @@ bool ByteCodeInstruction::UsesRegister(uint32 reg) const
return true; return true;
if (mCode == BC_BINOP_ADDA_16) if (mCode == BC_BINOP_ADDA_16)
return true; return true;
if (mCode == BC_MALLOC || mCode == BC_FREE)
return true;
} }
if (reg == BC_REG_ADDR) if (reg == BC_REG_ADDR)
@ -851,6 +858,8 @@ bool ByteCodeInstruction::ChangesRegister(uint32 reg) const
return true; return true;
if (mCode == BC_LOOP_U8) if (mCode == BC_LOOP_U8)
return true; return true;
if (mCode == BC_MALLOC || mCode == BC_FREE)
return true;
} }
if (reg == BC_REG_ADDR) if (reg == BC_REG_ADDR)
@ -869,6 +878,8 @@ bool ByteCodeInstruction::ChangesRegister(uint32 reg) const
{ {
if (mCode == BC_JSR || mCode == BC_CALL_ADDR || mCode == BC_CALL_ABS) if (mCode == BC_JSR || mCode == BC_CALL_ADDR || mCode == BC_CALL_ABS)
return true; return true;
if (mCode == BC_MALLOC || mCode == BC_FREE)
return true;
if (mCode == BC_BINOP_DIVR_I16 || mCode == BC_BINOP_DIVR_U16 || mCode == BC_BINOP_MODR_I16 || mCode == BC_BINOP_MODR_U16 || if (mCode == BC_BINOP_DIVR_I16 || mCode == BC_BINOP_DIVR_U16 || mCode == BC_BINOP_MODR_I16 || mCode == BC_BINOP_MODR_U16 ||
mCode == BC_BINOP_DIV_I32 || mCode == BC_BINOP_DIV_U32 || mCode == BC_BINOP_MOD_I32 || mCode == BC_BINOP_MOD_U32 || mCode == BC_BINOP_DIV_I32 || mCode == BC_BINOP_DIV_U32 || mCode == BC_BINOP_MOD_I32 || mCode == BC_BINOP_MOD_U32 ||
@ -1149,6 +1160,8 @@ void ByteCodeInstruction::Assemble(ByteCodeGenerator* generator, ByteCodeBasicBl
assert(false); assert(false);
break; break;
case BC_MALLOC:
case BC_FREE:
case BC_CALL_ADDR: case BC_CALL_ADDR:
block->PutCode(generator, mCode); block->PutCode(generator, mCode);
break; break;
@ -1578,6 +1591,49 @@ void ByteCodeBasicBlock::StrcpyValue(InterCodeProcedure* proc, const InterInstru
mIns.Push(cins); mIns.Push(cins);
} }
void ByteCodeBasicBlock::CallMalloc(InterCodeProcedure* proc, const InterInstruction* ins)
{
if (ins->mSrc[0].mTemp < 0)
{
ByteCodeInstruction dins(BC_CONST_16);
dins.mRegister = BC_REG_ACCU;
dins.mValue = int(ins->mSrc[0].mIntConst & 0xffff);
mIns.Push(dins);
}
else
{
ByteCodeInstruction dins(BC_LOAD_REG_16);
dins.mRegister = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp];
dins.mRegisterFinal = ins->mSrc[0].mFinal;
mIns.Push(dins);
}
ByteCodeInstruction cins(BC_MALLOC);
mIns.Push(cins);
ByteCodeInstruction bins(BC_STORE_REG_16);
bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];
mIns.Push(bins);
}
void ByteCodeBasicBlock::CallFree(InterCodeProcedure* proc, const InterInstruction* ins)
{
if (ins->mSrc[0].mTemp < 0)
{
ByteCodeInstruction dins(BC_CONST_16);
dins.mRegister = BC_REG_ACCU;
dins.mValue = int(ins->mSrc[0].mIntConst & 0xffff);
mIns.Push(dins);
}
else
{
ByteCodeInstruction dins(BC_LOAD_REG_16);
dins.mRegister = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp];
dins.mRegisterFinal = ins->mSrc[0].mFinal;
mIns.Push(dins);
}
ByteCodeInstruction cins(BC_FREE);
mIns.Push(cins);
}
void ByteCodeBasicBlock::StoreDirectValue(InterCodeProcedure* proc, const InterInstruction * ins) void ByteCodeBasicBlock::StoreDirectValue(InterCodeProcedure* proc, const InterInstruction * ins)
{ {
if (ins->mSrc[0].mType == IT_FLOAT) if (ins->mSrc[0].mType == IT_FLOAT)
@ -4259,6 +4315,12 @@ void ByteCodeBasicBlock::Compile(InterCodeProcedure* iproc, ByteCodeProcedure* p
case IC_STRCPY: case IC_STRCPY:
StrcpyValue(iproc, ins); StrcpyValue(iproc, ins);
break; break;
case IC_MALLOC:
CallMalloc(iproc, ins);
break;
case IC_FREE:
CallFree(iproc, ins);
break;
case IC_LOAD_TEMPORARY: case IC_LOAD_TEMPORARY:
{ {
if (ins->mSrc[0].mTemp != ins->mDst.mTemp) if (ins->mSrc[0].mTemp != ins->mDst.mTemp)

View File

@ -143,8 +143,8 @@ enum ByteCode
BC_BRANCHF_LE, BC_BRANCHF_LE,
BC_LOOP_U8, BC_LOOP_U8,
BC_UNUSED_2, BC_MALLOC,
BC_UNUSED_3, BC_FREE,
BC_UNUSED_4, BC_UNUSED_4,
BC_UNUSED_5, BC_UNUSED_5,
BC_UNUSED_6, BC_UNUSED_6,
@ -283,6 +283,8 @@ public:
void FloatConstToWork(double val); void FloatConstToWork(double val);
void CopyValue(InterCodeProcedure* proc, const InterInstruction * ins); void CopyValue(InterCodeProcedure* proc, const InterInstruction * ins);
void StrcpyValue(InterCodeProcedure* proc, const InterInstruction* ins); void StrcpyValue(InterCodeProcedure* proc, const InterInstruction* ins);
void CallMalloc(InterCodeProcedure* proc, const InterInstruction* ins);
void CallFree(InterCodeProcedure* proc, const InterInstruction* ins);
void LoadConstant(InterCodeProcedure* proc, const InterInstruction * ins); void LoadConstant(InterCodeProcedure* proc, const InterInstruction * ins);
void StoreDirectValue(InterCodeProcedure* proc, const InterInstruction * ins); void StoreDirectValue(InterCodeProcedure* proc, const InterInstruction * ins);
void LoadDirectValue(InterCodeProcedure* proc, const InterInstruction * ins); void LoadDirectValue(InterCodeProcedure* proc, const InterInstruction * ins);

View File

@ -669,6 +669,9 @@ bool Compiler::GenerateCode(void)
RegisterRuntime(loc, Ident::Unique("mods32")); RegisterRuntime(loc, Ident::Unique("mods32"));
RegisterRuntime(loc, Ident::Unique("divu32")); RegisterRuntime(loc, Ident::Unique("divu32"));
RegisterRuntime(loc, Ident::Unique("modu32")); RegisterRuntime(loc, Ident::Unique("modu32"));
RegisterRuntime(loc, Ident::Unique("malloc"));
RegisterRuntime(loc, Ident::Unique("free"));
} }
// Register extended byte code functions // Register extended byte code functions

View File

@ -187,7 +187,7 @@ enum ExpressionType
EX_ASSUME, EX_ASSUME,
EX_BANKOF, EX_BANKOF,
EX_CONSTRUCT, EX_CONSTRUCT,
EX_CLEANUP, EX_CLEANUP
}; };
class Expression class Expression

View File

@ -476,6 +476,13 @@ void ByteCodeDisassembler::Disassemble(FILE* file, const uint8* memory, int bank
fprintf(file, "CNVFS\tACCU"); fprintf(file, "CNVFS\tACCU");
break; break;
case BC_MALLOC:
fprintf(file, "MALLOC\tACCU");
break;
case BC_FREE:
fprintf(file, "FREE\tACCU");
break;
case BC_JUMPS: case BC_JUMPS:
fprintf(file, "JUMP\t$%04X", start + i + 1 + int8(memory[start + i + 0])); fprintf(file, "JUMP\t$%04X", start + i + 1 + int8(memory[start + i + 0]));
i++; i++;

View File

@ -634,7 +634,7 @@ bool InterCodeBasicBlock::CanSwapInstructions(const InterInstruction* ins0, cons
{ {
if (ins0->mCode == IC_CALL || ins0->mCode == IC_CALL_NATIVE || ins0->mCode == IC_ASSEMBLER || if (ins0->mCode == IC_CALL || ins0->mCode == IC_CALL_NATIVE || ins0->mCode == IC_ASSEMBLER ||
ins0->mCode == IC_RETURN || ins0->mCode == IC_RETURN_STRUCT || ins0->mCode == IC_RETURN_VALUE || ins0->mCode == IC_RETURN || ins0->mCode == IC_RETURN_STRUCT || ins0->mCode == IC_RETURN_VALUE ||
ins0->mCode == IC_PUSH_FRAME || ins0->mCode == IC_POP_FRAME) ins0->mCode == IC_PUSH_FRAME || ins0->mCode == IC_POP_FRAME || ins0->mCode == IC_MALLOC || ins0->mCode == IC_FREE)
return false; return false;
if (ins0->mCode == IC_LOAD || ins0->mCode == IC_STORE || ins0->mCode == IC_COPY || ins0->mCode == IC_STRCPY) if (ins0->mCode == IC_LOAD || ins0->mCode == IC_STORE || ins0->mCode == IC_COPY || ins0->mCode == IC_STRCPY)
@ -643,13 +643,30 @@ bool InterCodeBasicBlock::CanSwapInstructions(const InterInstruction* ins0, cons
if (ins0->mCode == IC_CALL || ins0->mCode == IC_CALL_NATIVE || ins0->mCode == IC_ASSEMBLER) if (ins0->mCode == IC_CALL || ins0->mCode == IC_CALL_NATIVE || ins0->mCode == IC_ASSEMBLER)
{ {
if (ins1->mCode == IC_RETURN || ins1->mCode == IC_RETURN_STRUCT || ins1->mCode == IC_RETURN_VALUE || if (ins1->mCode == IC_RETURN || ins1->mCode == IC_RETURN_STRUCT || ins1->mCode == IC_RETURN_VALUE ||
ins1->mCode == IC_PUSH_FRAME || ins1->mCode == IC_POP_FRAME) ins1->mCode == IC_PUSH_FRAME || ins1->mCode == IC_POP_FRAME || ins1->mCode == IC_MALLOC || ins1->mCode == IC_FREE)
return false; return false;
if (ins1->mCode == IC_LOAD || ins1->mCode == IC_STORE || ins1->mCode == IC_COPY || ins1->mCode == IC_STRCPY) if (ins1->mCode == IC_LOAD || ins1->mCode == IC_STORE || ins1->mCode == IC_COPY || ins1->mCode == IC_STRCPY)
return false; return false;
} }
if (ins0->mCode == IC_MALLOC || ins0->mCode == IC_FREE)
{
if (ins1->mCode == IC_MALLOC || ins1->mCode == IC_FREE)
return false;
}
if (ins0->mCode == IC_FREE)
{
if (ins1->mCode == IC_LOAD || ins1->mCode == IC_STORE || ins1->mCode == IC_COPY || ins1->mCode == IC_STRCPY)
return false;
}
if (ins1->mCode == IC_FREE)
{
if (ins0->mCode == IC_LOAD || ins0->mCode == IC_STORE || ins0->mCode == IC_COPY || ins0->mCode == IC_STRCPY)
return false;
}
// Check frame pointer // Check frame pointer
if (ins0->mCode == IC_PUSH_FRAME || ins0->mCode == IC_POP_FRAME) if (ins0->mCode == IC_PUSH_FRAME || ins0->mCode == IC_POP_FRAME)
{ {
@ -1151,17 +1168,17 @@ void ValueSet::InsertValue(InterInstruction * ins)
static bool HasSideEffect(InterCode code) static bool HasSideEffect(InterCode code)
{ {
return code == IC_CALL || code == IC_CALL_NATIVE || code == IC_ASSEMBLER; return code == IC_CALL || code == IC_CALL_NATIVE || code == IC_ASSEMBLER || code == IC_MALLOC || code == IC_FREE;
} }
static bool IsObservable(InterCode code) static bool IsObservable(InterCode code)
{ {
return code == IC_CALL || code == IC_CALL_NATIVE || code == IC_ASSEMBLER || code == IC_STORE || code == IC_COPY || code == IC_STRCPY; return code == IC_CALL || code == IC_CALL_NATIVE || code == IC_ASSEMBLER || code == IC_STORE || code == IC_COPY || code == IC_STRCPY || code == IC_MALLOC || code == IC_FREE;
} }
static bool IsMoveable(InterCode code) static bool IsMoveable(InterCode code)
{ {
if (HasSideEffect(code) || code == IC_COPY || code == IC_STRCPY || code == IC_STORE || code == IC_BRANCH || code == IC_POP_FRAME || code == IC_PUSH_FRAME) if (HasSideEffect(code) || code == IC_COPY || code == IC_STRCPY || code == IC_STORE || code == IC_BRANCH || code == IC_POP_FRAME || code == IC_PUSH_FRAME || code == IC_MALLOC || code == IC_FREE)
return false; return false;
if (code == IC_RETURN || code == IC_RETURN_STRUCT || code == IC_RETURN_VALUE) if (code == IC_RETURN || code == IC_RETURN_STRUCT || code == IC_RETURN_VALUE)
return false; return false;
@ -2762,12 +2779,43 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr
case IC_BRANCH: case IC_BRANCH:
if (ins->mSrc[0].mTemp >= 0 && tvalue[ins->mSrc[0].mTemp] && tvalue[ins->mSrc[0].mTemp]->mCode == IC_CONSTANT) if (ins->mSrc[0].mTemp >= 0 && tvalue[ins->mSrc[0].mTemp] && tvalue[ins->mSrc[0].mTemp]->mCode == IC_CONSTANT)
{ {
if (tvalue[ins->mSrc[0].mTemp]->mConst.mIntConst) InterInstruction* tins = tvalue[ins->mSrc[0].mTemp];
ins->mCode = IC_JUMP; if (IsIntegerType(tins->mConst.mType) || tins->mConst.mType == IT_BOOL)
else {
ins->mCode = IC_JUMPF; if (tins->mConst.mIntConst)
ins->mSrc[0].mTemp = -1; ins->mCode = IC_JUMP;
ins->mNumOperands = 0; else
ins->mCode = IC_JUMPF;
ins->mSrc[0].mTemp = -1;
ins->mNumOperands = 0;
}
else if (tins->mConst.mType == IT_POINTER)
{
if (tins->mConst.mMemory == IM_ABSOLUTE)
{
if (tins->mConst.mIntConst)
ins->mCode = IC_JUMP;
else
ins->mCode = IC_JUMPF;
ins->mSrc[0].mTemp = -1;
ins->mNumOperands = 0;
}
else if (tins->mConst.mMemory == IM_GLOBAL || tins->mConst.mMemory == IM_LOCAL || tins->mConst.mMemory == IM_PARAM || tins->mConst.mMemory == IM_FPARAM)
{
ins->mCode = IC_JUMP;
ins->mSrc[0].mTemp = -1;
ins->mNumOperands = 0;
}
}
else if (tins->mConst.mType == IT_FLOAT)
{
if (tins->mConst.mFloatConst)
ins->mCode = IC_JUMP;
else
ins->mCode = IC_JUMPF;
ins->mSrc[0].mTemp = -1;
ins->mNumOperands = 0;
}
} }
break; break;
case IC_PUSH_FRAME: case IC_PUSH_FRAME:
@ -4214,6 +4262,16 @@ void InterInstruction::Disassemble(FILE* file)
else else
fprintf(file, "COPY%c%c", memchars[mSrc[0].mMemory], memchars[mSrc[1].mMemory]); fprintf(file, "COPY%c%c", memchars[mSrc[0].mMemory], memchars[mSrc[1].mMemory]);
break; break;
case IC_MALLOC:
assert(mNumOperands == 1);
fprintf(file, "MALLOC");
break;
case IC_FREE:
assert(mNumOperands == 1);
fprintf(file, "FREE");
break;
case IC_STRCPY: case IC_STRCPY:
fprintf(file, "STRCPY%c%c", memchars[mSrc[0].mMemory], memchars[mSrc[1].mMemory]); fprintf(file, "STRCPY%c%c", memchars[mSrc[0].mMemory], memchars[mSrc[1].mMemory]);
break; break;
@ -7696,7 +7754,7 @@ bool InterCodeBasicBlock::CalculateSingleAssignmentTemps(FastNumberSet& tassigne
bool valid = j == ins->mNumOperands; bool valid = j == ins->mNumOperands;
if (valid) if (valid)
{ {
if (ins->mCode == IC_CALL || ins->mCode == IC_CALL_NATIVE || ins->mCode == IC_ASSEMBLER) if (ins->mCode == IC_CALL || ins->mCode == IC_CALL_NATIVE || ins->mCode == IC_ASSEMBLER || ins->mCode == IC_MALLOC || ins->mCode == IC_FREE)
valid = false; valid = false;
else if (ins->mCode == IC_LOAD) else if (ins->mCode == IC_LOAD)
{ {
@ -16035,7 +16093,7 @@ void InterCodeProcedure::Close(void)
{ {
GrowingTypeArray tstack(IT_NONE); GrowingTypeArray tstack(IT_NONE);
CheckFunc = !strcmp(mIdent->mString, "test"); CheckFunc = !strcmp(mIdent->mString, "main");
mEntryBlock = mBlocks[0]; mEntryBlock = mBlocks[0];

View File

@ -24,6 +24,8 @@ enum InterCode
IC_LEA, IC_LEA,
IC_COPY, IC_COPY,
IC_STRCPY, IC_STRCPY,
IC_MALLOC,
IC_FREE,
IC_TYPECAST, IC_TYPECAST,
IC_CONSTANT, IC_CONSTANT,
IC_BRANCH, IC_BRANCH,

View File

@ -2429,6 +2429,30 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
} }
mErrors->Error(exp->mLocation, ERRR_CANNOT_FIND_BANK_OF_EXPRESSION, "Cannot find bank of expressiohn"); mErrors->Error(exp->mLocation, ERRR_CANNOT_FIND_BANK_OF_EXPRESSION, "Cannot find bank of expressiohn");
} break; } break;
case TK_NEW:
{
ins->mCode = IC_MALLOC;
ins->mSrc[0].mType = InterTypeOf(vl.mType);
ins->mSrc[0].mTemp = vl.mTemp;
ins->mDst.mType = IT_POINTER;
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
block->Append(ins);
return ExValue(exp->mDecType, ins->mDst.mTemp, 0);
} break;
case TK_DELETE:
{
vl = Dereference(proc, exp, block, vl, 0);
ins->mCode = IC_FREE;
ins->mSrc[0].mType = IT_POINTER;
ins->mSrc[0].mTemp = vl.mTemp;
block->Append(ins);
return ExValue(TheConstVoidTypeDeclaration, -1);
} break;
} }
ins->mSrc[0].mType = InterTypeOf(vl.mType); ins->mSrc[0].mType = InterTypeOf(vl.mType);
@ -2611,6 +2635,42 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
return ExValue(TheFloatTypeDeclaration, ins->mDst.mTemp); return ExValue(TheFloatTypeDeclaration, ins->mDst.mTemp);
} }
else if (!strcmp(iname->mString, "malloc"))
{
vr = TranslateExpression(procType, proc, block, exp->mRight, destack, breakBlock, continueBlock, inlineMapper);
vr = Dereference(proc, exp, block, vr);
if (decf->mBase->mParams->CanAssign(vr.mType))
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types");
vr = CoerceType(proc, exp, block, vr, decf->mBase->mParams);
InterInstruction* ins = new InterInstruction(exp->mLocation, IC_MALLOC);
ins->mSrc[0].mType = IT_INT16;
ins->mSrc[0].mTemp = vr.mTemp;
ins->mNumOperands = 1;
ins->mDst.mType = IT_POINTER;
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
block->Append(ins);
return ExValue(TheVoidPointerTypeDeclaration, ins->mDst.mTemp);
}
else if (!strcmp(iname->mString, "free"))
{
vr = TranslateExpression(procType, proc, block, exp->mRight, destack, breakBlock, continueBlock, inlineMapper);
vr = Dereference(proc, exp, block, vr);
if (decf->mBase->mParams->CanAssign(vr.mType))
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types");
vr = CoerceType(proc, exp, block, vr, decf->mBase->mParams);
InterInstruction* ins = new InterInstruction(exp->mLocation, IC_FREE);
ins->mSrc[0].mType = IT_POINTER;
ins->mSrc[0].mTemp = vr.mTemp;
ins->mNumOperands = 1;
block->Append(ins);
return ExValue(TheVoidTypeDeclaration, 0);
}
else if (!strcmp(iname->mString, "strcpy")) else if (!strcmp(iname->mString, "strcpy"))
{ {
if (exp->mRight->mType == EX_LIST) if (exp->mRight->mType == EX_LIST)

View File

@ -489,8 +489,8 @@ void Linker::Link(void)
if (lsec->mType == LST_HEAP) if (lsec->mType == LST_HEAP)
{ {
lsec->mStart = lrgn->mStart + lrgn->mUsed; lsec->mStart = (lrgn->mStart + lrgn->mUsed + 3) & ~3;
lsec->mEnd = lrgn->mEnd; lsec->mEnd = lrgn->mEnd & ~3;
if (lsec->mStart + lsec->mSize > lsec->mEnd) if (lsec->mStart + lsec->mSize > lsec->mEnd)
{ {

View File

@ -7346,6 +7346,54 @@ NativeCodeBasicBlock * NativeCodeBasicBlock::CopyValue(InterCodeProcedure* proc,
} }
} }
void NativeCodeBasicBlock::CallMalloc(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc)
{
if (ins->mSrc[0].mTemp < 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("malloc")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
}
void NativeCodeBasicBlock::CallFree(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc)
{
if (ins->mSrc[0].mTemp < 0)
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
else
{
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
}
NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("free")));
mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
}
NativeCodeBasicBlock* NativeCodeBasicBlock::StrcpyValue(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc) NativeCodeBasicBlock* NativeCodeBasicBlock::StrcpyValue(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc)
{ {
int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], dreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]; int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], dreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
@ -17338,10 +17386,13 @@ bool NativeCodeBasicBlock::CombineZPPair(int at, int r0, int r1, bool use0, bool
} }
} }
} }
else if (ins.ChangesZeroPage(r0)) else
valid0 = false; {
else if (ins.ChangesZeroPage(r1)) if (ins.ChangesZeroPage(r0))
valid1 = false; valid0 = false;
if (ins.ChangesZeroPage(r1))
valid1 = false;
}
i++; i++;
} }
@ -40093,7 +40144,7 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc)
{ {
mInterProc = proc; mInterProc = proc;
CheckFunc = !strcmp(mInterProc->mIdent->mString, "strlen"); CheckFunc = !strcmp(mInterProc->mIdent->mString, "heapcheck");
int nblocks = proc->mBlocks.Size(); int nblocks = proc->mBlocks.Size();
tblocks = new NativeCodeBasicBlock * [nblocks]; tblocks = new NativeCodeBasicBlock * [nblocks];
@ -40881,7 +40932,7 @@ void NativeCodeProcedure::Optimize(void)
} }
#endif #endif
if (step == 5) if (step == 5 && cnt < 10)
{ {
ResetVisited(); ResetVisited();
if (mEntryBlock->RemoveDoubleZPStore()) if (mEntryBlock->RemoveDoubleZPStore())
@ -41703,6 +41754,14 @@ void NativeCodeProcedure::CompileInterBlock(InterCodeProcedure* iproc, InterCode
case IC_STRCPY: case IC_STRCPY:
block = block->StrcpyValue(iproc, ins, this); block = block->StrcpyValue(iproc, ins, this);
break; break;
case IC_MALLOC:
block->CallMalloc(iproc, ins, this);
break;
case IC_FREE:
block->CallFree(iproc, ins, this);
break;
case IC_LOAD_TEMPORARY: case IC_LOAD_TEMPORARY:
{ {
if (ins->mSrc[0].mTemp != ins->mDst.mTemp) if (ins->mSrc[0].mTemp != ins->mDst.mTemp)

View File

@ -336,6 +336,9 @@ public:
NativeCodeBasicBlock * StrcpyValue(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc); NativeCodeBasicBlock * StrcpyValue(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc);
void AddAsrSignedByte(InterCodeProcedure* proc, const InterInstruction* ains, const InterInstruction* sins); void AddAsrSignedByte(InterCodeProcedure* proc, const InterInstruction* ains, const InterInstruction* sins);
void CallMalloc(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc);
void CallFree(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc);
void LoadByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* rins); void LoadByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* rins);
void StoreByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* rins); void StoreByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* rins);

View File

@ -4470,7 +4470,7 @@ Expression* Parser::ParsePrefixExpression(bool lhs)
{ {
if (mScanner->mToken == TK_SUB || mScanner->mToken == TK_BINARY_NOT || mScanner->mToken == TK_LOGICAL_NOT || if (mScanner->mToken == TK_SUB || mScanner->mToken == TK_BINARY_NOT || mScanner->mToken == TK_LOGICAL_NOT ||
mScanner->mToken == TK_MUL || mScanner->mToken == TK_INC || mScanner->mToken == TK_DEC || mScanner->mToken == TK_BINARY_AND || mScanner->mToken == TK_MUL || mScanner->mToken == TK_INC || mScanner->mToken == TK_DEC || mScanner->mToken == TK_BINARY_AND ||
mScanner->mToken == TK_BANKOF) mScanner->mToken == TK_BANKOF || mScanner->mToken == TK_NEW || mScanner->mToken == TK_DELETE)
{ {
Expression* nexp; Expression* nexp;
if (mScanner->mToken == TK_LOGICAL_NOT) if (mScanner->mToken == TK_LOGICAL_NOT)
@ -4487,6 +4487,127 @@ Expression* Parser::ParsePrefixExpression(bool lhs)
nexp->mLeft = ParsePrefixExpression(false);; nexp->mLeft = ParsePrefixExpression(false);;
nexp->mDecType = nexp->mLeft->mDecType; nexp->mDecType = nexp->mLeft->mDecType;
} }
else if (mScanner->mToken == TK_NEW)
{
nexp = new Expression(mScanner->mLocation, EX_PREFIX);
nexp->mToken = TK_NEW;
mScanner->NextToken();
Declaration * dec = ParseBaseTypeDeclaration(0);
Declaration* sconst = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
sconst->mBase = TheUnsignedIntTypeDeclaration;
sconst->mInteger = dec->mSize;
Expression* sexp = new Expression(mScanner->mLocation, EX_CONSTANT);
sexp->mDecValue = sconst;
sexp->mDecType = TheUnsignedIntTypeDeclaration;
nexp->mLeft = sexp;
nexp->mDecType = dec->BuildPointer(mScanner->mLocation);
if (mScanner->mToken == TK_OPEN_PARENTHESIS || dec->mDefaultConstructor)
{
Declaration* vdec = new Declaration(mScanner->mLocation, DT_VARIABLE);
vdec->mVarIndex = mLocalIndex++;
vdec->mBase = nexp->mDecType;
vdec->mSize = 2;
Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE);
vexp->mDecType = vdec->mBase;
vexp->mDecValue = vdec;
Expression* iexp = new Expression(mScanner->mLocation, EX_INITIALIZATION);
iexp->mToken = TK_ASSIGN;
iexp->mLeft = vexp;
iexp->mRight = nexp;
iexp->mDecType = nexp->mDecType;
Declaration* mdec = dec->mDefaultConstructor;
Expression* pexp = iexp;
if (ConsumeTokenIf(TK_OPEN_PARENTHESIS))
{
if (!ConsumeTokenIf(TK_CLOSE_PARENTHESIS))
{
pexp = ParseListExpression();
mdec = dec->mScope->Lookup(dec->mIdent);
ConsumeToken(TK_CLOSE_PARENTHESIS);
Expression* lexp = new Expression(mScanner->mLocation, EX_LIST);
lexp->mLeft = iexp;
lexp->mRight = pexp;
pexp = lexp;
}
}
Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
cexp->mDecValue = mdec;
cexp->mDecType = cexp->mDecValue->mBase;
Expression* dexp = new Expression(mScanner->mLocation, EX_CALL);
dexp->mLeft = cexp;
dexp->mRight = pexp;
ResolveOverloadCall(cexp, pexp);
Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
sexp->mLeft = dexp;
sexp->mRight = vexp;
nexp = sexp;
}
}
else if (mScanner->mToken == TK_DELETE)
{
nexp = new Expression(mScanner->mLocation, EX_PREFIX);
nexp->mToken = TK_DELETE;
mScanner->NextToken();
nexp->mLeft = ParsePrefixExpression(false);
nexp->mDecType = TheVoidTypeDeclaration;
if (nexp->mLeft->mDecType->mType == DT_TYPE_POINTER)
{
Declaration* dec = nexp->mLeft->mDecType->mBase;
if (dec->mDestructor)
{
Declaration* vdec = new Declaration(mScanner->mLocation, DT_VARIABLE);
vdec->mVarIndex = mLocalIndex++;
vdec->mBase = nexp->mLeft->mDecType;
vdec->mSize = 2;
Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE);
vexp->mDecType = vdec->mBase;
vexp->mDecValue = vdec;
Expression* iexp = new Expression(mScanner->mLocation, EX_INITIALIZATION);
iexp->mToken = TK_ASSIGN;
iexp->mLeft = vexp;
iexp->mRight = nexp->mLeft;
iexp->mDecType = nexp->mLeft->mDecType;
Declaration* mdec = dec->mDestructor;
Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
cexp->mDecValue = mdec;
cexp->mDecType = cexp->mDecValue->mBase;
Expression* dexp = new Expression(mScanner->mLocation, EX_CALL);
dexp->mLeft = cexp;
dexp->mRight = iexp;
Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
sexp->mLeft = dexp;
sexp->mRight = nexp;
nexp->mLeft = iexp;
nexp = sexp;
}
}
}
else else
{ {
nexp = new Expression(mScanner->mLocation, EX_PREFIX); nexp = new Expression(mScanner->mLocation, EX_PREFIX);

View File

@ -158,6 +158,8 @@ const char* TokenNames[] =
"'public'", "'public'",
"'protected'", "'protected'",
"'private'", "'private'",
"'new'",
"'delete'",
}; };
@ -1406,6 +1408,10 @@ void Scanner::NextRawToken(void)
mToken = TK_PROTECTED; mToken = TK_PROTECTED;
else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "private")) else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "private"))
mToken = TK_PRIVATE; mToken = TK_PRIVATE;
else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "new"))
mToken = TK_NEW;
else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "delete"))
mToken = TK_DELETE;
else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "operator")) else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "operator"))
{ {
NextRawToken(); NextRawToken();

View File

@ -157,6 +157,8 @@ enum Token
TK_PUBLIC, TK_PUBLIC,
TK_PROTECTED, TK_PROTECTED,
TK_PRIVATE, TK_PRIVATE,
TK_NEW,
TK_DELETE,
NUM_TOKENS NUM_TOKENS
}; };