void RebuildCppProlog(SYMBOL *sym, int isproto) { int reg_used; int reg_alloc; int param_count; int need_comma; int n; // Find registers used in function reg_used = FunctionRegAnalyse(sym, &funcprop); reg_alloc = 0; // Output helpful header if (isproto == 0) { RebuildEmit("\n//****************************************\n"); RebuildEmit("// Function: %s\n", sym->Name); RebuildEmit("//****************************************\n\n"); } if (!isproto) { RebuildEmit("// rrrrrrrrrrrrrrrriiiiddddddddfrsz\n"); RebuildEmit("// fedcba9876543210321076543210rtpr\n"); RebuildEmit("//src_reg = %s\n", Bin32(funcprop.src_reg)); RebuildEmit("//dst_reg = %s\n", Bin32(funcprop.dst_reg)); RebuildEmit("//assign_reg = %s\n", Bin32(funcprop.assign_reg)); RebuildEmit("//uninit_reg = %s\n", Bin32(funcprop.uninit_reg)); RebuildEmit("//used_reg = %s\n", Bin32(funcprop.reg_used)); RebuildEmit("//tfr = %s\n", Bin32(ThisFunctionRegs)); RebuildEmit("\n"); } else RebuildEmit("static "); // Output function decl switch(ThisFunctionRetType) { case RET_null: RebuildEmit(" ?; // Error report to MobileSorcery\n"); break; case RET_void: RebuildEmit("void "); break; case RET_float: case RET_int: case RET_double: RebuildEmit("int "); break; } RebuildEmit("%s_%d(", sym->Name, sym->LocalScope); param_count = sym->Params; if (param_count > 4) param_count = 4; need_comma = 0; for (n=0;n<param_count;n++) { if (need_comma) RebuildEmit(", "); RebuildEmit("int %s", Cpp_reg[REG_i0 + n]); need_comma = 1; reg_alloc |= 1 << (REG_i0 + n); } if (isproto) { RebuildEmit(");\n"); return; } RebuildEmit(")\n{\n"); // Write local decl // Remove regs that are already declared in func decl // ok this has sort of been reverse engineered by looking at the bitmasks in the rebuilt code... ;) // this is added to remove warnings about unusued variables. reg_used &= ThisFunctionRegs | (1 << REG_r14) | (1 << REG_r15) | (1 << REG_i0) | (1 << REG_i1) | (1 << REG_i2) | (1 << REG_i3); reg_used &= (~reg_alloc); // remove sp from locals reg_used &= ~(1 << REG_sp); reg_used &= ~(1 << REG_zero); if (ThisFunctionRetType != RET_null && ThisFunctionRetType != RET_void) reg_used |= (1 << REG_r14); if (ThisFunctionRetType == RET_double) reg_used |= (1 << REG_r15); if (reg_used) { RebuildEmit("\tint "); need_comma = 0; for (n=0;n<32;n++) { if (reg_used & (1 << n)) { if (need_comma) RebuildEmit(", "); RebuildEmit("%s", Cpp_reg[n]); if (funcprop.uninit_reg & (1<<n)) RebuildEmit("=0"); need_comma = 1; } } RebuildEmit(";\n\n"); } }
int FunctionRegAnalyse(SYMBOL *sym, FuncProp *fp) { OpcodeInfo thisOp; uchar *ip, *ip_end; int params,n; fp->src_reg = 0; fp->dst_reg = 0; fp->assign_reg = 0; fp->uninit_reg = 0; // Make sure we have a valid symbol if (!sym) return -1; // Make sure the symbol is a function if (sym->Type != SECT_code) return -1; // Get the start and end of the function in the code array ip_end = (uchar *) ArrayPtr(&CodeMemArray, sym->EndIP); ip = (uchar *) ArrayPtr(&CodeMemArray, sym->Value); // Set up the parameter regs params = sym->Params; for (n=0;n<params;n++) { fp->assign_reg |= REGBIT(REG_i0 + n); } // Scan the function #ifdef AFDEBUG printf("\n"); #endif while(1) { if (ip > ip_end) break; #ifdef AFDEBUG { char buf[2560]; buf[0] = 0; DisassembleFromSource(ip - CodeMemArray.array, buf); printf("%s\n", buf); } #endif ip = DecodeOpcode(&thisOp, ip); // Ignor push and pop if (thisOp.op == _PUSH) continue; if (thisOp.op == _POP) continue; //----------------------------------------- // Deal with syscalls // for some strange reason rd is the syscallId which will // tag unused registers as used for void functions //----------------------------------------- if(thisOp.op == _SYSCALL) { FunctionReg_Syscall(&thisOp, fp); } // Check for a dest reg else if (thisOp.flags & fetch_d) { if (thisOp.rd < 32) { // Since this is a dst regs we say its initialized fp->assign_reg |= REGBIT(thisOp.rd); // Say this reg was used as a dst reg fp->dst_reg |= REGBIT(thisOp.rd); } } // Check for a source reg if (thisOp.flags & fetch_s) { if (thisOp.rs < 32) { // check if this reg was assigned previously, if it was'nt it is uninitialized before use int is_assigned = fp->assign_reg & REGBIT(thisOp.rs); if (!is_assigned) fp->uninit_reg |= REGBIT(thisOp.rs); fp->src_reg |= REGBIT(thisOp.rs); } } //----------------------------------------- // Deal with immediate calls //----------------------------------------- // Add the call parameters to the used list if (thisOp.op == _CALLI) { FunctionReg_Calli(&thisOp, fp); } //----------------------------------------- // Deal with register calls //----------------------------------------- // Add the call parameters to the used list if (thisOp.op == _CALL) { FunctionReg_CallReg(&thisOp, fp); } } #ifdef AFDEBUG printf("\n"); printf(" rrrrrrrrrrrrrrrriiiiddddddddfrsz\n"); printf(" fedcba9876543210321076543210rtpr\n"); printf("src_reg = %s\n", Bin32(fp->src_reg)); printf("dst_reg = %s\n", Bin32(fp->dst_reg)); printf("assign_reg = %s\n", Bin32(fp->assign_reg)); printf("uninit_reg = %s\n", Bin32(fp->uninit_reg)); if (fp->uninit_reg) printf(""); #endif // Make sure zr is never uninitialized fp->uninit_reg &= ~REGBIT(REG_zero); // Make a composit of which reg's were used fp->reg_used = fp->src_reg | fp->dst_reg; return fp->reg_used; }