diff options
Diffstat (limited to 'compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StructMoves.c')
-rw-r--r-- | compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StructMoves.c | 792 |
1 files changed, 792 insertions, 0 deletions
diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StructMoves.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StructMoves.c new file mode 100644 index 0000000..7c28b88 --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StructMoves.c @@ -0,0 +1,792 @@ +#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); +} |