diff options
Diffstat (limited to 'compiler_and_linker/unsorted/Switch.c')
-rw-r--r-- | compiler_and_linker/unsorted/Switch.c | 518 |
1 files changed, 0 insertions, 518 deletions
diff --git a/compiler_and_linker/unsorted/Switch.c b/compiler_and_linker/unsorted/Switch.c deleted file mode 100644 index 4bbd82e..0000000 --- a/compiler_and_linker/unsorted/Switch.c +++ /dev/null @@ -1,518 +0,0 @@ -#include "compiler/Switch.h" -#include "compiler/CError.h" -#include "compiler/CFunc.h" -#include "compiler/CInt64.h" -#include "compiler/CParser.h" -#include "compiler/InstrSelection.h" -#include "compiler/ObjGenMachO.h" -#include "compiler/Operands.h" -#include "compiler/PCode.h" -#include "compiler/PCodeUtilities.h" -#include "compiler/RegisterInfo.h" -#include "compiler/TOC.h" -#include "compiler/CompilerTools.h" -#include "compiler/objects.h" - -ObjectList *switchtables; -static SwitchCase **caselabels; -static CaseRange *caseranges; -static SInt32 ncases; -static SInt32 nranges_minus1; -static CInt64 min; -static CInt64 max; -static CInt64 first; -static short selector_gpr; -static short selector_gprHi; -static Type *selector_type; -static PCodeLabel *defaultlabel; -static CInt64 range; - -static int compare_cases(const void *a, const void *b) { - const SwitchCase **casea = (const SwitchCase **) a; - const SwitchCase **caseb = (const SwitchCase **) b; - - if (CInt64_Less((*casea)->min, (*caseb)->min)) - return -1; - if (CInt64_Greater((*casea)->min, (*caseb)->min)) - return 1; - return 0; -} - -static void build_case_ranges(Type *type, SwitchCase *cases, CLabel *label) { - SwitchCase **caseptr; - SInt32 i; - SwitchCase *curcase; - CaseRange *currange; - - if (type->size == 8) { - min.lo = 0; - min.hi = 0x80000000; - max.lo = 0xFFFFFFFF; - max.hi = 0x7FFFFFFF; - } else if (type->size == 4) { - CInt64_SetLong(&min, 0x80000000); - CInt64_SetLong(&max, 0x7FFFFFFF); - } else if (is_unsigned(type)) { - min.hi = 0; - min.lo = 0; - max.hi = 0; - max.lo = 0xFFFF; - } else { - CInt64_SetLong(&min, -0x8000); - CInt64_SetLong(&max, 0x7FFF); - } - - caselabels = lalloc(sizeof(SwitchCase *) * ncases); - caseptr = caselabels; - while (cases) { - *caseptr = cases; - cases = cases->next; - ++caseptr; - } - - caseranges = lalloc(((ncases * 2) + 2) * sizeof(CaseRange)); - if (type->size < 8) { - for (i = 0; i < ncases; i++) - CInt64_SetLong(&caselabels[i]->min, caselabels[i]->min.lo); - } - - qsort(caselabels, ncases, sizeof(SwitchCase *), &compare_cases); - - currange = caseranges; - currange->min = min; - currange->range = CInt64_Sub(max, min); - currange->label = label->pclabel; - - for (i = 0; i < ncases; i++) { - curcase = caselabels[i]; - if (CInt64_GreaterEqual(curcase->min, min) && CInt64_LessEqual(curcase->min, max)) { - if (CInt64_Equal(currange->min, min)) - first = curcase->min; - range = CInt64_Sub(curcase->min, first); - - if (CInt64_Greater(curcase->min, currange->min)) { - currange->range = CInt64_Sub(CInt64_Sub(curcase->min, currange->min), cint64_one); - (++currange)->min = curcase->min; - } else if (CInt64_Greater(currange->min, min) && curcase->label->pclabel == currange[-1].label) { - currange[-1].range = CInt64_Add(currange[-1].range, cint64_one); - if (CInt64_Equal(currange->range, cint64_zero)) { - currange--; - } else { - currange->min = CInt64_Add(currange->min, cint64_one); - currange->range = CInt64_Sub(currange->range, cint64_one); - } - continue; - } - - currange->range = cint64_zero; - currange->label = curcase->label->pclabel; - - if (CInt64_Less(curcase->min, max)) { - currange++; - currange->min = CInt64_Add(curcase->min, cint64_one); - currange->range = CInt64_Sub(max, currange->min); - currange->label = label->pclabel; - } - } - } - - nranges_minus1 = currange - caseranges; -} - -static void treecompare(SInt32 start, SInt32 end) { - SInt32 r30; - SInt32 r29; - CaseRange *currange; - int count; - - count = end - start; - CError_ASSERT(175, selector_type->size <= 4); - - r29 = start + (count >> 1) + 1; - currange = caseranges + r29; - - if (CInt64_Equal(currange[-1].range, cint64_zero) && (!(count & 1) || (CInt64_NotEqual(currange->range, cint64_zero) && count > 1))) { - currange--; - r29--; - } - - r30 = r29 - 1; - - if (selector_type->size < 4 && is_unsigned(selector_type)) { - emitpcode(PC_CMPLI, 0, selector_gpr, CInt64_GetULong(&currange->min)); - } else if (FITS_IN_SHORT((SInt32) CInt64_GetULong(&currange->min))) { - emitpcode(PC_CMPI, 0, selector_gpr, CInt64_GetULong(&currange->min)); - } else { - SInt32 value = CInt64_GetULong(&currange->min); - int reg = ALLOC_GPR(); - load_immediate(reg, value); - emitpcode(PC_CMP, 0, selector_gpr, reg); - } - - if (CInt64_Equal(currange->range, cint64_zero) && r29 < end) { - branch_conditional(0, EEQU, 1, currange->label); - r29++; - } - - if (r29 == end) { - if (start == r30) { - if (caseranges[start].label == caseranges[end].label) { - branch_always(caseranges[start].label); - } else { - branch_conditional(0, EGREATEREQU, 1, caseranges[end].label); - branch_always(caseranges[start].label); - } - } else { - branch_conditional(0, EGREATEREQU, 1, caseranges[end].label); - treecompare(start, r30); - } - } else { - if (start == r30) { - branch_conditional(0, ELESS, 1, caseranges[start].label); - treecompare(r29, end); - } else { - PCodeLabel *label = makepclabel(); - branch_conditional(0, EGREATEREQU, 1, label); - treecompare(start, r30); - branch_label(label); - treecompare(r29, end); - } - } -} - -static void I8_treecompare(SInt32 start, SInt32 end) { - SInt32 r30; - SInt32 r29; - CaseRange *currange; - int count; - - count = end - start; - - r29 = start + (count >> 1) + 1; - currange = caseranges + r29; - - if (CInt64_Equal(currange[-1].range, cint64_zero) && (!(count & 1) || (CInt64_NotEqual(currange->range, cint64_zero) && count > 1))) { - currange--; - r29--; - } - - r30 = r29 - 1; - - if (CInt64_Equal(currange->range, cint64_zero) && r29 < end) { - short a = ALLOC_GPR(); - short b = ALLOC_GPR(); - load_immediate(a, currange->min.lo); - load_immediate(b, currange->min.hi); - emitpcode(PC_XOR, a, selector_gpr, a); - emitpcode(PC_XOR, b, selector_gprHi, b); - emitpcode(PC_OR, b, a, b); - emitpcode(PC_CMPI, 0, b, 0); - branch_conditional(0, EEQU, 1, currange->label); - r29++; - } - - if (r29 == end) { - if (start == r30) { - if (caseranges[start].label == caseranges[end].label) { - branch_always(caseranges[start].label); - } else { - short a = ALLOC_GPR(); - short b = ALLOC_GPR(); - short c = ALLOC_GPR(); - short d = ALLOC_GPR(); - load_immediate(a, currange->min.lo); - load_immediate(b, currange->min.hi); - if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) { - emitpcode(PC_XORIS, c, selector_gprHi, 0x8000); - emitpcode(PC_XORIS, d, b, 0x8000); - } else { - c = selector_gprHi; - d = b; - } - emitpcode(PC_SUBFC, a, a, selector_gpr); - emitpcode(PC_SUBFE, b, d, c); - emitpcode(PC_SUBFE, b, a, a); - emitpcode(PC_NEG, b, b); - emitpcode(PC_CMPI, 0, b, 0); - branch_conditional(0, EEQU, 1, caseranges[end].label); - branch_always(caseranges[start].label); - } - } else { - short a = ALLOC_GPR(); - short b = ALLOC_GPR(); - short c = ALLOC_GPR(); - short d = ALLOC_GPR(); - load_immediate(a, currange->min.lo); - load_immediate(b, currange->min.hi); - if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) { - emitpcode(PC_XORIS, c, selector_gprHi, 0x8000); - emitpcode(PC_XORIS, d, b, 0x8000); - } else { - c = selector_gprHi; - d = b; - } - emitpcode(PC_SUBFC, a, a, selector_gpr); - emitpcode(PC_SUBFE, b, d, c); - emitpcode(PC_SUBFE, b, a, a); - emitpcode(PC_NEG, b, b); - emitpcode(PC_CMPI, 0, b, 0); - branch_conditional(0, EEQU, 1, caseranges[end].label); - I8_treecompare(start, r30); - } - } else { - if (start == r30) { - short a = ALLOC_GPR(); - short b = ALLOC_GPR(); - short c = ALLOC_GPR(); - short d = ALLOC_GPR(); - load_immediate(a, currange->min.lo); - load_immediate(b, currange->min.hi); - if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) { - emitpcode(PC_XORIS, c, selector_gprHi, 0x8000); - emitpcode(PC_XORIS, d, b, 0x8000); - } else { - c = selector_gprHi; - d = b; - } - emitpcode(PC_SUBFC, a, selector_gpr, a); - emitpcode(PC_SUBFE, b, c, d); - emitpcode(PC_SUBFE, b, a, a); - emitpcode(PC_NEG, b, b); - emitpcode(PC_CMPI, 0, b, 0); - branch_conditional(0, ENOTEQU, 1, caseranges[end].label); - I8_treecompare(r29, end); - } else { - PCodeLabel *label; - short a = ALLOC_GPR(); - short b = ALLOC_GPR(); - short c = ALLOC_GPR(); - short d = ALLOC_GPR(); - load_immediate(a, currange->min.lo); - load_immediate(b, currange->min.hi); - if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) { - emitpcode(PC_XORIS, c, selector_gprHi, 0x8000); - emitpcode(PC_XORIS, d, b, 0x8000); - } else { - c = selector_gprHi; - d = b; - } - emitpcode(PC_SUBFC, a, a, selector_gpr); - emitpcode(PC_SUBFE, b, d, c); - emitpcode(PC_SUBFE, b, a, a); - emitpcode(PC_NEG, b, b); - emitpcode(PC_CMPI, 0, b, 0); - label = makepclabel(); - branch_conditional(0, EEQU, 1, label); - I8_treecompare(start, r30); - branch_label(label); - I8_treecompare(r29, end); - } - } -} - -static void generate_tree(ENode *expr) { - Operand op; - - memclrw(&op, sizeof(Operand)); - if (TYPE_IS_8BYTES(expr->rtype)) { - GEN_NODE(expr, &op); - coerce_to_register_pair(&op, expr->rtype, 0, 0); - selector_type = expr->rtype; - selector_gpr = op.reg; - selector_gprHi = op.regHi; - I8_treecompare(0, nranges_minus1); - } else { - GEN_NODE(expr, &op); - if (expr->rtype->size < 4) - extend32(&op, expr->rtype, 0); - ENSURE_GPR(&op, expr->rtype, 0); - selector_type = expr->rtype; - selector_gpr = op.reg; - treecompare(0, nranges_minus1); - } -} - -static Object *create_switch_table(void) { - Object *obj; - ObjectList *list; - UInt32 *outptr; - CaseRange *currange; - SInt32 size; - CInt64 value; - - obj = galloc(sizeof(Object)); - list = galloc(sizeof(ObjectList)); - memclrw(obj, sizeof(Object)); - memclrw(list, sizeof(ObjectList)); - - obj->otype = OT_OBJECT; - obj->access = ACCESSPUBLIC; - obj->datatype = DDATA; - obj->name = CParser_GetUniqueName(); - obj->toc = NULL; - obj->sclass = TK_STATIC; - obj->qual = Q_CONST; - obj->flags |= OBJECT_FLAGS_2 | OBJECT_DEFINED; - obj->u.data.linkname = obj->name; - obj->type = NULL; - createIndirect(obj, 0, 0); - obj->type = TYPE(&void_ptr); - - size = CInt64_GetULong(&range) + 1; - obj->u.data.u.switchtable.size = size; - obj->u.data.u.switchtable.data = lalloc(4 * size); - - currange = caseranges; - outptr = (UInt32 *) obj->u.data.u.switchtable.data; - value = cint64_zero; - while (CInt64_LessEqual(value, range)) { - while (CInt64_Greater(CInt64_Add(first, value), CInt64_Add(currange->min, currange->range))) - currange++; - *outptr = CTool_CreateIndexFromPointer(currange->label); - value = CInt64_Add(value, cint64_one); - outptr++; - } - - list->object = obj; - list->next = switchtables; - switchtables = list; - return list->object; -} - -static void generate_table(ENode *expr, SwitchInfo *info) { - Object *table; - SwitchCase *curcase; - short reg; - short reg2; - short reg3; - Operand op1; - Operand op2; - - CInt64 val3 = {0, 3}; - memclrw(&op1, sizeof(Operand)); - memclrw(&op2, sizeof(Operand)); - - if (CInt64_Greater(first, cint64_zero) && CInt64_Less(first, val3)) { - range = CInt64_Add(range, first); - first = cint64_zero; - } - - table = create_switch_table(); - CError_ASSERT(553, !TYPE_IS_8BYTES(expr->rtype)); - - GEN_NODE(expr, &op1); - if (expr->rtype->size < 4) - extend32(&op1, expr->rtype, 0); - ENSURE_GPR(&op1, expr->rtype, 0); - - reg = op1.reg; - if (CInt64_NotEqual(first, cint64_zero)) { - SInt32 value; - reg = ALLOC_GPR(); - value = -CInt64_GetULong(&first); - if (!FITS_IN_SHORT(value)) { - emitpcode(PC_ADDIS, reg, op1.reg, 0, HIGH_PART(value)); - if (value) - emitpcode(PC_ADDI, reg, reg, 0, LOW_PART(value)); - } else { - emitpcode(PC_ADDI, reg, op1.reg, 0, value); - } - } - - if (!FITS_IN_SHORT(CInt64_GetULong(&range))) { - short tmp = ALLOC_GPR(); - load_immediate(tmp, CInt64_GetULong(&range)); - emitpcode(PC_CMPL, 0, reg, tmp); - } else { - emitpcode(PC_CMPLI, 0, reg, CInt64_GetULong(&range)); - } - - branch_conditional(0, EGREATER, 1, defaultlabel); - if (table->toc) { - op2.optype = OpndType_Symbol; - op2.object = table->toc; - indirect(&op2, NULL); - } else { - op2.optype = OpndType_Symbol; - op2.object = table; - } - - if (op2.optype != OpndType_GPR) { - Coerce_to_register(&op2, TYPE(&void_ptr), reg2 = ALLOC_GPR()); - } - - if (op2.optype != OpndType_GPR) { - CError_FATAL(599); - } else { - if (op2.reg != reg2) - emitpcode(PC_MR, reg2, op2.reg); - } - - if (CInt64_Equal(first, cint64_zero)) { - reg = ALLOC_GPR(); - emitpcode(PC_RLWINM, reg, op1.reg, 2, 0, 29); - } else { - emitpcode(PC_RLWINM, reg, reg, 2, 0, 29); - } - - reg3 = reg2; - emitpcode(PC_LWZX, reg3, reg3, reg); - for (curcase = info->cases; curcase; curcase = curcase->next) - pcbranch(pclastblock, curcase->label->pclabel); - pcbranch(pclastblock, info->defaultlabel->pclabel); - emitpcode(PC_MTCTR, reg3); - branch_indirect(table); -} - -void switchstatement(ENode *expr, SwitchInfo *info) { - Boolean use_table; - SwitchCase *swcase; - - use_table = copts.switch_tables; - - ncases = 0; - for (swcase = info->cases; swcase; swcase = swcase->next) { - if (!swcase->label->pclabel) - swcase->label->pclabel = makepclabel(); - ncases++; - } - - CError_ASSERT(656, ncases >= 0 && ncases <= 0x3333332U); - - if (!info->defaultlabel->pclabel) - info->defaultlabel->pclabel = makepclabel(); - defaultlabel = info->defaultlabel->pclabel; - - build_case_ranges(expr->rtype, info->cases, info->defaultlabel); - - if (TYPE_IS_8BYTES(expr->rtype)) { - generate_tree(expr); - return; - } - - if (!use_table || nranges_minus1 < 8 || (nranges_minus1 * 2) < ((range.lo / 2) + 4)) - generate_tree(expr); - else - generate_table(expr, info); -} - -void dumpswitchtables(Object *funcobj) { - Object *table; - ObjectList *list; - SInt32 size; - UInt32 *array; - - for (list = switchtables; list; list = list->next) { - table = list->object; - CError_ASSERT(694, table->otype == OT_OBJECT && table->access == ACCESSPUBLIC && table->datatype == DDATA); - - size = table->u.data.u.switchtable.size; - array = (UInt32 *) table->u.data.u.switchtable.data; - while (size--) { - *array = CTool_EndianConvertWord32(((PCodeLabel *) CTool_ResolveIndexToPointer(*array))->block->codeOffset); - array++; - } - - ObjGen_DeclareSwitchTable(table, funcobj); - } -} |