Skip to content

Commit

Permalink
AVM: Deadcode and basic block analysis (#3870)
Browse files Browse the repository at this point in the history
* Simplify assembly and add flexible opcode cost support

Unify most assembly routines to minimize difference and ease doc gen
Flexible opcode costs and fewer assembly routines

* Mark exiting opcodes

* Tracks types more accurately during assembly

Ignores deadcode.
Understands how jumps obscure typing info.
Detects error within basic blocks
Adds #pragma typetrack false
Makes spec creation a bit more uniform

* CR cleanup

* Retain type tracking state during consecutive type tracking enablements

* ensure type tracking continues after callsub

* Centralize OpStream initialization by introducing factory method

* Update missed references

* Remove redundant initialization

* CR updates

* Simplify the representation of deadcode in Programknowledge

* Update data/transactions/logic/assembler.go

Co-authored-by: Michael Diamant <[email protected]>

Co-authored-by: michaeldiamant <[email protected]>
  • Loading branch information
jannotti and michaeldiamant authored Apr 20, 2022
1 parent 07b2fbb commit 3dd1b6f
Show file tree
Hide file tree
Showing 17 changed files with 862 additions and 605 deletions.
56 changes: 32 additions & 24 deletions cmd/opdoc/opdoc.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,38 +122,46 @@ func fieldGroupMarkdown(out io.Writer, group *logic.FieldGroup) {

func immediateMarkdown(op *logic.OpSpec) string {
markdown := ""
for _, imm := range op.Details.Immediates {
for _, imm := range op.OpDetails.Immediates {
markdown = markdown + " " + imm.Name
}
return markdown
}

func stackMarkdown(op *logic.OpSpec) string {
out := "- Stack: "
special := logic.OpStackEffects(op.Name)
if special != "" {
return out + special + "\n"
}

out += "..."
for i, v := range op.Args {
out += fmt.Sprintf(", %c", rune(int('A')+i))
if v.Typed() {
out += fmt.Sprintf(": %s", v)
if op.Arg.Effects != "" {
out += ", " + op.Arg.Effects
} else {
for i, v := range op.Arg.Types {
out += fmt.Sprintf(", %c", rune(int('A')+i))
if v.Typed() {
out += fmt.Sprintf(": %s", v)
}
}
}
out += " &rarr; ..."

for i, rt := range op.Returns {
out += ", "
if len(op.Returns) > 1 {
start := int('X')
if len(op.Returns) > 3 {
start = int('Z') + 1 - len(op.Returns)
if op.AlwaysExits() {
return out + " &rarr; _exits_\n"
}

out += " &rarr; ..."
if op.Return.Effects != "" {
out += ", " + op.Return.Effects
} else {
for i, rt := range op.Return.Types {
out += ", "
if len(op.Return.Types) > 1 {
start := int('X')
if len(op.Return.Types) > 3 {
start = int('Z') + 1 - len(op.Return.Types)
}
out += fmt.Sprintf("%c: ", rune(start+i))
}
out += fmt.Sprintf("%c: ", rune(start+i))
out += rt.String()
}
out += rt.String()
}
return out + "\n"
}
Expand Down Expand Up @@ -196,8 +204,8 @@ func opToMarkdown(out io.Writer, op *logic.OpSpec, groupDocWritten map[string]bo
fmt.Fprintf(out, "- Mode: %s\n", op.Modes)
}

for i := range op.Details.Immediates {
group := op.Details.Immediates[i].Group
for i := range op.OpDetails.Immediates {
group := op.OpDetails.Immediates[i].Group
if group != nil && group.Doc != "" && !groupDocWritten[group.Name] {
fmt.Fprintf(out, "\n`%s` %s:\n\n", group.Name, group.Doc)
fieldGroupMarkdown(out, group)
Expand Down Expand Up @@ -314,9 +322,9 @@ func buildLanguageSpec(opGroups map[string][]string) *LanguageSpec {
for i, spec := range opSpecs {
records[i].Opcode = spec.Opcode
records[i].Name = spec.Name
records[i].Args = typeString(spec.Args)
records[i].Returns = typeString(spec.Returns)
records[i].Size = spec.Details.Size
records[i].Args = typeString(spec.Arg.Types)
records[i].Returns = typeString(spec.Return.Types)
records[i].Size = spec.OpDetails.Size
records[i].ArgEnum, records[i].ArgEnumTypes = argEnums(spec.Name)
records[i].Doc = logic.OpDoc(spec.Name)
records[i].DocExtra = logic.OpDocExtra(spec.Name)
Expand Down Expand Up @@ -361,7 +369,7 @@ func main() {
written := make(map[string]bool)
opSpecs := logic.OpcodesByVersion(logic.LogicVersion)
for _, spec := range opSpecs {
for _, imm := range spec.Details.Immediates {
for _, imm := range spec.OpDetails.Immediates {
if imm.Group != nil && !written[imm.Group.Name] {
out := create(strings.ToLower(imm.Group.Name) + "_fields.md")
fieldGroupMarkdown(out, imm.Group)
Expand Down
2 changes: 1 addition & 1 deletion cmd/opdoc/tmLanguage.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func buildSyntaxHighlight() *tmLanguage {
accumulated := make(map[string]bool)
opSpecs := logic.OpcodesByVersion(logic.LogicVersion)
for _, spec := range opSpecs {
for _, imm := range spec.Details.Immediates {
for _, imm := range spec.OpDetails.Immediates {
if imm.Group != nil && !accumulated[imm.Group.Name] {
allNamedFields = append(allNamedFields, imm.Group.Names...)
accumulated[imm.Group.Name] = true
Expand Down
6 changes: 3 additions & 3 deletions data/transactions/logic/TEAL_opcodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Ops have a 'cost' of 1 unless otherwise specified.
## err

- Opcode: 0x00
- Stack: ... &rarr; ...
- Stack: ... &rarr; _exits_
- Fail immediately.

## sha256
Expand Down Expand Up @@ -591,7 +591,7 @@ See `bnz` for details on how branches work. `b` always jumps to the offset.
## return

- Opcode: 0x43
- Stack: ..., A: uint64 &rarr; ...
- Stack: ..., A: uint64 &rarr; _exits_
- use A as success value; end
- Availability: v2

Expand Down Expand Up @@ -638,7 +638,7 @@ See `bnz` for details on how branches work. `b` always jumps to the offset.
## select

- Opcode: 0x4d
- Stack: ..., A, B, C &rarr; ..., A or B
- Stack: ..., A, B, C: uint64 &rarr; ..., A or B
- selects one of two values based on top-of-stack: B if C != 0, else A
- Availability: v3

Expand Down
Loading

0 comments on commit 3dd1b6f

Please sign in to comment.