mirror of https://git.wuffs.org/MWCC
1614 lines
54 KiB
C
1614 lines
54 KiB
C
#include "compiler/PCodeAssembly.h"
|
|
#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;
|
|
|
|
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)
|
|
PPCError_Error(PPCErrorStr109);
|
|
else if (offset < -0x8000)
|
|
PPCError_Error(PPCErrorStr109);
|
|
} else if (op->kind == PCOp_IMMEDIATE) {
|
|
offset = op->data.imm.value;
|
|
} else {
|
|
CError_FATAL(193);
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
bits |= 1;
|
|
break;
|
|
|
|
case PC_MTFSFI:
|
|
bits |= instr->args[0].data.reg.reg << 23;
|
|
bits |= (instr->args[1].data.imm.value & 15) << 12;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
bits |= 1;
|
|
break;
|
|
|
|
case PC_CLCS:
|
|
bits |= instr->args[0].data.reg.reg << 21;
|
|
bits |= instr->args[1].data.reg.reg << 16;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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;
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit)
|
|
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);
|
|
}
|
|
|
|
static PCode *targetinstruction(PCodeLabel *label) {
|
|
PCodeBlock *block = label->block;
|
|
while (block->pcodeCount == 0)
|
|
block = block->nextBlock;
|
|
return block->firstPCode;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
if (block->pcodeCount && (block->lastPCode->flags & fIsBranch))
|
|
i += 4;
|
|
}
|
|
}
|
|
|
|
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
|
if (block->pcodeCount && (block->lastPCode->flags & fIsBranch)) {
|
|
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;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
if (!(instr->flags & fIsBranch))
|
|
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;
|
|
}
|
|
|
|
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;
|
|
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) {
|
|
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))
|
|
)
|
|
{
|
|
PCodeBlock *block2 = instr->block;
|
|
label = instr->args[3].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[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) {
|
|
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;
|
|
else if ((val & 30) == 12)
|
|
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;
|
|
else if ((val & 30) == 12)
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
SInt32 assemblefunction(Object *func, EntryPoint *entrypoints) {
|
|
void *tbdata;
|
|
GList *gl;
|
|
PCodeBlock *block;
|
|
PCode *instr;
|
|
SInt32 offset2;
|
|
SInt32 codesize;
|
|
SInt32 tbsize;
|
|
SInt32 offset;
|
|
SectionHandle section;
|
|
EntryPoint *ep;
|
|
WeirdOperand wop;
|
|
|
|
codesize = pccomputeoffsets();
|
|
if (codesize <= 0)
|
|
PPCError_Error(PPCErrorStr190, func->name->name);
|
|
|
|
if (copts.peephole || copts.optimizationlevel >= 3)
|
|
codesize = optimizefinalbranches(codesize);
|
|
|
|
if (codesize > 32766) {
|
|
insertlongbranches(32766);
|
|
codesize = pccomputeoffsets();
|
|
}
|
|
|
|
if (copts.function_align > 4)
|
|
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;
|
|
section = ObjGen_DeclareCode(func, codesize + tbsize);
|
|
gl = ObjGen_GetSectionGList(section);
|
|
|
|
codebase = gl->size;
|
|
AppendGListNoData(gl, codesize + tbsize);
|
|
|
|
if (copts.filesyminfo) {
|
|
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)
|
|
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)
|
|
ObjGenMach_SymFuncEnd(func, codesize);
|
|
|
|
if (copts.traceback)
|
|
memcpy(*gl->data + codebase + codesize, tbdata, offset);
|
|
|
|
if (copts.traceback)
|
|
return codesize + tbsize;
|
|
else
|
|
return codesize;
|
|
}
|