mirror of https://git.wuffs.org/MWCC
793 lines
28 KiB
C
793 lines
28 KiB
C
#include "compiler/StructMoves.h"
|
|
#include "compiler/CError.h"
|
|
#include "compiler/CParser.h"
|
|
#include "compiler/CodeGen.h"
|
|
#include "compiler/Operands.h"
|
|
#include "compiler/PCode.h"
|
|
#include "compiler/PCodeUtilities.h"
|
|
#include "compiler/Registers.h"
|
|
|
|
void make_addressable(Operand *opnd, SInt32 offset, int unusedArg) {
|
|
int reg;
|
|
|
|
if (opnd->optype == OpndType_IndirectSymbol)
|
|
coerce_to_addressable(opnd);
|
|
|
|
if (opnd->optype != OpndType_IndirectGPR_ImmOffset || (opnd->immOffset + offset) > 0x7FFF) {
|
|
reg = used_virtual_registers[RegClass_GPR]++;
|
|
load_address(reg, opnd);
|
|
opnd->optype = OpndType_IndirectGPR_ImmOffset;
|
|
opnd->reg = reg;
|
|
opnd->object = NULL;
|
|
opnd->immOffset = 0;
|
|
}
|
|
}
|
|
|
|
static void load_displaced_address(Operand *opnd, SInt32 offset) {
|
|
int reg;
|
|
|
|
reg = used_virtual_registers[RegClass_GPR]++;
|
|
if (opnd->optype == OpndType_IndirectSymbol)
|
|
coerce_to_addressable(opnd);
|
|
|
|
if (opnd->optype == OpndType_IndirectGPR_ImmOffset) {
|
|
offset += opnd->immOffset;
|
|
if (!FITS_IN_SHORT(offset)) {
|
|
add_immediate(reg, opnd->reg, opnd->object, opnd->immOffset);
|
|
emitpcode(PC_ADDI, reg, reg, 0, offset - opnd->immOffset);
|
|
} else {
|
|
add_immediate(reg, opnd->reg, opnd->object, offset);
|
|
}
|
|
} else if (opnd->optype == OpndType_IndirectGPR_Indexed) {
|
|
emitpcode(PC_ADD, reg, opnd->reg, opnd->regOffset);
|
|
emitpcode(PC_ADDI, reg, reg, 0, offset);
|
|
} else {
|
|
CError_FATAL(80);
|
|
}
|
|
|
|
opnd->optype = OpndType_IndirectGPR_ImmOffset;
|
|
opnd->reg = reg;
|
|
opnd->object = NULL;
|
|
opnd->immOffset = 0;
|
|
}
|
|
|
|
static void move_block_via_load_store(Operand *dst, Operand *src, SInt32 len, SInt32 align) {
|
|
SInt32 step;
|
|
SInt32 pos;
|
|
int floatReg;
|
|
int reg;
|
|
|
|
if (src->optype == OpndType_IndirectSymbol)
|
|
coerce_to_addressable(src);
|
|
if (dst->optype == OpndType_IndirectSymbol)
|
|
coerce_to_addressable(dst);
|
|
|
|
if (len == 8) {
|
|
floatReg = used_virtual_registers[RegClass_FPR]++;
|
|
if (src->optype == OpndType_IndirectGPR_ImmOffset) {
|
|
load_store_register(PC_LFD, floatReg, src->reg, src->object, src->immOffset);
|
|
setpcodeflags(src->flags);
|
|
} else if (src->optype == OpndType_IndirectGPR_Indexed) {
|
|
emitpcode(PC_LFDX, floatReg, src->reg, src->regOffset);
|
|
setpcodeflags(src->flags);
|
|
} else {
|
|
CError_FATAL(145);
|
|
}
|
|
|
|
if (dst->optype == OpndType_IndirectGPR_ImmOffset) {
|
|
load_store_register(PC_STFD, floatReg, dst->reg, dst->object, dst->immOffset);
|
|
setpcodeflags(dst->flags);
|
|
} else if (dst->optype == OpndType_IndirectGPR_Indexed) {
|
|
emitpcode(PC_STFDX, floatReg, dst->reg, dst->regOffset);
|
|
setpcodeflags(dst->flags);
|
|
} else {
|
|
CError_FATAL(157);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) {
|
|
SInt32 tmp = (align == 0) ? 1 : (align > len) ? len : align;
|
|
step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp <= 2) ? (UInt32) tmp : 2;
|
|
} else {
|
|
step = ((UInt32) len > 4) ? 4 : ((UInt32) len <= 2) ? len : 2;
|
|
}
|
|
|
|
if (step != len) {
|
|
if (dst->optype == OpndType_IndirectGPR_Indexed)
|
|
make_addressable(dst, len, 0);
|
|
if (src->optype == OpndType_IndirectGPR_Indexed)
|
|
make_addressable(src, len, 0);
|
|
}
|
|
|
|
for (pos = 0; len != 0; len -= step, pos += step) {
|
|
reg = used_virtual_registers[RegClass_GPR]++;
|
|
if (src->optype == OpndType_IndirectGPR_ImmOffset) {
|
|
load_store_register(
|
|
(step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ,
|
|
reg,
|
|
src->reg,
|
|
src->object,
|
|
src->immOffset + pos
|
|
);
|
|
setpcodeflags(src->flags);
|
|
} else if (src->optype == OpndType_IndirectGPR_Indexed) {
|
|
emitpcode(
|
|
(step == 1) ? PC_LBZX : (step == 2) ? PC_LHZX : PC_LWZX,
|
|
reg,
|
|
src->reg,
|
|
src->regOffset
|
|
);
|
|
setpcodeflags(src->flags);
|
|
} else {
|
|
CError_FATAL(183);
|
|
}
|
|
|
|
if (dst->optype == OpndType_IndirectGPR_ImmOffset) {
|
|
load_store_register(
|
|
(step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW,
|
|
reg,
|
|
dst->reg,
|
|
dst->object,
|
|
dst->immOffset + pos
|
|
);
|
|
setpcodeflags(dst->flags);
|
|
} else if (dst->optype == OpndType_IndirectGPR_Indexed) {
|
|
emitpcode(
|
|
(step == 1) ? PC_STBX : (step == 2) ? PC_STHX : PC_STWX,
|
|
reg,
|
|
dst->reg,
|
|
dst->regOffset
|
|
);
|
|
setpcodeflags(dst->flags);
|
|
} else {
|
|
CError_FATAL(195);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void move_block_via_load_store_sequence(Operand *dst, Operand *src, SInt32 len, SInt32 align) {
|
|
SInt32 pos;
|
|
int i;
|
|
SInt32 step;
|
|
|
|
pos = 0;
|
|
make_addressable(dst, len, 0);
|
|
make_addressable(src, len, 0);
|
|
|
|
if ((align % 8) == 0) {
|
|
while (len >= 16) {
|
|
int reg1 = used_virtual_registers[RegClass_FPR]++;
|
|
int reg2 = used_virtual_registers[RegClass_FPR]++;
|
|
load_store_register(PC_LFD, reg1, src->reg, src->object, src->immOffset + pos);
|
|
setpcodeflags(src->flags);
|
|
load_store_register(PC_LFD, reg2, src->reg, src->object, src->immOffset + pos + 8);
|
|
setpcodeflags(src->flags);
|
|
|
|
load_store_register(PC_STFD, reg1, dst->reg, dst->object, dst->immOffset + pos);
|
|
setpcodeflags(dst->flags);
|
|
load_store_register(PC_STFD, reg2, dst->reg, dst->object, dst->immOffset + pos + 8);
|
|
setpcodeflags(dst->flags);
|
|
|
|
pos += 16;
|
|
len -= 16;
|
|
}
|
|
}
|
|
|
|
while (len >= 8) {
|
|
if ((align % 8) == 0) {
|
|
int reg = used_virtual_registers[RegClass_FPR]++;
|
|
|
|
load_store_register(PC_LFD, reg, src->reg, src->object, src->immOffset + pos);
|
|
setpcodeflags(src->flags);
|
|
|
|
load_store_register(PC_STFD, reg, dst->reg, dst->object, dst->immOffset + pos);
|
|
setpcodeflags(dst->flags);
|
|
|
|
pos += 8;
|
|
len -= 8;
|
|
} else {
|
|
if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) {
|
|
SInt32 tmp = (align == 0) ? 1 : (align > len) ? len : align;
|
|
step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp > 2) ? 2 : 1;
|
|
} else {
|
|
step = 4;
|
|
}
|
|
|
|
for (i = 0; i < 8; i += (step * 2)) {
|
|
int reg1 = used_virtual_registers[RegClass_GPR]++;
|
|
int reg2 = used_virtual_registers[RegClass_GPR]++;
|
|
|
|
load_store_register(
|
|
(step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ,
|
|
reg1,
|
|
src->reg,
|
|
src->object,
|
|
src->immOffset + pos
|
|
);
|
|
setpcodeflags(src->flags);
|
|
|
|
load_store_register(
|
|
(step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ,
|
|
reg2,
|
|
src->reg,
|
|
src->object,
|
|
src->immOffset + pos + step
|
|
);
|
|
setpcodeflags(src->flags);
|
|
|
|
load_store_register(
|
|
(step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW,
|
|
reg1,
|
|
dst->reg,
|
|
dst->object,
|
|
dst->immOffset + pos
|
|
);
|
|
setpcodeflags(dst->flags);
|
|
|
|
load_store_register(
|
|
(step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW,
|
|
reg2,
|
|
dst->reg,
|
|
dst->object,
|
|
dst->immOffset + pos + step
|
|
);
|
|
setpcodeflags(dst->flags);
|
|
|
|
pos += (step * 2);
|
|
len -= (step * 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
while (len) {
|
|
int reg;
|
|
|
|
if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) {
|
|
SInt32 tmp = (align == 0) ? 1 : (align > len) ? len : align;
|
|
step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp <= 2) ? (UInt32) tmp : 2;
|
|
} else {
|
|
step = ((UInt32) len > 4) ? 4 : ((UInt32) len <= 2) ? len : 2;
|
|
}
|
|
|
|
reg = used_virtual_registers[RegClass_GPR]++;
|
|
|
|
load_store_register(
|
|
(step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ,
|
|
reg,
|
|
src->reg,
|
|
src->object,
|
|
src->immOffset + pos
|
|
);
|
|
setpcodeflags(src->flags);
|
|
|
|
load_store_register(
|
|
(step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW,
|
|
reg,
|
|
dst->reg,
|
|
dst->object,
|
|
dst->immOffset + pos
|
|
);
|
|
setpcodeflags(dst->flags);
|
|
|
|
len -= step;
|
|
pos += step;
|
|
}
|
|
}
|
|
|
|
static void move_block_via_inline_loop(Operand *dst, Operand *src, SInt32 len, SInt32 align) {
|
|
PCodeLabel *label; // r25
|
|
SInt32 pos; // r25
|
|
SInt32 step; // r24
|
|
int reg1; // r22
|
|
int reg2; // r23
|
|
SInt32 remainder; // r23
|
|
|
|
label = makepclabel();
|
|
|
|
if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) {
|
|
SInt32 tmp = (align == 0) ? 1 : (align > len) ? len : align;
|
|
step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp <= 2) ? (UInt32) tmp : 2;
|
|
} else {
|
|
step = 4;
|
|
}
|
|
|
|
load_displaced_address(dst, -step);
|
|
load_displaced_address(src, -step);
|
|
|
|
CError_ASSERT(377, (len / step) != 0);
|
|
|
|
reg1 = used_virtual_registers[RegClass_GPR]++;
|
|
load_immediate(reg1, len / (step * 2));
|
|
emitpcode(PC_MTCTR, reg1);
|
|
branch_label(label);
|
|
|
|
reg1 = used_virtual_registers[RegClass_GPR]++;
|
|
reg2 = used_virtual_registers[RegClass_GPR]++;
|
|
|
|
load_store_register(
|
|
(step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ,
|
|
reg1,
|
|
src->reg,
|
|
NULL,
|
|
step
|
|
);
|
|
setpcodeflags(src->flags);
|
|
|
|
load_store_register(
|
|
(step == 1) ? PC_LBZU : (step == 2) ? PC_LHZU : PC_LWZU,
|
|
reg2,
|
|
src->reg,
|
|
NULL,
|
|
step * 2
|
|
);
|
|
setpcodeflags(src->flags);
|
|
|
|
load_store_register(
|
|
(step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW,
|
|
reg1,
|
|
dst->reg,
|
|
NULL,
|
|
step
|
|
);
|
|
setpcodeflags(dst->flags);
|
|
|
|
load_store_register(
|
|
(step == 1) ? PC_STBU : (step == 2) ? PC_STHU : PC_STWU,
|
|
reg2,
|
|
dst->reg,
|
|
NULL,
|
|
step * 2
|
|
);
|
|
setpcodeflags(dst->flags);
|
|
|
|
branch_decrement_always(PC_BDNZ, label);
|
|
|
|
for (remainder = len & 7, pos = step; remainder != 0; remainder -= step, pos += step) {
|
|
int reg;
|
|
|
|
if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) {
|
|
SInt32 tmp = (align == 0) ? 1 : (align > remainder) ? remainder : align;
|
|
step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp <= 2) ? (UInt32) tmp : 2;
|
|
} else {
|
|
step = ((UInt32) remainder > 4) ? 4 : ((UInt32) remainder <= 2) ? remainder : 2;
|
|
}
|
|
|
|
reg = used_virtual_registers[RegClass_GPR]++;
|
|
|
|
load_store_register(
|
|
(step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ,
|
|
reg,
|
|
src->reg,
|
|
NULL,
|
|
pos
|
|
);
|
|
setpcodeflags(src->flags);
|
|
|
|
load_store_register(
|
|
(step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW,
|
|
reg,
|
|
dst->reg,
|
|
NULL,
|
|
pos
|
|
);
|
|
setpcodeflags(dst->flags);
|
|
}
|
|
}
|
|
|
|
void move_block(Operand *dst, Operand *src, SInt32 len, SInt32 align) {
|
|
Operand myDst;
|
|
|
|
myDst = *dst;
|
|
|
|
CError_ASSERT(447, myDst.optype >= OpndType_IndirectGPR_ImmOffset);
|
|
CError_ASSERT(449, src->optype >= OpndType_IndirectGPR_ImmOffset);
|
|
|
|
if (len == 1 || len == 2 || len == 4)
|
|
move_block_via_load_store(&myDst, src, len, align);
|
|
else if (len == 8 && align == 8)
|
|
move_block_via_load_store(&myDst, src, len, align);
|
|
else if (len <= 16 || (copts.optimizesize == 0 && len <= 64))
|
|
move_block_via_load_store_sequence(&myDst, src, len, align);
|
|
else
|
|
move_block_via_inline_loop(&myDst, src, len, align);
|
|
}
|
|
|
|
static void load_word_of_small_struct(short dstReg, short srcReg, Operand *opnd, SInt32 offset, SInt32 len, SInt32 align) {
|
|
short tmpReg;
|
|
short extra = 0;
|
|
|
|
switch (len) {
|
|
case 1:
|
|
tmpReg = used_virtual_registers[RegClass_GPR]++;
|
|
load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset);
|
|
setpcodeflags(opnd->flags);
|
|
emitpcode(PC_RLWINM, dstReg, tmpReg, 24, 0, 7);
|
|
setpcodeflags(opnd->flags);
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
if (align > 1) {
|
|
tmpReg = used_virtual_registers[RegClass_GPR]++;
|
|
load_store_register(PC_LHZ, tmpReg, srcReg, opnd->object, offset);
|
|
extra += 2;
|
|
setpcodeflags(opnd->flags);
|
|
emitpcode(PC_RLWINM, dstReg, tmpReg, 16, 0, 15);
|
|
setpcodeflags(opnd->flags);
|
|
} else {
|
|
tmpReg = used_virtual_registers[RegClass_GPR]++;
|
|
load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset);
|
|
setpcodeflags(opnd->flags);
|
|
emitpcode(PC_RLWINM, dstReg, tmpReg, 24, 0, 7);
|
|
setpcodeflags(opnd->flags);
|
|
|
|
load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + 1);
|
|
extra += 2;
|
|
setpcodeflags(opnd->flags);
|
|
emitpcode(PC_RLWIMI, dstReg, tmpReg, 16, 8, 15);
|
|
setpcodeflags(opnd->flags);
|
|
}
|
|
if (len == 3) {
|
|
load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + extra);
|
|
setpcodeflags(opnd->flags);
|
|
emitpcode(PC_RLWIMI, dstReg, tmpReg, 8, 16, 23);
|
|
setpcodeflags(opnd->flags);
|
|
}
|
|
break;
|
|
case 4:
|
|
if (align > 2) {
|
|
load_store_register(PC_LWZ, dstReg, srcReg, opnd->object, offset);
|
|
setpcodeflags(opnd->flags);
|
|
} else if (align > 1) {
|
|
tmpReg = used_virtual_registers[RegClass_GPR]++;
|
|
load_store_register(PC_LHZ, tmpReg, srcReg, opnd->object, offset);
|
|
setpcodeflags(opnd->flags);
|
|
emitpcode(PC_RLWINM, dstReg, tmpReg, 16, 0, 15);
|
|
setpcodeflags(opnd->flags);
|
|
|
|
load_store_register(PC_LHZ, tmpReg, srcReg, opnd->object, offset + 2);
|
|
setpcodeflags(opnd->flags);
|
|
emitpcode(PC_RLWIMI, dstReg, tmpReg, 0, 16, 31);
|
|
setpcodeflags(opnd->flags);
|
|
} else {
|
|
tmpReg = used_virtual_registers[RegClass_GPR]++;
|
|
load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset);
|
|
setpcodeflags(opnd->flags);
|
|
emitpcode(PC_RLWINM, dstReg, tmpReg, 24, 0, 7);
|
|
setpcodeflags(opnd->flags);
|
|
|
|
load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + 1);
|
|
setpcodeflags(opnd->flags);
|
|
emitpcode(PC_RLWIMI, dstReg, tmpReg, 16, 8, 15);
|
|
setpcodeflags(opnd->flags);
|
|
|
|
load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + 2);
|
|
setpcodeflags(opnd->flags);
|
|
emitpcode(PC_RLWIMI, dstReg, tmpReg, 8, 16, 23);
|
|
setpcodeflags(opnd->flags);
|
|
|
|
load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + 3);
|
|
setpcodeflags(opnd->flags);
|
|
emitpcode(PC_RLWIMI, dstReg, tmpReg, 0, 24, 31);
|
|
setpcodeflags(opnd->flags);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void load_small_block_into_reg(short dstReg, Operand *srcOpnd, Type *type, SInt32 align) {
|
|
short finalReg;
|
|
short tmpReg;
|
|
SInt32 absAddress;
|
|
|
|
coerce_to_addressable(srcOpnd);
|
|
|
|
if (srcOpnd->optype == OpndType_IndirectGPR_Indexed) {
|
|
CError_FATAL(557);
|
|
|
|
tmpReg = used_virtual_registers[RegClass_GPR]++;
|
|
load_address(tmpReg, srcOpnd);
|
|
srcOpnd->optype = OpndType_IndirectGPR_ImmOffset;
|
|
srcOpnd->reg = tmpReg;
|
|
srcOpnd->object = NULL;
|
|
srcOpnd->immOffset = 0;
|
|
}
|
|
|
|
if (copts.misaligned_mem_access)
|
|
align = 4;
|
|
|
|
switch (srcOpnd->optype) {
|
|
case OpndType_GPRPair:
|
|
return;
|
|
case OpndType_GPR:
|
|
return;
|
|
case OpndType_GPR_ImmOffset:
|
|
finalReg = dstReg ? dstReg : used_virtual_registers[RegClass_GPR]++;
|
|
add_immediate(finalReg, srcOpnd->reg, srcOpnd->object, srcOpnd->immOffset);
|
|
break;
|
|
case OpndType_GPR_Indexed:
|
|
finalReg = dstReg ? dstReg : used_virtual_registers[RegClass_GPR]++;
|
|
emitpcode(PC_ADD, finalReg, srcOpnd->reg, srcOpnd->regOffset);
|
|
break;
|
|
case OpndType_Absolute:
|
|
finalReg = dstReg ? dstReg : used_virtual_registers[RegClass_GPR]++;
|
|
absAddress = srcOpnd->immediate;
|
|
if (FITS_IN_SHORT(absAddress)) {
|
|
emitpcode(PC_LI, finalReg, absAddress);
|
|
} else {
|
|
tmpReg = finalReg;
|
|
if (copts.optimizationlevel > 1 && absAddress)
|
|
tmpReg = used_virtual_registers[RegClass_GPR]++;
|
|
emitpcode(PC_LIS, tmpReg, 0, HIGH_PART(absAddress));
|
|
if (absAddress)
|
|
emitpcode(PC_ADDI, finalReg, tmpReg, 0, LOW_PART(absAddress));
|
|
}
|
|
break;
|
|
case OpndType_IndirectGPR_ImmOffset:
|
|
finalReg = dstReg ? dstReg : used_virtual_registers[RegClass_GPR]++;
|
|
load_word_of_small_struct(finalReg, srcOpnd->reg, srcOpnd, srcOpnd->immOffset, type->size, align);
|
|
break;
|
|
default:
|
|
CError_FATAL(606);
|
|
}
|
|
|
|
srcOpnd->optype = OpndType_GPR;
|
|
srcOpnd->reg = finalReg;
|
|
}
|
|
|
|
void load_small_block_into_reg_pair(short dstRegLo, short dstRegHi, Operand *srcOpnd, Type *type, SInt32 align) {
|
|
short finalRegLo;
|
|
short finalRegHi;
|
|
short tmpRegLo;
|
|
short tmpRegHi;
|
|
short tmpReg;
|
|
SInt32 absAddress;
|
|
|
|
finalRegHi = -1;
|
|
coerce_to_addressable(srcOpnd);
|
|
|
|
if (srcOpnd->optype == OpndType_IndirectGPR_Indexed) {
|
|
CError_FATAL(624);
|
|
|
|
tmpReg = used_virtual_registers[RegClass_GPR]++;
|
|
load_address(tmpReg, srcOpnd);
|
|
srcOpnd->optype = OpndType_IndirectGPR_ImmOffset;
|
|
srcOpnd->reg = tmpReg;
|
|
srcOpnd->object = NULL;
|
|
srcOpnd->immOffset = 0;
|
|
}
|
|
|
|
if (copts.misaligned_mem_access)
|
|
align = 4;
|
|
|
|
switch (srcOpnd->optype) {
|
|
case OpndType_GPRPair:
|
|
if (dstRegLo != 0 && dstRegHi == 0)
|
|
dstRegHi = used_virtual_registers[RegClass_GPR]++;
|
|
if (dstRegHi != 0 && dstRegLo == 0)
|
|
dstRegLo = used_virtual_registers[RegClass_GPR]++;
|
|
|
|
if (srcOpnd->reg != dstRegLo || srcOpnd->regHi != dstRegHi) {
|
|
tmpRegLo = dstRegLo ? dstRegLo : srcOpnd->reg;
|
|
tmpRegHi = dstRegHi ? dstRegHi : srcOpnd->regHi;
|
|
|
|
if (tmpRegLo != srcOpnd->reg) {
|
|
if (tmpRegLo == srcOpnd->regHi) {
|
|
CError_ASSERT(657, tmpRegLo != tmpRegHi);
|
|
emitpcode(PC_MR, tmpRegHi, srcOpnd->regHi);
|
|
emitpcode(PC_MR, tmpRegLo, srcOpnd->reg);
|
|
} else {
|
|
emitpcode(PC_MR, tmpRegLo, srcOpnd->reg);
|
|
if (srcOpnd->regHi != tmpRegHi)
|
|
emitpcode(PC_MR, tmpRegHi, srcOpnd->regHi);
|
|
}
|
|
} else if (tmpRegHi != srcOpnd->regHi) {
|
|
if (tmpRegHi == srcOpnd->reg) {
|
|
CError_ASSERT(671, tmpRegLo != tmpRegHi);
|
|
emitpcode(PC_MR, tmpRegLo, srcOpnd->reg);
|
|
emitpcode(PC_MR, tmpRegHi, srcOpnd->regHi);
|
|
} else {
|
|
emitpcode(PC_MR, tmpRegHi, srcOpnd->regHi);
|
|
if (srcOpnd->reg != tmpRegLo)
|
|
emitpcode(PC_MR, tmpRegLo, srcOpnd->reg);
|
|
}
|
|
}
|
|
}
|
|
|
|
finalRegLo = srcOpnd->reg;
|
|
finalRegHi = srcOpnd->regHi;
|
|
break;
|
|
case OpndType_GPR:
|
|
CError_FATAL(688);
|
|
break;
|
|
case OpndType_GPR_ImmOffset:
|
|
CError_FATAL(691);
|
|
break;
|
|
case OpndType_GPR_Indexed:
|
|
CError_FATAL(694);
|
|
break;
|
|
case OpndType_Absolute:
|
|
finalRegLo = dstRegLo ? dstRegLo : used_virtual_registers[RegClass_GPR]++;
|
|
absAddress = srcOpnd->immediate;
|
|
if (FITS_IN_SHORT(absAddress)) {
|
|
emitpcode(PC_LI, finalRegLo, absAddress);
|
|
} else {
|
|
tmpReg = finalRegLo;
|
|
if (copts.optimizationlevel > 1 && absAddress)
|
|
tmpReg = used_virtual_registers[RegClass_GPR]++;
|
|
emitpcode(PC_LIS, tmpReg, 0, HIGH_PART(absAddress));
|
|
if (absAddress)
|
|
emitpcode(PC_ADDI, finalRegLo, tmpReg, 0, LOW_PART(absAddress));
|
|
}
|
|
|
|
finalRegHi = dstRegHi ? dstRegHi : used_virtual_registers[RegClass_GPR]++;
|
|
if (is_unsigned(type) || absAddress >= 0)
|
|
load_immediate(finalRegHi, 0);
|
|
else
|
|
load_immediate(finalRegHi, -1);
|
|
|
|
break;
|
|
case OpndType_IndirectGPR_ImmOffset:
|
|
finalRegLo = dstRegLo ? dstRegLo : used_virtual_registers[RegClass_GPR]++;
|
|
finalRegHi = dstRegHi ? dstRegHi : used_virtual_registers[RegClass_GPR]++;
|
|
if (srcOpnd->reg == finalRegHi) {
|
|
if (srcOpnd->reg == finalRegLo) {
|
|
CError_FATAL(726);
|
|
} else {
|
|
load_word_of_small_struct(
|
|
finalRegLo, srcOpnd->reg, srcOpnd,
|
|
srcOpnd->immOffset + low_offset, type->size - 4, align);
|
|
load_word_of_small_struct(
|
|
finalRegHi, srcOpnd->reg, srcOpnd,
|
|
srcOpnd->immOffset + high_offset, 4, align);
|
|
}
|
|
} else {
|
|
load_word_of_small_struct(
|
|
finalRegHi, srcOpnd->reg, srcOpnd,
|
|
srcOpnd->immOffset + high_offset, 4, align);
|
|
load_word_of_small_struct(
|
|
finalRegLo, srcOpnd->reg, srcOpnd,
|
|
srcOpnd->immOffset + low_offset, type->size - 4, align);
|
|
}
|
|
break;
|
|
default:
|
|
CError_FATAL(737);
|
|
}
|
|
|
|
if (finalRegHi == -1) {
|
|
CError_FATAL(741);
|
|
} else {
|
|
srcOpnd->optype = OpndType_GPRPair;
|
|
srcOpnd->reg = finalRegLo;
|
|
srcOpnd->regHi = finalRegHi;
|
|
}
|
|
}
|
|
|
|
static void store_word_of_small_struct(short srcReg, short dstReg, Operand *opnd, SInt32 offset, SInt32 len, SInt32 align) {
|
|
short tmpReg;
|
|
short extra = 0;
|
|
|
|
switch (len) {
|
|
case 1:
|
|
tmpReg = used_virtual_registers[RegClass_GPR]++;
|
|
emitpcode(PC_RLWINM, tmpReg, srcReg, 8, 24, 31);
|
|
setpcodeflags(opnd->flags);
|
|
load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset);
|
|
setpcodeflags(opnd->flags);
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
if (align > 1) {
|
|
tmpReg = used_virtual_registers[RegClass_GPR]++;
|
|
emitpcode(PC_RLWINM, tmpReg, srcReg, 16, 16, 31);
|
|
setpcodeflags(opnd->flags);
|
|
load_store_register(PC_STH, tmpReg, dstReg, opnd->object, offset);
|
|
extra += 2;
|
|
setpcodeflags(opnd->flags);
|
|
} else {
|
|
tmpReg = used_virtual_registers[RegClass_GPR]++;
|
|
emitpcode(PC_RLWINM, tmpReg, srcReg, 8, 24, 31);
|
|
setpcodeflags(opnd->flags);
|
|
load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset);
|
|
setpcodeflags(opnd->flags);
|
|
|
|
emitpcode(PC_RLWINM, tmpReg, srcReg, 16, 24, 31);
|
|
setpcodeflags(opnd->flags);
|
|
load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset + 1);
|
|
extra += 2;
|
|
setpcodeflags(opnd->flags);
|
|
}
|
|
if (len == 3) {
|
|
emitpcode(PC_RLWINM, tmpReg, srcReg, 24, 24, 31);
|
|
setpcodeflags(opnd->flags);
|
|
load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset + extra);
|
|
setpcodeflags(opnd->flags);
|
|
}
|
|
break;
|
|
case 4:
|
|
if (align > 2) {
|
|
load_store_register(PC_STW, srcReg, dstReg, opnd->object, offset);
|
|
setpcodeflags(opnd->flags);
|
|
} else if (align > 1) {
|
|
tmpReg = used_virtual_registers[RegClass_GPR]++;
|
|
emitpcode(PC_RLWINM, tmpReg, srcReg, 16, 16, 31);
|
|
setpcodeflags(opnd->flags);
|
|
load_store_register(PC_STH, tmpReg, dstReg, opnd->object, offset);
|
|
setpcodeflags(opnd->flags);
|
|
|
|
load_store_register(PC_STH, srcReg, dstReg, opnd->object, offset + 2);
|
|
setpcodeflags(opnd->flags);
|
|
} else {
|
|
tmpReg = used_virtual_registers[RegClass_GPR]++;
|
|
emitpcode(PC_RLWINM, tmpReg, srcReg, 8, 24, 31);
|
|
setpcodeflags(opnd->flags);
|
|
load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset);
|
|
setpcodeflags(opnd->flags);
|
|
|
|
emitpcode(PC_RLWINM, tmpReg, srcReg, 16, 24, 31);
|
|
setpcodeflags(opnd->flags);
|
|
load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset + 1);
|
|
setpcodeflags(opnd->flags);
|
|
|
|
emitpcode(PC_RLWINM, tmpReg, srcReg, 24, 24, 31);
|
|
setpcodeflags(opnd->flags);
|
|
load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset + 2);
|
|
setpcodeflags(opnd->flags);
|
|
|
|
load_store_register(PC_STB, srcReg, dstReg, opnd->object, offset + 3);
|
|
setpcodeflags(opnd->flags);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void store_small_block_from_reg(short srcReg, Operand *dstOpnd, Type *type, SInt32 align) {
|
|
short tmpReg;
|
|
|
|
coerce_to_addressable(dstOpnd);
|
|
|
|
if (dstOpnd->optype == OpndType_IndirectGPR_Indexed) {
|
|
CError_FATAL(839);
|
|
|
|
tmpReg = used_virtual_registers[RegClass_GPR]++;
|
|
load_address(tmpReg, dstOpnd);
|
|
dstOpnd->optype = OpndType_IndirectGPR_ImmOffset;
|
|
dstOpnd->reg = tmpReg;
|
|
dstOpnd->object = NULL;
|
|
dstOpnd->immOffset = 0;
|
|
}
|
|
|
|
if (copts.misaligned_mem_access)
|
|
align = 4;
|
|
|
|
store_word_of_small_struct(srcReg, dstOpnd->reg, dstOpnd, dstOpnd->immOffset, type->size, align);
|
|
}
|
|
|
|
void store_small_block_from_reg_pair(short srcRegLo, short srcRegHi, Operand *dstOpnd, Type *type, SInt32 align) {
|
|
short tmpReg;
|
|
|
|
coerce_to_addressable(dstOpnd);
|
|
|
|
if (dstOpnd->optype == OpndType_IndirectGPR_Indexed) {
|
|
CError_FATAL(860);
|
|
|
|
tmpReg = used_virtual_registers[RegClass_GPR]++;
|
|
load_address(tmpReg, dstOpnd);
|
|
dstOpnd->optype = OpndType_IndirectGPR_ImmOffset;
|
|
dstOpnd->reg = tmpReg;
|
|
dstOpnd->object = NULL;
|
|
dstOpnd->immOffset = 0;
|
|
}
|
|
|
|
if (copts.misaligned_mem_access)
|
|
align = 4;
|
|
|
|
store_word_of_small_struct(
|
|
srcRegLo, dstOpnd->reg, dstOpnd,
|
|
dstOpnd->immOffset + low_offset, type->size - 4, align);
|
|
store_word_of_small_struct(
|
|
srcRegHi, dstOpnd->reg, dstOpnd,
|
|
dstOpnd->immOffset + high_offset, 4, align);
|
|
}
|