MWCC/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StructMoves.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);
}