<commit_before>// Make sure backbase.ts is loaded before us, otherwise 'extends AssemblerSnippets' fails at runtime
/// <reference path="backbase.ts"/>

namespace ts.pxtc {

    const inlineArithmetic: pxt.Map<string> = {
        "numops::adds": "_numops_adds",
        "numops::subs": "_numops_subs",
        "numops::orrs": "_numops_orrs",
        "numops::ands": "_numops_ands",
        "pxt::toInt": "_numops_toInt",
        "pxt::fromInt": "_numops_fromInt",
    }

    // snippets for ARM Thumb assembly
    export class ThumbSnippets extends AssemblerSnippets {
        nop() { return "nop" }
        reg_gets_imm(reg: string, imm: number) {
            return `movs ${reg}, #${imm}`
        }
        push_fixed(regs: string[]) { return "push {" + regs.join(", ") + "}" }
        pop_fixed(regs: string[]) { return "pop {" + regs.join(", ") + "}" }
        proc_setup(main?: boolean) { return "push {lr}" }
        proc_return() { return "pop {pc}" }

        debugger_stmt(lbl: string) {
            return `
    @stackempty locals
    ldr r0, [r6, #0] ; debugger
    subs r0, r0, #4  ; debugger
${lbl}:
    ldr r0, [r0, #0] ; debugger
`
        }

        debugger_bkpt(lbl: string) {
            return `
    @stackempty locals
    ldr r0, [r6, #0] ; brk
${lbl}:
    ldr r0, [r0, #0] ; brk
`
        }

        debugger_proc(lbl: string) {
            return `
    ldr r0, [r6, #0]  ; brk-entry
    ldr r0, [r0, #4]  ; brk-entry
${lbl}:`
        }

        push_local(reg: string) { return `push {${reg}}` }
        pop_locals(n: number) { return `add sp, #4*${n} ; pop locals${n}` }
        unconditional_branch(lbl: string) { return "bb " + lbl; }
        beq(lbl: string) { return "beq " + lbl }
        bne(lbl: string) { return "bne " + lbl }
        cmp(reg1: string, reg2: string) { return "cmp " + reg1 + ", " + reg2 }
        cmp_zero(reg1: string) { return "cmp " + reg1 + ", #0" }
        load_reg_src_off(reg: string, src: string, off: string, word?: boolean, store?: boolean, inf?: BitSizeInfo) {
            if (word) {
                off = `#4*${off}`
            }
            let str = "str"
            let ldr = "ldr"
            if (inf) {
                if (inf.immLimit == 32)
                    str = "strb"
                else if (inf.immLimit == 64)
                    str = "strh"
                if (inf.needsSignExt)
                    ldr = str.replace("str", "ldrs")
                else
                    ldr = str.replace("str", "ldr")
            }
            if (store)
                return `${str} ${reg}, [${src}, ${off}]`
            else
                return `${ldr} ${reg}, [${src}, ${off}]`
        }
        rt_call(name: string, r0: string, r1: string) {
            return name + " " + r0 + ", " + r1;
        }
        call_lbl(lbl: string) {
            if (target.taggedInts && !target.boxDebug) {
                let o = U.lookup(inlineArithmetic, lbl)
                if (o) lbl = o
            }
            return "bl " + lbl;
        }
        call_reg(reg: string) {
            return "blx " + reg;
        }
        // NOTE: 43 (in cmp instruction below) is magic number to distinguish
        // NOTE: Map from RefRecord
        vcall(mapMethod: string, isSet: boolean, vtableShift: number) {
            return `
    ldr r0, [sp, #${isSet ? 4 : 0}] ; ld-this
    ldrh r3, [r0, #2] ; ld-vtable
    lsls r3, r3, #${vtableShift}
    ldr r3, [r3, #4] ; iface table
    cmp r3, #43
    beq .objlit
.nonlit:
    lsls r1, ${isSet ? "r2" : "r1"}, #2
    ldr r0, [r3, r1] ; ld-method
    bx r0
.objlit:
    ${isSet ? "ldr r2, [sp, #0]" : ""}
    push {lr}
    bl ${mapMethod}
    pop {pc}
`;
        }
        prologue_vtable(arg_top_index: number, vtableShift: number) {
            return `
    ldr r0, [sp, #4*${arg_top_index}]  ; ld-this
    ldrh r0, [r0, #2] ; ld-vtable
    lsls r0, r0, #${vtableShift}
    `;
        }
        lambda_prologue() {
            return `
    @stackmark args
    push {lr}
    mov r5, r0
`;
        }
        lambda_epilogue() {
            return `
    bl pxtrt::getGlobalsPtr
    mov r6, r0
    pop {pc}
    @stackempty args
`
        }
        load_ptr_full(lbl: string, reg: string) {
            assert(!!lbl)
            return `
    ldlit ${reg}, ${lbl}
`
        }

