I64 OptPass789A(CCompCtrl *cc, COptReg *reg_offsets, U8 *buf, CDebugInfo **_debug) {/* cc->pass == 7 is first time cc->pass == 8 is second time cc->pass == 9 is third time cc->pass == 9 is fourth time and repeated until size stops shrinking size is now known cc->pass == 10 is final pass, code is placed into buf. */ CIntermediateCode *tmpi, *tmpi_next; I64 i, count,num_lines = cc->max_line + 1 - cc->min_line, rip = 0,rip2; U8 *ptr, saved_arg1_arg2_r[3 * sizeof(CICArg)]; CCodeMisc *lb; CAOT *tmpaot; CAOTAbsAddr *tmpa; CAOTImportExport *tmpie; CAOTHeapGlobal *tmphg; CAOTHeapGlobalRef *tmphgr; CDebugInfo *debug_info; CAOTCtrl *aotc = cc->aotc; Bool short_jmp; CHashClass *tmpc; CHashFun *tmpf; CHashGlobalVar *tmpg; CExternUsage *tmpeu; if (_debug) { *_debug = debug_info = CAlloc(offset(CDebugInfo.body) + sizeof(U32) * (num_lines + 1)); debug_info->min_line = cc->min_line; debug_info->max_line = cc->max_line; if (cc->flags & CCF_AOT_COMPILE) debug_info->body[0] = aotc->rip; else debug_info->body[0] = buf; } else debug_info = NULL; if (Bt(&cc->flags, CCf_PASS_TRACE_PRESENT) && Bt(&cc->saved_pass_trace, cc->pass)) "$BK,1$$LTRED$$IV,1$This code gets merged together and patched.\n" "$FG$$IV,0$$BK,0$"; cc->last_float_op_ic = NULL; tmpi = &cc->coc.coc_head; tmpi->ic_last_start = -1; tmpi->ic_count = 0; tmpi = tmpi->next; while (tmpi->ic_code) { tmpi_next = tmpi->next; if (tmpi->ic_flags & ICF_PASS_TRACE && Bt(&cc->saved_pass_trace, cc->pass)) ICPut(cc, tmpi); rip2 = rip; if (cc->flags & CCF_AOT_COMPILE) rip2 += aotc->rip; else rip2 += buf; cc->cur_ic_float_op_num = 0; if (!(tmpi->ic_flags & ICF_CODE_FINAL)) { tmpi->ic_flags = tmpi->ic_flags & ~(ICF_PREV_DELETED | ICF_DONT_RESTORE) | ICF_CODE_FINAL; if (cc->pass == 7) cc->dont_push_float = Btr(&tmpi->ic_flags, ICf_DONT_PUSH_FLOAT0); MemCopy(saved_arg1_arg2_r, &tmpi->arg1, 3 * sizeof(CICArg)); tmpi->ic_count = 0; tmpi->ic_last_start = -1; if (tmpi->arg2.type.mode) { if (tmpi->ic_flags & ICF_ARG2_TO_F64) { ICFConvert(cc, tmpi, REG_RAX, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, FALSE, CN_A2, rip2); tmpi->arg2.type = MDF_REG + RT_I64; tmpi->arg2.reg = REG_RAX; tmpi->arg2.disp = 0; } else if (tmpi->ic_flags & ICF_ARG2_TO_INT) { ICFConvert(cc, tmpi, REG_RAX, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, TRUE, CN_A2, rip2); tmpi->arg2.type = MDF_REG + RT_I64; tmpi->arg2.reg = REG_RAX; tmpi->arg2.disp = 0; } } if (tmpi->arg1.type.mode) { if (tmpi->ic_flags & ICF_ARG1_TO_F64) { ICFConvert(cc, tmpi, REG_RDX, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, FALSE, CN_A1, rip2); tmpi->arg1.type = MDF_REG + RT_I64; tmpi->arg1.reg = REG_RDX; tmpi->arg1.disp = 0; } else if (tmpi->ic_flags & ICF_ARG1_TO_INT) { ICFConvert(cc,tmpi, REG_RDX, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, TRUE, CN_A1, rip2); tmpi->arg1.type = MDF_REG+RT_I64; tmpi->arg1.reg = REG_RDX; tmpi->arg1.disp = 0; } } switch [tmpi->ic_code] { start: start: case IC_ABS_ADDR: ICU16(tmpi, 0xB848); ICU64(tmpi, tmpi->ic_data); if (buf && cc->flags & CCF_AOT_COMPILE && !(cc->flags & (CCF_NO_ABSS | CCF_ASM_EXPRESSIONS))) { tmpa = CAlloc(sizeof(CAOTAbsAddr)); tmpa->next = aotc->abss; tmpa->type = AAT_ADD_U64; aotc->abss = tmpa; tmpa->rip = rip2 + tmpi->ic_count - 8; } break; case IC_HEAP_GLOBAL: ICU16(tmpi, 0xB848); ICU64(tmpi, 0); tmphg = tmpi->ic_data; if (buf && cc->flags & CCF_AOT_COMPILE && !(cc->flags & (CCF_NO_ABSS | CCF_ASM_EXPRESSIONS))) {//TODO:is this necessary--flags? tmphgr = CAlloc(sizeof(CAOTHeapGlobalRef)); tmphgr->next = tmphg->references; tmphg->references = tmphgr; tmphgr->rip = rip2 + tmpi->ic_count - 8; } break; case IC_ADDR_IMPORT: ICU8(tmpi, 0xB8); ICU32(tmpi, 0); if (buf && !(cc->flags & CCF_NO_ABSS)) { tmpg = tmpi->ic_data; tmpie = CAlloc(sizeof(CAOTImportExport)); tmpie->type = IET_IMM_U32; tmpie->rip = rip2 + tmpi->ic_count - 4; tmpie->next = tmpg->ie_list; tmpg->ie_list = tmpie; } ICU24(tmpi, 0xC06348); break; case IC_RIP: ICU16(tmpi, 0xB848); ICU64(tmpi, rip2 + tmpi->ic_count - 2); if (cc->flags & CCF_AOT_COMPILE && buf &&!(cc->flags & CCF_NO_ABSS)) { tmpa = CAlloc(sizeof(CAOTAbsAddr)); tmpa->next = aotc->abss; tmpa->type = AAT_ADD_U64; aotc->abss = tmpa; tmpa->rip = rip2 + tmpi->ic_count - 8; } break; end: ICMov(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, MDF_REG + RT_I64, REG_RAX, 0, rip2); break; case IC_BR_CARRY: ICFlagBranch(tmpi, rip, 0x72820F, buf); break; case IC_BR_NOT_CARRY: ICFlagBranch(tmpi, rip, 0x73830F, buf); break; case IC_BR_ZERO: ICTestAndBranch(tmpi, rip, 0x74840F, buf, rip2); break; case IC_BR_NOT_ZERO: ICTestAndBranch(tmpi, rip, 0x75850F, buf, rip2); break; case IC_BR_MM_ZERO: ICPreIncDec(tmpi, SLASH_OP_DEC, rip2); ICFlagBranch(tmpi, rip, 0x74840F, buf); break; case IC_BR_MM_NOT_ZERO: ICPreIncDec(tmpi, SLASH_OP_DEC, rip2); ICFlagBranch(tmpi, rip, 0x75850F, buf); break; case IC_BR_EQU_EQU: ICCompAndBranch(tmpi, FALSE, rip, 0x74840F, 0x74840F, 0x74840F, 0x74840F, buf, rip2); break; case IC_BR_EQU_EQU2: ICCompAndBranch(tmpi, TRUE, rip, 0x74840F, 0x74840F, 0x74840F, 0x74840F, buf, rip2); break; case IC_BR_NOT_EQU: ICCompAndBranch(tmpi, FALSE, rip, 0x75850F, 0x75850F, 0x75850F, 0x75850F, buf, rip2); break; case IC_BR_NOT_EQU2: ICCompAndBranch(tmpi, TRUE, rip, 0x75850F, 0x75850F, 0x75850F, 0x75850F, buf, rip2); break; case IC_BR_LESS: if (tmpi->ic_flags & ICF_USE_F64) ICFCmpAndBranch(cc, tmpi, rip, 0x72820F, 0x77870F, buf, rip2); else ICCompAndBranch(tmpi, FALSE, rip, 0x72820F, 0x7C8C0F, 0x77870F, 0x7F8F0F, buf, rip2); break; case IC_BR_LESS2: ICCompAndBranch(tmpi, TRUE, rip, 0x72820F, 0x7C8C0F, 0x77870F, 0x7F8F0F, buf, rip2); break; case IC_BR_GREATER_EQU: if (tmpi->ic_flags & ICF_USE_F64) ICFCmpAndBranch(cc, tmpi, rip, 0x73830F, 0x76860F, buf, rip2); else ICCompAndBranch(tmpi, FALSE, rip, 0x73830F, 0x7D8D0F, 0x76860F, 0x7E8E0F, buf, rip2); break; case IC_BR_GREATER_EQU2: ICCompAndBranch(tmpi, TRUE, rip, 0x73830F, 0x7D8D0F, 0x76860F, 0x7E8E0F, buf, rip2); break; case IC_BR_GREATER: if (tmpi->ic_flags & ICF_USE_F64) ICFCmpAndBranch(cc, tmpi, rip, 0x77870F, 0x72820F, buf, rip2); else ICCompAndBranch(tmpi, FALSE, rip, 0x77870F, 0x7F8F0F, 0x72820F, 0x7C8C0F, buf, rip2); break; case IC_BR_GREATER2: ICCompAndBranch(tmpi, TRUE, rip, 0x77870F, 0x7F8F0F, 0x72820F, 0x7C8C0F, buf, rip2); break; case IC_BR_LESS_EQU: if (tmpi->ic_flags & ICF_USE_F64) ICFCmpAndBranch(cc, tmpi, rip, 0x76860F, 0x73830F, buf, rip2); else ICCompAndBranch(tmpi, FALSE, rip, 0x76860F, 0x7E8E0F, 0x73830F, 0x7D8D0F, buf, rip2); break; case IC_BR_LESS_EQU2: ICCompAndBranch(tmpi, TRUE, rip, 0x76860F, 0x7E8E0F, 0x73830F, 0x7D8D0F, buf, rip2); break; case IC_BR_BT: ICBrBitOps(tmpi, rip, 0xA30F, 0x20BA0F, 0x72820F, buf, rip2); break; case IC_BR_BTS: ICBrBitOps(tmpi, rip, 0xAB0F, 0x28BA0F, 0x72820F, buf, rip2); break; case IC_BR_BTR: ICBrBitOps(tmpi, rip, 0xB30F, 0x30BA0F, 0x72820F, buf, rip2); break; case IC_BR_BTC: ICBrBitOps(tmpi, rip, 0xBB0F, 0x38BA0F, 0x72820F, buf, rip2); break; case IC_BR_NOT_BT: ICBrBitOps(tmpi, rip, 0xA30F, 0x20BA0F, 0x73830F, buf, rip2); break; case IC_BR_NOT_BTS: ICBrBitOps(tmpi, rip, 0xAB0F, 0x28BA0F, 0x73830F, buf, rip2); break; case IC_BR_NOT_BTR: ICBrBitOps(tmpi, rip, 0xB30F, 0x30BA0F, 0x73830F, buf, rip2); break; case IC_BR_NOT_BTC: ICBrBitOps(tmpi, rip, 0xBB0F, 0x38BA0F, 0x73830F, buf, rip2); break; case IC_BR_AND_ZERO: ICAndBranch(tmpi, rip, 0x74840F, buf, rip2); break; case IC_BR_AND_NOT_ZERO: ICAndBranch(tmpi, rip, 0x75850F, buf, rip2); break; case IC_SUB_CALL: lb = OptLabelFwd(tmpi->ic_data); ICU8(tmpi, 0xE8); ICU32(tmpi, lb->addr - (rip + 5)); break; case IC_JMP: lb = OptLabelFwd(tmpi->ic_data); short_jmp = ToBool(tmpi->ic_flags & ICF_SHORT_JMP); if (!buf && lb->addr != INVALID_PTR && I8_MIN + 5 < lb->addr - rip < I8_MAX - 5) short_jmp = TRUE; if (short_jmp) { tmpi->ic_flags |= ICF_SHORT_JMP; i = lb->addr - (rip + 2); if (buf || i) ICU16(tmpi, i << 8 + 0xEB); else tmpi->ic_code = IC_NOP1; } else { i = lb->addr - (rip + 5); ICU8(tmpi, 0xE9); ICU32(tmpi, i); } break; case IC_LABEL: lb = tmpi->ic_data; lb->addr = rip; if (lb->flags & CMF_POP_CMP) { ICAddRSP(tmpi, -8, FALSE); ICAddRSP(tmpi, 8, FALSE); } if (lb->type == CMT_ASM_LABEL) lb->addr += lb->rip; break; case IC_STR_CONST: case IC_GET_LABEL: lb = tmpi->ic_data; if (cc->flags & CCF_AOT_COMPILE) i = lb->addr + aotc->rip; else i = lb->addr + buf; ICLea(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, MDF_RIP_DISP32 + RT_PTR, 0, i, cc, buf, rip2); break; case IC_ASM: tmpaot = tmpi->ic_data; tmpi->ic_count += tmpaot->aot_U8s; if (buf) { MemCopy(buf + rip,tmpaot->buf, tmpaot->aot_U8s); Free(tmpaot->buf); tmpaot->buf = buf; tmpaot->rip = rip; tmpaot->rip2 = rip2; if (cc->flags & CCF_AOT_COMPILE) CompFixUpAOTAsm(cc, tmpaot); else CompFixUpJITAsm(cc, tmpaot); count = tmpi->ic_count; goto op789A_skip_copy; } break; case IC_CALL: i = tmpi->ic_data - (rip2 + 5); if (!(I32_MIN <= i <= I32_MAX) && !(cc->flags & CCF_AOT_COMPILE)) { ICU16(tmpi, 0xBB48); ICU64(tmpi, tmpi->ic_data); ICU16(tmpi, 0xD3FF); } else { ICU8(tmpi, 0xE8); ICU32(tmpi, i); } break; case IC_CALL_EXTERN: //Only for static modules ICU8(tmpi, 0xE8); ICU32(tmpi, 0); if (buf) { tmpf = tmpi->ic_data; tmpeu = CAlloc(sizeof(CExternUsage)); tmpeu->next = tmpf->ext_list; tmpf->ext_list = tmpeu; tmpeu->rip = rip2 + 1; } break; case IC_CALL_INDIRECT2: ICU16(tmpi, 0xBB48); if (cc->flags & CCF_AOT_COMPILE) i = rip2 + tmpi->ic_count; ICU64(tmpi, tmpi->ic_data); ICU16(tmpi, 0x13FF); if (buf && cc->flags & CCF_AOT_COMPILE && !(cc->flags & CCF_NO_ABSS)) { tmpa = CAlloc(sizeof(CAOTAbsAddr)); tmpa->next = aotc->abss; tmpa->type = AAT_ADD_U64; aotc->abss = tmpa; tmpa->rip = i; } break; case IC_CALL_IMPORT: if (OptionGet(OPTf_USE_IMM64)) { ICU16(tmpi, 0xBB48); ICU64(tmpi, 0); if (buf) { tmpf = tmpi->ic_data; tmpie = CAlloc(sizeof(CAOTImportExport)); tmpie->type = IET_IMM_I64; tmpie->rip = rip2+tmpi->ic_count - 8; tmpie->next = tmpf->ie_list; tmpf->ie_list = tmpie; } ICU16(tmpi, 0xD3FF); } else { ICU8(tmpi, 0xE8); ICU32(tmpi, 0); if (buf) { tmpf = tmpi->ic_data; tmpie = CAlloc(sizeof(CAOTImportExport)); tmpie->type = IET_REL_I32; tmpie->rip = rip2 + tmpi->ic_count - 4; tmpie->next = tmpf->ie_list; tmpf->ie_list = tmpie; } } break; end: tmpi->ic_flags &= ~ICF_CODE_FINAL; break; case IC_LEAVE: if (cc->htc.fun) { if (Bt(&cc->htc.fun->flags,Ff_INTERRUPT)) ICPopRegs(tmpi, REGG_CLOBBERED | cc->htc.fun->used_reg_mask & (REGG_LOCAL_VARS | REGG_LOCAL_NON_PTR_VARS | REGG_STACK_TMP)); else ICPopRegs(tmpi, cc->htc.fun->used_reg_mask & (REGG_LOCAL_VARS | REGG_LOCAL_NON_PTR_VARS)); } if (tmpi->ic_data <= I16_MAX) { if (tmpi->ic_data) ICU8(tmpi, 0xC9); //LEAVE else ICU8(tmpi, 0x5D); //POP RBP } else { ICAddRSP(tmpi, tmpi->ic_data); ICU8(tmpi, 0x5D); //POP RBP } if (cc->htc.fun && Bt(&cc->htc.fun->flags, Ff_INTERRUPT)) { if (Bt(&cc->htc.fun->flags, Ff_HASERRCODE)) ICAddRSP(tmpi, 8); ICU16(tmpi, 0xCF48); } else if (cc->htc.fun && cc->htc.fun->arg_count && (Bt(&cc->htc.fun->flags, Ff_RET1) || Bt(&cc->htc.fun->flags, Ff_ARGPOP)) && !Bt(&cc->htc.fun->flags, Ff_NOARGPOP)) { ICU8(tmpi, 0xC2); ICU16(tmpi, cc->htc.fun->arg_count << 3); } else ICU8(tmpi, 0xC3); break; case IC_RET: ICU8(tmpi, 0xC3); break; case IC_FS: ICZero(tmpi, REG_RAX); ICU32(tmpi, 0x8B4864); break; case IC_GS: ICZero(tmpi, REG_RAX); ICU32(tmpi, 0x8B4865); break; case IC_MOV_FS: ICZero(tmpi, REG_RAX); ICU8(tmpi, 0x64); //It's ugly to use ic_class here ICMov(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, MDF_DISP + CompRawType(tmpi->ic_class), REG_RAX, tmpi->ic_data, rip2); break; case IC_MOV_GS: ICZero(tmpi, REG_RAX); ICU8(tmpi, 0x65); //It's ugly to use ic_class here ICMov(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, MDF_DISP + CompRawType(tmpi->ic_class), REG_RAX, tmpi->ic_data, rip2); break; case IC_HOLYC_TYPECAST: ICMov(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); break; case IC_COM: ICUnaries(tmpi, SLASH_OP_NOT,rip2); break; case IC_NOT: ICNot(tmpi, rip2); break; case IC_UNARY_MINUS: if (tmpi->res.type.raw_type == RT_F64) ICFUnaryMinus(cc, tmpi, buf, rip2); else ICUnaries(tmpi, SLASH_OP_NEG, rip2); break; case IC_ADDR: case IC_MOV: ICMov(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); break; case IC_DEREF: ICDeref(tmpi, rip2); break; case IC_DEREF_PP: ICDerefPostIncDec(tmpi, SLASH_OP_INC, rip2); break; case IC_DEREF_MM: ICDerefPostIncDec(tmpi, SLASH_OP_DEC, rip2); break; case IC__PP: if (tmpi->ic_flags & ICF_USE_INT) ICPostIncDec(tmpi, SLASH_OP_INC, rip2); else ICFPostIncDec(cc, tmpi, CMP_TEMPLATE_INC, rip2); break; case IC__MM: if (tmpi->ic_flags & ICF_USE_INT) ICPostIncDec(tmpi, SLASH_OP_DEC, rip2); else ICFPostIncDec(cc, tmpi, CMP_TEMPLATE_DEC, rip2); break; case IC_PP_: if (tmpi->ic_flags & ICF_USE_INT) ICPreIncDec(tmpi, SLASH_OP_INC, rip2); else ICFPreIncDec(cc, tmpi, CMP_TEMPLATE_INC, rip2); break; case IC_MM_: if (tmpi->ic_flags & ICF_USE_INT) ICPreIncDec(tmpi, SLASH_OP_DEC, rip2); else ICFPreIncDec(cc, tmpi, CMP_TEMPLATE_DEC, rip2); break; case IC_LEA: ICLea(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, cc, buf, rip2); break; case IC_POWER: ICFPow(cc, tmpi, buf, rip2); break; case IC_SHL: ICShift(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, 0xE0D1E0D3E0C1, 0xE0D1E0D3E0C1, rip2); break; case IC_SHR: ICShift(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, 0xE8D1E8D3E8C1, 0xF8D1F8D3F8C1, rip2); break; case IC_MUL: if (tmpi->ic_flags & ICF_USE_INT) ICMul(tmpi, rip2); else ICFMul(cc, tmpi, buf, rip2); break; case IC_DIV: if (tmpi->ic_flags & ICF_USE_INT) ICDiv(tmpi, rip2); else ICFDiv(cc, tmpi, buf, rip2); break; case IC_MOD: if (tmpi->ic_flags & ICF_USE_INT) ICMod(tmpi, rip2); else ICFMod(cc, tmpi, rip2); break; case IC_AND: ICAddEct(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, 0x23, rip2); break; case IC_OR: ICAddEct(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, 0x0B, rip2); break; case IC_XOR: ICAddEct(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, 0x33, rip2); break; case IC_ADD: if (tmpi->ic_flags & ICF_USE_INT) ICAddEct(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, 0x03, rip2); else ICFAdd(cc, tmpi, buf, rip2); break; case IC_SUB: if (tmpi->ic_flags & ICF_USE_INT) ICSub(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2); else ICFSub(cc, tmpi, buf, rip2); break; case IC_EQU_EQU: ICComp(tmpi, 0x75, 0x75, rip2); break; case IC_NOT_EQU: ICComp(tmpi, 0x74, 0x74, rip2); break; case IC_LESS: if (tmpi->ic_flags & ICF_USE_INT) ICComp(tmpi, 0x73, 0x7D, rip2); else ICFCmp(cc, tmpi, CMP_TEMPLATE_LESS, rip2); break; case IC_GREATER_EQU: if (tmpi->ic_flags & ICF_USE_INT) ICComp(tmpi, 0x72, 0x7C, rip2); else ICFCmp(cc, tmpi, CMP_TEMPLATE_GREATER_EQU, rip2); break; case IC_GREATER: if (tmpi->ic_flags & ICF_USE_INT) ICComp(tmpi, 0x76, 0x7E, rip2); else ICFCmp(cc, tmpi, CMP_TEMPLATE_GREATER, rip2); break; case IC_LESS_EQU: if (tmpi->ic_flags & ICF_USE_INT) ICComp(tmpi, 0x77, 0x7F, rip2); else ICFCmp(cc, tmpi, CMP_TEMPLATE_LESS_EQU, rip2); break; case IC_AND_AND: ICAndAnd(tmpi, rip2); break; case IC_OR_OR: ICOrOr(tmpi, rip2); break; case IC_XOR_XOR: ICXorXor(tmpi, rip2); break; case IC_ASSIGN: ICAssign(tmpi, rip2); break; case IC_ASSIGN_PP: ICAssignPostIncDec(tmpi, SLASH_OP_INC, rip2); break; case IC_ASSIGN_MM: ICAssignPostIncDec(tmpi, SLASH_OP_DEC, rip2); break; case IC_SHL_EQU: ICShiftEqu(tmpi, tmpi->arg1_type_pointed_to, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, 0xE0D1E0D3E0C1, 0xE0D1E0D3E0C1, rip2); break; case IC_SHR_EQU: ICShiftEqu(tmpi, tmpi->arg1_type_pointed_to, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, 0xE8D1E8D3E8C1, 0xF8D1F8D3F8C1, rip2); break; case IC_MUL_EQU: if (tmpi->ic_flags & ICF_USE_INT) ICMulEqu(tmpi, rip2); else ICFOpEqu(cc, tmpi, SLASH_OP_FMUL, buf, rip2); break; case IC_DIV_EQU: if (tmpi->ic_flags & ICF_USE_INT) ICDivEqu(tmpi, FALSE, rip2); else ICFOpEqu(cc, tmpi, SLASH_OP_FDIV, buf, rip2); break; case IC_MOD_EQU: if (tmpi->ic_flags & ICF_USE_INT) ICDivEqu(tmpi, TRUE, rip2); else ICFModEqu(cc, tmpi, rip2); break; case IC_AND_EQU: ICAndEqu(tmpi, rip2); break; case IC_OR_EQU: ICOrEqu(tmpi, rip2); break; case IC_XOR_EQU: ICXorEqu(tmpi, rip2); break; case IC_ADD_EQU: if (tmpi->ic_flags & ICF_USE_INT) ICAddSubEctEqu(tmpi, tmpi->arg1_type_pointed_to, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, 0x010000000003, rip2); else ICFOpEqu(cc, tmpi, SLASH_OP_FADD, buf, rip2); break; case IC_SUB_EQU: if (tmpi->ic_flags & ICF_USE_INT) ICAddSubEctEqu(tmpi, tmpi->arg1_type_pointed_to, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, 0x29000000052B, rip2); else ICFOpEqu(cc, tmpi, SLASH_OP_FSUB, buf, rip2); break; case IC_SHL_CONST: ICShift(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, MDF_IMM + RT_I64, 0, tmpi->ic_data, 0xE0D1E0D3E0C1, 0xE0D1E0D3E0C1, rip2); break; case IC_SHR_CONST: ICShift(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, MDF_IMM + RT_I64, 0, tmpi->ic_data, 0xE8D1E8D3E8C1, 0xF8D1F8D3F8C1, rip2); break; case IC_ADD_CONST: ICAddSubEctImm(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, tmpi->ic_data, 0x0003, rip2); break; case IC_SUB_CONST: ICAddSubEctImm(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, tmpi->ic_data, 0x052B, rip2); break; case IC_ENTER: ICU32(tmpi, 0xEC8B4855); if (tmpi->ic_data) ICAddRSP(tmpi, -tmpi->ic_data, FALSE); if (cc->htc.fun) { if (Bt(&cc->htc.fun->flags, Ff_INTERRUPT)) ICPushRegs(tmpi, REGG_CLOBBERED | cc->htc.fun->used_reg_mask & (REGG_LOCAL_VARS | REGG_LOCAL_NON_PTR_VARS | REGG_STACK_TMP)); else { if (sys_var_init_flag && i) ICLocalVarInit(tmpi); ICPushRegs(tmpi, cc->htc.fun->used_reg_mask & (REGG_LOCAL_VARS | REGG_LOCAL_NON_PTR_VARS)); } for (i = 0; i < REG_REGS_NUM; i++) if (reg_offsets[i] > 0 && reg_offsets[i].offset != I64_MAX) { tmpc = OptClassFwd(reg_offsets[i].m->member_class); ICMov(tmpi, MDF_REG + RT_I64, i, 0, MDF_DISP + tmpc->raw_type, REG_RBP, reg_offsets[i].offset, rip2); } } break; case IC_ADD_RSP: ICAddRSP(tmpi, tmpi->ic_data); break; case IC_CALL_INDIRECT: if (I8_MIN <= tmpi->ic_data <= I8_MAX) { ICU24(tmpi, 0x2454FF); //CALL disp[RSP] ICU8(tmpi, tmpi->ic_data); } else { ICU24(tmpi, 0x2494FF); //CALL disp[RSP] ICU32(tmpi, tmpi->ic_data); } break; case IC_PUSH: ICPush(tmpi, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); break; case IC_POP: ICU8(tmpi, 0x58); break; case IC_INVLPG: ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); ICU24(tmpi, 0x38010F); break; case IC_CLFLUSH: ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); ICU24(tmpi, 0x38AE0F); break; case IC_RFLAGS_GET: ICU8(tmpi, 0x9C); ICPop(tmpi, MDF_REG + RT_I64, REG_RAX, 0, rip2); break; case IC_CARRY: ICU24(tmpi, 0xC0920F); //SETC AL ICU24(tmpi, 0x01E083); //AND EAX,1 break; case IC_RDTSC: ICCopyTemplate(cc, tmpi, CMP_TEMPLATE_RDTSC, TRUE, FALSE, FALSE, CN_INST); break; case IC_RFLAGS_SET: ICPush(tmpi, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); ICU8(tmpi, 0x9D); break; case IC_RBP_GET: ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, MDF_REG + RT_I64, REG_RBP, 0, rip2); break; case IC_RBP_SET: ICMov(tmpi, MDF_REG + RT_I64, REG_RBP, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); break; case IC_RSP_GET: ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, MDF_REG + RT_I64, REG_RSP, 0, rip2); break; case IC_RSP_SET: ICMov(tmpi, MDF_REG + RT_I64, REG_RSP, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); break; case IC_RETURN_VAL: case IC_RAX_SET: ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); break; case IC_RETURN_VAL2: case IC_RAX_GET: break; case IC_BT: ICBitOps(tmpi, &tmpi->arg1, &tmpi->arg2, tmpi->next, 0xA30F, 0x20BA0F, rip2); break; case IC_BTS: case IC_LBTS: ICBitOps(tmpi, &tmpi->arg1, &tmpi->arg2, tmpi->next, 0xAB0F, 0x28BA0F, rip2); break; case IC_BTR: case IC_LBTR: ICBitOps(tmpi, &tmpi->arg1, &tmpi->arg2, tmpi->next, 0xB30F, 0x30BA0F, rip2); break; case IC_BTC: case IC_LBTC: ICBitOps(tmpi, &tmpi->arg1, &tmpi->arg2, tmpi->next, 0xBB0F, 0x38BA0F, rip2); break; case IC_BSF: ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); ICU32(tmpi, 0xC0BC0F48); ICU16(tmpi, 0x0375); ICU24(tmpi, 0xD0F748); break; case IC_BSR: ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); ICU32(tmpi, 0xC0BD0F48); ICU16(tmpi, 0x0375); ICU24(tmpi, 0xD0F748); break; case IC_POPCNT: ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); ICU16(tmpi, 0xF348); ICU32(tmpi, 0xC0B80F48); break; case IC_SIGN_I64: ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); ICCopyTemplate(cc, tmpi, CMP_TEMPLATE_SIGN_I64, TRUE, FALSE, FALSE, CN_INST); break; case IC_TOUPPER: ICToUpper(tmpi, rip2); break; case IC_TO_I64: ICToI64(cc, tmpi, rip2); break; case IC_TO_F64: ICToF64(cc, tmpi, rip2); break; case IC_TO_BOOL: ICToBool(cc, tmpi, rip2); break; case IC_SQR: ICFTemplateFun(cc, tmpi, CMP_TEMPLATE_SQR, rip2); break; case IC_ABS: ICFTemplateFun(cc, tmpi, CMP_TEMPLATE_ABS, rip2); break; case IC_SQRT: ICFTemplateFun(cc, tmpi, CMP_TEMPLATE_SQRT, rip2); break; case IC_SIN: ICFTemplateFun(cc, tmpi, CMP_TEMPLATE_SIN, rip2); break; case IC_COS: ICFTemplateFun(cc, tmpi, CMP_TEMPLATE_COS, rip2); break; case IC_TAN: ICFTemplateFun(cc, tmpi, CMP_TEMPLATE_TAN, rip2); break; case IC_ATAN: ICFTemplateFun(cc, tmpi, CMP_TEMPLATE_ATAN, rip2); break; case IC_ABS_I64: ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); ICU24(tmpi, 0xC08548); ICU16(tmpi, 0x0379); ICU24(tmpi, 0xD8F748); break; case IC_MIN_I64: ICMinMax(tmpi, 0x4F, rip2); break; case IC_MAX_I64: ICMinMax(tmpi, 0x4C, rip2); break; case IC_MIN_U64: ICMinMax(tmpi, 0x47, rip2); break; case IC_MAX_U64: ICMinMax(tmpi, 0x42, rip2); break; case IC_MOD_U64: ICModU64(tmpi, rip2); break; case IC_SQR_I64: ICSqr(tmpi, SLASH_OP_IMUL, rip2); break; case IC_SQR_U64: ICSqr(tmpi, SLASH_OP_MUL, rip2); break; case IC_SWAP_U8: case IC_SWAP_U16: case IC_SWAP_U32: case IC_SWAP_I64: ICSwap(tmpi, rip2); break; case IC_QUEUE_INIT: ICQueueInit(tmpi, rip2); break; case IC_QUEUE_INSERT: ICQueueInsert(tmpi, rip2); break; case IC_QUEUE_INSERT_REV: ICQueueInsertRev(tmpi, rip2); break; case IC_QUEUE_REMOVE: ICQueueRemove(tmpi, rip2); break; case IC_STRLEN: ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); ICCopyTemplate(cc, tmpi, CMP_TEMPLATE_STRLEN, TRUE, FALSE, FALSE, CN_INST); break; case IC_IN_U32: if (tmpi->arg1.type & MDF_IMM) { ICU16(tmpi, 0xC033); if (tmpi->arg1.disp <= U8_MAX) ICU16(tmpi, 0xE5 + tmpi->arg1.disp << 8); else { ICU32(tmpi, 0xBA00 + OC_OP_SIZE_PREFIX + tmpi->arg1.disp << 16); ICU8(tmpi, 0xED); } } else { ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); ICU16(tmpi, 0xC033); ICU8(tmpi, 0xED); } break; case IC_IN_U16: if (tmpi->arg1.type & MDF_IMM) { ICU16(tmpi, 0xC033); if (tmpi->arg1.disp <= U8_MAX) ICU24(tmpi, 0xE500 + OC_OP_SIZE_PREFIX + tmpi->arg1.disp << 16); else { ICU32(tmpi, 0xBA00 + OC_OP_SIZE_PREFIX + tmpi->arg1.disp << 16); ICU16(tmpi, 0xED00 + OC_OP_SIZE_PREFIX); } } else { ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); ICU16(tmpi, 0xC033); ICU16(tmpi, 0xED00 + OC_OP_SIZE_PREFIX); } break; case IC_IN_U8: if (tmpi->arg1.type & MDF_IMM) { ICU16(tmpi, 0xC033); if (tmpi->arg1.disp <= U8_MAX) ICU16(tmpi, 0xE4 + tmpi->arg1.disp << 8); else { ICU32(tmpi, 0xBA00 + OC_OP_SIZE_PREFIX + tmpi->arg1.disp << 16); ICU8(tmpi, 0xEC); } } else { ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); ICU16(tmpi, 0xC033); ICU8(tmpi, 0xEC); } break; case IC_OUT_U32: if (tmpi->arg2.type & MDF_IMM) { ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); if (tmpi->arg2.disp <= U8_MAX) ICU16(tmpi, 0xE7 + tmpi->arg2.disp << 8); else { ICU32(tmpi, 0xBA00 + OC_OP_SIZE_PREFIX + tmpi->arg2.disp << 16); ICU8(tmpi, 0xEF); } } else { ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2); ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); ICU8(tmpi, 0xEF); } break; case IC_OUT_U16: if (tmpi->arg2.type & MDF_IMM) { ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); if (tmpi->arg2.disp <= U8_MAX) ICU24(tmpi, 0xE700 + OC_OP_SIZE_PREFIX + tmpi->arg2.disp << 16); else { ICU32(tmpi, 0xBA00 + OC_OP_SIZE_PREFIX + tmpi->arg2.disp << 16); ICU16(tmpi, 0xEF00 + OC_OP_SIZE_PREFIX); } } else { ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2); ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); ICU16(tmpi, 0xEF00 + OC_OP_SIZE_PREFIX); } break; case IC_OUT_U8: if (tmpi->arg2.type & MDF_IMM) { ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); if (tmpi->arg2.disp <= U8_MAX) ICU16(tmpi, 0xE6 + tmpi->arg2.disp << 8); else { ICU32(tmpi, 0xBA00 + OC_OP_SIZE_PREFIX + tmpi->arg2.disp << 16); ICU8(tmpi, 0xEE); } } else { ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2); ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2); ICU8(tmpi, 0xEE); } break; case IC_NOBOUND_SWITCH: ICSwitch(tmpi, rip, TRUE, cc, buf, rip2); break; case IC_SWITCH: ICSwitch(tmpi, rip, FALSE, cc, buf, rip2); break; case IC_NOP1: case IC_NOP2: OptFree(tmpi); goto op789A_next; case IC_CALL_START: case IC_PUSH_REGS: ICPushRegs(tmpi, tmpi->ic_data); break; case IC_CALL_END: ICPopRegs(tmpi, tmpi->ic_data); if (tmpi->res.type.mode) ICMov(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, MDF_REG + RT_I64, REG_RAX, 0, rip2); break; case IC_POP_REGS: ICPopRegs(tmpi, tmpi->ic_data); break; case IC_PUSH_CMP: case IC_CALL_END2: case IC_END: case IC_ADD_RSP1: break; default: "Pass:%d Missing IC handler\n", cc->pass; ICPut(cc, tmpi); LexExcept(cc, "Compiler Optimization Error at "); } if (tmpi->res.type.mode) { if (tmpi->ic_flags & ICF_RES_TO_F64) { if (tmpi->ic_code == IC_PUSH_CMP) { ICU24(tmpi, 0x242CDF); //FILD U64 [RSP] ICU24(tmpi, 0x241CDD); //FSTP U64 [RSP] } else { ICFConvert(cc, tmpi, REG_RAX, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, FALSE, CN_RES, rip2); if (!Bt(&tmpi->ic_flags, ICf_DONT_POP_FLOAT0 + cc->cur_ic_float_op_num - 1)) ICMov(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, MDF_REG + RT_I64, REG_RAX, 0, rip2); } } else if (tmpi->ic_flags & ICF_RES_TO_INT) { ICFConvert(cc, tmpi, REG_RAX, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, TRUE, CN_RES, rip2); ICMov(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, MDF_REG + RT_I64, REG_RAX, 0, rip2); } } } count = tmpi->ic_count; if (tmpi->ic_flags & ICF_DEL_PREV_INS) { if (cc->pass > 8) count = tmpi->ic_last_start; tmpi->ic_flags &= ~ICF_DEL_PREV_INS; } if (count && buf) MemCopy(buf + rip, tmpi->ic_body, count); op789A_skip_copy: if (debug_info && cc->min_line <= tmpi->ic_line <= cc->max_line) { i = tmpi->ic_line-cc->min_line; if (!debug_info->body[i]) debug_info->body[i] = rip2; } if (tmpi->ic_flags & ICF_PASS_TRACE && Bt(&cc->saved_pass_trace, cc->pass) && count) { "$RED$"; if (buf) Un(buf + rip,count, 64); else Un(tmpi->ic_body, count, 64); "$FG$"; } if (!(tmpi->ic_flags & (ICF_CODE_FINAL | ICF_DONT_RESTORE))) MemCopy(&tmpi->arg1, saved_arg1_arg2_r, 3 * sizeof(CICArg)); rip += count; if (tmpi->ic_count >= IC_BODY_SIZE && tmpi->ic_code != IC_ASM) throw('Compiler'); op789A_next: tmpi = tmpi_next; } lb = cc->coc.coc_next_misc; while (lb != &cc->coc.coc_next_misc) { switch (lb->type) { case CMT_STR_CONST: lb->addr = rip; if (buf) MemCopy(buf + rip, lb->str, lb->st_len); rip += lb->st_len; break; case CMT_JMP_TABLE: lb->addr = rip; ptr = buf + lb->addr; if (lb->flags & (CMF_I8_JMP_TABLE | CMF_U8_JMP_TABLE)) { if (buf) for (i = 0; i < lb->range; i++) *ptr++ = lb->jmp_table[i]->addr - lb->begin->addr; rip += lb->range; } else if (lb->flags & (CMF_I16_JMP_TABLE | CMF_U16_JMP_TABLE)) { if (buf) for (i = 0; i < lb->range; i++) *ptr(U16 *)++ = lb->jmp_table[i]->addr - lb->begin->addr; rip += lb->range << 1; } else { if (buf) for (i = 0; i < lb->range; i++) { if (cc->flags & CCF_AOT_COMPILE && !(cc->flags & CCF_NO_ABSS)) { tmpa = CAlloc(sizeof(CAOTAbsAddr)); tmpa->next = aotc->abss; tmpa->type = AAT_ADD_U32; aotc->abss = tmpa; tmpa->rip = aotc->rip + lb->addr + i << 2; *ptr(U32 *)++ = lb->jmp_table[i]->addr + aotc->rip; } else *ptr(U32 *)++ = lb->jmp_table[i]->addr + buf; } rip += lb->range << 2; } break; case CMT_FLOAT_CONSTS: lb->addr = rip; if (buf) MemCopy(buf + lb->addr, lb->float_consts, lb->num_consts * sizeof(F64)); rip += lb->num_consts * sizeof(F64); break; } lb = lb->next; } if (debug_info) { if (cc->flags & CCF_AOT_COMPILE) debug_info->body[num_lines] = rip + aotc->rip; else debug_info->body[num_lines] = rip + buf; } return rip; }