Esempio n. 1
0
def _genAddPtr(resultLoc, src1Loc, src2Loc):
    if not src2Loc.getType().isInteger():
        raise SemanticError(src2Loc.getPosition(),
            "Can only add ponters and integers, not pointers and other types")
    memberSize = src1Loc.getType().deref().getSize()
    s1 = src1Loc.getSource()
    s2 = src2Loc.getSource()
    rs = resultLoc.getSource()
    t = resultLoc.getType()
    if src2Loc.getType().getSize() > 2:
        raise NatrixNotImplementedError(src2Loc.getPosition(), "Can only add integers up to 16 bit to pointers")
    result = '; {} = {} + {} * {}\n'.format(resultLoc, src1Loc, src2Loc, memberSize)
    isWord = src2Loc.getType().getSize() == 2
    if memberSize > 2:
        if src2Loc.getIndirLevel() == 0:
            pos = src1Loc.getPosition() - src2Loc.getPosition()
            offset = s2 * memberSize
            loc, code = _genIntBinary(resultLoc, src1Loc, Value(pos, t, 0, offset, True), "add", "adc", "({}) + ({})", operator.add, False)
            return loc, result + code
        elif not isPowerOfTwo(memberSize):
            raise NatrixNotImplementedError(src2Loc.getPosition(), f"sizeof({src1Loc.getType().deref()}) = {memberSize} is not a power of two")
        elif src1Loc == resultLoc:
            shift = log(memberSize)
            loc, code = _genIncDecPtr(resultLoc, src2Loc, shift, "add", "adc")
            return loc, result + code
        else:
            shift = log(memberSize)
            shiftedLoc, shiftCode = genSHLVarByConst(resultLoc, src2Loc, shift)
            loc, additionCode = _genIntBinary(resultLoc, shiftedLoc, src1Loc, "add", "adc", "({}) + ({})", operator.add, False)
            return loc, result + shiftCode + additionCode
    elif isWord:
        assert(not src2Loc.getSource().isRegister())
        if memberSize == 1:
            # no multiplication, just add
            loc, code = _genIntBinary(resultLoc, src1Loc, src2Loc.withType(t), "add", "adc", "({}) + ({})", operator.add, False)
            return loc, result + code
        elif memberSize == 2:
            if src2Loc.getIndirLevel() == 0:
                pos = src1Loc.getPosition() - src2Loc.getPosition()
                offset = s2 * 2
                loc, code = _genIntBinary(resultLoc, src1Loc, Value(pos, t, 0, offset, True), "add", "adc", "({}) + ({})", operator.add, False)
                return loc, result + code
            else:
                result += '''
                    ldi pl, lo({0})
                    ldi ph, hi({0})
                    ld b
                    inc pl
                '''.format(s2)
                if not src2Loc.isAligned():
                    result += '''
                        mov a, 0
                        adc ph, a
                    '''
                result += '''
                    ld a
                    shl a
                    shl b
                    adc a, 0
                '''
                if src1Loc.getIndirLevel() == 1:
                    result += '''
                        xor a, b
                        xor b, a
                        xor a, b
                        ldi pl, lo({0})
                        ldi ph, hi({0})
                        ld pl
                        add a, pl
                        ldi ph, hi({0} + 1)
                        ldi pl, lo({0} + 1)
                        ld pl
                        mov ph, a
                        mov a, pl
                        adc b, a
                        mov a, ph
                    '''.format(s1)
                    result += '''
                        ldi pl, lo({0})
                        ldi ph, hi({0})
                        st a
                        inc pl
                    '''.format(rs)
                    if not resultLoc.isAligned():
                        result += '''
                            mov a, 0
                            adc ph, a
                        '''
                    result += '''
                        st b
                    '''
                else:
                    # a:b - index
                    result += '''
                        mov ph, a
                        ldi a, lo({0})
                        add b, a
                        ldi a, hi({0})
                        adc a, ph
                    '''.format(s1)
                    result += '''
                        ldi pl, lo({0})
                        ldi ph, hi({0})
                        st b
                    '''.format(rs)
                    if resultLoc.isAligned():
                        result += '''
                            inc pl
                            st a
                        '''
                    else:
                        result += '''
                            ldi pl, lo({0} + 1)
                            ldi ph, hi({0} + 1)
                            st a
                        '''.format(rs)
    else: # not isWord
        if src2Loc.getIndirLevel() == 0:
            pos = src1Loc.getPosition() - src2Loc.getPosition()
            s2 = s2.widen(src2Loc.getType().getSign())
            offset = s2 * memberSize
            loc, code = _genIntBinary(resultLoc, src1Loc, Value(pos, t, 0, offset, True), "add", "adc", "({}) + ({})", operator.add, False)
            return loc, result + code
        if src2Loc.getType().getSign():
            raise SemanticError(src2Loc.getPosition(), "pointer arithmetic with s8 is not implemented")
        # s2.indirLevel == 1
        result += loadByte('b', src2Loc, 0)
        if memberSize == 1:
            if src1Loc.getIndirLevel() == 0:
                result += '''
                    ldi a, lo({0})
                    add b, a
                    ldi a, hi({0})
                    adc a, 0
                '''.format(src1Loc.getSource())
            else:
                result += '''
                    ldi pl, lo({0})
                    ldi ph, hi({0})
                    ld a
                    add b, a
                    ldi pl, lo({0} + 1)
                    ldi ph, hi({0} + 1)
                    ld a
                    adc a, 0
                '''.format(src1Loc.getSource())
        elif memberSize == 2:
            if src1Loc.getIndirLevel() == 0:
                result += '''
                    mov a, 0
                    mov pl, a
                    shl b
                    adc pl, a
                    ldi a, lo({0})
                    add b, a
                    ldi a, hi({0})
                    adc a, pl
                '''.format(src1Loc.getSource())
            else:
                result += '''
                    ldi pl, lo({0})
                    ldi ph, hi({0})
                    ld pl ; pl = p_l
                    mov a, 0
                    shl b ; b = i_l
                    adc a, 0
                    mov ph, a ; ph = i_h
                    mov a, pl
                    add b, a ; b = p_l + i_l = r_l
                    mov a, 0
                    adc a, 0 ; a = c
                    add a, ph ; a = i_h + c
                    ldi pl, lo({0} + 1)
                    ldi ph, hi({0} + 1)
                    ld pl
                    add a, pl ; a = i_h + c + p_h = r_h
                '''.format(src1Loc.getSource())
        if resultLoc.isAligned():
            result += '''
                ldi pl, lo({0})
                ldi ph, hi({0})
                st b
                inc pl
                st a
            '''.format(resultLoc.getSource())
        else:
            result += '''
                ldi pl, lo({0})
                ldi ph, hi({0})
                st b
                ldi pl, lo({0} + 1)
                ldi ph, hi({0} + 1)
                st a
            '''.format(resultLoc.getSource())
    return resultLoc, result