        load_ptr(lbl: string, reg: string) {
            assert(!!lbl)
            return `
    movs ${reg}, ${lbl}@hi  ; ldptr
    lsls ${reg}, ${reg}, #8
    adds ${reg}, ${lbl}@lo
`
        }

        arithmetic() {
            let r = ""

            if (!target.taggedInts || target.boxDebug) {
                return r
            }

            for (let op of ["adds", "subs", "ands", "orrs", "eors"]) {
                r +=
                    `
_numops_${op}:
    @scope _numops_${op}
    lsls r2, r0, #31
    beq .boxed
    lsls r2, r1, #31
    beq .boxed
`
                if (op == "adds" || op == "subs")
                    r += `
    subs r2, r1, #1
    ${op} r2, r0, r2
    bvs .boxed
    movs r0, r2
    blx lr
`
                else {
                    r += `    ${op} r0, r1\n`
                    if (op == "eors")
                        r += `    adds r0, r0, #1\n`
                    r += `    blx lr\n`
                }

                r += `
.boxed:
    push {lr}
    bl numops::${op}
    pop {pc}
`
            }

            r += `
@scope _numops_toInt
_numops_toInt:
    asrs r0, r0, #1
    bcc .over
    blx lr
.over:
    push {lr}
    bl pxt::toInt<commit_msg>Fix toInt conversion in assembly; fixes https://github.com/Microsoft/pxt-adafruit/issues/170<commit_after>// Make sure backbase.ts is loaded before us, otherwise 'extends AssemblerSnippets' fails at runtime
/// <reference path="backbase.ts"/>

namespace ts.pxtc {

    const inlineArithmetic: pxt.Map<string> = {
        "numops::adds": "_numops_adds",
        "numops::subs": "_numops_subs",
        "numops::orrs": "_numops_orrs",
        "numops::ands": "_numops_ands",
        "pxt::toInt": "_numops_toInt",
        "pxt::fromInt": "_numops_fromInt",
    }

    // snippets for ARM Thumb assembly
    export class ThumbSnippets extends AssemblerSnippets {
        nop() { return "nop" }
        reg_gets_imm(reg: string, imm: number) {
            return `movs ${reg}, #${imm}`
        }
        push_fixed(regs: string[]) { return "push {" + regs.join(", ") + "}" }
        pop_fixed(regs: string[]) { return "pop {" + regs.join(", ") + "}" }
        proc_setup(main?: boolean) { return "push {lr}" }
        proc_return() { return "pop {pc}" }

        debugger_stmt(lbl: string) {
            return `
    @stackempty locals
    ldr r0, [r6, #0] ; debugger
    subs r0, r0, #4  ; debugger
${lbl}:
    ldr r0, [r0, #0] ; debugger
`
        }

        debugger_bkpt(lbl: string) {
            return `
    @stackempty locals
    ldr r0, [r6, #0] ; brk
${lbl}:
    ldr r0, [r0, #0] ; brk
`
        }

        debugger_proc(lbl: string) {
            return `
    ldr r0, [r6, #0]  ; brk-entry
    ldr r0, [r0, #4]  ; brk-entry
${lbl}:`
        }

