Skip to content

Commit

Permalink
Optimization for constant assembly (#128)
Browse files Browse the repository at this point in the history
* Optimization added for repeated int constants under 2**7 w/ tests

* fixed type problem and formatted

* Expanded test and added comment for clarification
  • Loading branch information
algoidurovic authored Oct 15, 2021
1 parent 7cb7b9a commit 5636ccd
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 3 deletions.
13 changes: 10 additions & 3 deletions pyteal/compiler/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,14 @@ def createConstantBlocks(ops: List[TealComponent]) -> List[TealComponent]:
sortedInts = sorted(intFreqs, key=lambda x: intFreqs[x], reverse=True)
sortedBytes = sorted(byteFreqs, key=lambda x: byteFreqs[x], reverse=True)

intBlock = [i for i in sortedInts if intFreqs[i] > 1]
# Use Op.pushint if the constant does not occur in the top 4 most frequent and is smaller than
# 2 ** 7 to improve performance and save block space.
intBlock = [
val
for i, val in enumerate(sortedInts)
if intFreqs[val] > 1 and (i < 4 or isinstance(val, str) or val >= 2 ** 7)
]

byteBlock = [
("0x" + b.hex()) if type(b) is bytes else cast(str, b)
for b in sortedBytes
Expand All @@ -151,13 +158,13 @@ def createConstantBlocks(ops: List[TealComponent]) -> List[TealComponent]:

if basicOp == Op.int:
intValue = extractIntValue(op)
if intFreqs[intValue] == 1:
if intValue not in intBlock:
assembled.append(
TealOp(op.expr, Op.pushint, intValue, "//", *op.args)
)
continue

index = sortedInts.index(intValue)
index = intBlock.index(intValue)
if index == 0:
assembled.append(TealOp(op.expr, Op.intc_0, "//", *op.args))
elif index == 1:
Expand Down
74 changes: 74 additions & 0 deletions pyteal/compiler/constants_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -545,3 +545,77 @@ def test_createConstantBlocks_tmpl_all():

actual = createConstantBlocks(ops)
assert actual == expected


def test_createConstantBlocks_intc():
"""Test scenario where there are more than 4 constants in the intcblock.
If the 4th constant can't fit in one varuint byte (more than 2**7) it
should be referenced with the Op.intc 4 command.
"""

ops = [
TealOp(None, Op.int, 0),
TealOp(None, Op.int, 0),
TealOp(None, Op.int, 1),
TealOp(None, Op.int, 1),
TealOp(None, Op.int, 2),
TealOp(None, Op.int, 2),
TealOp(None, Op.int, 3),
TealOp(None, Op.int, 3),
TealOp(None, Op.int, 2 ** 7),
TealOp(None, Op.int, 2 ** 7),
]

expected = [
TealOp(None, Op.intcblock, 0, 1, 2, 3, 2 ** 7),
TealOp(None, Op.intc_0, "//", 0),
TealOp(None, Op.intc_0, "//", 0),
TealOp(None, Op.intc_1, "//", 1),
TealOp(None, Op.intc_1, "//", 1),
TealOp(None, Op.intc_2, "//", 2),
TealOp(None, Op.intc_2, "//", 2),
TealOp(None, Op.intc_3, "//", 3),
TealOp(None, Op.intc_3, "//", 3),
TealOp(None, Op.intc, 4, "//", 2 ** 7),
TealOp(None, Op.intc, 4, "//", 2 ** 7),
]

actual = createConstantBlocks(ops)
assert actual == expected


def test_createConstantBlocks_small_constant():
"""If a constant cannot be referenced using the intc_[0..3] commands
and it can be stored in one varuint it byte then Op.pushint is used.
"""

for cur in range(4, 2 ** 7):
ops = [
TealOp(None, Op.int, 0),
TealOp(None, Op.int, 0),
TealOp(None, Op.int, 1),
TealOp(None, Op.int, 1),
TealOp(None, Op.int, 2),
TealOp(None, Op.int, 2),
TealOp(None, Op.int, 3),
TealOp(None, Op.int, 3),
TealOp(None, Op.int, cur),
TealOp(None, Op.int, cur),
]

expected = [
TealOp(None, Op.intcblock, 0, 1, 2, 3),
TealOp(None, Op.intc_0, "//", 0),
TealOp(None, Op.intc_0, "//", 0),
TealOp(None, Op.intc_1, "//", 1),
TealOp(None, Op.intc_1, "//", 1),
TealOp(None, Op.intc_2, "//", 2),
TealOp(None, Op.intc_2, "//", 2),
TealOp(None, Op.intc_3, "//", 3),
TealOp(None, Op.intc_3, "//", 3),
TealOp(None, Op.pushint, cur, "//", cur),
TealOp(None, Op.pushint, cur, "//", cur),
]

actual = createConstantBlocks(ops)
assert actual == expected

0 comments on commit 5636ccd

Please sign in to comment.