def test_optimize_single_block(): slot1 = pt.ScratchSlot(1) slot2 = pt.ScratchSlot(2) # empty check empty_block = pt.TealSimpleBlock([]) _apply_slot_to_stack(empty_block, empty_block, {}) expected = pt.TealSimpleBlock([]) assert empty_block == expected # basic optimization block = pt.TealSimpleBlock([ pt.TealOp(None, pt.Op.store, slot1), pt.TealOp(None, pt.Op.load, slot1), ]) _apply_slot_to_stack(block, block, {}) expected = pt.TealSimpleBlock([]) assert block == expected # iterate optimization block = pt.TealSimpleBlock([ pt.TealOp(None, pt.Op.store, slot1), pt.TealOp(None, pt.Op.store, slot2), pt.TealOp(None, pt.Op.load, slot2), pt.TealOp(None, pt.Op.load, slot1), ]) _apply_slot_to_stack(block, block, {}) expected = pt.TealSimpleBlock([ pt.TealOp(None, pt.Op.store, slot1), pt.TealOp(None, pt.Op.load, slot1), ]) assert block == expected _apply_slot_to_stack(block, block, {}) expected = pt.TealSimpleBlock([]) assert block == expected # remove extraneous stores block = pt.TealSimpleBlock([ pt.TealOp(None, pt.Op.store, slot1), pt.TealOp(None, pt.Op.load, slot1), pt.TealOp(None, pt.Op.store, slot1), ]) _apply_slot_to_stack(block, block, {}) expected = pt.TealSimpleBlock([]) assert block == expected
def test_GetReferencedScratchSlots(): a = pt.ScratchSlot() b = pt.ScratchSlot() c = pt.ScratchSlot() d = pt.ScratchSlot() end = pt.TealSimpleBlock([pt.TealOp(None, pt.Op.load, d)]) trueBranch = pt.TealSimpleBlock([pt.TealOp(None, pt.Op.load, b)]) trueBranch.setNextBlock(end) falseBranch = pt.TealSimpleBlock([pt.TealOp(None, pt.Op.load, c)]) falseBranch.setNextBlock(end) splitBranch = pt.TealConditionalBlock([pt.TealOp(None, pt.Op.load, a)]) splitBranch.setTrueBlock(trueBranch) splitBranch.setFalseBlock(falseBranch) slotReferences = pt.TealBlock.GetReferencedScratchSlots(splitBranch) assert slotReferences == [a, b, c, d]
def test_scratch_load_default(): slot = pt.ScratchSlot() expr = pt.ScratchLoad(slot) assert expr.type_of() == pt.TealType.anytype expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.load, slot)]) actual, _ = expr.__teal__(options) assert actual == expected
def test_scratch_assign_id(): slot = pt.ScratchSlot(255) expr = pt.ScratchStackStore(slot) assert expr.type_of() == pt.TealType.none expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.store, slot)]) actual, _ = expr.__teal__(options) assert actual == expected
def test_scratch_load_type(): for type in (pt.TealType.uint64, pt.TealType.bytes, pt.TealType.anytype): slot = pt.ScratchSlot() expr = pt.ScratchLoad(slot, type) assert expr.type_of() == type expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.load, slot)]) actual, _ = expr.__teal__(options) assert actual == expected
def test_scratch_slot(): slot = pt.ScratchSlot() assert slot == slot assert slot.__hash__() == slot.__hash__() assert slot != pt.ScratchSlot() with pt.TealComponent.Context.ignoreExprEquality(): assert ( slot.store().__teal__(options)[0] == pt.ScratchStackStore(slot).__teal__(options)[0] ) assert ( slot.store(pt.Int(1)).__teal__(options)[0] == pt.ScratchStore(slot, pt.Int(1)).__teal__(options)[0] ) assert slot.load().type_of() == pt.TealType.anytype assert slot.load(pt.TealType.uint64).type_of() == pt.TealType.uint64 assert ( slot.load().__teal__(options)[0] == pt.ScratchLoad(slot).__teal__(options)[0] )
def test_assignScratchSlotsToSubroutines_slot_used_before_assignment(): def sub1Impl(): return None def sub2Impl(a1): return None def sub3Impl(a1, a2, a3): return None subroutine1 = pt.SubroutineDefinition(sub1Impl, pt.TealType.uint64) subroutine2 = pt.SubroutineDefinition(sub2Impl, pt.TealType.bytes) subroutine3 = pt.SubroutineDefinition(sub3Impl, pt.TealType.none) globalSlot1 = pt.ScratchSlot() subroutine1Slot1 = pt.ScratchSlot() subroutine1Slot2 = pt.ScratchSlot() subroutine1Ops = [ pt.TealOp(None, pt.Op.int, 1), pt.TealOp(None, pt.Op.store, subroutine1Slot1), pt.TealOp(None, pt.Op.int, 3), pt.TealOp(None, pt.Op.store, subroutine1Slot2), pt.TealOp(None, pt.Op.load, globalSlot1), pt.TealOp(None, pt.Op.retsub), ] subroutine2Slot1 = pt.ScratchSlot() subroutine2Ops = [ pt.TealOp(None, pt.Op.byte, '"value"'), pt.TealOp(None, pt.Op.store, subroutine2Slot1), pt.TealOp(None, pt.Op.load, subroutine2Slot1), pt.TealOp(None, pt.Op.retsub), ] subroutine3Ops = [ pt.TealOp(None, pt.Op.retsub), ] mainSlot1 = pt.ScratchSlot() mainSlot2 = pt.ScratchSlot() mainOps = [ pt.TealOp(None, pt.Op.int, 7), pt.TealOp(None, pt.Op.store, globalSlot1), pt.TealOp(None, pt.Op.int, 2), pt.TealOp(None, pt.Op.store, mainSlot2), pt.TealOp(None, pt.Op.load, mainSlot1), pt.TealOp(None, pt.Op.return_), ] subroutineBlocks = { None: pt.TealSimpleBlock(mainOps), subroutine1: pt.TealSimpleBlock(subroutine1Ops), subroutine2: pt.TealSimpleBlock(subroutine2Ops), subroutine3: pt.TealSimpleBlock(subroutine3Ops), } with pytest.raises(pt.TealInternalError): assignScratchSlotsToSubroutines(subroutineBlocks)
def test_scratch_index(): slot = pt.ScratchSlot() index = pt.ScratchIndex(slot) assert index.slot is slot assert str(index) == "(ScratchIndex " + str(slot) + ")" assert index.type_of() == pt.TealType.uint64 assert not index.has_return() expected = pt.TealSimpleBlock([pt.TealOp(index, pt.Op.int, slot)]) actual, _ = index.__teal__(options) assert actual == expected
def test_scratch_store(): for value in ( pt.Int(1), pt.Bytes("test"), pt.App.globalGet(pt.Bytes("key")), pt.If(pt.Int(1), pt.Int(2), pt.Int(3)), ): slot = pt.ScratchSlot() expr = pt.ScratchStore(slot, value) assert expr.type_of() == pt.TealType.none expected, valueEnd = value.__teal__(options) storeBlock = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.store, slot)]) valueEnd.setNextBlock(storeBlock) actual, _ = expr.__teal__(options) assert actual == expected
def test_scratch_assign_id_invalid(): with pytest.raises(pt.TealInputError): pt.ScratchSlot(-1) with pytest.raises(pt.TealInputError): pt.ScratchSlot(pt.NUM_SLOTS)
def test_MatchScratchSlotReferences(): class MatchSlotReferenceTest(NamedTuple): actual: List[pt.ScratchSlot] expected: List[pt.ScratchSlot] match: bool a = pt.ScratchSlot() b = pt.ScratchSlot() c = pt.ScratchSlot() d = pt.ScratchSlot() tests: List[MatchSlotReferenceTest] = [ MatchSlotReferenceTest( actual=[], expected=[], match=True, ), MatchSlotReferenceTest( actual=[a], expected=[], match=False, ), MatchSlotReferenceTest( actual=[a], expected=[a], match=True, ), MatchSlotReferenceTest( actual=[a], expected=[b], match=True, ), MatchSlotReferenceTest( actual=[a, a], expected=[a, a], match=True, ), MatchSlotReferenceTest( actual=[a, a], expected=[b, b], match=True, ), MatchSlotReferenceTest( actual=[a, b], expected=[a, b], match=True, ), MatchSlotReferenceTest( actual=[a, b], expected=[b, c], match=False, ), MatchSlotReferenceTest( actual=[a, b], expected=[c, d], match=True, ), MatchSlotReferenceTest( actual=[a, b, b, a, b], expected=[c, d, d, c, d], match=True, ), MatchSlotReferenceTest( actual=[a, b, b, a, b], expected=[a, d, d, a, d], match=True, ), MatchSlotReferenceTest( actual=[a, b, b, a, b], expected=[c, a, a, c, a], match=False, ), MatchSlotReferenceTest( actual=[a, b, b, a, b], expected=[c, d, d, c, c], match=False, ), ] for i, test in enumerate(tests): assert (pt.TealBlock.MatchScratchSlotReferences( test.actual, test.expected) == test.match), "Test at index {} failed".format(i)
def test_assignScratchSlotsToSubroutines_no_requested_ids(): def sub1Impl(): return None def sub2Impl(a1): return None def sub3Impl(a1, a2, a3): return None subroutine1 = pt.SubroutineDefinition(sub1Impl, pt.TealType.uint64) subroutine2 = pt.SubroutineDefinition(sub2Impl, pt.TealType.bytes) subroutine3 = pt.SubroutineDefinition(sub3Impl, pt.TealType.none) globalSlot1 = pt.ScratchSlot() subroutine1Slot1 = pt.ScratchSlot() subroutine1Slot2 = pt.ScratchSlot() subroutine1Ops = [ pt.TealOp(None, pt.Op.int, 1), pt.TealOp(None, pt.Op.store, subroutine1Slot1), pt.TealOp(None, pt.Op.int, 3), pt.TealOp(None, pt.Op.store, subroutine1Slot2), pt.TealOp(None, pt.Op.load, globalSlot1), pt.TealOp(None, pt.Op.retsub), ] subroutine2Slot1 = pt.ScratchSlot() subroutine2Ops = [ pt.TealOp(None, pt.Op.byte, '"value"'), pt.TealOp(None, pt.Op.store, subroutine2Slot1), pt.TealOp(None, pt.Op.load, subroutine2Slot1), pt.TealOp(None, pt.Op.retsub), ] subroutine3Ops = [ pt.TealOp(None, pt.Op.retsub), ] mainSlot1 = pt.ScratchSlot() mainSlot2 = pt.ScratchSlot() mainOps = [ pt.TealOp(None, pt.Op.int, 7), pt.TealOp(None, pt.Op.store, globalSlot1), pt.TealOp(None, pt.Op.int, 1), pt.TealOp(None, pt.Op.store, mainSlot1), pt.TealOp(None, pt.Op.int, 2), pt.TealOp(None, pt.Op.store, mainSlot2), pt.TealOp(None, pt.Op.load, mainSlot1), pt.TealOp(None, pt.Op.return_), ] subroutineBlocks = { None: pt.TealSimpleBlock(mainOps), subroutine1: pt.TealSimpleBlock(subroutine1Ops), subroutine2: pt.TealSimpleBlock(subroutine2Ops), subroutine3: pt.TealSimpleBlock(subroutine3Ops), } expectedAssignments = { globalSlot1: 0, subroutine1Slot1: 1, subroutine1Slot2: 2, subroutine2Slot1: 3, mainSlot1: 4, mainSlot2: 5, } expected = { None: {expectedAssignments[mainSlot1], expectedAssignments[mainSlot2]}, subroutine1: { expectedAssignments[subroutine1Slot1], expectedAssignments[subroutine1Slot2], }, subroutine2: {expectedAssignments[subroutine2Slot1]}, subroutine3: set(), } actual = assignScratchSlotsToSubroutines(subroutineBlocks) assert actual == expected assert subroutine1Ops == [ pt.TealOp(None, pt.Op.int, 1), pt.TealOp(None, pt.Op.store, expectedAssignments[subroutine1Slot1]), pt.TealOp(None, pt.Op.int, 3), pt.TealOp(None, pt.Op.store, expectedAssignments[subroutine1Slot2]), pt.TealOp(None, pt.Op.load, expectedAssignments[globalSlot1]), pt.TealOp(None, pt.Op.retsub), ] assert subroutine2Ops == [ pt.TealOp(None, pt.Op.byte, '"value"'), pt.TealOp(None, pt.Op.store, expectedAssignments[subroutine2Slot1]), pt.TealOp(None, pt.Op.load, expectedAssignments[subroutine2Slot1]), pt.TealOp(None, pt.Op.retsub), ] assert subroutine3Ops == [ pt.TealOp(None, pt.Op.retsub), ] assert mainOps == [ pt.TealOp(None, pt.Op.int, 7), pt.TealOp(None, pt.Op.store, expectedAssignments[globalSlot1]), pt.TealOp(None, pt.Op.int, 1), pt.TealOp(None, pt.Op.store, expectedAssignments[mainSlot1]), pt.TealOp(None, pt.Op.int, 2), pt.TealOp(None, pt.Op.store, expectedAssignments[mainSlot2]), pt.TealOp(None, pt.Op.load, expectedAssignments[mainSlot1]), pt.TealOp(None, pt.Op.return_), ]
def test_assignScratchSlotsToSubroutines_invalid_requested_id(): def sub1Impl(): return None def sub2Impl(a1): return None def sub3Impl(a1, a2, a3): return None subroutine1 = pt.SubroutineDefinition(sub1Impl, pt.TealType.uint64) subroutine2 = pt.SubroutineDefinition(sub2Impl, pt.TealType.bytes) subroutine3 = pt.SubroutineDefinition(sub3Impl, pt.TealType.none) globalSlot1 = pt.ScratchSlot(requestedSlotId=8) subroutine1Slot1 = pt.ScratchSlot() subroutine1Slot2 = pt.ScratchSlot(requestedSlotId=5) subroutine1Ops = [ pt.TealOp(None, pt.Op.int, 1), pt.TealOp(None, pt.Op.store, subroutine1Slot1), pt.TealOp(None, pt.Op.int, 3), pt.TealOp(None, pt.Op.store, subroutine1Slot2), pt.TealOp(None, pt.Op.load, globalSlot1), pt.TealOp(None, pt.Op.retsub), ] subroutine2Slot1 = pt.ScratchSlot(requestedSlotId=100) subroutine2Ops = [ pt.TealOp(None, pt.Op.byte, '"value"'), pt.TealOp(None, pt.Op.store, subroutine2Slot1), pt.TealOp(None, pt.Op.load, subroutine2Slot1), pt.TealOp(None, pt.Op.retsub), ] subroutine3Ops = [ pt.TealOp(None, pt.Op.retsub), ] mainSlot1 = pt.ScratchSlot() mainSlot2 = pt.ScratchSlot(requestedSlotId=100) mainOps = [ pt.TealOp(None, pt.Op.int, 7), pt.TealOp(None, pt.Op.store, globalSlot1), pt.TealOp(None, pt.Op.int, 1), pt.TealOp(None, pt.Op.store, mainSlot1), pt.TealOp(None, pt.Op.int, 2), pt.TealOp(None, pt.Op.store, mainSlot2), pt.TealOp(None, pt.Op.load, mainSlot1), pt.TealOp(None, pt.Op.return_), ] subroutineBlocks = { None: pt.TealSimpleBlock(mainOps), subroutine1: pt.TealSimpleBlock(subroutine1Ops), subroutine2: pt.TealSimpleBlock(subroutine2Ops), subroutine3: pt.TealSimpleBlock(subroutine3Ops), } # mainSlot2 and subroutine2Slot1 request the same ID, 100 with pytest.raises(pt.TealInternalError): assignScratchSlotsToSubroutines(subroutineBlocks)
def test_collectScratchSlots(): def sub1Impl(): return None def sub2Impl(a1): return None def sub3Impl(a1, a2, a3): return None subroutine1 = pt.SubroutineDefinition(sub1Impl, pt.TealType.uint64) subroutine2 = pt.SubroutineDefinition(sub2Impl, pt.TealType.bytes) subroutine3 = pt.SubroutineDefinition(sub3Impl, pt.TealType.none) globalSlot1 = pt.ScratchSlot() subroutine1Slot1 = pt.ScratchSlot() subroutine1Slot2 = pt.ScratchSlot() subroutine1Ops = [ pt.TealOp(None, pt.Op.int, 1), pt.TealOp(None, pt.Op.store, subroutine1Slot1), pt.TealOp(None, pt.Op.int, 3), pt.TealOp(None, pt.Op.store, subroutine1Slot2), pt.TealOp(None, pt.Op.load, globalSlot1), pt.TealOp(None, pt.Op.retsub), ] subroutine2Slot1 = pt.ScratchSlot() subroutine2Ops = [ pt.TealOp(None, pt.Op.byte, '"value"'), pt.TealOp(None, pt.Op.store, subroutine2Slot1), pt.TealOp(None, pt.Op.load, subroutine2Slot1), pt.TealOp(None, pt.Op.retsub), ] subroutine3Ops = [ pt.TealOp(None, pt.Op.retsub), ] mainSlot1 = pt.ScratchSlot() mainSlot2 = pt.ScratchSlot() mainOps = [ pt.TealOp(None, pt.Op.int, 7), pt.TealOp(None, pt.Op.store, globalSlot1), pt.TealOp(None, pt.Op.int, 1), pt.TealOp(None, pt.Op.store, mainSlot1), pt.TealOp(None, pt.Op.int, 2), pt.TealOp(None, pt.Op.store, mainSlot2), pt.TealOp(None, pt.Op.load, mainSlot1), pt.TealOp(None, pt.Op.return_), ] subroutineBlocks = { None: pt.TealSimpleBlock(mainOps), subroutine1: pt.TealSimpleBlock(subroutine1Ops), subroutine2: pt.TealSimpleBlock(subroutine2Ops), subroutine3: pt.TealSimpleBlock(subroutine3Ops), } expected_global = {globalSlot1} expected_local = { None: {mainSlot1, mainSlot2}, subroutine1: {subroutine1Slot1, subroutine1Slot2}, subroutine2: {subroutine2Slot1}, subroutine3: set(), } actual_global, actual_local = collectScratchSlots(subroutineBlocks) assert actual_global == expected_global assert actual_local == expected_local