Esempio n. 2
0
def _genIntBinary(resultLoc, src1Loc, src2Loc, opLo, opHi, pyPattern, constLambda, carryIrrelevant):
    if resultLoc.getType().isUnknown():
        resultLoc = resultLoc.removeUnknown(src1Loc.getType())
    if resultLoc.getType() != src1Loc.getType():
        raise SemanticError(resultLoc.getPosition(),
            "Incompatible result and source types: {} and {}".format(resultLoc.getType(), src1Loc.getType()))
    if src1Loc.getType() != src2Loc.getType():
        raise SemanticError(resultLoc.getPosition(),
            "Incompatible source types: {} and {}".format(src1Loc.getType(), src2Loc.getType()))
    assert(resultLoc.getIndirLevel() == 1)
    l1 = src1Loc.getIndirLevel()
    l2 = src2Loc.getIndirLevel()
    assert(l1 == 0 or l1 == 1)
    assert(l2 == 0 or l2 == 1)
    if l1 == 0 and l2 == 0:
        raise RuntimeError("Case unhandled by ConstTransformer")
    t = resultLoc.getType()
    rs = resultLoc.getSource()
    s1 = src1Loc.getSource()
    s2 = src2Loc.getSource()
    result = "; {} = {} {}, {}\n".format(resultLoc, opLo, src1Loc, src2Loc)
    if t.getSize() <= 2:
        isWord = t.getSize() == 2
        if not isWord:
            assert(not s1.isRegister() or not s2.isRegister())
            result += loadByte('b', src1Loc, 0)
            result += loadByte('a', src2Loc, 0)
            result += f'''
                {opLo} b, a
                mov a, b
            '''
            return Value.register(resultLoc.getPosition(), t), result
        # now it's a word
        if l2 == 0:
            # var + const
            result += '''
                ldi pl, lo({0})
                ldi ph, hi({0})
                ld b
            '''.format(src1Loc.getSource())
            result += incP(src1Loc.isAligned())
            c = src2Loc.getSource()
            result += loadByte('a', src2Loc, 0)
            result += f'''
                {opLo} b, a
                ld a
            '''
            result += loadByte('pl', src2Loc, 1)
            result += f'{opHi} a, pl\n'
            result += '''
                ldi pl, lo({0})
                ldi ph, hi({0})
                st b
            '''.format(rs)
            if resultLoc.isAligned():
                result += '''
                    inc pl
                    st a
                '''
            else:
                result += f'''
                    ldi pl, lo({rs} + 1)
                    ldi ph, hi({rs} + 1)
                    st a
                '''
        elif l1 == 0:
            # const + var
            result += '''
                ldi pl, lo({0})
                ldi ph, hi({0})
                ld a
            '''.format(src2Loc.getSource())
            if src2Loc.isAligned():
                result += 'inc pl\n'
            else:
                result += '''
                    ldi pl, lo({0} + 1)
                    ldi ph, hi({0} + 1)
                '''.format(src2Loc.getSource())
            result += loadByte('b', src1Loc, 0)
            result += f'''
                {opLo} b, a
                ld pl
            '''
            result += loadByte('a', src1Loc, 1)
            result += f'''
                {opHi} a, pl
                ldi pl, lo({rs})
                ldi ph, hi({rs})
                st b
            '''.format(rs)
            if resultLoc.isAligned():
                result += '''
                    inc pl
                    st a
                '''
            else:
                result += f'''
                    ldi pl, lo({rs} + 1)
                    ldi ph, hi({rs} + 1)
                    st a
                '''
        else:
            # var + var
            s1 = src1Loc.getSource()
            s2 = src2Loc.getSource()
            result += '''
                ldi pl, lo({0})
                ldi ph, hi({0})
                ld b
                ldi pl, lo({1})
                ldi ph, hi({1})
                ld a
                {2} b, a
            '''.format(s1, s2, opLo)
            if isWord:
                result += '''
                    ldi pl, lo({0} + 1)
                    ldi ph, hi({0} + 1)
                    ld a
                    ldi pl, lo({1} + 1)
                    ldi ph, hi({1} + 1)
                    ld pl
                    {2} a, pl
                '''.format(s1, s2, opHi)
            result += '''
                ldi pl, lo({0})
                ldi ph, hi({0})
                st b
            '''.format(rs)
            if isWord:
                if resultLoc.isAligned():
                    result += '''
                        inc pl
                        st a
                    '''
                else:
                    result += '''
                        ldi pl, lo({0} + 1)
                        ldi ph, hi({0} + 1)
                        st a
                    '''.format(rs)
    else:
        # size > 2
        # This produces less size-efficient code than above, that's why it's not a general case.
        for offset in range(0, t.getSize(), 2):
            rest = t.getSize() - offset
            result += loadByte('a', src1Loc, offset)
            if rest > 1:
                if l1 == 0:
                    result += loadByte('b', src1Loc, offset + 1)
                else:
                    if (offset == 0 or carryIrrelevant) and src1Loc.isAligned():
                        # can trash flags if it's the first pair of bytes or if op is like and, or, xor
                        result += '''
                            inc pl
                            ld b
                        '''
                    else:
                        # must preserve flags
                        if src1Loc.isAligned():
                            result += f'''
                                ldi pl, lo({s1} + {offset + 1})
                                ld b
                            '''
                        else:
                            result += loadByte('b', src1Loc, offset + 1)
            result += loadByte('pl', src2Loc, offset)
            if offset == 0:
                result += f'{opLo} a, pl\n'
            else:
                result += f'{opHi} a, pl\n'
            result += f'''
                ldi pl, lo({rs} + {offset})
                ldi ph, hi({rs} + {offset})
                st a
            '''
            if rest > 1:
                result += loadByte('a', src2Loc, offset + 1)
                result += f'''
                    {opHi} b, a
                    ldi pl, lo({rs} + {offset + 1})
                    ldi ph, hi({rs} + {offset + 1})
                    st b
                '''
    return resultLoc, result
