MWCC/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeAssembly.c

1614 lines
54 KiB
C
Raw Permalink Normal View History

#include "compiler/PCodeAssembly.h"
2022-12-29 12:32:55 +00:00
#include "compiler/CError.h"
#include "compiler/CFunc.h"
#include "compiler/CMangler.h"
#include "compiler/CParser.h"
#include "compiler/CodeGen.h"
#include "compiler/ObjGenMachO.h"
#include "compiler/PCode.h"
#include "compiler/PCodeInfo.h"
#include "compiler/PCodeListing.h"
#include "compiler/PPCError.h"
#include "compiler/RegisterInfo.h"
#include "compiler/StackFrame.h"
#include "compiler/TOC.h"
#include "compiler/objects.h"
static UInt32 codebase;
2022-12-29 12:32:55 +00:00
static SInt32 pcode_update_mem_labeldiff_imm(PCode *instr, const PCodeArg *op, WeirdOperand *wop) {
SInt32 offset;
Object *object;
UInt8 arg;
if (op->kind == PCOp_MEMORY) {
object = op->data.mem.obj;
offset = op->data.mem.offset;
switch (object->datatype) {
case DLOCAL:
switch ((UInt8) op->arg) {
case RefType_1:
offset += local_offset_16(object);
break;
case RefType_D:
offset = local_offset_lo(object, offset);
break;
case RefType_C:
offset = local_offset_ha(object, offset);
break;
default:
CError_FATAL(83);
}
break;
case DDATA:
case DFUNC:
case DVFUNC:
case DNONLAZYPTR:
switch ((UInt8) op->arg) {
case RefType_6:
wop->type = MW_RELOC_5_LO16;
break;
case RefType_2:
wop->type = MW_RELOC_3;
break;
case RefType_3:
wop->type = MW_RELOC_4;
break;
case RefType_8:
wop->type = MW_RELOC_7_HA16;
break;
case RefType_7:
wop->type = MW_RELOC_6_HI16;
break;
default:
CError_FATAL(135);
}
wop->x2 = object;
CError_ASSERT(144, offset == 0);
break;
default:
CError_FATAL(164);
}
} else if (op->kind == PCOp_LABELDIFF) {
arg = op->arg;
offset = op->data.labeldiff.labelA->block->codeOffset - op->data.labeldiff.labelB->block->codeOffset;
offset += op->data.labeldiff.offset;
if (arg == 1)
offset = -offset;
if (offset > 0x7FFF)
2023-01-20 12:25:38 +00:00
PPCError_Error(PPCErrorStr109);
2022-12-29 12:32:55 +00:00
else if (offset < -0x8000)
2023-01-20 12:25:38 +00:00
PPCError_Error(PPCErrorStr109);
2022-12-29 12:32:55 +00:00
} else if (op->kind == PCOp_IMMEDIATE) {
offset = op->data.imm.value;
} else {
CError_FATAL(193);
}
return offset;
}
2022-12-29 12:32:55 +00:00
UInt32 assemblepcode(PCode *instr, UInt32 offset, WeirdOperand *wop) {
UInt32 bits;
bits = opcodeinfo[instr->op].insn;
wop->type = -1;
wop->x6 = 0;
switch (instr->op) {
case PC_BL: {
int flag = PCODE_FLAG_SET_T(instr) & fAbsolute;
if (instr->args[0].kind == PCOp_MEMORY) {
bits |= instr->args[0].data.mem.offset & 0x3FFFFFC;
wop->type = MW_RELOC_2_BR24;
wop->x2 = instr->args[0].data.mem.obj;
if (flag == 0)
wop->type = MW_RELOC_2_BR24;
else
CError_FATAL(246);
} else if (instr->args[0].kind == PCOp_IMMEDIATE) {
bits |= instr->args[0].data.imm.value & 0x3FFFFFC;
if (flag)
bits |= 2;
} else {
bits |= (instr->args[0].data.label.label->block->codeOffset - offset) & 0x3FFFFFC;
if (flag)
CError_FATAL(261);
}
break;
}
case PC_B: {
int flag = PCODE_FLAG_SET_T(instr) & fAbsolute;
if (instr->args[0].kind == PCOp_MEMORY) {
bits |= instr->args[0].data.mem.offset & 0x3FFFFFC;
wop->x2 = instr->args[0].data.mem.obj;
if (flag == 0)
wop->type = MW_RELOC_2_BR24;
else
CError_FATAL(288);
} else if (instr->args[0].kind == PCOp_IMMEDIATE) {
bits |= instr->args[0].data.imm.value & 0x3FFFFFC;
if (flag)
bits |= 2;
} else {
bits |= (instr->args[0].data.label.label->block->codeOffset - offset) & 0x3FFFFFC;
if (flag)
CError_FATAL(302);
}
if (PCODE_FLAG_SET_T(instr) & fLink)
bits |= 1;
break;
}
case PC_BDNZ:
case PC_BDZ: {
int flag = PCODE_FLAG_SET_T(instr) & fAbsolute;
if (instr->args[0].kind == PCOp_MEMORY) {
bits |= instr->args[0].data.mem.offset & 0xFFFC;
wop->x2 = instr->args[0].data.mem.obj;
if (flag == 0)
wop->type = MW_RELOC_8;
else
CError_FATAL(333);
} else {
SInt32 value;
if (instr->args[0].kind == PCOp_IMMEDIATE)
value = instr->args[0].data.imm.value;
else
value = instr->args[0].data.label.label->block->codeOffset - offset;
bits |= value & 0xFFFF;
if (value < 0) {
if (PCODE_FLAG_SET_T(instr) & fBranchNotTaken)
bits |= 0x200000u;
} else {
if (PCODE_FLAG_SET_T(instr) & fBranchTaken)
bits |= 0x200000u;
}
}
if (PCODE_FLAG_SET_T(instr) & fLink)
bits |= 1;
break;
}
case PC_BC: {
int flag = PCODE_FLAG_SET_T(instr) & fAbsolute;
bits |= (instr->args[0].data.imm.value & 31) << 21;
bits |= ((instr->args[1].data.reg.reg * 4 + instr->args[2].data.imm.value) & 31) << 16;
if (instr->args[3].kind == PCOp_MEMORY) {
bits |= instr->args[3].data.mem.offset & 0xFFFC;
wop->x2 = instr->args[3].data.mem.obj;
if (flag == 0)
wop->type = MW_RELOC_8;
else
CError_FATAL(387);
} else {
SInt32 value;
if (instr->args[3].kind == PCOp_IMMEDIATE)
value = instr->args[3].data.imm.value;
else
value = instr->args[3].data.label.label->block->codeOffset - offset;
bits |= value & 0xFFFF;
if (value < 0) {
if (PCODE_FLAG_SET_T(instr) & fBranchNotTaken)
bits |= 0x200000u;
} else {
if (PCODE_FLAG_SET_T(instr) & fBranchTaken)
bits |= 0x200000u;
}
}
if (PCODE_FLAG_SET_T(instr) & fLink)
bits |= 1;
break;
}
case PC_BT:
case PC_BF:
case PC_BDNZT:
case PC_BDNZF:
case PC_BDZT:
case PC_BDZF: {
int flag = PCODE_FLAG_SET_T(instr) & fAbsolute;
bits |= ((instr->args[0].data.reg.reg * 4 + instr->args[1].data.imm.value) & 31) << 16;
if (instr->args[2].kind == PCOp_MEMORY) {
bits |= instr->args[2].data.mem.offset & 0xFFFC;
wop->x2 = instr->args[2].data.mem.obj;
if (flag == 0)
wop->type = MW_RELOC_8;
else
CError_FATAL(446);
} else {
SInt32 value;
if (instr->args[2].kind == PCOp_IMMEDIATE) {
value = instr->args[2].data.imm.value;
if (flag)
bits |= 2;
} else {
value = instr->args[2].data.label.label->block->codeOffset - offset;
CError_ASSERT(458, !flag);
}
bits |= value & 0xFFFF;
if (value < 0) {
if (PCODE_FLAG_SET_T(instr) & fBranchNotTaken)
bits |= 0x200000u;
} else {
if (PCODE_FLAG_SET_T(instr) & fBranchTaken)
bits |= 0x200000u;
}
}
if (PCODE_FLAG_SET_T(instr) & fLink)
bits |= 1;
break;
}
case PC_BTLR:
case PC_BTCTR:
case PC_BFLR:
case PC_BFCTR:
bits |= ((instr->args[0].data.reg.reg * 4 + instr->args[1].data.imm.value) & 31) << 16;
if (PCODE_FLAG_SET_T(instr) & fLink)
bits |= 1;
if (PCODE_FLAG_SET_T(instr) & fBranchTaken)
bits |= 0x200000u;
break;
case PC_BCLR:
case PC_BCCTR:
bits |= instr->args[0].data.imm.value << 21;
bits |= ((instr->args[1].data.reg.reg * 4 + instr->args[2].data.imm.value) & 31) << 16;
case PC_BLR:
case PC_BCTR:
case PC_BCTRL:
case PC_BLRL:
if (PCODE_FLAG_SET_T(instr) & fLink)
bits |= 1;
if (PCODE_FLAG_SET_T(instr) & fBranchTaken)
bits |= 0x200000u;
break;
case PC_CRAND:
case PC_CRANDC:
case PC_CREQV:
case PC_CRNAND:
case PC_CRNOR:
case PC_CROR:
case PC_CRORC:
case PC_CRXOR:
bits |= ((instr->args[0].data.reg.reg * 4 + instr->args[1].data.imm.value) & 31) << 21;
bits |= ((instr->args[2].data.reg.reg * 4 + instr->args[3].data.imm.value) & 31) << 16;
bits |= ((instr->args[4].data.reg.reg * 4 + instr->args[5].data.imm.value) & 31) << 11;
break;
case PC_MCRF:
bits |= instr->args[0].data.reg.reg << 23;
bits |= instr->args[1].data.reg.reg << 18;
break;
case PC_LBZ:
case PC_LBZU:
case PC_LHZ:
case PC_LHZU:
case PC_LHA:
case PC_LHAU:
case PC_LWZ:
case PC_LWZU:
case PC_LMW:
case PC_STB:
case PC_STBU:
case PC_STH:
case PC_STHU:
case PC_STW:
case PC_STWU:
case PC_STMW:
case PC_LFS:
case PC_LFSU:
case PC_LFD:
case PC_LFDU:
case PC_STFS:
case PC_STFSU:
case PC_STFD:
case PC_STFDU:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= pcode_update_mem_labeldiff_imm(instr, &instr->args[2], wop) & 0xFFFF;
break;
case PC_LBZX:
case PC_LBZUX:
case PC_LHZX:
case PC_LHZUX:
case PC_LHAX:
case PC_LHAUX:
case PC_LHBRX:
case PC_LWZX:
case PC_LWZUX:
case PC_LWBRX:
case PC_STBX:
case PC_STBUX:
case PC_STHX:
case PC_STHUX:
case PC_STHBRX:
case PC_STWX:
case PC_STWUX:
case PC_STWBRX:
case PC_LFSX:
case PC_LFSUX:
case PC_LFDX:
case PC_LFDUX:
case PC_STFSX:
case PC_STFSUX:
case PC_STFDX:
case PC_STFDUX:
case PC_LWARX:
case PC_LSWX:
case PC_STFIWX:
case PC_STSWX:
case PC_STWCX:
case PC_ECIWX:
case PC_ECOWX:
case PC_DCREAD:
case PC_TLBSX:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[2].data.reg.reg << 11;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_DCBF:
case PC_DCBST:
case PC_DCBT:
case PC_DCBTST:
case PC_DCBZ:
case PC_DCBI:
case PC_ICBI:
case PC_DCCCI:
case PC_ICBT:
case PC_ICCCI:
case PC_ICREAD:
case PC_DCBA:
bits |= instr->args[0].data.reg.reg << 16;
bits |= instr->args[1].data.reg.reg << 11;
break;
case PC_ADD:
case PC_ADDC:
case PC_ADDE:
case PC_DIVW:
case PC_DIVWU:
case PC_MULHW:
case PC_MULHWU:
case PC_MULLW:
case PC_SUBF:
case PC_SUBFC:
case PC_SUBFE:
bits |= instr->args[2].data.reg.reg << 11;
case PC_ADDME:
case PC_ADDZE:
case PC_NEG:
case PC_SUBFME:
case PC_SUBFZE:
case PC_MFROM:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
if (PCODE_FLAG_SET_F(instr) & fOverflow)
bits |= 0x400;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_ADDI:
case PC_ADDIC:
case PC_ADDICR:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= pcode_update_mem_labeldiff_imm(instr, &instr->args[2], wop) & 0xFFFF;
break;
case PC_ADDIS:
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[0].data.reg.reg << 21;
bits |= pcode_update_mem_labeldiff_imm(instr, &instr->args[2], wop) & 0xFFFF;
break;
case PC_MULLI:
case PC_SUBFIC:
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[2].data.imm.value & 0xFFFF;
break;
case PC_LI:
case PC_LIS:
bits |= instr->args[0].data.reg.reg << 21;
bits |= pcode_update_mem_labeldiff_imm(instr, &instr->args[1], wop) & 0xFFFF;
break;
case PC_ANDI:
case PC_ANDIS:
case PC_ORI:
case PC_ORIS:
case PC_XORI:
case PC_XORIS:
bits |= instr->args[0].data.reg.reg << 16;
bits |= instr->args[1].data.reg.reg << 21;
bits |= pcode_update_mem_labeldiff_imm(instr, &instr->args[2], wop) & 0xFFFF;
break;
case PC_AND:
case PC_OR:
case PC_XOR:
case PC_NAND:
case PC_NOR:
case PC_EQV:
case PC_ANDC:
case PC_ORC:
case PC_SLW:
case PC_SRW:
case PC_SRAW:
bits |= instr->args[0].data.reg.reg << 16;
bits |= instr->args[1].data.reg.reg << 21;
bits |= instr->args[2].data.reg.reg << 11;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_EXTSH:
case PC_EXTSB:
case PC_CNTLZW:
bits |= instr->args[0].data.reg.reg << 16;
bits |= instr->args[1].data.reg.reg << 21;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_MR:
bits |= instr->args[0].data.reg.reg << 16;
bits |= instr->args[1].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 11;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_NOT:
bits |= instr->args[0].data.reg.reg << 16;
bits |= instr->args[1].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 11;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_SRAWI:
bits |= instr->args[0].data.reg.reg << 16;
bits |= instr->args[1].data.reg.reg << 21;
bits |= (instr->args[2].data.imm.value & 31) << 11;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_RLWINM:
case PC_RLWIMI:
bits |= instr->args[0].data.reg.reg << 16;
bits |= instr->args[1].data.reg.reg << 21;
bits |= (instr->args[2].data.imm.value & 31) << 11;
bits |= (instr->args[3].data.imm.value & 31) << 6;
bits |= (instr->args[4].data.imm.value & 31) << 1;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_RLWNM:
bits |= instr->args[0].data.reg.reg << 16;
bits |= instr->args[1].data.reg.reg << 21;
bits |= instr->args[2].data.reg.reg << 11;
bits |= (instr->args[3].data.imm.value & 31) << 6;
bits |= (instr->args[4].data.imm.value & 31) << 1;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_CMP:
case PC_CMPL:
bits |= instr->args[0].data.reg.reg << 23;
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[2].data.reg.reg << 11;
break;
case PC_CMPI:
case PC_CMPLI:
bits |= instr->args[0].data.reg.reg << 23;
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[2].data.imm.value & 0xFFFF;
break;
case PC_MTXER:
case PC_MTCTR:
case PC_MTLR:
case PC_MTMSR:
case PC_MFMSR:
case PC_MFXER:
case PC_MFCTR:
case PC_MFLR:
case PC_MFCR:
bits |= instr->args[0].data.reg.reg << 21;
break;
case PC_MFFS:
bits |= instr->args[0].data.reg.reg << 21;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_MTCRF:
bits |= instr->args[0].data.imm.value << 12;
bits |= instr->args[1].data.reg.reg << 21;
break;
case PC_MTFSF:
bits |= (instr->args[0].data.imm.value & 0xFF) << 17;
bits |= instr->args[1].data.reg.reg << 11;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_FMR:
case PC_FABS:
case PC_FNEG:
case PC_FNABS:
case PC_FRES:
case PC_FRSQRTE:
case PC_FRSP:
case PC_FCTIW:
case PC_FCTIWZ:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 11;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_FADD:
case PC_FADDS:
case PC_FSUB:
case PC_FSUBS:
case PC_FDIV:
case PC_FDIVS:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[2].data.reg.reg << 11;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_FMADD:
case PC_FMADDS:
case PC_FMSUB:
case PC_FMSUBS:
case PC_FNMADD:
case PC_FNMADDS:
case PC_FNMSUB:
case PC_FNMSUBS:
case PC_FSEL:
bits |= instr->args[3].data.reg.reg << 11;
case PC_FMUL:
case PC_FMULS:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[2].data.reg.reg << 6;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_FCMPU:
case PC_FCMPO:
bits |= instr->args[0].data.reg.reg << 23;
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[2].data.reg.reg << 11;
break;
case PC_MTSPR:
if (instr->args[0].kind == PCOp_REGISTER) {
CError_ASSERT(1027, instr->args[0].arg == RegClass_SPR);
CError_ASSERT(1028, instr->args[0].data.reg.reg < 4);
bits |= ((spr_to_sysreg[instr->args[0].data.reg.reg] & 0x1F) << 16) +
((spr_to_sysreg[instr->args[0].data.reg.reg] & 0x3E0) << 6);
} else if (instr->args[0].kind == PCOp_SYSREG && instr->args[0].arg == 0) {
bits |= ((instr->args[0].data.reg.reg & 0x1F) << 16) +
((instr->args[0].data.reg.reg & 0x3E0) << 6);
} else {
CError_FATAL(1033);
}
bits |= instr->args[1].data.reg.reg << 21;
break;
case PC_MTDCR:
if (instr->args[0].kind == PCOp_IMMEDIATE) {
bits |= ((instr->args[0].data.imm.value & 0x1F) << 16) +
((instr->args[0].data.imm.value & 0x3E0) << 6);
} else {
CError_FATAL(1042);
}
bits |= instr->args[1].data.reg.reg << 21;
break;
case PC_MFSPR:
bits |= instr->args[0].data.reg.reg << 21;
if (instr->args[1].kind == PCOp_REGISTER && instr->args[1].arg == RegClass_SPR) {
CError_ASSERT(1055, instr->args[1].data.reg.reg < 4);
bits |= ((spr_to_sysreg[instr->args[1].data.reg.reg] & 0x1F) << 16) +
((spr_to_sysreg[instr->args[1].data.reg.reg] & 0x3E0) << 6);
} else if (instr->args[1].kind == PCOp_SYSREG && instr->args[1].arg == 0) {
bits |= ((instr->args[1].data.reg.reg & 0x1F) << 16) +
((instr->args[1].data.reg.reg & 0x3E0) << 6);
} else {
CError_FATAL(1060);
}
break;
case PC_MFDCR:
bits |= instr->args[0].data.reg.reg << 21;
if (instr->args[1].kind == PCOp_IMMEDIATE) {
bits |= ((instr->args[1].data.imm.value & 0x1F) << 16) +
((instr->args[1].data.imm.value & 0x3E0) << 6);
} else {
CError_FATAL(1069);
}
break;
case PC_LSWI:
case PC_STSWI:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= (instr->args[2].data.imm.value & 31) << 11;
break;
case PC_MCRFS:
bits |= (instr->args[1].data.imm.value & 7) << 18;
case PC_MCRXR:
bits |= instr->args[0].data.reg.reg << 23;
break;
case PC_MFTB:
bits |= instr->args[0].data.reg.reg << 21;
if (instr->args[1].kind == PCOp_SYSREG && instr->args[1].arg == 0) {
if (instr->args[1].data.reg.reg == 284)
bits |= 0xC4000u;
else if (instr->args[1].data.reg.reg == 285)
bits |= 0xD4000u;
else
CError_FATAL(1100);
} else {
CError_FATAL(1103);
}
break;
case PC_MTSR:
bits |= instr->args[1].data.reg.reg << 21;
bits |= (instr->args[0].data.imm.value & 15) << 16;
break;
case PC_MFSR:
bits |= instr->args[0].data.reg.reg << 21;
bits |= (instr->args[1].data.imm.value & 15) << 16;
break;
case PC_MFSRIN:
case PC_MTSRIN:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 11;
break;
case PC_MTFSB0:
case PC_MTFSB1:
bits |= (instr->args[0].data.imm.value & 31) << 21;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_MTFSFI:
bits |= instr->args[0].data.reg.reg << 23;
bits |= (instr->args[1].data.imm.value & 15) << 12;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_FSQRT:
case PC_FSQRTS:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 11;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_TLBIE:
case PC_TLBLD:
case PC_TLBLI:
bits |= instr->args[0].data.reg.reg << 11;
break;
case PC_TW:
bits |= (instr->args[0].data.imm.value & 31) << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[2].data.reg.reg << 11;
break;
case PC_TWI:
bits |= (instr->args[0].data.imm.value & 31) << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[2].data.imm.value & 0xFFFF;
break;
case PC_OPWORD:
CError_ASSERT(1176, instr->args[0].kind != PCOp_MEMORY);
bits = pcode_update_mem_labeldiff_imm(instr, &instr->args[0], wop);
break;
case PC_MASKG:
case PC_MASKIR:
bits |= instr->args[1].data.reg.reg << 21;
bits |= instr->args[0].data.reg.reg << 16;
bits |= instr->args[2].data.reg.reg << 11;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_LSCBX:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[2].data.reg.reg << 11;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_DIV:
case PC_DIVS:
case PC_DOZ:
case PC_MUL:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[2].data.reg.reg << 11;
if (PCODE_FLAG_SET_F(instr) & fOverflow)
bits |= 0x400;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_NABS:
case PC_ABS:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
if (PCODE_FLAG_SET_F(instr) & fOverflow)
bits |= 0x400;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_CLCS:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_DOZI:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[2].data.imm.value & 0xFFFF;
break;
case PC_RLMI:
bits |= instr->args[1].data.reg.reg << 21;
bits |= instr->args[0].data.reg.reg << 16;
bits |= instr->args[2].data.reg.reg << 11;
bits |= (instr->args[3].data.imm.value & 31) << 6;
bits |= (instr->args[4].data.imm.value & 31) << 1;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_SLE:
case PC_SLEQ:
case PC_SLLQ:
case PC_SLQ:
case PC_SRAQ:
case PC_SRE:
case PC_SREA:
case PC_SREQ:
case PC_SRLQ:
case PC_SRQ:
case PC_RRIB:
bits |= instr->args[1].data.reg.reg << 21;
bits |= instr->args[0].data.reg.reg << 16;
bits |= instr->args[2].data.reg.reg << 11;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_SLIQ:
case PC_SLLIQ:
case PC_SRAIQ:
case PC_SRIQ:
case PC_SRLIQ:
bits |= instr->args[1].data.reg.reg << 21;
bits |= instr->args[0].data.reg.reg << 16;
bits |= (instr->args[2].data.imm.value & 31) << 11;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 1;
break;
case PC_TLBRE:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= (instr->args[2].data.imm.value & 1) << 11;
break;
case PC_TLBWE:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= (instr->args[2].data.imm.value & 1) << 11;
break;
case PC_WRTEE:
bits |= instr->args[0].data.reg.reg << 21;
break;
case PC_WRTEEI:
bits |= instr->args[0].data.imm.value << 15;
break;
case PC_DSTT:
case PC_DSTSTT:
bits |= 0x2000000u;
bits |= instr->args[0].data.reg.reg << 16;
bits |= instr->args[1].data.reg.reg << 11;
bits |= (instr->args[2].data.imm.value & 3) << 21;
break;
case PC_DST:
case PC_DSTST:
bits |= (instr->args[3].data.imm.value & 1) << 25;
bits |= instr->args[0].data.reg.reg << 16;
bits |= instr->args[1].data.reg.reg << 11;
bits |= (instr->args[2].data.imm.value & 3) << 21;
break;
case PC_DSSALL:
bits |= 0x2000000u;
break;
case PC_DSS:
bits |= (instr->args[1].data.imm.value & 1) << 25;
bits |= (instr->args[0].data.imm.value & 3) << 21;
break;
case PC_LVEBX:
case PC_LVEHX:
case PC_LVEWX:
case PC_LVSL:
case PC_LVSR:
case PC_LVX:
case PC_LVXL:
case PC_STVEBX:
case PC_STVEHX:
case PC_STVEWX:
case PC_STVX:
case PC_STVXL:
case PC_VADDCUW:
case PC_VADDFP:
case PC_VADDSBS:
case PC_VADDSHS:
case PC_VADDSWS:
case PC_VADDUBM:
case PC_VADDUBS:
case PC_VADDUHM:
case PC_VADDUHS:
case PC_VADDUWM:
case PC_VADDUWS:
case PC_VAND:
case PC_VANDC:
case PC_VAVGSB:
case PC_VAVGSH:
case PC_VAVGSW:
case PC_VAVGUB:
case PC_VAVGUH:
case PC_VAVGUW:
case PC_VMAXFP:
case PC_VMAXSB:
case PC_VMAXSH:
case PC_VMAXSW:
case PC_VMAXUB:
case PC_VMAXUH:
case PC_VMAXUW:
case PC_VMINFP:
case PC_VMINSB:
case PC_VMINSH:
case PC_VMINSW:
case PC_VMINUB:
case PC_VMINUH:
case PC_VMINUW:
case PC_VMRGHB:
case PC_VMRGHH:
case PC_VMRGHW:
case PC_VMRGLB:
case PC_VMRGLH:
case PC_VMRGLW:
case PC_VMULESB:
case PC_VMULESH:
case PC_VMULEUB:
case PC_VMULEUH:
case PC_VMULOSB:
case PC_VMULOSH:
case PC_VMULOUB:
case PC_VMULOUH:
case PC_VNOR:
case PC_VOR:
case PC_VPKPX:
case PC_VPKSHSS:
case PC_VPKSHUS:
case PC_VPKSWSS:
case PC_VPKSWUS:
case PC_VPKUHUM:
case PC_VPKUHUS:
case PC_VPKUWUM:
case PC_VPKUWUS:
case PC_VRLB:
case PC_VRLH:
case PC_VRLW:
case PC_VSL:
case PC_VSLB:
case PC_VSLH:
case PC_VSLO:
case PC_VSLW:
case PC_VSR:
case PC_VSRAB:
case PC_VSRAH:
case PC_VSRAW:
case PC_VSRB:
case PC_VSRH:
case PC_VSRO:
case PC_VSRW:
case PC_VSUBCUW:
case PC_VSUBFP:
case PC_VSUBSBS:
case PC_VSUBSHS:
case PC_VSUBSWS:
case PC_VSUBUBM:
case PC_VSUBUBS:
case PC_VSUBUHM:
case PC_VSUBUHS:
case PC_VSUBUWM:
case PC_VSUBUWS:
case PC_VSUMSWS:
case PC_VSUM2SWS:
case PC_VSUM4SBS:
case PC_VSUM4SHS:
case PC_VSUM4UBS:
case PC_VXOR:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[2].data.reg.reg << 11;
break;
case PC_VCFSX:
case PC_VCFUX:
case PC_VCTSXS:
case PC_VCTUXS:
case PC_VSPLTB:
case PC_VSPLTH:
case PC_VSPLTW:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 11;
bits |= (instr->args[2].data.imm.value & 31) << 16;
break;
case PC_VEXPTEFP:
case PC_VLOGEFP:
case PC_VREFP:
case PC_VRFIM:
case PC_VRFIN:
case PC_VRFIP:
case PC_VRFIZ:
case PC_VRSQRTEFP:
case PC_VUPKHPX:
case PC_VUPKHSB:
case PC_VUPKHSH:
case PC_VUPKLPX:
case PC_VUPKLSB:
case PC_VUPKLSH:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 11;
break;
case PC_VCMPBFP:
case PC_VCMPEQFP:
case PC_VCMPEQUB:
case PC_VCMPEQUH:
case PC_VCMPEQUW:
case PC_VCMPGEFP:
case PC_VCMPGTFP:
case PC_VCMPGTSB:
case PC_VCMPGTSH:
case PC_VCMPGTSW:
case PC_VCMPGTUB:
case PC_VCMPGTUH:
case PC_VCMPGTUW:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[2].data.reg.reg << 11;
2023-01-11 22:29:53 +00:00
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
2022-12-29 12:32:55 +00:00
bits |= 0x400;
break;
case PC_VSPLTISB:
case PC_VSPLTISH:
case PC_VSPLTISW:
bits |= instr->args[0].data.reg.reg << 21;
bits |= (instr->args[1].data.imm.value & 31) << 16;
break;
case PC_VMHADDSHS:
case PC_VMHRADDSHS:
case PC_VMLADDUHM:
case PC_VMSUMMBM:
case PC_VMSUMSHM:
case PC_VMSUMSHS:
case PC_VMSUMUBM:
case PC_VMSUMUHM:
case PC_VMSUMUHS:
case PC_VPERM:
case PC_VSEL:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[2].data.reg.reg << 11;
bits |= instr->args[3].data.reg.reg << 6;
break;
case PC_VMADDFP:
case PC_VNMSUBFP:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[2].data.reg.reg << 6;
bits |= instr->args[3].data.reg.reg << 11;
break;
case PC_VSLDOI:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[2].data.reg.reg << 11;
bits |= (instr->args[3].data.imm.value & 15) << 6;
break;
case PC_VMR:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[1].data.reg.reg << 11;
break;
case PC_VMRP:
bits |= instr->args[0].data.reg.reg << 21;
bits |= instr->args[1].data.reg.reg << 16;
bits |= instr->args[1].data.reg.reg << 11;
break;
case PC_MFVSCR:
bits |= instr->args[0].data.reg.reg << 21;
break;
case PC_MTVSCR:
bits |= instr->args[0].data.reg.reg << 11;
break;
case PC_EIEIO:
case PC_ISYNC:
case PC_SYNC:
case PC_RFI:
case PC_NOP:
case PC_SC:
case PC_TLBIA:
case PC_TLBSYNC:
case PC_TRAP:
case PC_DSA:
case PC_ESA:
case PC_RFCI:
break;
default:
CError_FATAL(2203);
}
return CTool_EndianConvertWord32(bits);
}
2022-12-29 12:32:55 +00:00
static PCode *targetinstruction(PCodeLabel *label) {
PCodeBlock *block = label->block;
while (block->pcodeCount == 0)
block = block->nextBlock;
return block->firstPCode;
}
2022-12-29 12:32:55 +00:00
static void invertybit(PCode *instr, SInt32 value) {
if (instr->op == PC_BC) {
if (instr->args[0].data.imm.value & 1) {
if (value < 0)
instr->flags |= fBranchNotTaken;
else
instr->flags |= fBranchTaken;
}
} else if (instr->op == PC_BCCTR || instr->op == PC_BCLR) {
if (instr->args[0].data.imm.value & 1)
instr->flags |= fBranchTaken;
}
if (PCODE_FLAG_SET_T(instr) & fBranchTaken)
instr->flags = (instr->flags & ~fBranchTaken) | fBranchNotTaken;
else if (PCODE_FLAG_SET_T(instr) & fBranchNotTaken)
instr->flags = (instr->flags & ~fBranchNotTaken) | fBranchTaken;
else if (value < 0)
instr->flags = (instr->flags & ~fBranchTaken) | fBranchNotTaken;
else
instr->flags = (instr->flags & ~fBranchNotTaken) | fBranchTaken;
}
2022-12-29 12:32:55 +00:00
static void insertlongbranches(SInt32 mask) {
PCodeBlock *block;
PCodeLabel *label;
SInt32 i;
i = 0;
for (block = pcbasicblocks; block; block = block->nextBlock) {
block->codeOffset = i;
if (block->pcodeCount) {
i += block->pcodeCount * 4;
2023-01-11 22:29:53 +00:00
if (block->pcodeCount && (block->lastPCode->flags & fIsBranch))
2022-12-29 12:32:55 +00:00
i += 4;
}
}
for (block = pcbasicblocks; block; block = block->nextBlock) {
2023-01-11 22:29:53 +00:00
if (block->pcodeCount && (block->lastPCode->flags & fIsBranch)) {
2022-12-29 12:32:55 +00:00
switch (block->lastPCode->op) {
case PC_BT:
case PC_BF:
i = block->codeOffset + ((block->pcodeCount - 1) * 4);
if (block->lastPCode->args[2].kind == PCOp_LABEL) {
label = block->lastPCode->args[2].data.label.label;
i = label->block->codeOffset - i;
if (i != ((SInt16) (i & mask))) {
block->lastPCode->op = (block->lastPCode->op == PC_BT) ? PC_BF : PC_BT;
block->lastPCode->args[2].data.label.label = block->nextBlock->labels;
invertybit(block->lastPCode, i);
appendpcode(block, makepcode(PC_B, label));
}
}
break;
case PC_BC:
i = block->codeOffset + ((block->pcodeCount - 1) * 4);
if (block->lastPCode->args[3].kind == PCOp_LABEL) {
label = block->lastPCode->args[3].data.label.label;
i = label->block->codeOffset - i;
invertybit(block->lastPCode, i);
if (i != ((SInt16) (i & mask))) {
switch (block->lastPCode->args[0].data.imm.value & 30) {
case 0:
case 2:
case 8:
case 10:
block->lastPCode->args[0].data.imm.value ^= 11;
block->lastPCode->args[3].data.label.label = block->nextBlock->labels;
break;
case 16:
case 18:
block->lastPCode->args[0].data.imm.value ^= 3;
block->lastPCode->args[3].data.label.label = block->nextBlock->labels;
break;
case 4:
case 12:
block->lastPCode->args[0].data.imm.value ^= 9;
block->lastPCode->args[3].data.label.label = block->nextBlock->labels;
break;
case 20:
deletepcode(block->lastPCode);
break;
default:
CError_FATAL(2368);
}
appendpcode(block, makepcode(PC_B, label));
}
}
break;
case PC_BDNZ:
case PC_BDZ:
i = block->codeOffset + ((block->pcodeCount - 1) * 4);
if (block->lastPCode->args[0].kind == PCOp_LABEL) {
label = block->lastPCode->args[0].data.label.label;
i = label->block->codeOffset - i;
if (i != ((SInt16) (i & mask))) {
switch (block->lastPCode->op) {
case PC_BDZ:
block->lastPCode->op = PC_BDNZ;
break;
case PC_BDNZ:
block->lastPCode->op = PC_BDZ;
break;
default:
CError_FATAL(2389);
}
block->lastPCode->args[0].data.label.label = block->nextBlock->labels;
invertybit(block->lastPCode, i);
appendpcode(block, makepcode(PC_B, label));
}
}
break;
case PC_BDNZT:
case PC_BDNZF:
case PC_BDZT:
case PC_BDZF:
i = block->codeOffset + ((block->pcodeCount - 1) * 4);
if (block->lastPCode->args[2].kind == PCOp_LABEL) {
label = block->lastPCode->args[2].data.label.label;
i = label->block->codeOffset - i;
if (i != ((SInt16) (i & mask))) {
switch (block->lastPCode->op) {
case PC_BDNZT:
block->lastPCode->op = PC_BDZF;
break;
case PC_BDNZF:
block->lastPCode->op = PC_BDZT;
break;
case PC_BDZT:
block->lastPCode->op = PC_BDNZF;
break;
case PC_BDZF:
block->lastPCode->op = PC_BDNZT;
break;
default:
CError_FATAL(2420);
}
block->lastPCode->args[2].data.label.label = block->nextBlock->labels;
invertybit(block->lastPCode, i);
appendpcode(block, makepcode(PC_B, label));
}
}
break;
}
}
}
}
2022-12-29 12:32:55 +00:00
SInt32 optimizefinalbranches(SInt32 codesize) {
PCodeBlock *block;
PCode *instr;
SInt32 offset;
int changed;
int deleted;
PCodeLabel *label;
PCode *target;
do {
changed = deleted = 0;
for (block = pcbasicblocks; block; block = block->nextBlock) {
if (block->pcodeCount == 0)
continue;
instr = block->lastPCode;
2023-01-11 22:29:53 +00:00
if (!(instr->flags & fIsBranch))
2022-12-29 12:32:55 +00:00
continue;
offset = block->codeOffset + (block->pcodeCount - 1) * 4;
if (instr->op == PC_B && instr->args[0].kind == PCOp_LABEL) {
label = instr->args[0].data.label.label;
target = targetinstruction(label);
if (label->block->codeOffset == (offset + 4)) {
deletepcode(instr);
changed = deleted = 1;
} else if (target->op == PC_B) {
if (target->args[0].kind == PCOp_LABEL && target->args[0].data.label.label != instr->args[0].data.label.label) {
instr->args[0].data.label.label = target->args[0].data.label.label;
changed = 1;
}
} else if (target->op == PC_BLR) {
instr->op = PC_BLR;
changed = 1;
}
continue;
}
2023-01-13 02:19:29 +00:00
if ((instr->op == PC_BT || instr->op == PC_BF) && instr->args[2].kind == PCOp_LABEL) {
PCodeBlock *block2 = instr->block;
label = instr->args[2].data.label.label;
2022-12-29 12:32:55 +00:00
target = targetinstruction(label);
if (label->block->codeOffset == (offset + 4)) {
deletepcode(instr);
changed = deleted = 1;
} else if (target->op == PC_B) {
if (target->args[0].kind == PCOp_LABEL && target->args[0].data.label.label != instr->args[2].data.label.label) {
instr->args[2].data.label.label = target->args[0].data.label.label;
changed = 1;
}
} else if (copts.opt_bcc_lr_ctr) {
2022-12-29 12:32:55 +00:00
if (target->op == PC_BLR) {
if (instr->op == PC_BT)
instr->op = PC_BTLR;
else
instr->op = PC_BFLR;
instr->argCount = 2;
changed = 1;
} else if (target->op == PC_BCTR) {
if (instr->op == PC_BT)
instr->op = PC_BTCTR;
else
instr->op = PC_BFCTR;
instr->argCount = 2;
changed = 1;
} else if (
block2->nextBlock &&
block2->nextBlock->firstPCode &&
block2->nextBlock->firstPCode->op == PC_BLR &&
label->block->codeOffset == (offset + 8)
) {
if (
block2->nextBlock->predecessors &&
block2->nextBlock->predecessors->block == block2 &&
!block2->nextBlock->predecessors->nextLink
) {
if (instr->op == PC_BT)
instr->op = PC_BFLR;
else
instr->op = PC_BTLR;
change_num_operands(instr, 2);
deletepcode(block2->nextBlock->firstPCode);
changed = deleted = 1;
}
} else if (
block2->nextBlock &&
block2->nextBlock->firstPCode &&
block2->nextBlock->firstPCode->op == PC_BCTR &&
label->block->codeOffset == (offset + 8)
) {
if (
block2->nextBlock->predecessors &&
block2->nextBlock->predecessors->block == block2 &&
!block2->nextBlock->predecessors->nextLink
) {
if (instr->op == PC_BT)
instr->op = PC_BFCTR;
else
instr->op = PC_BTCTR;
change_num_operands(instr, 2);
deletepcode(block2->nextBlock->firstPCode);
changed = deleted = 1;
}
}
}
continue;
}
if (
instr->op == PC_BC &&
instr->args[3].kind == PCOp_LABEL &&
!(PCODE_FLAG_SET_T(instr) & (fSideEffects | fLink))
)
{
2023-01-13 02:19:29 +00:00
PCodeBlock *block2 = instr->block;
label = instr->args[3].data.label.label;
2022-12-29 12:32:55 +00:00
target = targetinstruction(label);
if (label->block->codeOffset == (offset + 4)) {
deletepcode(instr);
changed = deleted = 1;
} else if (target->op == PC_B) {
if (target->args[0].kind == PCOp_LABEL && target->args[0].data.label.label != instr->args[3].data.label.label) {
instr->args[3].data.label.label = target->args[0].data.label.label;
changed = 1;
}
} else if (copts.opt_bcc_lr_ctr) {
2022-12-29 12:32:55 +00:00
if (target->op == PC_BLR) {
instr->op = PC_BCLR;
instr->argCount = 3;
changed = 1;
} else if (target->op == PC_BCTR) {
instr->op = PC_BCCTR;
instr->argCount = 3;
changed = 1;
} else if (
block2->nextBlock &&
block2->nextBlock->firstPCode &&
block2->nextBlock->firstPCode->op == PC_BLR &&
label->block->codeOffset == (offset + 8)
) {
SInt32 val = instr->args[0].data.imm.value & 30;
if (
block2->nextBlock->predecessors &&
block2->nextBlock->predecessors->block == block2 &&
!block2->nextBlock->predecessors->nextLink
) {
if ((val & 30) == 4)
instr->args[0].data.imm.value = val | 12;
2023-01-13 02:19:29 +00:00
else if ((val & 30) == 12)
2022-12-29 12:32:55 +00:00
instr->args[0].data.imm.value = val & 23;
instr->op = PC_BCLR;
instr->argCount = 3;
deletepcode(block2->nextBlock->firstPCode);
changed = deleted = 1;
}
} else if (
block2->nextBlock &&
block2->nextBlock->firstPCode &&
block2->nextBlock->firstPCode->op == PC_BCTR &&
label->block->codeOffset == (offset + 8)
) {
SInt32 val = instr->args[0].data.imm.value & 30;
if (
block2->nextBlock->predecessors &&
block2->nextBlock->predecessors->block == block2 &&
!block2->nextBlock->predecessors->nextLink
) {
if ((val & 30) == 4)
instr->args[0].data.imm.value = val | 12;
2023-01-13 02:19:29 +00:00
else if ((val & 30) == 12)
2022-12-29 12:32:55 +00:00
instr->args[0].data.imm.value = val & 23;
instr->op = PC_BCCTR;
instr->argCount = 3;
deletepcode(block2->nextBlock->firstPCode);
changed = deleted = 1;
}
}
}
}
}
if (deleted)
codesize = pccomputeoffsets();
} while (changed);
return codesize;
}
2022-12-29 12:32:55 +00:00
static SInt32 insert_align_nops(Object *func, SInt32 codesize) {
PCodeBlock *block;
int changed;
PCodeBlock *prev;
do {
changed = 0;
for (block = pcbasicblocks; block; block = block->nextBlock) {
if (
(block->flags & fPCBlockFlag6000) == fPCBlockFlag2000 &&
(block->codeOffset & 7) &&
block->pcodeCount < 8 &&
(prev = block->prevBlock) &&
!(prev->flags & fPCBlockFlag2000)
)
{
if (prev->lastPCode && prev->lastPCode->op == PC_NOP && !(prev->lastPCode->flags & fSideEffects)) {
deletepcode(prev->lastPCode);
} else {
PCode *nop = makepcode(PC_NOP);
nop->flags &= ~fSideEffects;
appendpcode(prev, nop);
}
codesize = pccomputeoffsets();
changed = 1;
}
}
if (changed) {
pclistblocks(CMangler_GetLinkName(func)->name, "AFTER INSERT ALIGN NOPs");
if (codesize > 32766) {
insertlongbranches(32766);
codesize = pccomputeoffsets();
}
}
} while (changed);
return codesize;
}
2022-12-29 12:32:55 +00:00
SInt32 assemblefunction(Object *func, EntryPoint *entrypoints) {
void *tbdata;
GList *gl;
PCodeBlock *block;
PCode *instr;
SInt32 offset2;
SInt32 codesize;
SInt32 tbsize;
SInt32 offset;
2023-01-19 13:00:09 +00:00
SectionHandle section;
2022-12-29 12:32:55 +00:00
EntryPoint *ep;
WeirdOperand wop;
codesize = pccomputeoffsets();
if (codesize <= 0)
2023-01-20 12:25:38 +00:00
PPCError_Error(PPCErrorStr190, func->name->name);
2022-12-29 12:32:55 +00:00
if (copts.peephole || copts.optimizationlevel >= 3)
codesize = optimizefinalbranches(codesize);
if (codesize > 32766) {
insertlongbranches(32766);
codesize = pccomputeoffsets();
}
if (copts.function_align > 4)
2022-12-29 12:32:55 +00:00
codesize = insert_align_nops(func, codesize);
tbsize = 0;
if (copts.traceback)
tbdata = generate_traceback(codesize, CMangler_GetLinkName(func)->name, &tbsize, func);
if (func->section == SECT_DEFAULT)
func->section = SECT_TEXT;
offset = tbsize;
2023-01-19 13:00:09 +00:00
section = ObjGen_DeclareCode(func, codesize + tbsize);
2022-12-29 12:32:55 +00:00
gl = ObjGen_GetSectionGList(section);
codebase = gl->size;
AppendGListNoData(gl, codesize + tbsize);
if (copts.filesyminfo) {
2022-12-29 12:32:55 +00:00
ObjGen_SymFunc(func);
ObjGen_Line(functionbodyoffset, 0);
ObjGen_DeclareSymInfo();
}
if (uses_globals && pic_base_reg)
ObjGen_DeclarePICBase(func, pic_base_pcodelabel->block->codeOffset);
if (entrypoints) {
for (ep = entrypoints; ep; ep = ep->next) {
ObjGen_DeclareEntry(ep->object, ep->block->codeOffset);
}
}
for (block = pcbasicblocks; block; block = block->nextBlock) {
for (offset2 = block->codeOffset, instr = block->firstPCode; instr; instr = instr->nextPCode, offset2 += 4) {
if (copts.filesyminfo && instr->sourceoffset != -1)
2022-12-29 12:32:55 +00:00
ObjGen_Line(instr->sourceoffset, offset2);
*((UInt32 *) (*gl->data + codebase + offset2)) = assemblepcode(instr, offset2, &wop);
if (wop.type != -1)
ObjGen_RelocateObj(section, offset2, wop.x2, wop.type);
}
}
if (copts.filesyminfo)
2022-12-29 12:32:55 +00:00
ObjGenMach_SymFuncEnd(func, codesize);
if (copts.traceback)
memcpy(*gl->data + codebase + codesize, tbdata, offset);
if (copts.traceback)
return codesize + tbsize;
else
return codesize;
}