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 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 size_t BasicBlock_size(KonohaContext *kctx, kBasicBlock *bb, size_t c) { L_TAIL:; if(bb == NULL || BasicBlock_isVisited(bb)) return c; BasicBlock_setVisited(bb, 1); if(bb->nextBlock != NULL) { if(BasicBlock_isVisited(bb) || BasicBlock_opcode(bb->nextBlock) == OPCODE_RET) { kBasicBlock *bb2 = (kBasicBlock*)new_BasicBlockLABEL(kctx); bb2->branchBlock = bb->nextBlock; ((kBasicBlock*)bb)->nextBlock = bb2; } } if(bb->branchBlock != NULL && bb->nextBlock != NULL) { DBG_ASSERT(bb->branchBlock != bb->nextBlock); c = BasicBlock_size(kctx, bb->nextBlock, c + BasicBlock_peephole(kctx, bb)); bb = bb->branchBlock; goto L_TAIL; } if(bb->branchBlock != NULL) { DBG_ASSERT(bb->nextBlock == NULL); kBasicBlock_add(bb, JMP); c = BasicBlock_peephole(kctx, bb) + c; bb = bb->branchBlock; goto L_TAIL; } c = BasicBlock_peephole(kctx, bb) + c; bb = bb->nextBlock; goto L_TAIL; }
static kByteCode* new_ByteCode(KonohaContext *kctx, kBasicBlock *beginBlock, kBasicBlock *endBlock) { #define CT_ByteCodeVar CT_ByteCode kByteCodeVar *kcode = GCSAFE_new(ByteCodeVar, NULL); kBasicBlock *prev[1] = {}; kcode->fileid = ctxcode->uline; //TODO kcode->codesize = BasicBlock_size(kctx, beginBlock, 0) * sizeof(VirtualMachineInstruction); kcode->code = (VirtualMachineInstruction*)KCALLOC(kcode->codesize, 1); endBlock->code = kcode->code; // dummy { VirtualMachineInstruction *op = BasicBlock_copy(kctx, kcode->code, beginBlock, prev); DBG_ASSERT(op - kcode->code > 0); endBlock->code = NULL; BasicBlock_copy(kctx, op, endBlock, prev); BasicBlock_setjump(beginBlock); } return kcode; }
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; }