Esempio n. 3
0
def _genBoolBinary(resultLoc, src1Loc, src2Loc, op, pyPattern, constLambda):
    if resultLoc.getType().isUnknown():
        resultLoc = resultLoc.removeUnknown(src1Loc.getType())
    if resultLoc.getType() != src1Loc.getType():
        raise SemanticError(resultLoc.getPosition(),
            "Incompatible result and source types: {} and {}".format(resultLoc.getType(), src1Loc.getType()))
    if src1Loc.getType() != src2Loc.getType():
        raise SemanticError(src1Loc.getPosition() - src2Loc.getPosition(),
            "Incompatible source types: {} and {}".format(src1Loc.getType(), src2Loc.getType()))
    if src1Loc.getType() != BoolType():
        raise SemanticError(src1Loc.getPosition(),
            "Bool type (u8) expected")
    assert(resultLoc.getIndirLevel() == 1)
    rs = resultLoc.getSource()
    s1 = src1Loc.getSource()
    s2 = src2Loc.getSource()
    l1 = src1Loc.getIndirLevel()
    l2 = src2Loc.getIndirLevel()
    result = '; {} = bool {} {}, {}\n'.format(resultLoc, op, src1Loc, src2Loc)
    pos = src1Loc.getPosition() - src2Loc.getPosition()
    if l1 == 0 and l2 == 0:
        # const and const
        if s1.isNumber() and s2.isNumber():
            return Value(pos, BoolType(), 0, int(constLambda(bool(s1), bool(s2))), True), result
        else:
            return Value(pos, BoolType(), 0, pyPattern.format(s1, s2), True), result
    elif l1 == 0 or l2 == 0:
        # var and const
        if l1 == 0:
            s1, s2 = s2, s1
            src1Loc, src2Loc = src2Loc, src1Loc
        if s2.isNumber():
            s2 = bool(s2)
            if op == 'or':
                if not s2:
                    return src1Loc, ""
                else:
                    return Value(pos, BoolType(), 0, 1, True), ""
            elif op == 'and':
                if not s2:
                    return Value(pos, BoolType(), 0, 0, True), ""
                else:
                    return src1Loc, result
            else:
                raise RuntimeError("Unhandled binary boolean op: {}".format(op))
        else:
            result += loadByte('a', src1Loc, 0)
            result += f'''
                dec a
                ldi a, 1
                sbb a, 0
                ldi b, int(bool({s2}))
                {op} a, b
            '''
    else:
        # var and var
        assert(not s1.isRegister() or not s2.isRegister())
        if s2.isRegister():
            s1, s2 = s2, s1
            src1Loc, src2Loc = src2Loc, src1Loc
        result += loadByte('a', src1Loc, 0)
        result += f'''
            dec a
            ldi a, 1
            sbb a, 0
            mov b, a
        '''
        result += loadByte('a', src2Loc, 0)
        result += f'''
            dec a
            ldi a, 1
            sbb a, 0
            {op} a, b
        '''
    return Value.register(src1Loc.getPosition() - src2Loc.getPosition(), BoolType()), result