static void BasicBlock_SetJumpAddr(KonohaContext *kctx, BasicBlock *bb, char *vcode) { while(bb != NULL) { BasicBlock_SetVisited(bb); if(bb->branchid != -1) { BasicBlock *bbJ = BasicBlock_leapJump(kctx, BasicBlock_FindById(kctx, bb->branchid)); KVirtualCode *op = (KVirtualCode *)(vcode + bb->lastoffset); OPJMP *j = (OPJMP *) op; DBG_ASSERT(j->opcode == OPCODE_JMP || j->opcode == OPCODE_JMPF); j->jumppc = (KVirtualCode *)(vcode + bbJ->codeoffset); if(BasicBlock_size(bb) > 1) { KVirtualCode *opPREV = (KVirtualCode *)(vcode + bb->lastoffset - sizeof(KVirtualCode)); if(opPREV->opcode == OPCODE_JMPF && bb->nextid != -1) { BasicBlock *block = BasicBlock_leapJump(kctx, BasicBlock_FindById(kctx, bb->nextid)); ((OPJMPF *)opPREV)->jumppc = (KVirtualCode *)(vcode + block->codeoffset); } } bbJ = BasicBlock_FindById(kctx, bb->branchid); if(!BasicBlock_isVisited(bbJ)) { BasicBlock_SetVisited(bbJ); BasicBlock_SetJumpAddr(kctx, bbJ, vcode); } } bb = BasicBlock_FindById(kctx, bb->nextid); } }
static void MiniVMBuilder_setBlock(KonohaContext *kctx, KBuilder *builder, bblock_t labelId) { BasicBlock *labelNode; BasicBlock *bb = BasicBlock_FindById(kctx, builder->bbMainId); DBG_ASSERT(bb != NULL); labelNode = BasicBlock_FindById(kctx, labelId); labelNode->incoming += 1; builder->bbMainId = BasicBlock_id(kctx, labelNode); }
static void ASM_LABEL(KonohaContext *kctx, KBuilder *builder, bblock_t labelId) { BasicBlock *bb = BasicBlock_FindById(kctx, builder->bbMainId); DBG_ASSERT(bb != NULL); DBG_ASSERT(bb->nextid == -1); BasicBlock *labelNode = BasicBlock_FindById(kctx, labelId); labelNode->incoming += 1; builder->bbMainId = BasicBlock_id(kctx, labelNode); bb->nextid = builder->bbMainId; }
static BasicBlock *BasicBlock_leapJump(KonohaContext *kctx, BasicBlock *bb) { while(bb->nextid != -1) { if(BasicBlock_size(bb) != 0) return bb; bb = BasicBlock_FindById(kctx, bb->nextid); } if(bb->nextid == -1 && bb->branchid != -1 && BasicBlock_size(bb) == 1) { return BasicBlock_leapJump(kctx, BasicBlock_FindById(kctx, bb->branchid)); } return bb; }
static void MiniVMBuilder_JumpTo(KonohaContext *kctx, KBuilder *builder, bblock_t labelId) { BasicBlock *bb = BasicBlock_FindById(kctx, builder->bbMainId); DBG_ASSERT(bb != NULL); //DBG_ASSERT(bb->nextid == -1); if(bb->branchid == -1) { BasicBlock *labelNode; ASM(JMP, NULL); labelNode = BasicBlock_FindById(kctx, labelId); bb = BasicBlock_FindById(kctx, builder->bbMainId); bb->branchid = BasicBlock_id(kctx, labelNode); labelNode->incoming += 1; } }
static BasicBlock *new_BasicBlock(KonohaContext *kctx, size_t max, bblock_t oldId) { BasicBlock *bb; KBuffer wb; KLIB KBuffer_Init(&(kctx->stack->cwb), &wb); bb = (BasicBlock *)KLIB KBuffer_Alloca(kctx, &wb, max); if(oldId != -1) { BasicBlock *oldbb = BasicBlock_FindById(kctx, oldId); if(((char *)oldbb) + oldbb->max == (char *)bb) { oldbb->max += (max - sizeof(BasicBlock)); wb.m->bytesize -= sizeof(BasicBlock); return oldbb; } memcpy(bb, oldbb, oldbb->size); oldbb->newid = BasicBlock_id(kctx, bb); oldbb->size = 0; } else { bb->size = sizeof(BasicBlock); bb->newid = -1; bb->nextid = -1; bb->branchid = -1; } bb->max = max; bb->codeoffset = -1; bb->lastoffset = -1; return bb; }
static bblock_t BasicBlock_id(KonohaContext *kctx, BasicBlock *bb) { while(bb->newid != -1) { bb = BasicBlock_FindById(kctx, bb->newid); } return ((char *)bb) - kctx->stack->cwb.bytebuf; }
static bblock_t AsmJMPF(KonohaContext *kctx, KBuilder *builder, int localStack, bblock_t jumpId) { BasicBlock *bb = BasicBlock_FindById(kctx, builder->bbMainId); DBG_ASSERT(bb != NULL); DBG_ASSERT(bb->nextid == -1 && bb->branchid == -1); bblock_t nextId = new_BasicBlockLABEL(kctx); ASM(JMPF, NULL, NC_(localStack)); bb = BasicBlock_FindById(kctx, builder->bbMainId); BasicBlock *jumpBlock = BasicBlock_FindById(kctx, jumpId); BasicBlock *nextBlock = BasicBlock_FindById(kctx, nextId); bb->branchid = BasicBlock_id(kctx, jumpBlock); bb->nextid = nextId; nextBlock->incoming += 1; jumpBlock->incoming += 1; builder->bbMainId = nextId; return nextId; }
static void CreateBranch(KonohaContext *kctx, KBuilder *builder, intptr_t src, bblock_t ThenBB, bblock_t ElseBB, bool emitJumpToThenBlock) { BasicBlock *ThenBlock, *ElseBlock; BasicBlock *bb = BasicBlock_FindById(kctx, builder->bbMainId); DBG_ASSERT(bb != NULL); DBG_ASSERT(/*bb->nextid == -1 &&*/ bb->branchid == -1); ASM(JMPF, NULL, NC_(src)); if(emitJumpToThenBlock) { ASM(JMP, NULL); } bb = BasicBlock_FindById(kctx, builder->bbMainId); ThenBlock = BasicBlock_FindById(kctx, ThenBB); ElseBlock = BasicBlock_FindById(kctx, ElseBB); bb->branchid = ElseBB; bb->nextid = ThenBB; ThenBlock->incoming += 1; ElseBlock->incoming += 1; }
static void BasicBlock_WriteByteCode(KonohaContext *kctx, bblock_t blockId, ByteCodeWriter *writer) { BasicBlock *bb = BasicBlock_FindById(kctx, blockId); while(bb != NULL && bb->codeoffset == -1) { intptr_t len = bb->size - sizeof(BasicBlock); bb->codeoffset = CodeOffset(writer); bb->lastoffset = -1; // reset lastoffset if(len > 0) { bblock_t id = BasicBlock_id(kctx, bb); WriteByteCode(writer, ((char *)bb) + sizeof(BasicBlock), len); bb = BasicBlock_FindById(kctx, id); // recheck bb->lastoffset = CodeOffset(writer) - sizeof(KVirtualCode); DBG_ASSERT(bb->codeoffset + ((len / sizeof(KVirtualCode)) - 1) * sizeof(KVirtualCode) == (size_t) bb->lastoffset); } else { DBG_ASSERT(bb->branchid == -1); } bb = BasicBlock_FindById(kctx, bb->nextid); } bb = BasicBlock_FindById(kctx, blockId); while(bb != NULL) { if(bb->branchid != -1) { BasicBlock *bbJ = BasicBlock_FindById(kctx, bb->branchid); if(bbJ->codeoffset == -1) { BasicBlock_WriteByteCode(kctx, bb->branchid, writer); } } bb = BasicBlock_FindById(kctx, bb->nextid); } }
static void BasicBlock_WriteBuffer(KonohaContext *kctx, bblock_t blockId, KBuffer *wb) { BasicBlock *bb = BasicBlock_FindById(kctx, blockId); while(bb != NULL && bb->codeoffset == -1) { size_t len = bb->size - sizeof(BasicBlock); bb->codeoffset = CodeOffset(wb); if(bb->nextid == bb->branchid && bb->nextid != -1) { bb->branchid = -1; len -= sizeof(KVirtualCode); // remove unnecesarry jump .. } if(len > 0) { bblock_t id = BasicBlock_id(kctx, bb); char buf[len]; // bb is growing together with wb. memcpy(buf, ((char *)bb) + sizeof(BasicBlock), len); KLIB KBuffer_Write(kctx, wb, buf, len); bb = BasicBlock_FindById(kctx, id); // recheck bb->lastoffset = CodeOffset(wb) - sizeof(KVirtualCode); DBG_ASSERT(bb->codeoffset + ((len / sizeof(KVirtualCode)) - 1) * sizeof(KVirtualCode) == bb->lastoffset); } else { DBG_ASSERT(bb->branchid == -1); } bb = BasicBlock_FindById(kctx, bb->nextid); } bb = BasicBlock_FindById(kctx, blockId); while(bb != NULL) { if(bb->branchid != -1 /*&& bb->branchid != builder->bbReturnId*/) { BasicBlock *bbJ = BasicBlock_FindById(kctx, bb->branchid); if(bbJ->codeoffset == -1) { BasicBlock_WriteBuffer(kctx, bb->branchid, wb); } } bb = BasicBlock_FindById(kctx, bb->nextid); } }
static void BasicBlock_Optimize(KonohaContext *kctx, bblock_t blockId, ByteCodeWriter *writer) { BasicBlock *bb = BasicBlock_FindById(kctx, blockId); while(bb != NULL && bb->lastoffset == -1) { bb->lastoffset = 0; if(bb->nextid == bb->branchid && bb->nextid != -1) { //bb->branchid = -1; //writer->codesize -= sizeof(KVirtualCode); //bb->size -= sizeof(KVirtualCode); // remove unnecesarry jump .. } bb = BasicBlock_FindById(kctx, bb->nextid); } bb = BasicBlock_FindById(kctx, blockId); while(bb != NULL) { if(bb->branchid != -1) { BasicBlock *bbJ = BasicBlock_FindById(kctx, bb->branchid); if(bbJ->lastoffset == -1) { BasicBlock_Optimize(kctx, bb->branchid, writer); } } bb = BasicBlock_FindById(kctx, bb->nextid); } }
static bblock_t BasicBlock_Add(KonohaContext *kctx, bblock_t blockId, kfileline_t uline, KVirtualCode *op, size_t size, size_t padding_size) { BasicBlock *bb = BasicBlock_FindById(kctx, blockId); DBG_ASSERT(bb->newid == -1); DBG_ASSERT(size <= padding_size); DBG_ASSERT(bb->nextid == -1 && bb->branchid == -1); if(!(bb->size + size < bb->max)) { size_t newsize = newsize2(bb->max); bb = new_BasicBlock(kctx, newsize, blockId); } memcpy(((char *)bb) + bb->size, op, size); bb->size += padding_size; return BasicBlock_id(kctx, bb); }
static struct KVirtualCode *CompileVirtualCode(KonohaContext *kctx, KBuilder *builder, bblock_t beginId, bblock_t returnId) { KVirtualCode *vcode; ByteCodeWriter writer = {NULL, 0, builder->InstructionSize * sizeof(KVirtualCode)}; BasicBlock_Optimize(kctx, beginId, &writer); DBG_P(">>>>>> codesize=%d", writer.codesize); DBG_ASSERT(writer.codesize != 0); vcode = (KVirtualCode *)KCalloc_UNTRACE(writer.codesize, 1); writer.current = vcode; BasicBlock_WriteByteCode(kctx, beginId, &writer); BasicBlock_WriteByteCode(kctx, returnId, &writer); BasicBlock_SetJumpAddr(kctx, BasicBlock_FindById(kctx, beginId), (char *)vcode); vcode = MakeThreadedCode(kctx, builder, vcode, writer.codesize); DumpVirtualCode(kctx, vcode); return vcode; }
static bool Block_HasTerminatorInst(KonohaContext *kctx, bblock_t blockId) { BasicBlock *bb = BasicBlock_FindById(kctx, blockId); unsigned size = BasicBlock_size(bb); KVirtualCode *code, *lastInst; if(size == 0) return false; code = (KVirtualCode *)(((char *)bb) + sizeof(BasicBlock)); lastInst = code + (size - 1); switch(lastInst->opcode) { #define CASE(OP) case OPCODE_##OP: return true; CASE(EXIT); CASE(RET); CASE(JMP); CASE(JMPF); CASE(YIELD); CASE(ERROR); #undef CASE } return false; }