From 094b96ca1df4a035b5f93c351f773306c0241f3f Mon Sep 17 00:00:00 2001
From: Ash Wolf <ninji@wuffs.org>
Date: Thu, 26 Jan 2023 11:30:47 +0000
Subject: move lots of source files around to match their actual placement in
 the original tree

---
 .../PowerPC/InlineAssembler/FuncLevelAsmPPC.c      |  393 +++
 .../BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c |  230 ++
 .../BackEnd/PowerPC/InlineAssembler/InlineAsm.c    |  680 +++++
 .../BackEnd/PowerPC/InlineAssembler/InlineAsmPPC.c | 2586 ++++++++++++++++++++
 4 files changed, 3889 insertions(+)
 create mode 100644 compiler_and_linker/BackEnd/PowerPC/InlineAssembler/FuncLevelAsmPPC.c
 create mode 100644 compiler_and_linker/BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c
 create mode 100644 compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsm.c
 create mode 100644 compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsmPPC.c

(limited to 'compiler_and_linker/BackEnd/PowerPC/InlineAssembler')

diff --git a/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/FuncLevelAsmPPC.c b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/FuncLevelAsmPPC.c
new file mode 100644
index 0000000..340a54b
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/FuncLevelAsmPPC.c
@@ -0,0 +1,393 @@
+#include "compiler/FuncLevelAsmPPC.h"
+#include "compiler/CCompiler.h"
+#include "compiler/CError.h"
+#include "compiler/CFunc.h"
+#include "compiler/CMangler.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CodeGen.h"
+#include "compiler/Coloring.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/DumpIR.h"
+#include "compiler/InlineAsmPPC.h"
+#include "compiler/InlineAsmRegisters.h"
+#include "compiler/ObjGenMachO.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeAssembly.h"
+#include "compiler/PCodeListing.h"
+#include "compiler/PCodeUtilities.h"
+#include "compiler/PPCError.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/StackFrame.h"
+#include "compiler/TOC.h"
+#include "compiler/objects.h"
+
+static EntryPoint *entrypoints_head;
+static EntryPoint **entrypoints_tail;
+
+void setup_assembly_argument(Object *obj, short reg) {
+    VarInfo *vi;
+    Type *type;
+
+    vi = Registers_GetVarInfo(obj);
+    type = obj->type;
+    vi->used = 1;
+
+    if (!requires_frame) {
+        if (is_register_object(obj)) {
+            if (!reg)
+                CError_Error(CErrorStr263, obj->name->name);
+
+            if (TYPE_IS_8BYTES(type)) {
+                short regLo;
+                short regHi;
+                if (reg < 10) {
+                    if (copts.littleendian) {
+                        regLo = reg;
+                        regHi = reg + 1;
+                    } else {
+                        regLo = reg + 1;
+                        regHi = reg;
+                    }
+                    retain_GPR_pair(obj, regLo, regHi);
+                    InlineAsm_InsertRegister(obj->name->name, RegClass_GPR, regLo, obj);
+                }
+            } else if (IS_TYPE_FLOAT(type)) {
+                retain_register(obj, RegClass_FPR, reg);
+                InlineAsm_InsertRegister(obj->name->name, RegClass_FPR, reg, obj);
+            } else if (IS_TYPE_VECTOR(type)) {
+                retain_register(obj, RegClass_VR, reg);
+                InlineAsm_InsertRegister(obj->name->name, RegClass_VR, reg, obj);
+            } else {
+                retain_register(obj, RegClass_GPR, reg);
+                InlineAsm_InsertRegister(obj->name->name, RegClass_GPR, reg, obj);
+            }
+        }
+    } else {
+        if (is_register_object(obj)) {
+            vi = Registers_GetVarInfo(obj);
+            if (!vi->reg) {
+                assign_register_by_type(obj);
+                if (!(vi->flags & VarInfoFlag2))
+                    CError_Error(CErrorStr263, obj->name->name);
+                else
+                    InlineAsm_InsertRegister(obj->name->name, vi->rclass, vi->reg, obj);
+            }
+        }
+    }
+}
+
+void assign_local_addresses(void) {
+    VarInfo *vi;
+    ObjectList *list;
+    Object *object;
+
+    for (list = locals; list; list = list->next) {
+        vi = CodeGen_GetNewVarInfo();
+        list->object->u.var.info = vi;
+        list->object->flags |= OBJECT_USED;
+        vi->used = 1;
+    }
+
+    for (list = locals; list; list = list->next) {
+        object = list->object;
+        if (is_register_object(object)) {
+            vi = Registers_GetVarInfo(object);
+            if (!vi->reg) {
+                assign_register_by_type(object);
+                if (!(vi->flags & VarInfoFlag2))
+                    CError_Error(CErrorStr263, object->name->name);
+                else
+                    InlineAsm_InsertRegister(object->name->name, vi->rclass, vi->reg, object);
+            }
+        }
+    }
+
+    for (list = locals; list; list = list->next) {
+        object = list->object;
+        if (OBJECT_REG(object) == 0)
+            assign_local_memory(object);
+    }
+}
+
+static void FuncAsm_PreScanDirectives(void) {
+    SInt32 directive;
+    Boolean save_eoltokens;
+
+    in_assembler = 1;
+    save_eoltokens = cprep_eoltokens;
+    cprep_eoltokens = 1;
+
+    if (setjmp(InlineAsm_assemblererror) == 0) {
+        while (tk == TK_IDENTIFIER && (directive = InlineAsm_IsDirective(AssemblerType_1))) {
+            InlineAsm_ProcessDirective(directive);
+
+            if (tk == ';' || tk == TK_EOL) {
+                CPrep_TokenStreamFlush();
+                tk = lex();
+            } else {
+                InlineAsm_SyntaxError(CErrorStr113);
+            }
+
+            if (directive == IADirective_FrAlloc) {
+                requires_frame = 1;
+                break;
+            } else if (directive == IADirective_NoFrAlloc) {
+                user_responsible_for_frame = 1;
+                break;
+            }
+        }
+    }
+
+    in_assembler = 0;
+    cprep_eoltokens = save_eoltokens;
+}
+
+static void FuncAsm_AddEntryPoint(Statement *stmt, PCodeBlock *block) {
+    EntryPoint *ep;
+    IAEntryPoint *ia_ep;
+
+    ia_ep = (IAEntryPoint *) stmt->expr;
+    ep = lalloc(sizeof(EntryPoint));
+    memclrw(ep, sizeof(EntryPoint));
+
+    ep->object = ia_ep->x8;
+    ep->block = block;
+
+    *entrypoints_tail = ep;
+    entrypoints_tail = &ep->next;
+
+    block->flags |= fPCBlockFlag8000;
+}
+
+void Assembler(Object *func) {
+    PCodeBlock *block;
+    Statement *stmt;
+    Boolean flag17;
+    Boolean flag16;
+    char *name;
+    InlineAsm *ia;
+    Boolean save_unusedvar;
+    Boolean save_unusedarg;
+
+    flag17 = 0;
+    flag16 = 0;
+
+    init_endian();
+    init_stack_globals(func);
+    memclrw(asm_alloc_flags, sizeof(asm_alloc_flags));
+    fralloc_parameter_area_size = 0;
+    user_responsible_for_frame = 0;
+    assembledinstructions = 0;
+
+    entrypoints_head = NULL;
+    entrypoints_tail = &entrypoints_head;
+
+    stmt = curstmt;
+
+    if (func && func->name)
+        PrintProgressFunction(func->name->name);
+
+    CodeGen_InitialSanityCheck();
+
+    if (func->qual & Q_INLINE)
+        PPCError_Warning(PPCErrorStr173);
+
+    CheckCLabels();
+
+    if (fatalerrors)
+        return;
+
+    if (copts.filesyminfo)
+        CPrep_SetSourceFile(&cparser_fileoffset);
+
+    sm_section = SECT_TEXT;
+
+    initpcode();
+
+    pclabel(prologue = makepcblock(), makepclabel());
+    pclabel(block = makepcblock(), makepclabel());
+    pcbranch(prologue, block->labels);
+
+    resetTOCvarinfo();
+    InlineAsm_InitializePPC();
+    FuncAsm_PreScanDirectives();
+
+    disable_optimizer = 1;
+
+    init_registers();
+    assign_arguments_to_memory(func, 0, 0);
+    init_frame_sizes(0);
+
+    if (copts.debuglisting)
+        DumpIR(stmt, func);
+
+    cprep_eoltokens = 1;
+    in_assembler = 1;
+
+    save_unusedvar = copts.warn_unusedvar;
+    save_unusedarg = copts.warn_unusedarg;
+    copts.warn_unusedvar = 0;
+    copts.warn_unusedarg = 0;
+
+    InlineAsm_ScanFunction('}');
+
+    expandTOCreferences(&stmt->next);
+
+    if (!anyerrors && copts.debuglisting)
+        DumpIR(stmt, func);
+
+    in_assembler = 0;
+    cprep_eoltokens = 0;
+
+    name = CMangler_GetLinkName(func)->name;
+    func->flags |= OBJECT_DEFINED;
+
+    if (fralloc_parameter_area_size)
+        update_out_param_size(fralloc_parameter_area_size);
+    if (!user_responsible_for_frame)
+        process_arguments(move_assigned_argument, 0);
+
+    branch_label(makepclabel());
+    assign_labels(stmt->next);
+
+    copts.warn_unusedvar = save_unusedvar;
+    copts.warn_unusedarg = save_unusedarg;
+
+    for (stmt = stmt->next; stmt; stmt = stmt->next) {
+        current_statement = stmt;
+        switch (stmt->type) {
+            case ST_ASM:
+                if ((ia = (InlineAsm *) stmt->expr)) {
+                    if (ia->flags & IAFlag1) {
+                        if (ia->opcode == IADirective_Entry) {
+                            branch_label(makepclabel());
+                            FuncAsm_AddEntryPoint(stmt, pclastblock);
+                        } else if (ia->opcode == IADirective_FrFree) {
+                            if (flag16)
+                                PPCError_Error(PPCErrorStr188);
+                            else
+                                flag16 = 1;
+
+                            asm_alloc_flags[3] = 1;
+                            asm_alloc_flags[4] = 1;
+                            branch_label(makepclabel());
+
+                            epilogue = pclastblock;
+                            pclastblock->flags |= fIsEpilogue;
+
+                            CheckCLabels();
+                            if (fatalerrors)
+                                return;
+
+                            pccomputepredecessors();
+                            if (copts.debuglisting)
+                                pclistblocks(name, "[FUNCTION-LEVEL ASM] INITIAL CODE");
+                            colorinstructions(func);
+                            if (copts.debuglisting)
+                                pclistblocks(name, "[FUNCTION-LEVEL ASM] AFTER REGISTER COLORING");
+                            compute_frame_sizes();
+                            generate_prologue(prologue, 0);
+                            epilogue = pclastblock;
+                            generate_epilogue(epilogue, 0);
+                            if (copts.debuglisting)
+                                pclistblocks(name, "[FUNCTION-LEVEL ASM] AFTER PROLOGUE/EPILOGUE CREATION");
+
+                            flag17 = 1;
+                        }
+                    } else {
+                        branch_label(makepclabel());
+                        asm_alloc_flags[6] = 0;
+                        asm_alloc_flags[7] = 0;
+                        InlineAsm_TranslateIRtoPCode(stmt);
+                        asm_alloc_flags[4] = 0;
+                    }
+                }
+                break;
+            case ST_LABEL:
+                if (!stmt->label->pclabel->resolved)
+                    branch_label(stmt->label->pclabel);
+                break;
+            default:
+                CError_FATAL(525);
+        }
+    }
+
+    current_statement = NULL;
+
+    if (fatalerrors)
+        return;
+    CheckCLabels();
+    if (fatalerrors)
+        return;
+
+    if (!flag17) {
+        branch_label(makepclabel());
+
+        epilogue = pclastblock;
+        pclastblock->flags |= fIsEpilogue;
+
+        pccomputepredecessors();
+        if (copts.debuglisting)
+            pclistblocks(name, "[FUNCTION-LEVEL ASM] INITIAL CODE");
+
+        if (!asm_alloc_flags[1]) {
+            colorinstructions(func);
+            if (fatalerrors)
+                return;
+
+            if (copts.debuglisting)
+                pclistblocks(name, "[FUNCTION-LEVEL ASM] AFTER REGISTER COLORING");
+        }
+
+        compute_frame_sizes();
+        if (asm_alloc_flags[1])
+            no_frame_for_asm();
+
+        if (fatalerrors)
+            return;
+
+        if (!asm_alloc_flags[1]) {
+            generate_prologue(prologue, 0);
+            generate_epilogue(epilogue, !asm_alloc_flags[6] && !asm_alloc_flags[7]);
+        }
+
+        if (copts.debuglisting)
+            pclistblocks(name, "[FUNCTION-LEVEL ASM] AFTER PROLOGUE/EPILOGUE CREATION");
+    }
+
+    if (fatalerrors)
+        return;
+
+    if (!asm_alloc_flags[1] && needs_frame()) {
+        if (asm_alloc_flags[3]) {
+            if (!asm_alloc_flags[5] || !asm_alloc_flags[6])
+                PPCError_Warning(PPCErrorStr187, "blr");
+            if (asm_alloc_flags[8])
+                PPCError_Warning(PPCErrorStr186);
+        } else {
+            PPCError_Warning(PPCErrorStr185, "blr");
+        }
+    }
+
+    func->section = sm_section;
+
+    if (copts.filesyminfo)
+        symdeclend = CPrep_GetFileOffsetInfo(&cparser_fileoffset);
+
+    copts.peephole = 0;
+    if (pic_base_label)
+        pic_base_pcodelabel = pic_base_label->pclabel;
+    assemblefunction(func, entrypoints_head);
+
+    if (copts.debuglisting)
+        pclistblocks(CMangler_GetLinkName(func)->name, "[FUNCTION-LEVEL ASM] FINAL CODE");
+
+    CFunc_WarnUnused();
+}
+
+void SetupAssembler(void) {
+}
+
+void CleanupAssembler(void) {
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c
new file mode 100644
index 0000000..897df9b
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c
@@ -0,0 +1,230 @@
+#include "compiler/GCCInlineAsm.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInt64.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/InlineAsm.h"
+#include "compiler/objects.h"
+
+Statement *first_ST_ASM;
+IALookupResult gcc_name_list[20];
+int gcc_name_list_index;
+
+void InlineAsm_SkipComment(void) {
+    while (1) {
+        if (tk != '/')
+            break;
+        if (lookahead() != '*')
+            break;
+
+        tk = lex();
+        while (!((tk = lex()) == '*' && (tk = lex()) == '/')) {
+            // nothing
+        }
+        tk = lex();
+    }
+}
+
+static char gcc_parse_attribute(void) {
+    char ch;
+
+    while (tk == TK_EOL)
+        tk = lex();
+
+    if (tk != '"')
+        CError_Error(CErrorStr105);
+
+    while ((tk = lex()) != TK_IDENTIFIER) {
+        // nothing
+    }
+
+    ch = tkidentifier->name[0];
+
+    if ((tk = lex()) != '"')
+        CError_Error(CErrorStr105);
+    tk = lex();
+
+    return ch;
+}
+
+static void gcc_parse_name(Boolean flag, char attribute) {
+    IALookupResult *nameentry;
+    ENode *expr;
+    Object *tempobj;
+    ENode *tempexpr;
+    Statement *stmt;
+
+    while (tk == TK_EOL)
+        tk = lex();
+
+    if (tk != '(')
+        CError_Error(CErrorStr114);
+
+    tk = lex();
+
+    if (flag) {
+        if (tk != TK_IDENTIFIER)
+            CError_Error(CErrorStr105);
+
+        InlineAsm_LookupSymbol(tkidentifier, &gcc_name_list[++gcc_name_list_index]);
+        if (gcc_name_list[gcc_name_list_index].object && gcc_name_list[gcc_name_list_index].object->u.var.info)
+            gcc_name_list[gcc_name_list_index].object->u.var.info->used = 1;
+
+        tk = lex();
+    } else {
+        in_assembler = 0;
+        cprep_nostring = 0;
+        nameentry = &gcc_name_list[++gcc_name_list_index];
+
+        expr = expression();
+        if (attribute == 'i' || attribute == 'I') {
+            if (!ENODE_IS(expr, EINTCONST))
+                CError_Error(CErrorStr144);
+            nameentry->value = CInt64_GetULong(&expr->data.intval);
+            nameentry->has_value = 1;
+        } else {
+            tempobj = create_temp_object(expr->rtype);
+            tempexpr = create_objectnode(tempobj);
+            if (tempobj->u.var.info)
+                tempobj->u.var.info->used = 1;
+            expr = makediadicnode(tempexpr, expr, EASS);
+
+            stmt = CFunc_InsertBeforeStatement(ST_EXPRESSION, first_ST_ASM);
+            first_ST_ASM = stmt->next;
+            if (!first_ST_ASM->next)
+                curstmt = first_ST_ASM;
+            stmt->expr = expr;
+
+            nameentry->name = tempobj->name;
+            nameentry->object = tempobj;
+            nameentry->label = NULL;
+            nameentry->type = NULL;
+            nameentry->has_value = 0;
+        }
+    }
+
+    cprep_nostring = 1;
+    in_assembler = 1;
+
+    if (tk != ')')
+        CError_Error(CErrorStr115);
+    tk = lex();
+}
+
+static void gcc_parse_expression(Boolean flag) {
+    while (1) {
+        gcc_parse_name(flag, gcc_parse_attribute());
+        if (tk != ',')
+            break;
+        tk = lex();
+    }
+}
+
+static void gcc_parse_input(void) {
+    if (tk == ':') {
+        if ((tk = lex()) == ':' || tk == ')' || tk == '}')
+            return;
+        gcc_parse_expression(0);
+    }
+}
+
+static void gcc_parse_output(void) {
+    if (tk == ':') {
+        if ((tk = lex()) == ':' || tk == ')' || tk == '}')
+            return;
+        gcc_parse_expression(1);
+    }
+}
+
+static void gcc_parse_killed(void) {
+    if (tk == ':') {
+        while (1) {
+            if ((tk = lex()) != '"')
+                return;
+
+            tk = lex();
+            while (1) {
+                if (tk == '"') {
+                    if (lookahead() == ',') {
+                        tk = lex();
+                        break;
+                    }
+                    tk = lex();
+                    return;
+                }
+                tk = lex();
+            }
+        }
+    }
+}
+
+static void gcc_replace_arg_st_asm(Statement *stmt) {
+    InlineAsm *ia;
+    int i;
+    IAOperand *op;
+    short effect;
+    short rclass;
+    SInt32 num;
+
+    if ((ia = (InlineAsm *) stmt->expr)) {
+        for (i = 0, op = ia->args; i < ia->argcount; i++, op++) {
+            switch (op->type) {
+                case IAOpnd_Imm:
+                case IAOpnd_Reg:
+                case IAOpnd_3:
+                case IAOpnd_4:
+                case IAOpnd_Lab:
+                    break;
+
+                case IAOpnd_6:
+                    if (op->u.unk6.unk4 == 2) {
+                        effect = op->u.unk6.effect;
+                        rclass = op->u.unk6.rclass;
+                        num = op->u.unk6.num;
+                        op->type = IAOpnd_Reg;
+                        op->u.reg.effect = effect;
+                        op->u.reg.rclass = rclass;
+                        op->u.reg.object = NULL;
+                        if (num <= gcc_name_list_index)
+                            op->u.reg.object = gcc_name_list[num].object;
+                        else
+                            CError_Error(CErrorStr144);
+                        op->u.reg.num = 0;
+                    } else {
+                        CError_FATAL(365);
+                    }
+                    break;
+
+                case IAOpnd_7:
+                    op->type = IAOpnd_Imm;
+                    op->u.imm.value = gcc_name_list[op->u.unk7.value].value;
+                    break;
+            }
+        }
+    }
+}
+
+static void gcc_replace_arg(void) {
+    Statement *stmt;
+
+    for (stmt = first_ST_ASM; stmt; stmt = stmt->next) {
+        if (stmt->type == ST_ASM)
+            gcc_replace_arg_st_asm(stmt);
+    }
+}
+
+void InlineAsm_gcc_parse(void) {
+    gcc_name_list_index = -1;
+    cprep_eoltokens = 0;
+
+    if (tk == TK_EOL)
+        tk = lex();
+
+    gcc_parse_output();
+    gcc_parse_input();
+    gcc_parse_killed();
+    gcc_replace_arg();
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsm.c b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsm.c
new file mode 100644
index 0000000..46a95d2
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsm.c
@@ -0,0 +1,680 @@
+#include "compiler/InlineAsm.h"
+#include "compiler/InlineAsmPPC.h"
+#include "compiler/GCCInlineAsm.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInit.h"
+#include "compiler/CInline.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMachine.h"
+#include "compiler/COptimizer.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CScope.h"
+#include "compiler/PCode.h"
+#include "compiler/Registers.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/types.h"
+
+int allow_array_expressions = 1;
+
+int backtracking;
+jmp_buf backtrack;
+jmp_buf InlineAsm_assemblererror;
+static int ASMstmtnb;
+
+void AssemblerError(void) {
+    longjmp(InlineAsm_assemblererror, 1);
+}
+
+void InlineAsm_SyntaxError(short code) {
+    if (backtracking)
+        longjmp(backtrack, 1);
+
+    if (tk == TK_EOL || tk == ';')
+        code = CErrorStr112;
+    CError_Error(code);
+}
+
+CLabel *InlineAsm_LookupLabel(HashNameNode *name) {
+    CLabel *label;
+
+    for (label = Labels; label; label = label->next) {
+        if (name == label->name)
+            break;
+    }
+
+    return label;
+}
+
+CLabel *InlineAsm_DeclareLabel(HashNameNode *name) {
+    CLabel *label = newlabel();
+    label->name = name;
+    label->next = Labels;
+    Labels = label;
+    return label;
+}
+
+static void InlineAsm_DefineLabel(HashNameNode *name) {
+    CLabel *label;
+    Statement *stmt;
+
+    label = InlineAsm_LookupLabel(name);
+    if (!label) {
+        label = InlineAsm_DeclareLabel(name);
+    } else {
+        if (label->stmt)
+            CError_Error(CErrorStr171, name->name);
+    }
+
+    stmt = CFunc_AppendStatement(ST_LABEL);
+    stmt->label = label;
+    label->stmt = stmt;
+}
+
+Boolean InlineAsm_LookupSymbolOrTag(HashNameNode *name, IALookupResult *result, Boolean allow_tag) {
+    ObjBase *obj;
+    NameSpace *nspace;
+    NameSpaceObjectList *list;
+
+    result->name = name;
+    result->object = NULL;
+    result->label = NULL;
+    result->type = NULL;
+    result->has_value = 0;
+
+    if ((result->label = InlineAsm_LookupLabel(name)))
+        return 1;
+
+    for (nspace = cscope_current; nspace; nspace = nspace->parent) {
+        if ((list = CScope_FindName(nspace, name))) {
+            obj = list->object;
+            switch (obj->otype) {
+                case OT_ENUMCONST:
+                    result->has_value = 1;
+                    result->value = OBJ_ENUM_CONST(list->object)->val.lo;
+                    return 1;
+                case OT_OBJECT:
+                    if (OBJECT(obj)->datatype == DABSOLUTE) {
+                        result->has_value = 1;
+                        result->value = OBJECT(obj)->u.address;
+                    } else {
+                        if (OBJECT(obj)->datatype == DDATA && (OBJECT(obj)->qual & Q_INLINE_DATA))
+                            CInit_ExportConst(OBJECT(obj));
+                        result->object = OBJECT(obj);
+                    }
+                    return 1;
+                case OT_TYPE:
+                    result->type = OBJ_TYPE(obj)->type;
+                    return 1;
+                case OT_TYPETAG:
+                    if (allow_tag) {
+                        result->type = OBJ_TYPE_TAG(obj)->type;
+                        return 1;
+                    }
+                case OT_NAMESPACE:
+                case OT_MEMBERVAR:
+                    return 0;
+                default:
+                    CError_FATAL(245);
+            }
+        }
+    }
+
+    return 0;
+}
+
+Boolean InlineAsm_LookupSymbol(HashNameNode *name, IALookupResult *result) {
+    return InlineAsm_LookupSymbolOrTag(name, result, 0);
+}
+
+static ObjMemberVar *isclassmember(TypeClass *tclass, HashNameNode *name) {
+    NameSpaceObjectList *list;
+
+    list = CScope_FindName(tclass->nspace, name);
+    return (list && list->object->otype == OT_MEMBERVAR) ? OBJ_MEMBER_VAR(list->object) : NULL;
+}
+
+SInt32 InlineAsm_StructMemberOffset(Type *type) {
+    StructMember *member;
+    ObjMemberVar *ivar;
+    SInt32 offset = 0;
+
+    do {
+        if (IS_TYPE_STRUCT(type)) {
+            tk = lex();
+            if (tk != TK_IDENTIFIER)
+                InlineAsm_SyntaxError(CErrorStr107);
+            member = ismember(TYPE_STRUCT(type), tkidentifier);
+            if (!member)
+                CError_Error(CErrorStr150, tkidentifier->name);
+            offset += member->offset;
+            type = member->type;
+            tk = lex();
+        } else if (IS_TYPE_CLASS(type)) {
+            tk = lex();
+            if (tk != TK_IDENTIFIER)
+                InlineAsm_SyntaxError(CErrorStr107);
+            ivar = isclassmember(TYPE_CLASS(type), tkidentifier);
+            if (!ivar)
+                CError_Error(CErrorStr150, tkidentifier->name);
+            offset += ivar->offset;
+            type = ivar->type;
+            tk = lex();
+        } else {
+            CError_Error(CErrorStr149);
+        }
+    } while (tk == '.');
+
+    return offset;
+}
+
+SInt32 InlineAsm_StructArrayMemberOffset(Type *type) {
+    StructMember *member;
+    ObjMemberVar *ivar;
+    SInt32 offset = 0;
+
+    do {
+        if (tk == '.') {
+            if (IS_TYPE_STRUCT(type)) {
+                tk = lex();
+                if (tk != TK_IDENTIFIER)
+                    InlineAsm_SyntaxError(CErrorStr107);
+                member = ismember(TYPE_STRUCT(type), tkidentifier);
+                if (!member)
+                    CError_Error(CErrorStr150, tkidentifier->name);
+                offset += member->offset;
+                type = member->type;
+                tk = lex();
+            } else if (IS_TYPE_CLASS(type)) {
+                tk = lex();
+                if (tk != TK_IDENTIFIER)
+                    InlineAsm_SyntaxError(CErrorStr107);
+                ivar = isclassmember(TYPE_CLASS(type), tkidentifier);
+                if (!ivar)
+                    CError_Error(CErrorStr150, tkidentifier->name);
+                offset += ivar->offset;
+                type = ivar->type;
+                tk = lex();
+            } else {
+                CError_Error(CErrorStr149);
+            }
+        } else {
+            if (IS_TYPE_ARRAY(type)) {
+                type = TPTR_TARGET(type);
+                tk = lex();
+                offset += type->size * InlineAsm_ConstantExpression();
+                if (tk != ']')
+                    InlineAsm_SyntaxError(125);
+                tk = lex();
+            } else {
+                CError_Error(CErrorStr148);
+            }
+        }
+    } while (tk == '.' || tk == '[');
+
+    return offset;
+}
+
+SInt32 InlineAsm_StructPointerMemberOffset(Type *type) {
+    StructMember *member;
+    ObjMemberVar *ivar;
+    SInt32 offset;
+
+    tk = lex();
+    if (tk != TK_IDENTIFIER)
+        InlineAsm_SyntaxError(107);
+
+    if (IS_TYPE_STRUCT(type)) {
+        member = ismember(TYPE_STRUCT(type), tkidentifier);
+        if (!member)
+            CError_Error(CErrorStr150, tkidentifier->name);
+        offset = member->offset;
+        type = member->type;
+    } else {
+        ivar = isclassmember(TYPE_CLASS(type), tkidentifier);
+        if (!ivar)
+            CError_Error(CErrorStr150, tkidentifier->name);
+        offset = ivar->offset;
+        type = ivar->type;
+    }
+
+    tk = lex();
+    if (tk == '.' || tk == '[')
+        offset += InlineAsm_StructArrayMemberOffset(type);
+
+    return offset;
+}
+
+static SInt32 DiadicOperator(SInt32 left, short op, SInt32 right) {
+    CInt64 left64;
+    CInt64 right64;
+    CInt64_SetLong(&left64, left);
+    CInt64_SetLong(&right64, right);
+    right64 = CMach_CalcIntDiadic(TYPE(&stsignedint), left64, op, right64);
+    return CInt64_GetULong(&right64);
+}
+
+static SInt32 PrimaryExpression(void) {
+    IALookupResult result;
+    SInt32 value;
+
+    switch (tk) {
+        case TK_IDENTIFIER:
+            if (InlineAsm_LookupSymbol(tkidentifier, &result)) {
+                if (result.has_value) {
+                    tk = lex();
+                    return result.value;
+                }
+
+                if (result.type && (IS_TYPE_STRUCT(result.type) || IS_TYPE_CLASS(result.type))) {
+                    tk = lex();
+                    if (tk != '.')
+                        InlineAsm_SyntaxError(120);
+                    if (allow_array_expressions)
+                        return InlineAsm_StructArrayMemberOffset(result.type);
+                    else
+                        return InlineAsm_StructMemberOffset(result.type);
+                } else {
+                    InlineAsm_SyntaxError(124);
+                }
+            } else {
+                InlineAsm_SyntaxError(124);
+            }
+            break;
+        case TK_INTCONST:
+            value = tkintconst.lo;
+            tk = lex();
+            return value;
+        case TK_SIZEOF:
+            return scansizeof();
+        case '+':
+            tk = lex();
+            return PrimaryExpression();
+        case '-':
+            tk = lex();
+            return -PrimaryExpression();
+        case '!':
+            tk = lex();
+            return PrimaryExpression() == 0;
+        case '~':
+            tk = lex();
+            return ~PrimaryExpression();
+        case '(':
+            tk = lex();
+            value = InlineAsm_ConstantExpression();
+            if (tk != ')')
+                InlineAsm_SyntaxError(115);
+            tk = lex();
+            return value;
+        default:
+            InlineAsm_SyntaxError(120);
+    }
+
+    return 0;
+}
+
+static SInt32 ConstantExpressionTail(SInt32 value) {
+    SInt32 right;
+    short left_token;
+    short right_prec;
+
+    while (1) {
+        left_token = tk;
+        tk = lex();
+        right = PrimaryExpression();
+
+        right_prec = GetPrec(tk);
+        if (right_prec == 0)
+            return DiadicOperator(value, left_token, right);
+
+        if (GetPrec(left_token) >= right_prec) {
+            value = DiadicOperator(value, left_token, right);
+        } else {
+            value = DiadicOperator(value, left_token, ConstantExpressionTail(right));
+            if (GetPrec(tk) == 0)
+                return value;
+        }
+    }
+}
+
+SInt32 InlineAsm_ConstantExpression(void) {
+    SInt32 value = PrimaryExpression();
+
+    if (GetPrec(tk) == 0)
+        return value;
+    else
+        return ConstantExpressionTail(value);
+}
+
+HashNameNode *MakeLocalLabel(CInt64 num) {
+    char buf[80];
+    sprintf(buf, "@%i_%i", ASMstmtnb, CInt64_GetULong(&num));
+    return GetHashNameNodeExport(buf);
+}
+
+static void ScanOptionalLabel(void) {
+    if (tk == TK_INTCONST) {
+        if (lookahead() == ':') {
+            InlineAsm_DefineLabel(MakeLocalLabel(tkintconst));
+            tk = lex();
+            tk = lex();
+        }
+    } else {
+        if (tkidentifier->name[0] == '@') {
+            InlineAsm_DefineLabel(tkidentifier);
+            tk = lex();
+            if (tk == ':')
+                tk = lex();
+        } else {
+            HashNameNode *name = tkidentifier;
+            short t = lookahead();
+            tkidentifier = name;
+            if (t == ':') {
+                InlineAsm_DefineLabel(name);
+                tk = lex();
+                tk = lex();
+            }
+        }
+    }
+}
+
+static void ScanStatements(volatile short endToken, AssemblerType mode) {
+    if (setjmp(InlineAsm_assemblererror)) {
+        while (tk != TK_EOL && tk != endToken && tk != '}' && tk)
+            tk = lex();
+        if (tk == ';' || tk == TK_EOL)
+            tk = lex();
+    } else {
+        InlineAsm_Initialize(mode);
+        InlineAsm_gccmode = 0;
+        if (setjmp(InlineAsm_assemblererror)) {
+            while (tk != ';' && tk != TK_EOL && tk != endToken && tk != '}' && tk)
+                tk = lex();
+            if (tk == ';' || tk == TK_EOL)
+                tk = lex();
+        }
+
+        while (tk && tk != endToken) {
+            backtracking = 0;
+            sourceoffset = CPrep_GetFileOffsetInfo(&cparser_fileoffset);
+            if (tk == '"') {
+                if (InlineAsm_gccmode) {
+                    tk = lex();
+                    InlineAsm_gcc_parse();
+                } else {
+                    InlineAsm_gccmode = 1;
+                    copts.cplusplus = 0;
+                    copts.asmpoundcomment = 1;
+                    tk = lex();
+                }
+            }
+
+            if (tk == '.') {
+                InlineAsm_ScanAssemblyDirective();
+            } else if (tk == TK_IDENTIFIER) {
+                ScanOptionalLabel();
+                if (tk == TK_IDENTIFIER)
+                    InlineAsm_ScanAssemblyInstruction();
+            } else if (tk == TK_INTCONST) {
+                ScanOptionalLabel();
+                if (tk == TK_IDENTIFIER)
+                    InlineAsm_ScanAssemblyInstruction();
+            }
+
+            if (InlineAsm_gccmode && tk == '"') {
+                tk = lex();
+                InlineAsm_gcc_parse();
+            }
+
+            if (tk == ';' || tk == TK_EOL) {
+                CPrep_TokenStreamFlush();
+                tk = lex();
+            } else if (tk != endToken) {
+                if (endToken == ')')
+                    CError_Error(CErrorStr115);
+                else
+                    CError_Error(CErrorStr113);
+            }
+        }
+    }
+}
+
+void InlineAsm_ScanStatements(volatile short endToken) {
+    ScanStatements(endToken, AssemblerType_0);
+}
+
+void InlineAsm_ScanFunction(volatile short endToken) {
+    ScanStatements(endToken, AssemblerType_1);
+}
+
+void InlineAsm_Assemble(void) {
+    short token = (tk == '(') ? ')' : '}';
+    char save_pc = copts.asmpoundcomment;
+    char save_cpp = copts.cplusplus;
+
+    cprep_nostring = 1;
+    CFunc_AppendStatement(ST_NOP);
+    first_ST_ASM = curstmt;
+    ASMstmtnb++;
+
+    cprep_eoltokens = 1;
+    in_assembler = 1;
+    tk = lex();
+    InlineAsm_ScanStatements(token);
+    in_assembler = 0;
+    cprep_eoltokens = 0;
+    cprep_nostring = 0;
+
+    copts.asmpoundcomment = save_pc;
+    copts.cplusplus = save_cpp;
+}
+
+void InlineAsm_PackAsmStatement(Statement *stmt, Statement *first, void **output, SInt32 *outsize) {
+    InlineAsm *src;
+    InlineAsm *dest;
+    IAOperand *op;
+    SInt32 i;
+    SInt32 size;
+
+    src = (InlineAsm *) stmt->expr;
+    size = sizeof(InlineAsm) + sizeof(IAOperand) * src->argcount;
+    dest = galloc(size);
+    memcpy(dest, src, size);
+
+    for (i = 0, op = dest->args; i < dest->argcount; i++, op++) {
+        switch (op->type) {
+            case IAOpnd_0:
+                break;
+            case IAOpnd_Reg:
+            case IAOpnd_4:
+                op->u.reg.object = (Object *) CInline_GetLocalID(op->u.reg.object);
+                break;
+            case IAOpnd_Lab:
+                op->u.lab.label = (CLabel *) CInline_GetStatementNumber(first, op->u.lab.label->stmt);
+                break;
+            case IAOpnd_LabDiff:
+                op->u.labdiff.label1 = (CLabel *) CInline_GetStatementNumber(first, op->u.labdiff.label1->stmt);
+                op->u.labdiff.label2 = (CLabel *) CInline_GetStatementNumber(first, op->u.labdiff.label2->stmt);
+                break;
+        }
+    }
+
+    *output = dest;
+    *outsize = size;
+}
+
+void InlineAsm_UnpackAsmStatement(Statement *stmt, CLabel **labelArray, Boolean flag, void *data, SInt32 size) {
+    InlineAsm *ia;
+    IAOperand *op;
+    SInt32 i;
+
+    ia = galloc(size);
+    memcpy(ia, data, size);
+
+    for (i = 0, op = ia->args; i < ia->argcount; i++, op++) {
+        switch (op->type) {
+            case IAOpnd_0:
+                break;
+            case IAOpnd_Reg:
+            case IAOpnd_4:
+                op->u.reg.object = CInline_GetLocalObj((SInt32) op->u.reg.object, flag);
+                break;
+            case IAOpnd_Lab:
+                op->u.lab.label = labelArray[(SInt16) op->u.lab.label];
+                break;
+            case IAOpnd_LabDiff:
+                op->u.labdiff.label1 = labelArray[(SInt16) op->u.labdiff.label1];
+                op->u.labdiff.label2 = labelArray[(SInt16) op->u.labdiff.label2];
+                break;
+        }
+    }
+
+    stmt->expr = (ENode *) ia;
+}
+
+void InlineAsm_CheckLocalUsage(Statement *stmt) {
+    InlineAsm *ia = (InlineAsm *) stmt->expr;
+    IAOperand *op;
+    SInt32 i;
+
+    for (i = 0, op = ia->args; i < ia->argcount; i++, op++) {
+        switch (op->type) {
+            case IAOpnd_Reg:
+                if (op->u.reg.object)
+                    SetVarUsage(op->u.reg.object, 0);
+                break;
+            case IAOpnd_4:
+                SetVarUsage(op->u.obj.obj, 1);
+                break;
+        }
+    }
+}
+
+CLabel *InlineAsm_GetReferencedLabel(Statement *stmt) {
+    InlineAsm *ia = (InlineAsm *) stmt->expr;
+    IAOperand *op;
+    SInt32 i;
+
+    for (i = 0, op = ia->args; i < ia->argcount; i++, op++) {
+        if (op->type == IAOpnd_Lab)
+            return op->u.lab.label;
+        if (op->type == IAOpnd_LabDiff)
+            return op->u.labdiff.label1;
+    }
+
+    return NULL;
+}
+
+CLabel *InlineAsm_GetReferencedLabel2(Statement *stmt) {
+    InlineAsm *ia = (InlineAsm *) stmt->expr;
+    IAOperand *op;
+    SInt32 i;
+
+    for (i = 0, op = ia->args; i < ia->argcount; i++, op++) {
+        if (op->type == IAOpnd_LabDiff)
+            return op->u.labdiff.label2;
+    }
+
+    return NULL;
+}
+
+Object *InlineAsm_GetObjectOffset(InlineAsm *ia, SInt32 index, SInt32 *offset) {
+    IAOperand *op;
+    SInt32 i;
+    SInt32 counter;
+
+    for (i = 0, counter = 0, op = ia->args; i < ia->argcount; i++, op++) {
+        if (op->type == IAOpnd_3) {
+            if (counter++ == index) {
+                *offset = ((intptr_t) &op->u.obj.obj) - ((intptr_t) ia);
+                return op->u.obj.obj;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+char *InlineAsm_DumpStatement(Statement *stmt) {
+    static char buffer[1024];
+    InlineAsm *ia;
+    IAOperand *arg;
+    int i;
+    char ch;
+    SInt32 offset;
+
+    ia = (InlineAsm *) stmt->expr;
+
+    strcpy(buffer, "\"");
+    strcat(buffer, InlineAsm_GetMnemonic(ia));
+    strcat(buffer, "\"");
+
+    for (i = 0, arg = ia->args; i < ia->argcount; i++, arg++) {
+        char argbuf[1024];
+
+        switch (arg->type) {
+            case IAOpnd_Imm:
+                sprintf(argbuf, " imm(%ld)", arg->u.imm.value);
+                break;
+            case IAOpnd_Reg:
+                ch = ' ';
+                if (arg->u.reg.effect & EffectWrite) {
+                    if (arg->u.reg.effect & EffectRead)
+                        ch = '+';
+                    else
+                        ch = '=';
+                } else {
+                    if (!(arg->u.reg.effect & EffectRead))
+                        ch = '0';
+                }
+
+                if (arg->u.reg.object) {
+                    sprintf(argbuf,
+                            "%creg(%s)",
+                            ch,
+                            arg->u.reg.object->name->name);
+                } else {
+                    sprintf(argbuf,
+                            "%creg(%s%d)",
+                            ch,
+                            register_class_name[arg->u.reg.rclass],
+                            arg->u.reg.num);
+                }
+                break;
+
+            case IAOpnd_3:
+            case IAOpnd_4:
+                if (arg->u.obj.offset > 0)
+                    sprintf(argbuf, " obj(%s+%ld)", arg->u.obj.obj->name->name, arg->u.obj.offset);
+                else if (arg->u.obj.offset < 0)
+                    sprintf(argbuf, " obj(%s-%ld)", arg->u.obj.obj->name->name, -arg->u.obj.offset);
+                else
+                    sprintf(argbuf, " obj(%s)", arg->u.obj.obj->name->name);
+                break;
+
+            case IAOpnd_Lab:
+                sprintf(argbuf, " lab(%s)", arg->u.lab.label->uniquename->name);
+                break;
+
+            case IAOpnd_LabDiff:
+                offset = !arg->negated ? 0 : arg->u.labdiff.offset;
+                sprintf(argbuf,
+                        " labdiff(%s-%s%c%d)",
+                        arg->u.labdiff.label1->uniquename->name,
+                        arg->u.labdiff.label2->uniquename->name,
+                        (arg->negated == 1) ? '-' : '+',
+                        offset
+                        );
+                break;
+        }
+
+        strcat(buffer, argbuf);
+    }
+
+    return buffer;
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsmPPC.c b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsmPPC.c
new file mode 100644
index 0000000..464f9f9
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsmPPC.c
@@ -0,0 +1,2586 @@
+#include "compiler/InlineAsmPPC.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CInt64.h"
+#include "compiler/CFunc.h"
+#include "compiler/CMachine.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/Alias.h"
+#include "compiler/CodeGen.h"
+#include "compiler/CodeGenOptPPC.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/Exceptions.h"
+#include "compiler/FuncLevelAsmPPC.h"
+#include "compiler/InlineAsm.h"
+#include "compiler/InlineAsmMnemonicsPPC.h"
+#include "compiler/InlineAsmRegisters.h"
+#include "compiler/InlineAsmRegistersPPC.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeUtilities.h"
+#include "compiler/PPCError.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/StackFrame.h"
+#include "compiler/TOC.h"
+#include "compiler/objects.h"
+
+char asm_alloc_flags[10];
+Section sm_section;
+UInt32 cpu;
+SInt32 fralloc_parameter_area_size;
+Boolean user_responsible_for_frame;
+Boolean supports_hardware_fpu;
+UInt32 assembledinstructions;
+AssemblerType assembler_type;
+char volatileasm;
+Boolean InlineAsm_gccmode;
+Boolean InlineAsm_labelref;
+CLabel *pic_base_label;
+
+// forward decls
+static SInt32 InlineAsm_ConstantExpressionPPC(SInt32 value);
+static Object *isvariableoperand(void);
+static Object *isregisterstructpointeroperand(void);
+static void registeroperand(IAOperand *op, char rclass, short effect);
+static void DiadicOperatorPPC(IAExpr *left, short token, IAExpr *right);
+static void InlineAsm_ExpressionPPC(IAExpr *expr, SInt32 value);
+static void savepicbase(short reg, HashNameNode *name);
+
+CW_INLINE SInt32 ExtractValue(CInt64 value) {
+    return (SInt32) CInt64_GetULong(&value);
+}
+
+static void IllegalObjectOperator(HashNameNode *name1, HashNameNode *name2, short token) {
+    char *opstr;
+    switch (token) {
+        case '*': opstr = "*"; break;
+        case '/': opstr = "/"; break;
+        case '%': opstr = "%"; break;
+        case '+': opstr = "+"; break;
+        case '-': opstr = "-"; break;
+        case TK_SHL: opstr = "<<"; break;
+        case TK_SHR: opstr = ">>"; break;
+        case '<': opstr = "<"; break;
+        case '>': opstr = ">"; break;
+        // bug? these two seem swapped
+        case TK_LESS_EQUAL: opstr = ">="; break;
+        case TK_GREATER_EQUAL: opstr = "<="; break;
+        case TK_LOGICAL_EQ: opstr = "=="; break;
+        case TK_LOGICAL_NE: opstr = "!="; break;
+        case '&': opstr = "&"; break;
+        case '^': opstr = "^"; break;
+        case '|': opstr = "|"; break;
+        case TK_LOGICAL_AND: opstr = "&&"; break;
+        case TK_LOGICAL_OR: opstr = "||"; break;
+        default: opstr = "???";
+    }
+
+    if (!name2) {
+        PPCError_Error(PPCErrorStr119, opstr, name1->name);
+    } else if (!name1) {
+        PPCError_Error(PPCErrorStr120, opstr, name2->name);
+    } else {
+        PPCError_Error(PPCErrorStr118, name1->name, opstr, name2->name);
+    }
+}
+
+static void IllegalObjectInConst(IAExpr *expr) {
+    if (expr->xC) {
+        PPCError_Error(PPCErrorStr122, expr->xC->name->name);
+    } else if (expr->object) {
+        PPCError_Error(PPCErrorStr122, expr->object->name->name);
+    } else if (expr->label) {
+        PPCError_Error(PPCErrorStr166, expr->label->name->name);
+    }
+}
+
+static void NotInRegisterError(char *name, char rclass) {
+    PPCError_Error(PPCErrorStr167, name, register_class_name[rclass]);
+}
+
+static int isregisteroperand(char rclass) {
+    IARegister *reg;
+
+    return (tk == TK_IDENTIFIER && (reg = InlineAsm_LookupRegisterPPCName(tkidentifier)) && reg->rclass == rclass);
+}
+
+static SInt32 getcroperand(char rclass) {
+    SInt32 value;
+    IARegister *reg;
+
+    value = 0;
+    if (tk == TK_IDENTIFIER && (reg = InlineAsm_LookupRegisterPPCName(tkidentifier)) && reg->rclass == rclass) {
+        value = reg->num;
+    } else {
+        PPCError_Error(PPCErrorStr167, tkidentifier->name);
+    }
+
+    tk = lex();
+    return value;
+}
+
+static SInt32 getimmediateoperand(SInt32 minimum, SInt32 maximum) {
+    SInt32 value = InlineAsm_ConstantExpressionPPC(0);
+    if (value < minimum || value > maximum)
+        CError_Error(CErrorStr154);
+    return value;
+}
+
+static void PrimaryExpressionPPC(IAExpr *expr, SInt32 value) {
+    Object *obj;
+    IALookupResult result;
+    IAExpr subexpr;
+    IAExprType type = IAExpr_0;
+    SInt32 v;
+
+    switch (tk) {
+        case TK_IDENTIFIER:
+            if ((obj = isregisterstructpointeroperand())) {
+                tk = lex();
+                InlineAsm_InitExpr5(expr, InlineAsm_StructPointerMemberOffset(TPTR_TARGET(obj->type)));
+                expr->object = obj;
+                return;
+            }
+
+            if ((obj = isvariableoperand())) {
+                short reg;
+                InlineAsm_InitExpr5(expr, 0);
+                expr->xC = obj;
+
+                if (obj->datatype == DLOCAL)
+                    reg = 1;
+                else
+                    reg = pic_base_reg;
+
+                tk = lex();
+                if (tk == '.' || tk == '[') {
+                    InlineAsm_InitExpr5(&subexpr, InlineAsm_StructArrayMemberOffset(obj->type));
+                    DiadicOperatorPPC(expr, '+', &subexpr);
+                }
+
+                if (tk == '+') {
+                    tk = lex();
+                    InlineAsm_ExpressionPPC(&subexpr, value);
+                    DiadicOperatorPPC(expr, '+', &subexpr);
+                } else if (tk == '-') {
+                    tk = lex();
+                    InlineAsm_ExpressionPPC(&subexpr, value);
+                    DiadicOperatorPPC(expr, '-', &subexpr);
+                } else if (!strcmp(tkidentifier->name, "@loword")) {
+                    tk = lex();
+                    if (low_offset) {
+                        InlineAsm_InitExpr5(&subexpr, low_offset);
+                        DiadicOperatorPPC(expr, '+', &subexpr);
+                    }
+                } else if (!strcmp(tkidentifier->name, "@hiword")) {
+                    tk = lex();
+                    if (high_offset) {
+                        InlineAsm_InitExpr5(&subexpr, high_offset);
+                        DiadicOperatorPPC(expr, '+', &subexpr);
+                    }
+                }
+                expr->reg = reg;
+                return;
+            }
+
+            if (InlineAsm_LookupSymbolOrTag(tkidentifier, &result, 1)) {
+                if (result.has_value) {
+                    tk = lex();
+                    InlineAsm_InitExpr5(expr, result.value);
+                    return;
+                }
+
+                if (result.type && (IS_TYPE_STRUCT(result.type) || IS_TYPE_CLASS(result.type))) {
+                    tk = lex();
+                    if (tk != '.')
+                        CError_Error(CErrorStr120);
+
+                    if (allow_array_expressions) {
+                        InlineAsm_InitExpr5(expr, InlineAsm_StructArrayMemberOffset(result.type));
+                        return;
+                    }
+
+                    InlineAsm_InitExpr5(expr, InlineAsm_StructMemberOffset(result.type));
+                    return;
+                }
+
+                if (result.object && result.object->datatype == DABSOLUTE) {
+                    tk = lex();
+                    InlineAsm_InitExpr5(expr, result.object->u.address);
+                    return;
+                }
+            } else if (value) {
+                if (isregisteroperand(RegClass_CRFIELD)) {
+                    InlineAsm_InitExpr5(expr, getcroperand(RegClass_CRFIELD));
+                    return;
+                }
+                if (isregisteroperand(RegClass_6)) {
+                    InlineAsm_InitExpr5(expr, getcroperand(RegClass_6));
+                    return;
+                }
+                if (strlen(tkidentifier->name) == 6 && !strncmp(tkidentifier->name, "cr", 2) && tkidentifier->name[3] == '_') {
+                    IARegister *reg;
+                    char regname[4];
+                    regname[0] = tkidentifier->name[0];
+                    regname[1] = tkidentifier->name[1];
+                    regname[2] = tkidentifier->name[2];
+                    regname[3] = 0;
+                    if ((reg = InlineAsm_LookupRegisterPPC(regname)) && reg->rclass == RegClass_CRFIELD) {
+                        SInt32 v = reg->num * 4;
+                        regname[0] = tkidentifier->name[4];
+                        regname[1] = tkidentifier->name[5];
+                        regname[2] = 0;
+                        if ((reg = InlineAsm_LookupRegisterPPC(regname)) && reg->rclass == RegClass_6) {
+                            tk = lex();
+                            InlineAsm_InitExpr5(expr, v + reg->num);
+                            return;
+                        }
+                    }
+                }
+            }
+
+            if (!strcmp("ha16", tkidentifier->name))
+                type = IAExpr_8;
+            else if (!strcmp("hi16", tkidentifier->name))
+                type = IAExpr_7;
+            else if (!strcmp("lo16", tkidentifier->name))
+                type = IAExpr_6;
+
+            if (type != IAExpr_0) {
+                tk = lex();
+                if (tk == '(') {
+                    SInt32 v;
+                    tk = lex();
+                    PrimaryExpressionPPC(expr, value);
+                    expr->type = type;
+                    if (tk != ')')
+                        CError_Error(CErrorStr115);
+
+                    tk = lex();
+                    if (InlineAsm_CheckExpr(expr)) {
+                        expr->value = InlineAsm_GetExprValue(expr);
+                        expr->type = IAExpr_5;
+                    }
+                    return;
+                }
+
+                CError_Error(CErrorStr114);
+            } else {
+                if (!result.label)
+                    result.label = InlineAsm_DeclareLabel(tkidentifier);
+
+                InlineAsm_InitExpr5(expr, 0);
+                expr->flags |= IAFlag1;
+                expr->label = result.label;
+                tk = lex();
+                return;
+            }
+            break;
+
+        case TK_INTCONST:
+            v = CInt64_GetULong(&tkintconst);
+            tk = lex();
+            InlineAsm_InitExpr5(expr, v);
+            return;
+
+        case TK_SIZEOF:
+            InlineAsm_InitExpr5(expr, scansizeof());
+            return;
+
+        case '+':
+            tk = lex();
+            PrimaryExpressionPPC(expr, value);
+            return;
+
+        case '-':
+            tk = lex();
+            PrimaryExpressionPPC(expr, value);
+            if (InlineAsm_CheckExpr(expr))
+                expr->value = -expr->value;
+            else
+                CError_Error(CErrorStr124);
+            return;
+
+        case '!':
+            tk = lex();
+            PrimaryExpressionPPC(expr, value);
+            if (InlineAsm_CheckExpr(expr))
+                expr->value = !expr->value;
+            else
+                CError_Error(CErrorStr124);
+            return;
+
+        case '~':
+            tk = lex();
+            PrimaryExpressionPPC(expr, value);
+            if (InlineAsm_CheckExpr(expr))
+                expr->value = ~expr->value;
+            else
+                CError_Error(CErrorStr124);
+            return;
+
+        case '(':
+            tk = lex();
+            InlineAsm_ExpressionPPC(expr, value);
+            if (tk != ')')
+                CError_Error(CErrorStr115);
+            tk = lex();
+            return;
+
+        default:
+            CError_Error(CErrorStr120);
+    }
+
+    InlineAsm_InitExpr5(expr, 0);
+}
+
+static void DiadicOperatorPPC(IAExpr *left, short token, IAExpr *right) {
+    CInt64 leftval;
+    CInt64 rightval;
+
+    CInt64_SetLong(&leftval, left->value);
+    CInt64_SetLong(&rightval, right->value);
+    rightval = CMach_CalcIntDiadic(TYPE(&stsignedint), leftval, token, rightval);
+
+    if (left->xC) {
+        if (right->label)
+            PPCError_Error(PPCErrorStr124, left->xC->name->name, right->label->name->name);
+
+        if (right->xC) {
+            if (left->x10) {
+                PPCError_Error(PPCErrorStr121, left->xC->name->name, left->x10->name->name, right->xC->name->name);
+            } else if (right->x10) {
+                PPCError_Error(PPCErrorStr121, left->xC->name->name, right->xC->name->name, right->x10->name->name);
+            } else if (token == '-') {
+                left->value = CInt64_GetULong(&rightval);
+                left->x10 = right->xC;
+            } else {
+                IllegalObjectOperator(left->xC->name, right->xC->name, token);
+            }
+        } else if (token == '-' || token == '+') {
+            left->value = CInt64_GetULong(&rightval);
+        } else {
+            IllegalObjectOperator(left->xC->name, NULL, token);
+        }
+    } else if (right->xC) {
+        if (right->label)
+            PPCError_Error(PPCErrorStr124, right->xC->name->name, right->label->name->name);
+
+        if (token == '+') {
+            left->xC = right->xC;
+            left->x10 = right->x10;
+            left->value = CInt64_GetULong(&rightval);
+        } else {
+            IllegalObjectOperator(NULL, right->xC->name, token);
+        }
+    } else if (left->label) {
+        if (left->xC)
+            PPCError_Error(PPCErrorStr124, left->label->name->name, left->xC->name->name);
+
+        if (right->label) {
+            if (left->x18) {
+                PPCError_Error(PPCErrorStr121, left->label->name->name, left->x18->name->name, right->label->name->name);
+            } else if (right->x18) {
+                PPCError_Error(PPCErrorStr121, left->label->name->name, right->label->name->name, right->x18->name->name);
+            } else if (token == '-') {
+                left->value = CInt64_GetULong(&rightval);
+                left->x18 = right->label;
+            } else {
+                IllegalObjectOperator(left->label->name, right->label->name, token);
+            }
+        } else if (token == '+' || token == '-') {
+            left->value = CInt64_GetULong(&rightval);
+        } else {
+            IllegalObjectOperator(NULL, left->label->name, token);
+        }
+    } else if (right->label) {
+        if (token == '+') {
+            left->label = right->label;
+            left->x18 = right->x18;
+            left->value = CInt64_GetULong(&rightval);
+        } else {
+            IllegalObjectOperator(NULL, right->label->name, token);
+        }
+    } else {
+        left->value = CInt64_GetULong(&rightval);
+    }
+
+    left->flags |= right->flags;
+    if (left->type == IAOpnd_Lab) {
+        if (right->type != IAOpnd_Lab)
+            left->type = right->type;
+    } else {
+        if (right->type != IAOpnd_Lab && right->type != left->type)
+            PPCError_Error(PPCErrorStr126);
+    }
+}
+
+static void ExpressionTailPPC(IAExpr *left, SInt32 value) {
+    IAExpr right;
+    short left_tk;
+    short right_prec;
+
+    while (1) {
+        left_tk = tk;
+        tk = lex();
+
+        PrimaryExpressionPPC(&right, value);
+        right_prec = GetPrec(tk);
+        if (right_prec == 0) {
+            DiadicOperatorPPC(left, left_tk, &right);
+            break;
+        }
+
+        if (GetPrec(left_tk) >= right_prec) {
+            DiadicOperatorPPC(left, left_tk, &right);
+        } else {
+            ExpressionTailPPC(&right, value);
+            DiadicOperatorPPC(left, left_tk, &right);
+            if (GetPrec(tk) == 0)
+                break;
+        }
+    }
+}
+
+static void immediateoperand(IAOperand *op, SInt32 minval, SInt32 maxval) {
+    SInt32 value;
+    if (InlineAsm_gccmode && tk == '%') {
+        tk = lex();
+        if (tk != TK_INTCONST) {
+            CError_Error(CErrorStr144);
+        } else {
+            CInt64 c = tkintconst;
+            value = CInt64_GetULong(&c);
+            if (value < 0)
+                CError_Error(CErrorStr144);
+        }
+        op->type = IAOpnd_7;
+        op->u.unk7.value = value;
+        op->u.unk7.unk1 = 1;
+        op->u.unk7.unk2 = 0;
+        op->u.unk7.unk3 = 0;
+        tk = lex();
+    } else {
+        value = InlineAsm_ConstantExpressionPPC(0);
+        if (value < minval || value > maxval)
+            CError_Error(CErrorStr154);
+        op->type = IAOpnd_Imm;
+        op->u.imm.value = value;
+    }
+}
+
+static SInt32 immediatevalue(IAOperand *op, SInt32 minval, SInt32 maxval) {
+    SInt32 value;
+    if (InlineAsm_gccmode && tk == '%') {
+        CError_Error(CErrorStr144);
+        return 0;
+    } else {
+        value = InlineAsm_ConstantExpressionPPC(0);
+        if (value < minval || value > maxval)
+            CError_Error(CErrorStr154);
+        op->type = IAOpnd_Imm;
+        op->u.imm.value = value;
+        return value;
+    }
+}
+
+static void InlineAsm_ExpressionPPC(IAExpr *expr, SInt32 value) {
+    PrimaryExpressionPPC(expr, value);
+    if (GetPrec(tk))
+        ExpressionTailPPC(expr, value);
+    if (GetPrec(tk))
+        ExpressionTailPPC(expr, value);
+
+    if (expr->type == IAExpr_5 && tk == TK_IDENTIFIER) {
+        if (!strcmp(tkidentifier->name, "@l")) {
+            expr->type = IAExpr_6;
+            tk = lex();
+        } else if (!strcmp(tkidentifier->name, "@ha")) {
+            expr->type = IAExpr_8;
+            tk = lex();
+        } else if (!strcmp(tkidentifier->name, "@h")) {
+            expr->type = IAExpr_7;
+            tk = lex();
+        }
+    }
+}
+
+static SInt32 InlineAsm_ConstantExpressionPPC(SInt32 value) {
+    IAExpr expr;
+
+    InlineAsm_ExpressionPPC(&expr, value);
+    if (!InlineAsm_CheckExpr(&expr)) {
+        IllegalObjectInConst(&expr);
+        return 0;
+    } else {
+        return InlineAsm_GetExprValue(&expr);
+    }
+}
+
+static SInt32 crbitoperand(void) {
+    SInt32 value = InlineAsm_ConstantExpressionPPC(1);
+    if (value < 0 || value > 31)
+        CError_Error(CErrorStr154);
+    return value;
+}
+
+static void floatoperand(IAOperand *op, InlineAsm *ia, Type *type) {
+    Object *obj;
+
+    obj = createfloatconstant(type, &tkfloatconst);
+    op[0].type = IAOpnd_Reg;
+    op[0].u.reg.rclass = RegClass_GPR;
+    op[0].u.reg.object = NULL;
+    op[0].u.reg.effect = EffectRead;
+    op[0].u.reg.num = pic_base_reg;
+
+    ia->argcount++;
+    op[1].type = IAOpnd_4;
+    op[1].u.obj.obj = obj;
+    PPCError_Error(PPCErrorStr179);
+    op[1].u.obj.unk = IAExpr_2;
+    op[1].u.obj.offset = 0;
+    tk = lex();
+}
+
+static Object *isvariableoperand(void) {
+    IALookupResult result;
+    Object *obj;
+
+    if (tk == TK_IDENTIFIER) {
+        InlineAsm_LookupSymbol(tkidentifier, &result);
+        if ((obj = result.object)) {
+            if (obj->datatype == DLOCAL) {
+                if (OBJECT_REG(obj))
+                    return NULL;
+                return obj;
+            }
+
+            if (obj->datatype == DFUNC || obj->datatype == DVFUNC)
+                return obj;
+
+            if (obj->datatype == DDATA) {
+                createIndirect(obj, 0, 0);
+                return obj;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+static Object *isregisterstructpointeroperand(void) {
+    IALookupResult result;
+    Object *obj;
+
+    if (tk != TK_IDENTIFIER)
+        return NULL;
+
+    InlineAsm_LookupSymbol(tkidentifier, &result);
+    if ((obj = result.object)) {
+        if (obj->datatype != DLOCAL)
+            return NULL;
+        if (!OBJECT_REG(obj) && !is_register_object(obj))
+            return NULL;
+        if (!IS_TYPE_POINTER(obj->type))
+            return NULL;
+        if (!IS_TYPE_STRUCT(TPTR_TARGET(obj->type)) && !IS_TYPE_CLASS(TPTR_TARGET(obj->type)))
+            return NULL;
+        return obj;
+    }
+
+    return NULL;
+}
+
+static void memoryoperand(IAOperand *op, InlineAsm *ia, Boolean flag, short effect) {
+    IAExpr expr;
+
+    InlineAsm_ExpressionPPC(&expr, 0);
+    if (expr.object) {
+        if (!flag)
+            CError_Error(CErrorStr155);
+        if (expr.xC)
+            PPCError_Error(PPCErrorStr122, expr.xC);
+
+        op[0].type = IAOpnd_Reg;
+        op[0].u.reg.rclass = RegClass_GPR;
+        op[0].u.reg.object = expr.object;
+        op[0].u.reg.num = 0;
+        op[0].u.reg.effect = effect;
+        if (expr.object || expr.reg)
+            op[0].u.reg.effect = effect;
+        else
+            op[0].u.reg.effect = 0;
+
+        ia->argcount++;
+        op[1].type = IAOpnd_Imm;
+        switch (expr.type) {
+            case IAExpr_5:
+                expr.type = IAExpr_6;
+                if (expr.object->datatype != DLOCAL || !OBJECT_REG(expr.object))
+                    PPCError_Error(PPCErrorStr180);
+            case IAExpr_2:
+            case IAExpr_6:
+            case IAExpr_7:
+            case IAExpr_8:
+                op[1].u.imm.value = InlineAsm_GetExprValue(&expr);
+                break;
+            default:
+                CError_Error(CErrorStr155);
+        }
+
+        expr.object->flags |= OBJECT_USED;
+        return;
+    }
+
+    if (expr.xC) {
+        if (expr.x10)
+            PPCError_Error(PPCErrorStr123, expr.xC->name->name, expr.x10->name->name);
+
+        if (flag) {
+            if (tk == '(') {
+                if (flag) {
+                    tk = lex();
+                    registeroperand(op, RegClass_GPR, effect);
+                    if ((expr.type == IAExpr_8 || expr.type == IAExpr_7) && copts.codegen_pic && pic_base_reg)
+                        CError_Error(CErrorStr155);
+                    if (tk != ')')
+                        CError_Error(CErrorStr115);
+                    tk = lex();
+                }
+            } else {
+                op[0].type = IAOpnd_Reg;
+                op[0].u.reg.rclass = RegClass_GPR;
+                op[0].u.reg.object = expr.object;
+                op[0].u.reg.num = expr.reg;
+            }
+
+            if (expr.object || expr.reg)
+                op[0].u.reg.effect = effect;
+            else
+                op[0].u.reg.effect = 0;
+
+            ia->argcount++;
+            op++;
+        }
+
+        if (expr.xC->datatype == DLOCAL) {
+            op[0].type = IAOpnd_4;
+            op[0].u.obj.unk = IAExpr_1;
+        } else {
+            op[0].type = IAOpnd_3;
+            if (expr.type == IAExpr_5) {
+                expr.type = IAExpr_6;
+                PPCError_Error(PPCErrorStr180);
+            }
+            op[0].u.obj.unk = expr.type;
+        }
+
+        op[0].u.obj.obj = expr.xC;
+        op[0].u.obj.offset = expr.value;
+        expr.xC->flags |= OBJECT_USED;
+        return;
+    }
+
+    if (flag) {
+        if (tk == '(') {
+            tk = lex();
+            registeroperand(op, RegClass_GPR, effect);
+            ia->argcount++;
+            op++;
+            if (tk != ')')
+                CError_Error(CErrorStr115);
+            tk = lex();
+        } else {
+            op->type = IAOpnd_Reg;
+            op->u.reg.rclass = RegClass_GPR;
+            op->u.reg.object = expr.object;
+            op->u.reg.num = expr.reg;
+            ia->argcount++;
+            op++;
+        }
+    }
+
+    if (expr.label) {
+        if (expr.x18) {
+            op->type = IAOpnd_LabDiff;
+            op->negated = 0;
+            op->u.labdiff.label1 = expr.label;
+            op->u.labdiff.label2 = expr.x18;
+            op->u.labdiff.offset = expr.value;
+        } else {
+            PPCError_Error(PPCErrorStr125, expr.label->name->name);
+        }
+    } else {
+        op->type = IAOpnd_Imm;
+        op->u.imm.value = InlineAsm_GetExprValue(&expr);
+    }
+}
+
+static void registeroperand(IAOperand *op, char rclass, short effect) {
+    IARegister *reg;
+    Object *obj;
+
+    if (tk == TK_IDENTIFIER && (reg = InlineAsm_LookupRegisterPPCName(tkidentifier)) && reg->rclass == rclass) {
+        SInt32 num;
+        obj = reg->object;
+        num = reg->num;
+        op->type = IAOpnd_Reg;
+        op->u.reg.rclass = rclass;
+        op->u.reg.object = obj;
+        op->u.reg.num = num;
+        op->u.reg.effect = effect;
+        if (obj) {
+            reg->object->flags |= OBJECT_USED;
+            Registers_GetVarInfo(obj)->flags |= VarInfoFlag40;
+        }
+    } else if (rclass == RegClass_CRFIELD) {
+        op->type = IAOpnd_Reg;
+        op->u.reg.rclass = RegClass_CRFIELD;
+        op->u.reg.object = NULL;
+        op->u.reg.num = getimmediateoperand(0, 7);
+        op->u.reg.effect = effect;
+        return;
+    } else if (rclass == RegClass_SPR) {
+        op->type = IAOpnd_Reg;
+        op->u.reg.rclass = RegClass_SPR;
+        op->u.reg.object = NULL;
+        op->u.reg.num = getimmediateoperand(0, 1024);
+        op->u.reg.effect = effect;
+        return;
+    } else if (tk == '%' && InlineAsm_gccmode) {
+        SInt32 num;
+        tk = lex();
+        if (tk != TK_INTCONST) {
+            CError_Error(CErrorStr144);
+        } else {
+            num = ExtractValue(tkintconst);
+            if (num < 0)
+                CError_Error(CErrorStr144);
+        }
+
+        op->type = IAOpnd_6;
+        op->u.unk6.num = num;
+        op->u.unk6.unk4 = 2;
+        op->u.unk6.effect = effect;
+        op->u.unk6.rclass = rclass;
+        tk = lex();
+        return;
+    } else if (tk == TK_IDENTIFIER) {
+        NotInRegisterError(tkidentifier->name, rclass);
+    } else {
+        PPCError_Error(PPCErrorStr171);
+    }
+
+    tk = lex();
+    if (!strcmp(tkidentifier->name, "@loword")) {
+        tk = lex();
+    } else if (!strcmp(tkidentifier->name, "@hiword")) {
+        if (reg->object)
+            op->u.reg.num = 1;
+        else
+            PPCError_Error(PPCErrorStr168);
+        tk = lex();
+    } else if (rclass == RegClass_GPR) {
+        if (reg->object && reg->object->type->size == 8) {
+            HashNameNode *name = reg->object->name;
+            PPCError_Error(PPCErrorStr127, name->name, name->name, name->name);
+        }
+    }
+}
+
+static void cr0_operand(IAOperand *op, short effect) {
+    IARegister *reg;
+
+    if ((reg = InlineAsm_LookupRegisterPPC("cr0"))) {
+        op->type = IAOpnd_Reg;
+        op->u.reg.rclass = RegClass_CRFIELD;
+        op->u.reg.object = reg->object;
+        op->u.reg.num = reg->num;
+        op->u.reg.effect = effect;
+    } else {
+        NotInRegisterError("cr0", RegClass_CRFIELD);
+    }
+}
+
+static void r0_operand(IAOperand *op) {
+    IARegister *reg;
+
+    if ((reg = InlineAsm_LookupRegisterPPC("r0"))) {
+        op->type = IAOpnd_Reg;
+        op->u.reg.rclass = RegClass_GPR;
+        op->u.reg.object = reg->object;
+        op->u.reg.num = reg->num;
+        op->u.reg.effect = 0;
+        tk = lex();
+    } else {
+        NotInRegisterError("r0", RegClass_GPR);
+    }
+}
+
+static void labeloperand(InlineAsm *ia, IAOperand *op, Boolean flag1, Boolean flag2, Boolean flag3) {
+    IALookupResult result;
+
+    if (tk == TK_IDENTIFIER) {
+        if (!InlineAsm_LookupSymbol(tkidentifier, &result))
+            result.label = InlineAsm_DeclareLabel(tkidentifier);
+
+        if (result.label) {
+            op->type = IAOpnd_Lab;
+            op->u.lab.label = result.label;
+        } else if (result.object && result.object->datatype == DFUNC) {
+            if (flag3)
+                ia->flags |= IAFlag2;
+            op->type = IAOpnd_3;
+            op->u.obj.obj = result.object;
+            op->u.obj.offset = 0;
+
+            if (flag1) {
+                op->u.obj.unk = IAExpr_4;
+                if (flag2)
+                    CError_Error(CErrorStr261);
+            } else {
+                op->u.obj.unk = IAExpr_2;
+                if (flag2)
+                    op->u.obj.unk = IAExpr_10;
+                op->u.obj.unk = IAExpr_6;
+                PPCError_Error(PPCErrorStr180);
+            }
+        } else {
+            CError_Error(CErrorStr144);
+        }
+
+        tk = lex();
+    } else if (tk == '*') {
+        if (!flag2) {
+            tk = lex();
+            if (tk == '+') {
+                tk = lex();
+                if (flag1)
+                    immediateoperand(op, -0x2000000, 0x1FFFFFF);
+                else
+                    immediateoperand(op, -0x8000, 0xFFFF);
+            } else if (tk == '-') {
+                tk = lex();
+                op->u.imm.value = flag1 ? -immediatevalue(op, -0x1FFFFFF, 0x2000000) : -immediatevalue(op, -0x7FFF, 0x10000);
+            } else {
+                CError_Error(CErrorStr144);
+            }
+        } else {
+            CError_Error(CErrorStr144);
+        }
+    } else {
+        if (flag2) {
+            if (flag1)
+                immediateoperand(op, -0x2000000, 0x1FFFFFF);
+            else
+                immediateoperand(op, -0x8000, 0xFFFF);
+        } else {
+            CError_Error(CErrorStr144);
+        }
+    }
+}
+
+static void imm_or_labeldiff_operand(InlineAsm *ia, IAOperand *op, SInt32 minimum, SInt32 maximum, Boolean negate) {
+    IAExpr expr;
+    Object *obj;
+    SInt32 value;
+
+    InlineAsm_ExpressionPPC(&expr, 0);
+
+    if ((obj = expr.xC) && !expr.x10 && expr.type == IAExpr_5 && obj->datatype == DDATA && IS_TYPE_INT_OR_ENUM(obj->type) && (obj->qual & Q_INLINE_DATA)) {
+        switch (ia->opcode) {
+            case PC_ADDI:
+            case PC_ADDIC:
+            case PC_ADDICR:
+            case PC_ADDIS:
+            case PC_ORI:
+            case PC_ORIS:
+                if (ia->args[1].u.imm.value) {
+                    SInt32 cmp;
+                    if (obj->datatype != DLOCAL) {
+                        cmp = copts.codegen_pic ? INVALID_PIC_REG : NO_REG;
+                    } else {
+                        cmp = local_base_register(obj);
+                    }
+                    if (ia->args[1].u.imm.value == cmp)
+                        break;
+                }
+            case PC_LI:
+            case PC_LIS:
+            case PC_TWI:
+            case PC_OPWORD:
+                InlineAsm_InitExpr5(&expr, expr.value + CInt64_GetULong(&obj->u.data.u.intconst));
+                break;
+        }
+    }
+
+    if (expr.label) {
+        if (expr.x18) {
+            op->type = IAOpnd_LabDiff;
+            if (negate)
+                op->negated = 1;
+            else
+                op->negated = 0;
+            op->u.labdiff.label1 = expr.label;
+            op->u.labdiff.label2 = expr.x18;
+            op->u.labdiff.offset = expr.value;
+        } else {
+            PPCError_Error(PPCErrorStr125, expr.label->name->name);
+        }
+        return;
+    }
+
+    if (expr.xC) {
+        if (!expr.x10) {
+            if (ia->opcode != PC_OPWORD && expr.type == IAExpr_5) {
+                IllegalObjectInConst(&expr);
+                return;
+            }
+
+            if (expr.xC->datatype == DLOCAL) {
+                op->type = IAOpnd_4;
+                op->u.obj.unk = IAExpr_1;
+            } else {
+                op->type = IAOpnd_3;
+                if (expr.type == IAExpr_5) {
+                    expr.type = IAExpr_6;
+                    PPCError_Error(PPCErrorStr180);
+                }
+                op->u.obj.unk = expr.type;
+            }
+            op->u.obj.obj = expr.xC;
+            op->u.obj.offset = expr.value;
+        } else {
+            PPCError_Error(PPCErrorStr123, expr.xC->name->name, expr.x10->name->name);
+        }
+        return;
+    }
+
+    value = InlineAsm_GetExprValue(&expr);
+    if (value < minimum || value > maximum)
+        CError_Error(CErrorStr154);
+
+    op->type = IAOpnd_Imm;
+    if (negate)
+        op->u.imm.value = -value;
+    else
+        op->u.imm.value = value;
+}
+
+static void eatcommatoken(void) {
+    if (tk == ',')
+        tk = lex();
+    else
+        CError_Error(CErrorStr116);
+}
+
+static InlineAsm *InlineAsm_ScanAssemblyOperands(IAMnemonic *mnemonic) {
+    OpcodeInfo *info;
+    InlineAsm *ia;
+    SInt32 buffersize;
+    IAOperand *op;
+    int argcount;
+    char *format;
+    IARegister *reg;
+
+    char code;
+    short effect;
+    Boolean has_excl;
+    Boolean has_question;
+    Boolean negate;
+    UInt32 t;
+
+    info = &opcodeinfo[mnemonic->x4];
+    argcount = info->x8;
+    if (PCODE_FLAG_SET_F(info) & fCanSetRecordBit)
+        argcount++;
+    if (!(PCODE_FLAG_SET_F(info) & fSetsCarry) && (PCODE_FLAG_SET_F(info) & fCanSetCarry))
+        argcount++;
+    if (PCODE_FLAG_SET_T(info) & fCanLink)
+        argcount++;
+
+    buffersize = sizeof(InlineAsm) + sizeof(IAOperand) * argcount;
+    ia = galloc(buffersize);
+    memset(ia, 0, buffersize);
+
+    ia->opcode = mnemonic->x4;
+    ia->flags = 0;
+    ia->argcount = 0;
+
+    op = ia->args;
+    for (format = mnemonic->format; *format; format++) {
+        CError_ASSERT(1664, ia->argcount < argcount);
+
+        if (*format == ',') {
+            eatcommatoken();
+            format++;
+        } else if (*format == ';') {
+            format++;
+        }
+
+        if (*format == '[' || *format == '(')
+            format++;
+
+        effect = EffectRead;
+        has_excl = 0;
+        has_question = 0;
+        negate = 0;
+        if (*format == '=') {
+            effect = EffectWrite;
+            format++;
+        } else if (*format == '+') {
+            effect = EffectRead | EffectWrite;
+            format++;
+        }
+
+        if (*format == '-') {
+            negate = 1;
+            format++;
+        }
+
+        if (*format == '?') {
+            has_question = 1;
+            format++;
+        }
+
+        if (*format == '!') {
+            has_excl = 1;
+            format++;
+        }
+
+        switch (*format) {
+            case 'p':
+                continue;
+            case '&':
+                if (format[1] == '2') {
+                    op[0] = op[-2];
+                    format++;
+                    if (op->type == IAOpnd_Reg)
+                        op->u.reg.effect = effect;
+                    ia->argcount++;
+
+                    op[1] = op[-1];
+                    op++;
+                    if (op->type == IAOpnd_Reg)
+                        op->u.reg.effect = effect;
+                } else {
+                    op[0] = op[-1];
+                    if (op->type == IAOpnd_Reg)
+                        op->u.reg.effect = effect;
+                }
+                break;
+
+            case '%': {
+                SInt32 value;
+                format += pcode_const_from_format(format + 1, &value);
+                op->type = IAOpnd_Imm;
+                op->u.imm.value = value;
+                break;
+            }
+
+            case 'b':
+                if (!isregisteroperand(RegClass_GPR)) {
+                    if (tk == TK_INTCONST && tkintconst.lo == 0)
+                        r0_operand(op);
+                } else {
+                    registeroperand(op, RegClass_GPR, effect);
+                    if (op->u.reg.object == NULL && op->u.reg.num == 0)
+                        op->u.reg.effect = 0;
+                }
+                break;
+
+            case 'r':
+                registeroperand(op, RegClass_GPR, effect);
+                break;
+
+            case 'B':
+            case 'a':
+            case 'i':
+            case 't':
+            case 'u':
+            case 'x':
+            {
+                SInt32 value, hi, lo;
+                code = *format;
+                value = 16;
+                if (code == 'a') {
+                    if (isdigit(format[1]))
+                        code = *(++format);
+                    else
+                        CError_FATAL(1804);
+                }
+
+                if (isdigit(format[1])) {
+                    format += pcode_const_from_format(format + 1, &value);
+                } else if (code == 't' || code == 'B') {
+                    code = 'u';
+                    value = 5;
+                }
+
+                pcode_get_hi_lo(value, code, &hi, &lo);
+                if (!has_question || tk == ',') {
+                    if (has_question)
+                        tk = lex();
+                    if (has_excl)
+                        getimmediateoperand(lo, hi);
+                    else
+                        immediateoperand(op, lo, hi);
+                } else {
+                    op->type = IAOpnd_Imm;
+                    op->u.imm.value = 0;
+                }
+
+                if (code == 'i' && value == 16)
+                    op->u.imm.value = (short) op->u.imm.value;
+                if (negate)
+                    op->u.imm.value = -op->u.imm.value;
+
+                if (pcode_check_imm_bits(op->u.imm.value, value, code))
+                    CError_FATAL(1838);
+
+                break;
+            }
+
+            case 'O':
+                if (tk == TK_INTCONST && tkintconst.lo == 0) {
+                    getimmediateoperand(0, 0);
+                    eatcommatoken();
+                }
+                continue;
+
+            case 'f':
+                registeroperand(op, RegClass_FPR, effect);
+                break;
+
+            case 'v':
+                registeroperand(op, RegClass_VR, effect);
+                break;
+
+            case 'T':
+                if (!has_question || tk == ',') {
+                    if (has_question)
+                        tk = lex();
+
+                    immediateoperand(op, 268, 269);
+                    if (op->u.reg.num == 268)
+                        op->u.reg.num = 284;
+                    else
+                        op->u.reg.num = 285;
+                } else {
+                    op->u.reg.num = 284;
+                }
+
+                op->type = IAOpnd_Reg;
+                op->u.reg.rclass = RegClass_SPR;
+                op->u.reg.effect = effect;
+                break;
+
+            case 'S':
+            {
+                SInt32 value;
+                format += pcode_const_from_format(format + 1, &value);
+                op->type = IAOpnd_Reg;
+                op->u.reg.rclass = RegClass_SPR;
+                op->u.reg.num = value;
+                op->u.reg.effect = effect;
+                break;
+            }
+
+            case 'c':
+                if (has_question) {
+                    if (isregisteroperand(RegClass_CRFIELD) || tk == TK_INTCONST) {
+                        registeroperand(op, RegClass_CRFIELD, effect);
+                    } else {
+                        cr0_operand(op, effect);
+                        if (format[1] == ',')
+                            format++;
+                    }
+                } else {
+                    registeroperand(op, RegClass_CRFIELD, effect);
+                }
+                break;
+
+            case 'l':
+                switch (ia->opcode) {
+                    case PC_B:
+                    case PC_BL:
+                        labeloperand(ia, op, 1, mnemonic->x10 & 2, mnemonic->x10 & 1);
+                        break;
+                    default:
+                        labeloperand(ia, op, 0, mnemonic->x10 & 2, mnemonic->x10 & 1);
+                        break;
+                }
+                break;
+
+            case 'w':
+                imm_or_labeldiff_operand(ia, op, -0x80000000, 0x7FFFFFFF, negate);
+                break;
+
+            case 'M':
+            case 'm':
+            case 'n':
+                imm_or_labeldiff_operand(ia, op, -0x8000, 0xFFFF, negate);
+                break;
+
+            case 'Q':
+            {
+                SInt32 cr = crbitoperand();
+                op->type = IAOpnd_Reg;
+                op->u.reg.num = cr >> 2;
+                op->u.reg.rclass = RegClass_CRFIELD;
+                op->u.reg.effect = effect;
+
+                ia->argcount++;
+                op[1].type = IAOpnd_Imm;
+                op[1].u.imm.value = cr % 4;
+                op++;
+                break;
+            }
+
+            case 'd': {
+                short effect2;
+                CError_ASSERT(1971, format[1] == '(');
+                format++;
+                effect2 = EffectRead;
+                if (format[1] == '=') {
+                    effect2 = EffectWrite;
+                    format++;
+                } else if (format[1] == '+') {
+                    effect2 = EffectRead | EffectWrite;
+                    format++;
+                }
+
+                CError_ASSERT(1983, format[1] == 'b');
+                CError_ASSERT(1985, format[2] == ')');
+                format += 2;
+
+                switch (ia->opcode) {
+                    case PC_LFS:
+                        if (tk == TK_FLOATCONST)
+                            floatoperand(op, ia, TYPE(&stfloat));
+                        else
+                            memoryoperand(op, ia, 1, effect2);
+                        break;
+                    case PC_LFD:
+                        if (tk == TK_FLOATCONST)
+                            floatoperand(op, ia, TYPE(&stdouble));
+                        else
+                            memoryoperand(op, ia, 1, effect2);
+                        break;
+                    default:
+                        memoryoperand(op, ia, 1, effect2);
+                }
+
+                break;
+            }
+
+            case 'N':
+                immediateoperand(op, 1, 32);
+                break;
+
+            case 's':
+                registeroperand(op, RegClass_SPR, effect);
+                break;
+
+            case 'D':
+                if (tk == TK_IDENTIFIER && (reg = InlineAsm_LookupDCRRegister(tkidentifier->name))) {
+                    op->type = IAOpnd_Imm;
+                    op->u.imm.value = reg->num;
+                } else {
+                    immediateoperand(op, 0, 1023);
+                }
+                break;
+
+            case 'Y':
+            {
+                SInt32 mask = 255;
+                SInt32 i;
+                if (ia->opcode == PC_MTCRF) {
+                    if (ia->args[0].type != IAOpnd_Imm)
+                        CError_Error(CErrorStr144);
+                    mask = ia->args[0].u.imm.value;
+                }
+                for (i = 0; i < 8; i++) {
+                    if ((0x80 >> i) & mask) {
+                        op->type = IAOpnd_Reg;
+                        op->u.reg.num = i;
+                        op->u.reg.rclass = RegClass_CRFIELD;
+                        op->u.reg.effect = effect;
+                        ia->argcount++;
+                        op++;
+                    }
+                }
+                ia->argcount--;
+                op--;
+                break;
+            }
+
+            case 'P':
+                op->type = IAOpnd_Reg;
+                op->u.reg.rclass = RegClass_SPR;
+                op->u.reg.object = NULL;
+                if (format[1] == '3') {
+                    format++;
+                    op->u.reg.num = getimmediateoperand(0, 7);
+                } else {
+                    op->u.reg.num = getimmediateoperand(0, 3);
+                }
+                op->u.reg.effect = effect;
+                break;
+
+            case 'C':
+                op->type = IAOpnd_Reg;
+                op->u.reg.rclass = RegClass_SPR;
+                op->u.reg.object = NULL;
+                op->u.reg.num = 9;
+                op->u.reg.effect = effect;
+                break;
+
+            case 'L':
+                op->type = IAOpnd_Reg;
+                op->u.reg.rclass = RegClass_SPR;
+                op->u.reg.object = NULL;
+                op->u.reg.num = 8;
+                op->u.reg.effect = effect;
+                break;
+
+            case 'X':
+                op->type = IAOpnd_Reg;
+                op->u.reg.rclass = RegClass_SPR;
+                op->u.reg.object = NULL;
+                op->u.reg.num = 1;
+                op->u.reg.effect = effect;
+                break;
+
+            case 'Z':
+                op->type = IAOpnd_Reg;
+                op->u.reg.rclass = RegClass_CRFIELD;
+                op->u.reg.object = NULL;
+                t = info->flags & 0xC0000000;
+                if (t == 0x40000000) {
+                    op->u.reg.num = 1;
+                } else if (t == 0xC0000000) {
+                    op->u.reg.num = 6;
+                } else {
+                    op->u.reg.num = 0;
+                }
+                op->u.reg.effect = effect;
+                break;
+
+            default:
+                CError_FATAL(2266);
+        }
+
+        while (format[1] && strchr("/<>|*", format[1])) {
+            int index;
+            SInt32 value;
+            SInt32 value2;
+            IAOperand tmp;
+            switch ((code = *(++format))) {
+                case '/':
+                    index = -1;
+                    if (format[1] == '2') {
+                        index = -2;
+                        format++;
+                    }
+
+                    tmp = op[index];
+                    op[index] = op[0];
+                    op[0] = tmp;
+                    break;
+                case '*':
+                case '<':
+                case '>':
+                case '|':
+                    if (op->type == IAOpnd_Imm)
+                        value = op->u.imm.value;
+                    else if (op->type == IAOpnd_Reg)
+                        value = op->u.reg.num;
+                    else
+                        CError_FATAL(2312);
+
+                    if (format[1] == 'p') {
+                        format++;
+                        if (op[-1].type == IAOpnd_Imm)
+                            value2 = op[-1].u.imm.value;
+                        else if (op[-1].type == IAOpnd_Reg)
+                            value2 = op[-1].u.reg.num;
+                        else
+                            CError_FATAL(2322);
+                    } else if (isdigit(format[1])) {
+                        format += pcode_const_from_format(format + 1, &value2);
+                    } else {
+                        CError_FATAL(2327);
+                    }
+
+                    switch (code) {
+                        case '<':
+                            value = value2 - value;
+                            break;
+                        case '>':
+                            value = value - value2;
+                            break;
+                        case '|':
+                            value = value + value2;
+                            break;
+                        case '*':
+                            value = value * value2;
+                            break;
+                        default:
+                            CError_FATAL(2348);
+                    }
+
+                    if (op->type == IAOpnd_Imm)
+                        op->u.imm.value = value;
+                    else if (op->type == IAOpnd_Reg)
+                        op->u.reg.num = value;
+                    else
+                        CError_FATAL(2355);
+                    break;
+            }
+        }
+
+        ia->argcount++;
+        op++;
+        if (format[1] == ']' || format[1] == ')')
+            format++;
+    }
+
+    return ia;
+}
+
+static int mnemonic_has_overflow(char *buf) {
+    int result = 0;
+
+    if (buf[strlen(buf) - 1] == 'o') {
+        if (!strcmp(buf, "bso"))
+            return 0;
+        if (!strcmp(buf, "fcmpo"))
+            return 0;
+        if (!strcmp(buf, "eieio"))
+            return 0;
+        if (!strcmp(buf, "vslo"))
+            return 0;
+        if (!strcmp(buf, "vsro"))
+            return 0;
+        result = 1;
+    }
+
+    return result;
+}
+
+static int mnemonic_has_absolute(const char *buf) {
+    int result = 0;
+    char last = buf[strlen(buf) - 1];
+
+    if (buf[0] == 'b' && last == 'a')
+        result = 1;
+
+    return result;
+}
+
+static int mnemonic_has_linkregister(const char *buf) {
+    int result = 0;
+    char last = buf[strlen(buf) - 1];
+
+    if (buf[0] == 'b' && last == 'l')
+        result = 1;
+
+    return result;
+}
+
+static int mnemonic_has_record(char *buf) {
+    int result = 0;
+
+    if (lookahead() == '.') {
+        tk = lex();
+        result = 1;
+        strcat(buf, ".");
+    }
+
+    return result;
+}
+
+static void installregistervariables(void) {
+}
+
+void InlineAsm_InitializePPC(void) {
+    Test_Version_Numbers();
+    allow_array_expressions = 1;
+    supports_hardware_fpu = 1;
+    assembledinstructions = 0;
+
+    switch (copts.processor) {
+        case CPU_PPC401: cpu = CPUMask_401; break;
+        case CPU_PPC403: cpu = CPUMask_403; break;
+        case CPU_PPC505: cpu = CPUMask_50x; break;
+        case CPU_PPC509: cpu = CPUMask_50x; break;
+        case CPU_PPC555: cpu = CPUMask_55x_56x; break;
+        case CPU_PPC556: cpu = CPUMask_55x_56x; break;
+        case CPU_PPC565: cpu = CPUMask_55x_56x; break;
+        case CPU_PPC601: cpu = CPUMask_601; break;
+        case CPU_PPC602: cpu = CPUMask_602; break;
+        case CPU_PPC8240: cpu = CPUMask_8240; break;
+        case CPU_PPC8260: cpu = CPUMask_8260; break;
+        case CPU_PPC603: cpu = CPUMask_603; break;
+        case CPU_PPC603e: cpu = CPUMask_603; break;
+        case CPU_PPC604: cpu = CPUMask_604; break;
+        case CPU_PPC604e: cpu = CPUMask_604; break;
+        case CPU_PPC740: cpu = CPUMask_740_750; break;
+        case CPU_PPC750: cpu = CPUMask_740_750; break;
+        case CPU_PPC801: cpu = CPUMask_801_821_860; break;
+        case CPU_PPC821: cpu = CPUMask_801_821_860; break;
+        case CPU_PPC823: cpu = CPUMask_823_850; break;
+        case CPU_PPC850: cpu = CPUMask_823_850; break;
+        case CPU_PPC860: cpu = CPUMask_801_821_860; break;
+        case CPU_PPC7400: case CPU_PPC7450: cpu = CPUMask_74xx; break;
+        case CPU_Generic: cpu = CPUMask_Generic; break;
+        default:
+            CError_FATAL(2613);
+    }
+
+    if (copts.altivec_model)
+        cpu |= 0x40000000;
+}
+
+void InlineAsm_Initialize(AssemblerType assemblertype) {
+    assembler_type = assemblertype;
+
+    if (assembler_type == 0) {
+        InlineAsm_InitializePPC();
+        pic_base_reg = INVALID_PIC_REG;
+    } else {
+        pic_base_reg = 0;
+        pic_base_label = NULL;
+    }
+
+    InlineAsm_InitializeMnemonicsPPC();
+    InlineAsm_InitializeRegisters();
+    InlineAsm_InitializeRegistersPPC();
+
+    if (assembler_type == 0) {
+        installregistervariables();
+    } else {
+        process_arguments(setup_assembly_argument, 0);
+        assign_local_addresses();
+    }
+}
+
+static IAEntryPoint *InlineAsm_CreateEntryPoint(HashNameNode *name, Boolean flag) {
+    Object *obj;
+    IAEntryPoint *ep;
+    IALookupResult result;
+
+    if (InlineAsm_LookupSymbol(name, &result) && (obj = result.object)) {
+        if (!(obj->datatype == DFUNC && !(obj->flags & OBJECT_DEFINED)))
+            CError_Error(CErrorStr122, name->name);
+
+        obj->flags |= OBJECT_DEFINED;
+        obj->sclass = flag ? TK_STATIC : TK_EXTERN;
+
+        ep = lalloc(sizeof(IAEntryPoint));
+        memclrw(ep, sizeof(IAEntryPoint));
+        ep->x0 = IADirective_Entry;
+        ep->x2 = 1;
+        ep->x8 = obj;
+        ep->size = assembledinstructions * 4;
+    } else {
+        CError_Error(CErrorStr140, name->name);
+    }
+
+    return ep;
+}
+
+static InlineAsm *InlineAsm_CreateFrFree(void) {
+    InlineAsm *ia = lalloc(sizeof(InlineAsm));
+    memclrw(ia, sizeof(InlineAsm));
+    ia->opcode = IADirective_FrFree;
+    ia->flags = IAFlag1;
+    return ia;
+}
+
+SInt32 InlineAsm_IsDirective(AssemblerType assemblertype) {
+    char *name;
+    SInt32 directive = IADirective_Null;
+
+    if (tk == '.')
+        tk = lex();
+
+    if (tk == TK_IDENTIFIER) {
+        name = tkidentifier->name;
+        if (!strcmp(name, "machine")) {
+            directive = IADirective_Machine;
+        } else if (assemblertype == AssemblerType_1) {
+            if (!strcmp(name, "entry")) {
+                directive = IADirective_Entry;
+            } else if (!strcmp(name, "fralloc")) {
+                directive = IADirective_FrAlloc;
+            } else if (!strcmp(name, "nofralloc")) {
+                directive = IADirective_NoFrAlloc;
+            } else if (!strcmp(name, "frfree")) {
+                directive = IADirective_FrFree;
+            } else if (!strcmp(name, "smclass")) {
+                directive = IADirective_SmClass;
+            } else if (!strcmp(name, "picbase")) {
+                directive = IADirective_PicBase;
+            } else {
+                directive = IADirective_Null;
+            }
+        }
+    }
+
+    return directive;
+}
+
+void InlineAsm_ProcessDirective(SInt32 directive) {
+    Boolean flag;
+    Statement *stmt;
+    IAOperand op;
+
+    switch (directive) {
+        case IADirective_Entry:
+            flag = 0;
+            tk = lex();
+            if (tk == TK_STATIC) {
+                flag = 1;
+                tk = lex();
+            } else if (tk == TK_EXTERN) {
+                tk = lex();
+            }
+
+            if (tk != TK_IDENTIFIER)
+                CError_Error(CErrorStr107);
+
+            stmt = CFunc_AppendStatement(ST_ASM);
+            stmt->expr = NULL;
+            stmt->expr = (ENode *) InlineAsm_CreateEntryPoint(tkidentifier, flag);
+            stmt->sourceoffset = -1;
+            tk = lex();
+            break;
+
+        case IADirective_FrAlloc:
+            if (assembledinstructions)
+                CError_Error(CErrorStr166);
+            if (asm_alloc_flags[0])
+                CError_Error(CErrorStr165);
+            if (asm_alloc_flags[1] || asm_alloc_flags[2])
+                CError_Error(CErrorStr166);
+
+            tk = lex();
+            if (tk != TK_EOL && tk != ';')
+                fralloc_parameter_area_size = getimmediateoperand(0x20, 0x7FFE);
+
+            requires_frame = 1;
+            asm_alloc_flags[0] = 1;
+            break;
+
+        case IADirective_NoFrAlloc:
+            if (asm_alloc_flags[0] || asm_alloc_flags[1])
+                CError_Error(CErrorStr165);
+            if (asm_alloc_flags[2])
+                CError_Error(CErrorStr166);
+            if (assembledinstructions)
+                CError_Error(CErrorStr166);
+            tk = lex();
+
+            asm_alloc_flags[1] = 1;
+            user_responsible_for_frame = 1;
+            break;
+
+        case IADirective_FrFree:
+            if (asm_alloc_flags[1] || asm_alloc_flags[2])
+                CError_Error(CErrorStr166);
+
+            asm_alloc_flags[2] = 1;
+            stmt = CFunc_AppendStatement(ST_ASM);
+            stmt->expr = NULL;
+            stmt->expr = (ENode *) InlineAsm_CreateFrFree();
+            if (copts.filesyminfo)
+                stmt->sourceoffset = CPrep_GetFileOffsetInfo(&cparser_fileoffset);
+            else
+                stmt->sourceoffset = -1;
+            tk = lex();
+            break;
+
+        case IADirective_Machine:
+            tk = lex();
+            if (tk == TK_INTCONST) {
+                switch (tkintconst.lo) {
+                    case 401: cpu = CPUMask_401; break;
+                    case 403: cpu = CPUMask_403; break;
+                    case 505: cpu = CPUMask_50x; break;
+                    case 509: cpu = CPUMask_50x; break;
+                    case 555: cpu = CPUMask_55x_56x; break;
+                    case 556: cpu = CPUMask_55x_56x; break;
+                    case 565: cpu = CPUMask_55x_56x; break;
+                    case 601: cpu = CPUMask_601; break;
+                    case 602: cpu = CPUMask_602; break;
+                    case 8240: cpu = CPUMask_8240; break;
+                    case 8260: cpu = CPUMask_8260; break;
+                    case 603: cpu = CPUMask_603; break;
+                    case 604: cpu = CPUMask_604; break;
+                    case 740: cpu = CPUMask_740_750; break;
+                    case 750: cpu = CPUMask_740_750; break;
+                    case 801: cpu = CPUMask_801_821_860; break;
+                    case 821: cpu = CPUMask_801_821_860; break;
+                    case 823: cpu = CPUMask_823_850; break;
+                    case 850: cpu = CPUMask_823_850; break;
+                    case 860: cpu = CPUMask_801_821_860; break;
+                    case 7400: cpu = CPUMask_74xx; break;
+                    default:
+                        CError_Error(CErrorStr144);
+                }
+            } else if (tk == TK_IDENTIFIER) {
+                if (!strcmp(tkidentifier->name, "all")) {
+                    cpu = CPUMask_All;
+                } else if (!strcmp(tkidentifier->name, "generic")) {
+                    cpu = CPUMask_Generic;
+                } else if (!strcmp(tkidentifier->name, "603e")) {
+                    cpu = CPUMask_603;
+                } else if (!strcmp(tkidentifier->name, "604e")) {
+                    cpu = CPUMask_604;
+                } else if (!strcmp(tkidentifier->name, "PPC603e")) {
+                    cpu = CPUMask_603;
+                } else if (!strcmp(tkidentifier->name, "PPC604e")) {
+                    cpu = CPUMask_604;
+                } else if (!strcmp(tkidentifier->name, "altivec")) {
+                    cpu = CPUMask_74xx;
+                } else {
+                    CError_Error(CErrorStr144);
+                }
+            } else {
+                CError_Error(CErrorStr144);
+            }
+            tk = lex();
+            break;
+
+        case IADirective_SmClass:
+            tk = lex();
+            if (tk == TK_IDENTIFIER) {
+                if (!strcmp(tkidentifier->name, "PR"))
+                    sm_section = SECT_TEXT;
+                else
+                    CError_Error(CErrorStr144);
+            } else {
+                CError_Error(CErrorStr144);
+            }
+            tk = lex();
+            break;
+
+        case IADirective_PicBase:
+            tk = lex();
+            registeroperand(&op, RegClass_GPR, EffectRead);
+
+            if (!(op.type == IAOpnd_Reg && op.u.reg.object == NULL))
+                CError_Error(CErrorStr144);
+
+            tk = lex();
+            if (tk == TK_IDENTIFIER) {
+                savepicbase(op.u.reg.num, tkidentifier);
+                tk = lex();
+            } else {
+                CError_Error(CErrorStr144);
+            }
+            break;
+
+        default:
+            CError_Error(CErrorStr261);
+    }
+}
+
+void InlineAsm_ScanAssemblyDirective(void) {
+    SInt32 directive;
+
+    if ((directive = InlineAsm_IsDirective(assembler_type)) != IADirective_Null)
+        InlineAsm_ProcessDirective(directive);
+}
+
+void InlineAsm_ScanAssemblyInstruction(void) {
+    Statement *stmt;
+    InlineAsm *ia;
+    IAMnemonic *mnemonic;
+    Boolean record_flag;
+    Boolean flag3;
+    Boolean flag4;
+    Boolean flag5;
+    Boolean flag1;
+    Boolean flag2;
+    SInt32 directive;
+    OpcodeInfo *info;
+    char buf[20];
+
+    flag1 = 0;
+    flag2 = 0;
+    if ((directive = InlineAsm_IsDirective(assembler_type)) != IADirective_Null) {
+        InlineAsm_ProcessDirective(directive);
+        return;
+    }
+
+    stmt = CFunc_AppendStatement(ST_ASM);
+    stmt->expr = NULL;
+    if (copts.filesyminfo)
+        stmt->sourceoffset = CPrep_GetFileOffsetInfo(&cparser_fileoffset);
+    else
+        stmt->sourceoffset = -1;
+
+    strncpy(buf, tkidentifier->name, sizeof(buf));
+    record_flag = mnemonic_has_record(buf);
+    mnemonic = InlineAsm_LookupMnemonicPPC(buf);
+    if (!mnemonic)
+        CError_Error(CErrorStr261);
+
+    info = &opcodeinfo[mnemonic->x4];
+    flag3 = (FLAG_SET_F(info->flags) & fCanSetCarry) && (mnemonic->x10 & 0x400);
+    flag4 = (FLAG_SET_T(info->flags) & fCanBeAbsolute) && (mnemonic->x10 & 2);
+    flag5 = (FLAG_SET_T(info->flags) & fCanLink) && (mnemonic->x10 & 1);
+
+    if ((cpu == CPUMask_Generic) && (cpu & CPUFLAG_LOW_MASK) != ((cpu & mnemonic->cpu) & CPUFLAG_LOW_MASK)) {
+        CError_Error(CErrorStr152);
+    } else if (((cpu & mnemonic->cpu) & CPUFLAG_LOW_MASK) == 0) {
+        CError_Error(CErrorStr152);
+    } else if ((mnemonic->cpu & CPUFLAG_10000000) && !(cpu & CPUFLAG_10000000)) {
+        CError_Error(CErrorStr152);
+    } else if ((mnemonic->cpu & CPUFLAG_8000000) && !(cpu & CPUFLAG_8000000)) {
+        CError_Error(CErrorStr152);
+    } else if ((mnemonic->cpu & CPUFLAG_2000000) && !(cpu & CPUFLAG_2000000)) {
+        CError_Error(CErrorStr152);
+    } else if ((mnemonic->cpu & CPUFLAG_4000000) && !(cpu & CPUFLAG_4000000)) {
+        CError_Error(CErrorStr152);
+    } else if ((mnemonic->cpu & CPUFLAG_1000000) && !(cpu & CPUFLAG_1000000)) {
+        CError_Error(CErrorStr152);
+    } else if ((mnemonic->cpu & CPUFLAG_40000000) && !(cpu & CPUFLAG_40000000)) {
+        CError_Error(CErrorStr152);
+    } else if ((mnemonic->cpu & CPUFLAG_20000000) && !(cpu & CPUFLAG_20000000)) {
+        CError_Error(CErrorStr152);
+    } else if ((mnemonic->cpu & CPUFLAG_800000) && !(cpu & CPUFLAG_800000)) {
+        CError_Error(CErrorStr152);
+    }
+
+    tk = lex();
+    if (tk == '+' || tk == '-') {
+        if (
+                ((OPCODE_PART_1(mnemonic->x10) == 16) && (OPCODE_PART_2(mnemonic->x10) != 20)) ||
+                ((OPCODE_PART_1(mnemonic->x10) == 19) && (OPCODE_PART_3(mnemonic->x10) == 528) && (OPCODE_PART_2(mnemonic->x10) != 20)) ||
+                ((OPCODE_PART_1(mnemonic->x10) == 19) && (OPCODE_PART_3(mnemonic->x10) == 16) && (OPCODE_PART_2(mnemonic->x10) != 20))
+                ) {
+            if (tk == '+')
+                flag1 = 1;
+            else if (tk == '-')
+                flag2 = 1;
+            tk = lex();
+        } else {
+            CError_Error(CErrorStr120);
+        }
+    }
+
+    stmt->expr = (ENode *) InlineAsm_ScanAssemblyOperands(mnemonic);
+
+    ia = (InlineAsm *) stmt->expr;
+    if (record_flag)
+        ia->flags2 |= IAFlagsB_1;
+    if (flag3)
+        ia->flags2 |= IAFlagsB_2;
+    if (flag4)
+        ia->flags2 |= IAFlagsB_4;
+    if (flag5)
+        ia->flags2 |= IAFlagsB_8;
+    if (flag1)
+        ia->flags2 |= IAFlagsB_10;
+    if (flag2)
+        ia->flags2 |= IAFlagsB_20;
+    if (volatileasm)
+        ia->flags2 |= IAFlagsB_40;
+
+    ++assembledinstructions;
+}
+
+static PCode *InlineAsm_TranslateIRtoPCodePPC(InlineAsm *ia, int argcount, AssemblerType assemblertype) {
+    PCode *pc;
+    int index;
+    int extra_args;
+    int reg;
+    int newargcount;
+    SInt32 buffersize;
+    IAOperand *src;
+    PCodeArg *dest;
+    OpcodeInfo *info;
+
+    info = &opcodeinfo[ia->opcode];
+    index = 0;
+    extra_args = 0;
+    reg = 0;
+
+    if ((PCODE_FLAG_SET_F(info) & fCanSetRecordBit) && !(PCODE_FLAG_SET_F(info) & fRecordBit))
+        extra_args++;
+
+    if (!(PCODE_FLAG_SET_F(info) & fSetsCarry) && (PCODE_FLAG_SET_F(info) & fCanSetCarry))
+        extra_args++;
+
+    if (argcount < ia->argcount) {
+        if ((argcount + extra_args) >= ia->argcount) {
+            extra_args -= (ia->argcount - argcount);
+            argcount = ia->argcount;
+        } else {
+            CError_FATAL(3317);
+        }
+    }
+
+    if (ia->opcode == PC_B && ia->args[0].type == IAOpnd_Imm)
+        ia->flags2 |= IAFlagsB_40;
+
+    if (ia->opcode == PC_TWI || ia->opcode == PC_TW || ia->opcode == PC_TRAP || ia->opcode == PC_SC)
+        ia->flags |= IAFlag2;
+
+    if (ia->flags & IAFlag2) {
+        newargcount = argcount + branch_count_volatiles();
+        if (copts.exceptions && current_statement && assembler_type == 0)
+            newargcount += countexceptionactionregisters(current_statement->dobjstack);
+
+        buffersize = sizeof(PCode) + sizeof(PCodeArg) * (newargcount + extra_args);
+        pc = lalloc(buffersize);
+        memset(pc, 0, buffersize);
+        pc->argCount = newargcount;
+    } else if (ia->opcode == PC_STMW || ia->opcode == PC_LMW) {
+        reg = ia->args[0].u.reg.object ? OBJECT_REG(ia->args[0].u.reg.object) : ia->args[0].u.reg.num;
+        newargcount = argcount + (32 - reg);
+
+        buffersize = sizeof(PCode) + sizeof(PCodeArg) * newargcount;
+        pc = lalloc(buffersize);
+        memset(pc, 0, buffersize);
+        pc->argCount = newargcount;
+    } else {
+        buffersize = sizeof(PCode) + sizeof(PCodeArg) * (argcount + extra_args);
+        pc = lalloc(buffersize);
+        memset(pc, 0, buffersize);
+        pc->argCount = (ia->argcount > argcount) ? ia->argcount : argcount;
+    }
+
+    pc->op = ia->opcode;
+    pc->flags = info->flags;
+    pc->sourceoffset = current_statement ? current_statement->sourceoffset : -1;
+
+    dest = pc->args;
+    src = ia->args;
+    argcount += extra_args;
+    while (index < argcount) {
+        if (index >= ia->argcount) {
+            dest->kind = PCOp_PLACEHOLDEROPERAND;
+        } else {
+            switch (src->type) {
+                case IAOpnd_0:
+                    dest->kind = PCOp_PLACEHOLDEROPERAND;
+                    break;
+
+                case IAOpnd_Imm:
+                    dest->kind = PCOp_IMMEDIATE;
+                    dest->data.imm.value = src->u.imm.value;
+                    if (pc->flags & (fIsRead | fIsWrite))
+                        pc->flags |= fIsPtrOp;
+                    dest->data.imm.obj = NULL;
+                    break;
+
+                case IAOpnd_Reg: {
+                    int r20;
+                    r20 = 0;
+                    if (src->u.reg.object) {
+                        if (Registers_GetVarInfo(src->u.reg.object)->flags & VarInfoFlag2) {
+                            if (src->u.reg.num == 1)
+                                r20 = OBJECT_REG_HI(src->u.reg.object);
+                            else
+                                r20 = OBJECT_REG(src->u.reg.object);
+                        } else {
+                            if (Registers_GetVarInfo(src->u.reg.object)->flags & VarInfoFlag40)
+                                PPCError_Error(PPCErrorStr172, src->u.reg.object->name->name);
+                            else
+                                PPCError_Error(PPCErrorStr167, src->u.reg.object->name->name);
+                        }
+                    } else if (src->u.reg.num == INVALID_PIC_REG) {
+                        r20 = pic_base_reg;
+                    } else {
+                        r20 = src->u.reg.num;
+                    }
+
+                    dest->kind = PCOp_REGISTER;
+                    dest->arg = src->u.reg.rclass;
+                    dest->data.reg.reg = r20;
+                    dest->data.reg.effect = src->u.reg.effect;
+                    if (pc->op == PC_RLWIMI && (dest->data.reg.effect & EffectWrite) && dest->arg == RegClass_GPR && !(dest->data.reg.effect & EffectRead))
+                        CError_FATAL(3442);
+
+                    if (dest->arg == RegClass_SPR) {
+                        int i;
+                        dest->kind = PCOp_SYSREG;
+                        for (i = 0; i < 4; i++) {
+                            if (dest->data.reg.reg == spr_to_sysreg[i]) {
+                                dest->kind = PCOp_REGISTER;
+                                dest->arg = RegClass_SPR;
+                                dest->data.reg.reg = i;
+                                break;
+                            }
+                        }
+                        pcsetsideeffects(pc);
+                    } else if (dest->arg == RegClass_6 || dest->arg == RegClass_DCR) {
+                        short save = dest->data.reg.reg;
+                        dest->kind = PCOp_IMMEDIATE;
+                        dest->data.imm.value = save;
+                        dest->data.imm.obj = NULL;
+                        break;
+                    }
+
+                    if ((src->u.reg.effect & EffectWrite) && dest->data.reg.reg < n_real_registers[dest->arg]) {
+                        if (src->u.reg.object) {
+                            if (Registers_GetVarInfo(src->u.reg.object)->flags & VarInfoFlag4) {
+                                int reg, regHi;
+                                CError_ASSERT(3474, dest->arg == RegClass_GPR);
+
+                                regHi = OBJECT_REG_HI(src->u.reg.object);
+                                reg = OBJECT_REG(src->u.reg.object);
+                                retain_GPR_pair(src->u.reg.object, reg, regHi);
+                            } else {
+                                retain_register(src->u.reg.object, dest->arg, dest->data.reg.reg);
+                            }
+                        } else {
+                            retain_register(NULL, dest->arg, dest->data.reg.reg);
+                        }
+                    }
+
+                    break;
+                }
+
+                case IAOpnd_Lab:
+                    if (!src->u.lab.label->pclabel)
+                        src->u.lab.label->pclabel = makepclabel();
+                    dest->kind = PCOp_LABEL;
+                    dest->data.label.label = src->u.lab.label->pclabel;
+                    break;
+
+                case IAOpnd_3:
+                case IAOpnd_4:
+                    dest->kind = PCOp_MEMORY;
+                    dest->arg = src->u.obj.unk;
+                    dest->data.mem.obj = src->u.obj.obj;
+                    dest->data.mem.offset = src->u.obj.offset;
+                    if (pc->flags & (fIsRead | fIsWrite | fPCodeFlag20000 | fPCodeFlag40000)) {
+                        pc->alias = make_alias(dest->data.mem.obj, dest->data.mem.offset, nbytes_loaded_or_stored_by(pc));
+                        if (is_volatile_object(dest->data.mem.obj))
+                            pc->flags |= fIsVolatile;
+                        if (OBJ_GET_TARGET_CONST(dest->data.mem.obj))
+                            pc->flags |= fIsConst;
+                    }
+                    break;
+
+                case IAOpnd_LabDiff:
+                    if (src->u.labdiff.label1->pclabel == NULL)
+                        src->u.labdiff.label1->pclabel = makepclabel();
+                    if (src->u.labdiff.label2->pclabel == NULL)
+                        src->u.labdiff.label2->pclabel = makepclabel();
+                    if (pc->flags & (fIsRead | fIsWrite))
+                        pc->flags |= fIsPtrOp;
+                    dest->kind = PCOp_LABELDIFF;
+                    dest->data.labeldiff.labelA = src->u.labdiff.label1->pclabel;
+                    dest->data.labeldiff.labelB = src->u.labdiff.label2->pclabel;
+                    dest->arg = src->negated;
+                    dest->data.labeldiff.offset = src->u.labdiff.offset;
+                    break;
+
+                default:
+                    CError_FATAL(3528);
+            }
+        }
+
+        index++;
+        dest++;
+        src++;
+    }
+
+    if (ia->opcode == PC_STMW || ia->opcode == PC_LMW) {
+        int i;
+        for (i = reg; i < 32; i++, dest++) {
+            dest->kind = PCOp_REGISTER;
+            dest->arg = RegClass_GPR;
+            dest->data.reg.reg = i;
+            dest->data.reg.effect = ((ia->opcode == PC_LMW) ? EffectWrite : EffectRead);
+        }
+    }
+
+    if (ia->flags & IAFlag2) {
+        UInt32 masks[5] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
+        branch_record_volatiles(dest, masks);
+        if (copts.exceptions && current_statement && assembler_type == 0)
+            noteexceptionactionregisters(current_statement->dobjstack, dest);
+    }
+
+    return pc;
+}
+
+void InlineAsm_TranslateIRtoPCode(Statement *stmt) {
+    InlineAsm *ia;
+    PCode *pc;
+
+    ia = (InlineAsm *) stmt->expr;
+    pc = InlineAsm_TranslateIRtoPCodePPC(ia, opcodeinfo[ia->opcode].x8, assembler_type);
+    appendpcode(pclastblock, pc);
+
+    if ((ia->flags2 & IAFlagsB_40) || !copts.optimizewithasm)
+        setpcodeflags(fSideEffects);
+
+    if (ia->flags2 & IAFlagsB_1) {
+        if (PCODE_FLAG_SET_F(pc) & fCanSetRecordBit)
+            pcsetrecordbit(pclastblock->lastPCode);
+        else
+            CError_Error(CErrorStr261);
+    }
+
+    if (ia->flags2 & IAFlagsB_2) {
+        if (PCODE_FLAG_SET_F(pc) & fCanSetCarry)
+            setpcodeflags(fOverflow); // idk?
+        else
+            CError_Error(CErrorStr261);
+    }
+
+    if (ia->flags2 & IAFlagsB_4) {
+        if (PCODE_FLAG_SET_T(pc) & fCanBeAbsolute) {
+            int i;
+            for (i = 0; i < pc->argCount; i++) {
+                if (pc->args[i].kind == PCOp_LABEL || pc->args[i].kind == PCOp_MEMORY) {
+                    PPCError_Error(PPCErrorStr177);
+                    break;
+                }
+            }
+            setpcodeflags(fAbsolute);
+        } else {
+            CError_Error(CErrorStr261);
+        }
+    }
+
+    if (ia->flags2 & IAFlagsB_8) {
+        if (PCODE_FLAG_SET_T(pc) & fCanLink) {
+            pcsetlinkbit(pclastblock->lastPCode);
+            if (!(ia->flags & IAFlag2)) {
+                pclastblock->lastPCode->flags &= ~fIsCall;
+                pclastblock->lastPCode->flags |= fIsBranch;
+            }
+            makes_call = 1;
+        } else {
+            CError_Error(CErrorStr261);
+        }
+    }
+
+    if (ia->flags2 & IAFlagsB_10)
+        setpcodeflags(fCanSetRecordBit);
+    if (ia->flags2 & IAFlagsB_20)
+        setpcodeflags(fCanSetCarry);
+
+    if (OPCODE_PART_1(opcodeinfo[pc->op].insn) == 16) {
+        PCodeLabel *dest = NULL;
+        PCodeLabel *src = makepclabel();
+        switch (pc->op) {
+            case PC_BC:
+                if (pc->args[3].kind == PCOp_LABEL)
+                    dest = pc->args[3].data.label.label;
+                break;
+            case PC_BT:
+            case PC_BF:
+            case PC_BDNZT:
+            case PC_BDNZF:
+            case PC_BDZT:
+            case PC_BDZF:
+                if (pc->args[2].kind == PCOp_LABEL)
+                    dest = pc->args[2].data.label.label;
+                break;
+            case PC_BDNZ:
+            case PC_BDZ:
+                if (pc->args[0].kind == PCOp_LABEL)
+                    dest = pc->args[0].data.label.label;
+                break;
+            default:
+                CError_FATAL(3715);
+        }
+
+        if (dest) {
+            pcbranch(pclastblock, dest);
+            pcbranch(pclastblock, src);
+            makepcblock();
+            pclabel(pclastblock, src);
+        }
+        return;
+    }
+
+    if (OPCODE_PART_1(opcodeinfo[pc->op].insn) == 18) {
+        PCodeLabel *label;
+        if (ia->flags2 & IAFlagsB_8) {
+            label = makepclabel();
+            pcbranch(pclastblock, label);
+        }
+        if (pc->args[0].kind == PCOp_LABEL)
+            pcbranch(pclastblock, pc->args[0].data.label.label);
+        makepcblock();
+        if (ia->flags2 & IAFlagsB_8) {
+            pclabel(pclastblock, label);
+        }
+        return;
+    }
+
+    if (OPCODE_PART_1(opcodeinfo[pc->op].insn) == 19) {
+        switch (pc->op) {
+            case PC_BLR:
+            case PC_RFI:
+                if (asm_alloc_flags[3])
+                    asm_alloc_flags[9] = 1;
+                else
+                    asm_alloc_flags[8] = 1;
+
+                if (asm_alloc_flags[4])
+                    asm_alloc_flags[5] = 1;
+
+                if (pc->op == PC_BLR)
+                    asm_alloc_flags[6] = 1;
+                else
+                    asm_alloc_flags[7] = 1;
+                break;
+        }
+    }
+}
+
+const char *InlineAsm_GetMnemonic(InlineAsm *ia) {
+    return opcodeinfo[ia->opcode].name;
+}
+
+static void savepicbase(short reg, HashNameNode *name) {
+    IALookupResult result;
+
+    if (!InlineAsm_LookupSymbol(name, &result))
+        result.label = InlineAsm_DeclareLabel(name);
+
+    pic_base_label = result.label;
+    pic_base_reg = reg;
+    uses_globals = 1;
+}
+
+static SInt32 InlineAsm_OpcodeSize(InlineAsm *ia) {
+    if (opcodeinfo[ia->opcode].flags & (fIsRead | fIsWrite)) {
+        switch (ia->opcode) {
+            case PC_LBZ:
+            case PC_LBZU:
+            case PC_LBZX:
+            case PC_LBZUX:
+            case PC_STB:
+            case PC_STBU:
+            case PC_STBX:
+            case PC_STBUX:
+                return 1;
+            case PC_LHZ:
+            case PC_LHZU:
+            case PC_LHZX:
+            case PC_LHZUX:
+            case PC_LHA:
+            case PC_LHAU:
+            case PC_LHAX:
+            case PC_LHAUX:
+            case PC_LHBRX:
+            case PC_STH:
+            case PC_STHU:
+            case PC_STHX:
+            case PC_STHUX:
+            case PC_STHBRX:
+                return 2;
+            case PC_LWZ:
+            case PC_LWZU:
+            case PC_LWZX:
+            case PC_LWZUX:
+            case PC_LWBRX:
+            case PC_STW:
+            case PC_STWU:
+            case PC_STWX:
+            case PC_STWUX:
+            case PC_STWBRX:
+            case PC_LFS:
+            case PC_LFSU:
+            case PC_LFSX:
+            case PC_LFSUX:
+            case PC_STFS:
+            case PC_STFSU:
+            case PC_STFSX:
+            case PC_STFSUX:
+            case PC_LWARX:
+            case PC_STFIWX:
+            case PC_STWCX:
+            case PC_ECIWX:
+            case PC_ECOWX:
+            case PC_MFROM:
+            case PC_LSCBX:
+                return 4;
+            case PC_LMW:
+            case PC_STMW:
+                if (ia->args[0].type == IAOpnd_Reg && ia->args[0].u.reg.object == NULL)
+                    return (32 - ia->args[0].u.reg.num) * 4;
+                else
+                    return 128;
+            case PC_LFD:
+            case PC_LFDU:
+            case PC_LFDX:
+            case PC_LFDUX:
+            case PC_STFD:
+            case PC_STFDU:
+            case PC_STFDX:
+            case PC_STFDUX:
+                return 8;
+            case PC_LSWI:
+            case PC_STSWI:
+                return ia->args[2].u.imm.value;
+            case PC_LSWX:
+            case PC_STSWX:
+                return 128;
+            case PC_LVEBX:
+            case PC_STVEBX:
+                return 1;
+            case PC_LVEHX:
+            case PC_STVEHX:
+                return 2;
+            case PC_LVEWX:
+            case PC_STVEWX:
+                return 4;
+            case PC_LVSL:
+            case PC_LVSR:
+            case PC_LVX:
+            case PC_LVXL:
+            case PC_STVX:
+            case PC_STVXL:
+                return 16;
+            default:
+                CError_FATAL(3924);
+        }
+    } else {
+        if (opcodeinfo[ia->opcode].flags & fOpTypeGPR)
+            return 4;
+        if (opcodeinfo[ia->opcode].flags & fOpTypeFPR)
+            return 8;
+        if (opcodeinfo[ia->opcode].flags & fOpTypeVR)
+            return 16;
+
+        if (opcodeinfo[ia->opcode].flags & fSideEffects) {
+            switch (ia->opcode) {
+                case PC_TLBIE:
+                case PC_TLBLD:
+                case PC_TLBLI:
+                    return 4;
+                default:
+                    CError_FATAL(3941);
+            }
+        }
+    }
+
+    CError_FATAL(3944);
+    return 0;
+}
+
+void CodeGen_GetAsmEffects(Statement *stmt, IAEffects *effects) {
+    InlineAsm *ia;
+    OpcodeInfo *info;
+    int i;
+    IAOperand *op;
+    VarInfo *vi;
+
+    ia = (InlineAsm *) stmt->expr;
+    info = &opcodeinfo[ia->opcode];
+
+    effects->numoperands = 0;
+    effects->numlabels = 0;
+    effects->x1 = 0;
+    effects->x2 = 0;
+    effects->x3 = 0;
+    effects->x4 = 0;
+    effects->x0 = 0;
+    effects->x5 = 0;
+
+    if (info->flags & fIsPtrOp) {
+        if (info->flags & fIsRead)
+            effects->x1 = 1;
+        if (info->flags & fIsWrite)
+            effects->x2 = 1;
+    }
+
+    if (PCODE_FLAG_SET_T(info) & fCanLink) {
+        if (ia->flags2 & IAFlagsB_8)
+            effects->x4 = 1;
+        else if ((info->flags & fIsCall) || (info->flags & fIsWrite))
+            effects->x3 = 1;
+
+        if (ia->opcode == PC_B) {
+            if (ia->args[0].type == IAOpnd_Imm)
+                effects->x0 = 1;
+            effects->x5 = 1;
+        }
+    }
+
+    if (info->flags & fSideEffects)
+        effects->x0 = 1;
+
+    if (ia->opcode == PC_BC && (ia->flags2 & IAFlagsB_8))
+        effects->x4 = 1;
+
+    for (i = 0, op = ia->args; i < ia->argcount; i++, op++) {
+        switch (op->type) {
+            case IAOpnd_0:
+            case IAOpnd_Imm:
+                break;
+            case IAOpnd_Reg:
+                if (op->u.reg.object) {
+                    if ((vi = Registers_GetVarInfo(op->u.reg.object)))
+                        vi->flags |= VarInfoFlag40;
+                    if (op->u.reg.effect & EffectRead) {
+                        if (
+                                TYPE_FITS_IN_REGISTER(op->u.reg.object->type) ||
+                                IS_TYPE_FLOAT(op->u.reg.object->type) ||
+                                IS_TYPE_VECTOR(op->u.reg.object->type)
+                                ) {
+                            effects->operands[effects->numoperands].type = IAEffect_0;
+                            effects->operands[effects->numoperands].object = op->u.reg.object;
+                            effects->operands[effects->numoperands].offset = 0;
+                            effects->operands[effects->numoperands].size = op->u.reg.object->type->size;
+                            effects->numoperands++;
+                        } else {
+                            CError_FATAL(4051);
+                        }
+                    }
+                }
+                break;
+            case IAOpnd_3:
+            case IAOpnd_4:
+                if (op->u.obj.obj) {
+                    if (info->flags & fIsRead) {
+                        effects->operands[effects->numoperands].type = IAEffect_0;
+                        effects->operands[effects->numoperands].object = op->u.obj.obj;
+                        effects->operands[effects->numoperands].offset = op->u.obj.offset;
+                        effects->operands[effects->numoperands].size = InlineAsm_OpcodeSize(ia);
+                        effects->numoperands++;
+                    } else if (!(info->flags & (fIsBranch | fIsCall))) {
+                        effects->operands[effects->numoperands].type = IAEffect_3;
+                        effects->operands[effects->numoperands].object = op->u.obj.obj;
+                        effects->operands[effects->numoperands].offset = op->u.obj.offset;
+                        effects->operands[effects->numoperands].size = InlineAsm_OpcodeSize(ia);
+                        effects->numoperands++;
+                    }
+                }
+                break;
+            case IAOpnd_Lab:
+                effects->labels[effects->numlabels] = op->u.lab.label;
+                effects->numlabels++;
+                break;
+            case IAOpnd_LabDiff:
+                effects->labels[effects->numlabels] = op->u.labdiff.label1;
+                effects->numlabels++;
+                effects->labels[effects->numlabels] = op->u.labdiff.label2;
+                effects->numlabels++;
+                effects->x3 = 1;
+                break;
+            default:
+                CError_FATAL(4087);
+        }
+
+        CError_ASSERT(4090, (UInt32) effects->numoperands <= IAMaxOperands);
+        CError_ASSERT(4093, (UInt32) effects->numlabels <= IAMaxLabels);
+    }
+
+    for (i = 0, op = ia->args; i < ia->argcount; i++, op++) {
+        switch (op->type) {
+            case IAOpnd_Reg:
+                if (op->u.reg.object) {
+                    if ((vi = Registers_GetVarInfo(op->u.reg.object)))
+                        vi->flags |= VarInfoFlag40;
+                    if (op->u.reg.effect & EffectWrite) {
+                        if (
+                                TYPE_FITS_IN_REGISTER(op->u.reg.object->type) ||
+                                IS_TYPE_FLOAT(op->u.reg.object->type) ||
+                                IS_TYPE_VECTOR(op->u.reg.object->type)
+                                ) {
+                            effects->operands[effects->numoperands].type = IAEffect_1;
+                            effects->operands[effects->numoperands].object = op->u.reg.object;
+                            effects->operands[effects->numoperands].offset = 0;
+                            effects->operands[effects->numoperands].size = op->u.reg.object->type->size;
+                            effects->numoperands++;
+                        } else {
+                            CError_FATAL(4132);
+                        }
+                    }
+                }
+                break;
+            case IAOpnd_3:
+            case IAOpnd_4:
+                if (op->u.obj.obj) {
+                    if (info->flags & fIsWrite) {
+                        effects->operands[effects->numoperands].type = IAEffect_1;
+                        effects->operands[effects->numoperands].object = op->u.obj.obj;
+                        effects->operands[effects->numoperands].offset = op->u.obj.offset;
+                        effects->operands[effects->numoperands].size = InlineAsm_OpcodeSize(ia);
+                        effects->numoperands++;
+                    }
+                }
+                break;
+        }
+
+        CError_ASSERT(4151, (UInt32) effects->numoperands <= IAMaxOperands);
+    }
+
+    if ((info->flags & (fIsBranch | fIsCall)) && (SInt32)effects->numlabels == 0)
+        effects->x3 = 1;
+}
+
+void CodeGen_PropagateIntoAsm(Statement *stmt, Object *obj, ENode *expr) {
+    InlineAsm *ia;
+    Object *newobj;
+
+    ia = (InlineAsm *) stmt->expr;
+    if (ENODE_IS(expr, EOBJREF)) {
+        newobj = expr->data.objref;
+        if (obj->otype == newobj->otype && obj->datatype == newobj->datatype) {
+            int i;
+            for (i = 0; i < ia->argcount; i++) {
+                switch (ia->args[i].type) {
+                    case IAOpnd_Reg:
+                        if (ia->args[i].u.reg.object == obj &&
+                            (ia->args[i].u.reg.effect & (EffectRead | EffectWrite)) == EffectRead) {
+                            if (TYPE_FITS_IN_REGISTER(newobj->type) &&
+                                ia->args[i].u.reg.rclass == RegClass_GPR) {
+                                ia->args[i].u.reg.object = newobj;
+                            } else if (IS_TYPE_FLOAT(newobj->type) &&
+                                       ia->args[i].u.reg.rclass == RegClass_FPR) {
+                                ia->args[i].u.reg.object = newobj;
+                            } else if (IS_TYPE_VECTOR(newobj->type) &&
+                                       ia->args[i].u.reg.rclass == RegClass_VR) {
+                                ia->args[i].u.reg.object = newobj;
+                            }
+                        }
+                        break;
+                    case IAOpnd_3:
+                    case IAOpnd_4:
+                        if (!(opcodeinfo[ia->opcode].flags & (fIsWrite | fPCodeFlag40000)) &&
+                            ia->args[i].u.obj.obj == obj)
+                            ia->args[i].u.obj.obj = newobj;
+                        break;
+                }
+            }
+        }
+    }
+}
+
+Statement *CodeGen_CopyAsmStat(Statement *stmt) {
+    Statement *copy;
+    SInt32 size;
+    InlineAsm *ia;
+    InlineAsm *iacopy;
+
+    copy = galloc(sizeof(Statement));
+    *copy = *stmt;
+
+    ia = (InlineAsm *) stmt->expr;
+    size = sizeof(InlineAsm) + sizeof(IAOperand) * ia->argcount;
+    iacopy = galloc(size);
+    memcpy(iacopy, ia, size);
+    copy->expr = (ENode *) iacopy;
+
+    return copy;
+}
+
-- 
cgit v1.2.3