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
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
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