        push_local(reg: string) { return `push {${reg}}` }
        pop_locals(n: number) { return `add sp, #4*${n} ; pop locals${n}` }
        unconditional_branch(lbl: string) { return "bb " + lbl; }
        beq(lbl: string) { return "beq " + lbl }
        bne(lbl: string) { return "bne " + lbl }
        cmp(reg1: string, reg2: string) { return "cmp " + reg1 + ", " + reg2 }
        cmp_zero(reg1: string) { return "cmp " + reg1 + ", #0" }
        load_reg_src_off(reg: string, src: string, off: string, word?: boolean, store?: boolean, inf?: BitSizeInfo) {
            if (word) {
                off = `#4*${off}`
            }
            let str = "str"
            let ldr = "ldr"
            if (inf) {
                if (inf.immLimit == 32)
                    str = "strb"
                else if (inf.immLimit == 64)
                    str = "strh"
                if (inf.needsSignExt)
                    ldr = str.replace("str", "ldrs")
                else
                    ldr = str.replace("str", "ldr")
            }
            if (store)
                return `${str} ${reg}, [${src}, ${off}]`
            else
                return `${ldr} ${reg}, [${src}, ${off}]`
        }
        rt_call(name: string, r0: string, r1: string) {
            return name + " " + r0 + ", " + r1;
        }
        call_lbl(lbl: string) {
            if (target.taggedInts && !target.boxDebug) {
                let o = U.lookup(inlineArithmetic, lbl)
                if (o) lbl = o
            }
            return "bl " + lbl;
        }
        call_reg(reg: string) {
            return "blx " + reg;
        }
        // NOTE: 43 (in cmp instruction below) is magic number to distinguish
        // NOTE: Map from RefRecord
        vcall(mapMethod: string, isSet: boolean, vtableShift: number) {
            return `
    ldr r0, [sp, #${isSet ? 4 : 0}] ; ld-this
    ldrh r3, [r0, #2] ; ld-vtable
    lsls r3, r3, #${vtableShift}
    ldr r3, [r3, #4] ; iface table
    cmp r3, #43
    beq .objlit
.nonlit:
    lsls r1, ${isSet ? "r2" : "r1"}, #2
    ldr r0, [r3, r1] ; ld-method
    bx r0
.objlit:
    ${isSet ? "ldr r2, [sp, #0]" : ""}
    push {lr}
    bl ${mapMethod}
    pop {pc}
`;
        }
        prologue_vtable(arg_top_index: number, vtableShift: number) {
            return `
    ldr r0, [sp, #4*${arg_top_index}]  ; ld-this
    ldrh r0, [r0, #2] ; ld-vtable
    lsls r0, r0, #${vtableShift}
    `;
        }
        lambda_prologue() {
            return `
    @stackmark args
    push {lr}
    mov r5, r0
`;
        }
        lambda_epilogue() {
            return `
    bl pxtrt::getGlobalsPtr
    mov r6, r0
    pop {pc}
    @stackempty args
`
        }
        load_ptr_full(lbl: string, reg: string) {
            assert(!!lbl)
            return `
    ldlit ${reg}, ${lbl}
`
        }

        load_ptr(lbl: string, reg: string) {
            assert(!!lbl)
            return `
    movs ${reg}, ${lbl}@hi  ; ldptr
    lsls ${reg}, ${reg}, #8
    adds ${reg}, ${lbl}@lo
`
        }

        arithmetic() {
            let r = ""

            if (!target.taggedInts || target.boxDebug) {
                return r
            }

            for (let op of ["adds", "subs", "ands", "orrs", "eors"]) {
                r +=
                    `
_numops_${op}:
    @scope _numops_${op}
    lsls r2, r0, #31
    beq .boxed
    lsls r2, r1, #31
    beq .boxed
`
                if (op == "adds" || op == "subs")
                    r += `
    subs r2, r1, #1
    ${op} r2, r0, r2
    bvs .boxed
    movs r0, r2
    blx lr
`
                else {
                    r += `    ${op} r0, r1\n`
                    if (op == "eors")
                        r += `    adds r0, r0, #1\n`
                    r += `    blx lr\n`
                }

                r += `
.boxed:
    push {lr}
    bl numops::${op}
    pop {pc}
`
            }

            r += `
@scope _numops_toInt
_numops_toInt:
    asrs r0, r0, #1
    bcc .over
    blx lr
.over:
    push {lr}
    lsls r0, r0, #1
    bl pxt::toInt
{'fraction_non_alphanumeric': 0.1539227219256176, 'fraction_numerical': 0.01864084698217356, 'mean_word_length': 1.5066908596053528, 'pattern_counts': {'":': 12, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1664265', 'n_tokens_mistral': 4098, 'n_tokens_neox': 4004, 'n_words': 987}