From 6a7d3decbe08be8f4f105e514456d764f93afc5c Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Wed, 27 Oct 2021 01:18:49 -0700 Subject: [PATCH] cmd/addchain: templated output generation (#127) Provides support for templated output based on addition chain programs. The new `addchain gen` subcommand allows for templated output, including some built-in templates. The new feature has full documentation, auto-generated as usual to keep in sync: * Full working example of fp25519 inversion * Template input data and functions * Example output for all builtin templates Fixes #94 --- .golangci.yml | 1 + README.md | 7 +- acc/printer/printer.go | 9 + cmd/addchain/gen.go | 118 +++ cmd/addchain/main.go | 1 + doc/gen.md | 989 ++++++++++++++++++ internal/cli/util.go | 16 + internal/examples/fp25519/00-search.out | 5 + internal/examples/fp25519/00-search.sh | 1 + internal/examples/fp25519/01-listing.out | 25 + internal/examples/fp25519/01-listing.sh | 1 + internal/examples/fp25519/02-generate.out | 0 internal/examples/fp25519/02-generate.sh | 1 + internal/examples/fp25519/fp.go | 37 + internal/examples/fp25519/fp_test.go | 31 + internal/examples/fp25519/inv.acc | 14 + internal/examples/fp25519/inv.go | 136 +++ internal/examples/fp25519/inv.tmpl | 46 + .../examples/{cli/output => search/cmd.out} | 0 internal/examples/{cli => search}/cmd.sh | 0 internal/gen/functions.go | 88 ++ internal/gen/functions_test.go | 26 + internal/gen/gen.go | 90 ++ internal/gen/gen_test.go | 76 ++ internal/gen/templates.go | 53 + internal/gen/templates/chain.tmpl | 3 + internal/gen/templates/listing.tmpl | 16 + internal/gen/templates/ops.tmpl | 3 + internal/gen/templates/script.tmpl | 1 + internal/gen/testdata/builtin/chain.golden | 267 +++++ internal/gen/testdata/builtin/listing.golden | 25 + internal/gen/testdata/builtin/ops.golden | 266 +++++ internal/gen/testdata/builtin/script.golden | 14 + internal/gen/testdata/input.acc | 14 + internal/tools/docgen/main.go | 60 +- internal/tools/docgen/templates/gen.tmpl | 106 ++ internal/tools/docgen/templates/readme.tmpl | 13 +- script/generate | 23 +- 38 files changed, 2550 insertions(+), 32 deletions(-) create mode 100644 cmd/addchain/gen.go create mode 100644 doc/gen.md create mode 100644 internal/examples/fp25519/00-search.out create mode 100644 internal/examples/fp25519/00-search.sh create mode 100644 internal/examples/fp25519/01-listing.out create mode 100644 internal/examples/fp25519/01-listing.sh create mode 100644 internal/examples/fp25519/02-generate.out create mode 100644 internal/examples/fp25519/02-generate.sh create mode 100644 internal/examples/fp25519/fp.go create mode 100644 internal/examples/fp25519/fp_test.go create mode 100644 internal/examples/fp25519/inv.acc create mode 100644 internal/examples/fp25519/inv.go create mode 100644 internal/examples/fp25519/inv.tmpl rename internal/examples/{cli/output => search/cmd.out} (100%) rename internal/examples/{cli => search}/cmd.sh (100%) create mode 100644 internal/gen/functions.go create mode 100644 internal/gen/functions_test.go create mode 100644 internal/gen/gen.go create mode 100644 internal/gen/gen_test.go create mode 100644 internal/gen/templates.go create mode 100644 internal/gen/templates/chain.tmpl create mode 100644 internal/gen/templates/listing.tmpl create mode 100644 internal/gen/templates/ops.tmpl create mode 100644 internal/gen/templates/script.tmpl create mode 100644 internal/gen/testdata/builtin/chain.golden create mode 100644 internal/gen/testdata/builtin/listing.golden create mode 100644 internal/gen/testdata/builtin/ops.golden create mode 100644 internal/gen/testdata/builtin/script.golden create mode 100644 internal/gen/testdata/input.acc create mode 100644 internal/tools/docgen/templates/gen.tmpl diff --git a/.golangci.yml b/.golangci.yml index 65473a4..1a654ae 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -15,6 +15,7 @@ linters: - maligned - nlreturn - paralleltest + - prealloc - predeclared - revive - testpackage diff --git a/README.md b/README.md index efc3866..ad2987c 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ generators. * Generic optimization methods eliminate redundant operations * Simple domain-specific language for addition chain computations * Command-line interface or library +* Code generation and templated output support ## Table of Contents @@ -106,8 +107,8 @@ delta from the library result. | [secp256k1 (Bitcoin) Scalar Inversion](doc/results.md#secp256k1-bitcoin-scalar-inversion) | 293 | 290 | +3 | -See [full results listing](doc/results.md) for more detail and results for -less common exponents. +See [full results listing](doc/results.md) for more detail and +results for less common exponents. These results demonstrate that `addchain` is competitive with hand-optimized chains, often with equivalent or better performance. Even when `addchain` is @@ -162,6 +163,8 @@ x250 = x240 << 10 + x10 return (x250 << 2 + 1) << 3 + _11 ``` +Next, you can [generate code from this addition chain](doc/gen.md). + ### Library Install: diff --git a/acc/printer/printer.go b/acc/printer/printer.go index 97f6534..96e8baa 100644 --- a/acc/printer/printer.go +++ b/acc/printer/printer.go @@ -11,6 +11,15 @@ import ( "github.com/mmcloughlin/addchain/internal/print" ) +// String prints the AST and returns resulting string. +func String(n interface{}) (string, error) { + b, err := Bytes(n) + if err != nil { + return "", err + } + return string(b), nil +} + // Bytes prints the AST and returns resulting bytes. func Bytes(n interface{}) ([]byte, error) { var buf bytes.Buffer diff --git a/cmd/addchain/gen.go b/cmd/addchain/gen.go new file mode 100644 index 0000000..6a026ad --- /dev/null +++ b/cmd/addchain/gen.go @@ -0,0 +1,118 @@ +package main + +import ( + "context" + "errors" + "flag" + "fmt" + "io/ioutil" + "strings" + + "github.com/google/subcommands" + + "github.com/mmcloughlin/addchain/acc/parse" + "github.com/mmcloughlin/addchain/acc/pass" + "github.com/mmcloughlin/addchain/internal/cli" + "github.com/mmcloughlin/addchain/internal/gen" +) + +// generate subcommand. +type generate struct { + cli.Command + + typ string + tmpl string + output string +} + +func (*generate) Name() string { return "gen" } +func (*generate) Synopsis() string { return "generate output from an addition chain program" } +func (*generate) Usage() string { + return `Usage: gen [-type ] [-tmpl ] [-out ] [] + +Generate output from an addition chain program. + +` +} + +func (cmd *generate) SetFlags(f *flag.FlagSet) { + defaulttype := "listing" + if !gen.IsBuiltinTemplate(defaulttype) { + panic("bad default template") + } + f.StringVar(&cmd.typ, "type", defaulttype, fmt.Sprintf("`name` of a builtin template (%s)", strings.Join(gen.BuiltinTemplateNames(), ","))) + f.StringVar(&cmd.tmpl, "tmpl", "", "template `file` (overrides type)") + f.StringVar(&cmd.output, "out", "", "output `file` (default stdout)") +} + +func (cmd *generate) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) (status subcommands.ExitStatus) { + // Read input. + input, r, err := cli.OpenInput(f.Arg(0)) + if err != nil { + return cmd.Error(err) + } + defer cmd.CheckClose(&status, r) + + // Parse to a syntax tree. + s, err := parse.Reader(input, r) + if err != nil { + return cmd.Error(err) + } + + // Prepare template data. + cfg := gen.Config{ + Allocator: pass.Allocator{ + Input: "x", + Output: "z", + Format: "t%d", + }, + } + + data, err := gen.PrepareData(cfg, s) + if err != nil { + return cmd.Error(err) + } + + // Load template. + tmpl, err := cmd.LoadTemplate() + if err != nil { + return cmd.Error(err) + } + + // Open output. + _, w, err := cli.OpenOutput(cmd.output) + if err != nil { + return cmd.Error(err) + } + defer cmd.CheckClose(&status, w) + + // Generate. + if err := gen.Generate(w, tmpl, data); err != nil { + return cmd.Error(err) + } + + return subcommands.ExitSuccess +} + +func (cmd *generate) LoadTemplate() (string, error) { + // Explicit filename has precedence. + if cmd.tmpl != "" { + b, err := ioutil.ReadFile(cmd.tmpl) + if err != nil { + return "", err + } + return string(b), nil + } + + // Lookup type name in builtin templates. + if cmd.typ == "" { + return "", errors.New("no builtin template specified") + } + + s, err := gen.BuiltinTemplate(cmd.typ) + if err != nil { + return "", err + } + + return s, nil +} diff --git a/cmd/addchain/main.go b/cmd/addchain/main.go index 9c97edd..3bb06c9 100644 --- a/cmd/addchain/main.go +++ b/cmd/addchain/main.go @@ -18,6 +18,7 @@ func main() { subcommands.Register(&search{Command: base}, "") subcommands.Register(&eval{Command: base}, "") subcommands.Register(&format{Command: base}, "") + subcommands.Register(&generate{Command: base}, "") if meta.Meta.BuildVersion != "" { subcommands.Register(&version{version: meta.Meta.BuildVersion, Command: base}, "") diff --git a/doc/gen.md b/doc/gen.md new file mode 100644 index 0000000..0e350b7 --- /dev/null +++ b/doc/gen.md @@ -0,0 +1,989 @@ +# Output Generation + +## Table of Contents + +* [Example](#example) +* [Template Reference](#template-reference) +* [Builtin Templates](#builtin-templates) + * [chain](#chain) + * [listing](#listing) + * [ops](#ops) + * [script](#script) + + +## Example + +Let's show an example of generating code for curve25519 field inversion. Search +for the best addition chain and save the result: + +```sh +addchain search '2^255 - 19 - 2' > inv.acc +``` + +Now we can use the `addchain` generate command to generate code to +execute the addition chain. By default, the generate command will show us a +concise listing of the instructions required to compute the addition chain. + +```sh +addchain gen inv.acc +``` +Output: +``` +tmp t0 t1 t2 +double z x +add z x z +shift t0 z 2 +add t0 z t0 +shift t1 t0 4 +add t0 t0 t1 +shift t0 t0 2 +add t0 z t0 +shift t1 t0 10 +add t1 t0 t1 +shift t1 t1 10 +add t1 t0 t1 +shift t2 t1 30 +add t1 t1 t2 +shift t2 t1 60 +add t1 t1 t2 +shift t2 t1 120 +add t1 t1 t2 +shift t1 t1 10 +add t0 t0 t1 +shift t0 t0 2 +add t0 x t0 +shift t0 t0 3 +add z z t0 +``` + +This listing is intended to be a simple text format that could directly be +turned into code. The directives mean: + +* `tmp v ...`: declare temporary variables `v ...` +* `add z x y`: execute addition `z = x+y` +* `double z x`: execute doubling `z = 2*x` +* `shift z x n`: execute repeated doubling z = 2n*x + +Under the hood, `addchain` has processed the addition chain into the [`ir.Program`](https://pkg.go.dev/github.com/mmcloughlin/addchain/acc/ir#Program) intermediate representation and used an allocation +pass to assign the minimum number of temporary variables. The listing format is +intended be a convient and easy-to-parse text format to use as input to other +tools. + +In addition, `addchain` also offers templated output. In fact, the +listing is actually produced by the [listing](#listing) builtin template. See +below for details of the [templating language](#template-reference) +and [builtin template examples](#builtin-templates). The following template +can be used to directly produce Go code to execute the inversion chain: + +``` +// Code generated by {{ .Meta.Name }}. DO NOT EDIT. + +package fp25519 + +// Inv computes z = 1/x (mod p) and returns it. +func (z *Elt) Inv(x *Elt) *Elt { + // Inversion computation is derived from the addition chain: + // + {{- range lines (format .Script) }} + // {{ . }} + {{- end }} + // + // Operations: {{ .Ops.Doubles }} squares {{ .Ops.Adds }} multiplies + // + // Generated by {{ .Meta.Module }} {{ .Meta.ReleaseTag }}. + + // Allocate Temporaries. + var ( + {{- range .Program.Temporaries }} + {{ . }} = new(Elt) + {{- end -}} + ) + + {{ range $i := .Program.Instructions }} + // {{ printf "Step %d: %s = x^%#x" $i.Output.Index $i.Output (index $.Chain $i.Output.Index) }} + {{- with add $i.Op }} + {{ $i.Output }}.Mul({{ .X }}, {{ .Y }}) + {{ end -}} + + {{- with double $i.Op }} + {{ $i.Output }}.Sqr({{ .X }}) + {{ end -}} + + {{- with shift $i.Op -}} + {{- $first := 0 -}} + {{- if ne $i.Output.Identifier .X.Identifier }} + {{ $i.Output }}.Sqr({{ .X }}) + {{- $first = 1 -}} + {{- end }} + for s := {{ $first }}; s < {{ .S }}; s++ { + {{ $i.Output }}.Sqr({{ $i.Output }}) + } + {{ end -}} + {{- end }} + return z +} +``` + +Generate code by passing the template to `addchain`: +```sh +addchain gen -tmpl inv.tmpl inv.acc | gofmt > inv.go +``` +The end product: +```go +// Code generated by addchain. DO NOT EDIT. + +package fp25519 + +// Inv computes z = 1/x (mod p) and returns it. +func (z *Elt) Inv(x *Elt) *Elt { + // Inversion computation is derived from the addition chain: + // + // _10 = 2*1 + // _11 = 1 + _10 + // _1100 = _11 << 2 + // _1111 = _11 + _1100 + // _11110000 = _1111 << 4 + // _11111111 = _1111 + _11110000 + // x10 = _11111111 << 2 + _11 + // x20 = x10 << 10 + x10 + // x30 = x20 << 10 + x10 + // x60 = x30 << 30 + x30 + // x120 = x60 << 60 + x60 + // x240 = x120 << 120 + x120 + // x250 = x240 << 10 + x10 + // return (x250 << 2 + 1) << 3 + _11 + // + // Operations: 254 squares 12 multiplies + // + // Generated by github.com/mmcloughlin/addchain v0.3.0. + + // Allocate Temporaries. + var ( + t0 = new(Elt) + t1 = new(Elt) + t2 = new(Elt) + ) + + // Step 1: z = x^0x2 + z.Sqr(x) + + // Step 2: z = x^0x3 + z.Mul(x, z) + + // Step 4: t0 = x^0xc + t0.Sqr(z) + for s := 1; s < 2; s++ { + t0.Sqr(t0) + } + + // Step 5: t0 = x^0xf + t0.Mul(z, t0) + + // Step 9: t1 = x^0xf0 + t1.Sqr(t0) + for s := 1; s < 4; s++ { + t1.Sqr(t1) + } + + // Step 10: t0 = x^0xff + t0.Mul(t0, t1) + + // Step 12: t0 = x^0x3fc + for s := 0; s < 2; s++ { + t0.Sqr(t0) + } + + // Step 13: t0 = x^0x3ff + t0.Mul(z, t0) + + // Step 23: t1 = x^0xffc00 + t1.Sqr(t0) + for s := 1; s < 10; s++ { + t1.Sqr(t1) + } + + // Step 24: t1 = x^0xfffff + t1.Mul(t0, t1) + + // Step 34: t1 = x^0x3ffffc00 + for s := 0; s < 10; s++ { + t1.Sqr(t1) + } + + // Step 35: t1 = x^0x3fffffff + t1.Mul(t0, t1) + + // Step 65: t2 = x^0xfffffffc0000000 + t2.Sqr(t1) + for s := 1; s < 30; s++ { + t2.Sqr(t2) + } + + // Step 66: t1 = x^0xfffffffffffffff + t1.Mul(t1, t2) + + // Step 126: t2 = x^0xfffffffffffffff000000000000000 + t2.Sqr(t1) + for s := 1; s < 60; s++ { + t2.Sqr(t2) + } + + // Step 127: t1 = x^0xffffffffffffffffffffffffffffff + t1.Mul(t1, t2) + + // Step 247: t2 = x^0xffffffffffffffffffffffffffffff000000000000000000000000000000 + t2.Sqr(t1) + for s := 1; s < 120; s++ { + t2.Sqr(t2) + } + + // Step 248: t1 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + t1.Mul(t1, t2) + + // Step 258: t1 = x^0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00 + for s := 0; s < 10; s++ { + t1.Sqr(t1) + } + + // Step 259: t0 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + t0.Mul(t0, t1) + + // Step 261: t0 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc + for s := 0; s < 2; s++ { + t0.Sqr(t0) + } + + // Step 262: t0 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd + t0.Mul(x, t0) + + // Step 265: t0 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe8 + for s := 0; s < 3; s++ { + t0.Sqr(t0) + } + + // Step 266: z = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb + z.Mul(z, t0) + + return z +} +``` + +This code is part of a [full working example](../internal/examples/fp25519) that passes tests. + +## Template Reference + +Templates use Go [`text/template`](https://pkg.go.dev/text/template) syntax. The data structure passed +to the template is: + +```go +type Data struct { + // Chain is the addition chain as a list of integers. + Chain addchain.Chain + + // Ops is the complete sequence of addition operations required to compute + // the addition chain. + Ops addchain.Program + + // Script is the condensed representation of the addition chain computation + // in the "addition chain calculator" language. + Script *ast.Chain + + // Program is the intermediate representation of the addition chain + // computation. This representation is likely the most convenient for code + // generation. It contains a sequence of add, double and shift (repeated + // doubling) instructions required to compute the chain. Temporary variable + // allocation has been performed and the list of required temporaries + // populated. + Program *ir.Program + + // Metadata about the addchain project and the specific release parameters. + // Please use this to include a reference or citation back to the addchain + // project in your generated output. + Meta *meta.Properties +} +``` + +In addition to the [builtin functions](https://pkg.go.dev/text/template#hdr-Functions), +templates may use: + +| Name | Signature | Description | +| ---- | --------- | ----------- | +| **`add`** | `func(ir.Op) ir.Op` | If the input operation is an `ir.Add` then return it, otherwise return `nil` | +| **`double`** | `func(ir.Op) ir.Op` | If the input operation is an `ir.Double` then return it, otherwise return `nil` | +| **`shift`** | `func(ir.Op) ir.Op` | If the input operation is an `ir.Shift` then return it, otherwise return `nil` | +| **`inc`** | `func(int) int` | Increment an integer | +| **`format`** | `func(interface {}) (string, error)` | Formats an addition chain script (`*ast.Chain`) as a string | +| **`split`** | `func(string, string) []string` | Calls `strings.Split` | +| **`join`** | `func([]string, string) string` | Calls `strings.Join` | +| **`lines`** | `func(string) []string` | Split input string into lines | + + +## Builtin Templates + +Example output for each builtin template is generated from the chain: + +``` +_10 = 2*1 +_11 = 1 + _10 +_1100 = _11 << 2 +_1111 = _11 + _1100 +_11110000 = _1111 << 4 +_11111111 = _1111 + _11110000 +x10 = _11111111 << 2 + _11 +x20 = x10 << 10 + x10 +x30 = x20 << 10 + x10 +x60 = x30 << 30 + x30 +x120 = x60 << 60 + x60 +x240 = x120 << 120 + x120 +x250 = x240 << 10 + x10 +return (x250 << 2 + 1) << 3 + _11 +``` + + +### chain + +``` +{{- range $n, $value := .Chain -}} +{{- printf "%3d: %#x\n" (inc $n) $value -}} +{{- end -}} +``` + +
+Output of chain template + +``` + 1: 0x1 + 2: 0x2 + 3: 0x3 + 4: 0x6 + 5: 0xc + 6: 0xf + 7: 0x1e + 8: 0x3c + 9: 0x78 + 10: 0xf0 + 11: 0xff + 12: 0x1fe + 13: 0x3fc + 14: 0x3ff + 15: 0x7fe + 16: 0xffc + 17: 0x1ff8 + 18: 0x3ff0 + 19: 0x7fe0 + 20: 0xffc0 + 21: 0x1ff80 + 22: 0x3ff00 + 23: 0x7fe00 + 24: 0xffc00 + 25: 0xfffff + 26: 0x1ffffe + 27: 0x3ffffc + 28: 0x7ffff8 + 29: 0xfffff0 + 30: 0x1ffffe0 + 31: 0x3ffffc0 + 32: 0x7ffff80 + 33: 0xfffff00 + 34: 0x1ffffe00 + 35: 0x3ffffc00 + 36: 0x3fffffff + 37: 0x7ffffffe + 38: 0xfffffffc + 39: 0x1fffffff8 + 40: 0x3fffffff0 + 41: 0x7ffffffe0 + 42: 0xfffffffc0 + 43: 0x1fffffff80 + 44: 0x3fffffff00 + 45: 0x7ffffffe00 + 46: 0xfffffffc00 + 47: 0x1fffffff800 + 48: 0x3fffffff000 + 49: 0x7ffffffe000 + 50: 0xfffffffc000 + 51: 0x1fffffff8000 + 52: 0x3fffffff0000 + 53: 0x7ffffffe0000 + 54: 0xfffffffc0000 + 55: 0x1fffffff80000 + 56: 0x3fffffff00000 + 57: 0x7ffffffe00000 + 58: 0xfffffffc00000 + 59: 0x1fffffff800000 + 60: 0x3fffffff000000 + 61: 0x7ffffffe000000 + 62: 0xfffffffc000000 + 63: 0x1fffffff8000000 + 64: 0x3fffffff0000000 + 65: 0x7ffffffe0000000 + 66: 0xfffffffc0000000 + 67: 0xfffffffffffffff + 68: 0x1ffffffffffffffe + 69: 0x3ffffffffffffffc + 70: 0x7ffffffffffffff8 + 71: 0xfffffffffffffff0 + 72: 0x1ffffffffffffffe0 + 73: 0x3ffffffffffffffc0 + 74: 0x7ffffffffffffff80 + 75: 0xfffffffffffffff00 + 76: 0x1ffffffffffffffe00 + 77: 0x3ffffffffffffffc00 + 78: 0x7ffffffffffffff800 + 79: 0xfffffffffffffff000 + 80: 0x1ffffffffffffffe000 + 81: 0x3ffffffffffffffc000 + 82: 0x7ffffffffffffff8000 + 83: 0xfffffffffffffff0000 + 84: 0x1ffffffffffffffe0000 + 85: 0x3ffffffffffffffc0000 + 86: 0x7ffffffffffffff80000 + 87: 0xfffffffffffffff00000 + 88: 0x1ffffffffffffffe00000 + 89: 0x3ffffffffffffffc00000 + 90: 0x7ffffffffffffff800000 + 91: 0xfffffffffffffff000000 + 92: 0x1ffffffffffffffe000000 + 93: 0x3ffffffffffffffc000000 + 94: 0x7ffffffffffffff8000000 + 95: 0xfffffffffffffff0000000 + 96: 0x1ffffffffffffffe0000000 + 97: 0x3ffffffffffffffc0000000 + 98: 0x7ffffffffffffff80000000 + 99: 0xfffffffffffffff00000000 +100: 0x1ffffffffffffffe00000000 +101: 0x3ffffffffffffffc00000000 +102: 0x7ffffffffffffff800000000 +103: 0xfffffffffffffff000000000 +104: 0x1ffffffffffffffe000000000 +105: 0x3ffffffffffffffc000000000 +106: 0x7ffffffffffffff8000000000 +107: 0xfffffffffffffff0000000000 +108: 0x1ffffffffffffffe0000000000 +109: 0x3ffffffffffffffc0000000000 +110: 0x7ffffffffffffff80000000000 +111: 0xfffffffffffffff00000000000 +112: 0x1ffffffffffffffe00000000000 +113: 0x3ffffffffffffffc00000000000 +114: 0x7ffffffffffffff800000000000 +115: 0xfffffffffffffff000000000000 +116: 0x1ffffffffffffffe000000000000 +117: 0x3ffffffffffffffc000000000000 +118: 0x7ffffffffffffff8000000000000 +119: 0xfffffffffffffff0000000000000 +120: 0x1ffffffffffffffe0000000000000 +121: 0x3ffffffffffffffc0000000000000 +122: 0x7ffffffffffffff80000000000000 +123: 0xfffffffffffffff00000000000000 +124: 0x1ffffffffffffffe00000000000000 +125: 0x3ffffffffffffffc00000000000000 +126: 0x7ffffffffffffff800000000000000 +127: 0xfffffffffffffff000000000000000 +128: 0xffffffffffffffffffffffffffffff +129: 0x1fffffffffffffffffffffffffffffe +130: 0x3fffffffffffffffffffffffffffffc +131: 0x7fffffffffffffffffffffffffffff8 +132: 0xffffffffffffffffffffffffffffff0 +133: 0x1fffffffffffffffffffffffffffffe0 +134: 0x3fffffffffffffffffffffffffffffc0 +135: 0x7fffffffffffffffffffffffffffff80 +136: 0xffffffffffffffffffffffffffffff00 +137: 0x1fffffffffffffffffffffffffffffe00 +138: 0x3fffffffffffffffffffffffffffffc00 +139: 0x7fffffffffffffffffffffffffffff800 +140: 0xffffffffffffffffffffffffffffff000 +141: 0x1fffffffffffffffffffffffffffffe000 +142: 0x3fffffffffffffffffffffffffffffc000 +143: 0x7fffffffffffffffffffffffffffff8000 +144: 0xffffffffffffffffffffffffffffff0000 +145: 0x1fffffffffffffffffffffffffffffe0000 +146: 0x3fffffffffffffffffffffffffffffc0000 +147: 0x7fffffffffffffffffffffffffffff80000 +148: 0xffffffffffffffffffffffffffffff00000 +149: 0x1fffffffffffffffffffffffffffffe00000 +150: 0x3fffffffffffffffffffffffffffffc00000 +151: 0x7fffffffffffffffffffffffffffff800000 +152: 0xffffffffffffffffffffffffffffff000000 +153: 0x1fffffffffffffffffffffffffffffe000000 +154: 0x3fffffffffffffffffffffffffffffc000000 +155: 0x7fffffffffffffffffffffffffffff8000000 +156: 0xffffffffffffffffffffffffffffff0000000 +157: 0x1fffffffffffffffffffffffffffffe0000000 +158: 0x3fffffffffffffffffffffffffffffc0000000 +159: 0x7fffffffffffffffffffffffffffff80000000 +160: 0xffffffffffffffffffffffffffffff00000000 +161: 0x1fffffffffffffffffffffffffffffe00000000 +162: 0x3fffffffffffffffffffffffffffffc00000000 +163: 0x7fffffffffffffffffffffffffffff800000000 +164: 0xffffffffffffffffffffffffffffff000000000 +165: 0x1fffffffffffffffffffffffffffffe000000000 +166: 0x3fffffffffffffffffffffffffffffc000000000 +167: 0x7fffffffffffffffffffffffffffff8000000000 +168: 0xffffffffffffffffffffffffffffff0000000000 +169: 0x1fffffffffffffffffffffffffffffe0000000000 +170: 0x3fffffffffffffffffffffffffffffc0000000000 +171: 0x7fffffffffffffffffffffffffffff80000000000 +172: 0xffffffffffffffffffffffffffffff00000000000 +173: 0x1fffffffffffffffffffffffffffffe00000000000 +174: 0x3fffffffffffffffffffffffffffffc00000000000 +175: 0x7fffffffffffffffffffffffffffff800000000000 +176: 0xffffffffffffffffffffffffffffff000000000000 +177: 0x1fffffffffffffffffffffffffffffe000000000000 +178: 0x3fffffffffffffffffffffffffffffc000000000000 +179: 0x7fffffffffffffffffffffffffffff8000000000000 +180: 0xffffffffffffffffffffffffffffff0000000000000 +181: 0x1fffffffffffffffffffffffffffffe0000000000000 +182: 0x3fffffffffffffffffffffffffffffc0000000000000 +183: 0x7fffffffffffffffffffffffffffff80000000000000 +184: 0xffffffffffffffffffffffffffffff00000000000000 +185: 0x1fffffffffffffffffffffffffffffe00000000000000 +186: 0x3fffffffffffffffffffffffffffffc00000000000000 +187: 0x7fffffffffffffffffffffffffffff800000000000000 +188: 0xffffffffffffffffffffffffffffff000000000000000 +189: 0x1fffffffffffffffffffffffffffffe000000000000000 +190: 0x3fffffffffffffffffffffffffffffc000000000000000 +191: 0x7fffffffffffffffffffffffffffff8000000000000000 +192: 0xffffffffffffffffffffffffffffff0000000000000000 +193: 0x1fffffffffffffffffffffffffffffe0000000000000000 +194: 0x3fffffffffffffffffffffffffffffc0000000000000000 +195: 0x7fffffffffffffffffffffffffffff80000000000000000 +196: 0xffffffffffffffffffffffffffffff00000000000000000 +197: 0x1fffffffffffffffffffffffffffffe00000000000000000 +198: 0x3fffffffffffffffffffffffffffffc00000000000000000 +199: 0x7fffffffffffffffffffffffffffff800000000000000000 +200: 0xffffffffffffffffffffffffffffff000000000000000000 +201: 0x1fffffffffffffffffffffffffffffe000000000000000000 +202: 0x3fffffffffffffffffffffffffffffc000000000000000000 +203: 0x7fffffffffffffffffffffffffffff8000000000000000000 +204: 0xffffffffffffffffffffffffffffff0000000000000000000 +205: 0x1fffffffffffffffffffffffffffffe0000000000000000000 +206: 0x3fffffffffffffffffffffffffffffc0000000000000000000 +207: 0x7fffffffffffffffffffffffffffff80000000000000000000 +208: 0xffffffffffffffffffffffffffffff00000000000000000000 +209: 0x1fffffffffffffffffffffffffffffe00000000000000000000 +210: 0x3fffffffffffffffffffffffffffffc00000000000000000000 +211: 0x7fffffffffffffffffffffffffffff800000000000000000000 +212: 0xffffffffffffffffffffffffffffff000000000000000000000 +213: 0x1fffffffffffffffffffffffffffffe000000000000000000000 +214: 0x3fffffffffffffffffffffffffffffc000000000000000000000 +215: 0x7fffffffffffffffffffffffffffff8000000000000000000000 +216: 0xffffffffffffffffffffffffffffff0000000000000000000000 +217: 0x1fffffffffffffffffffffffffffffe0000000000000000000000 +218: 0x3fffffffffffffffffffffffffffffc0000000000000000000000 +219: 0x7fffffffffffffffffffffffffffff80000000000000000000000 +220: 0xffffffffffffffffffffffffffffff00000000000000000000000 +221: 0x1fffffffffffffffffffffffffffffe00000000000000000000000 +222: 0x3fffffffffffffffffffffffffffffc00000000000000000000000 +223: 0x7fffffffffffffffffffffffffffff800000000000000000000000 +224: 0xffffffffffffffffffffffffffffff000000000000000000000000 +225: 0x1fffffffffffffffffffffffffffffe000000000000000000000000 +226: 0x3fffffffffffffffffffffffffffffc000000000000000000000000 +227: 0x7fffffffffffffffffffffffffffff8000000000000000000000000 +228: 0xffffffffffffffffffffffffffffff0000000000000000000000000 +229: 0x1fffffffffffffffffffffffffffffe0000000000000000000000000 +230: 0x3fffffffffffffffffffffffffffffc0000000000000000000000000 +231: 0x7fffffffffffffffffffffffffffff80000000000000000000000000 +232: 0xffffffffffffffffffffffffffffff00000000000000000000000000 +233: 0x1fffffffffffffffffffffffffffffe00000000000000000000000000 +234: 0x3fffffffffffffffffffffffffffffc00000000000000000000000000 +235: 0x7fffffffffffffffffffffffffffff800000000000000000000000000 +236: 0xffffffffffffffffffffffffffffff000000000000000000000000000 +237: 0x1fffffffffffffffffffffffffffffe000000000000000000000000000 +238: 0x3fffffffffffffffffffffffffffffc000000000000000000000000000 +239: 0x7fffffffffffffffffffffffffffff8000000000000000000000000000 +240: 0xffffffffffffffffffffffffffffff0000000000000000000000000000 +241: 0x1fffffffffffffffffffffffffffffe0000000000000000000000000000 +242: 0x3fffffffffffffffffffffffffffffc0000000000000000000000000000 +243: 0x7fffffffffffffffffffffffffffff80000000000000000000000000000 +244: 0xffffffffffffffffffffffffffffff00000000000000000000000000000 +245: 0x1fffffffffffffffffffffffffffffe00000000000000000000000000000 +246: 0x3fffffffffffffffffffffffffffffc00000000000000000000000000000 +247: 0x7fffffffffffffffffffffffffffff800000000000000000000000000000 +248: 0xffffffffffffffffffffffffffffff000000000000000000000000000000 +249: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +250: 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe +251: 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc +252: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8 +253: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0 +254: 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0 +255: 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0 +256: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80 +257: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +258: 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00 +259: 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00 +260: 0x3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +261: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe +262: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc +263: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd +264: 0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa +265: 0x3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4 +266: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe8 +267: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb +``` + +
+ +### listing + +``` +{{ printf "tmp\t%s" (join .Program.Temporaries "\t") }} +{{ range $i := .Program.Instructions -}} + +{{- with add $i.Op -}} +{{ printf "add\t%s\t%s\t%s" $i.Output .X .Y }} +{{ end -}} + +{{- with double $i.Op -}} +{{ printf "double\t%s\t%s" $i.Output .X }} +{{ end -}} + +{{- with shift $i.Op -}} +{{ printf "shift\t%s\t%s\t%d" $i.Output .X .S }} +{{ end -}} + +{{- end -}} +``` + +
+Output of listing template + +``` +tmp t0 t1 t2 +double z x +add z x z +shift t0 z 2 +add t0 z t0 +shift t1 t0 4 +add t0 t0 t1 +shift t0 t0 2 +add t0 z t0 +shift t1 t0 10 +add t1 t0 t1 +shift t1 t1 10 +add t1 t0 t1 +shift t2 t1 30 +add t1 t1 t2 +shift t2 t1 60 +add t1 t1 t2 +shift t2 t1 120 +add t1 t1 t2 +shift t1 t1 10 +add t0 t0 t1 +shift t0 t0 2 +add t0 x t0 +shift t0 t0 3 +add z z t0 +``` + +
+ +### ops + +``` +{{- range $n, $op := .Ops -}} +{{- printf "[%3d] %4d+%-4d %#x\n" $n $op.I $op.J (index $.Chain (inc $n)) -}} +{{- end -}} +``` + +
+Output of ops template + +``` +[ 0] 0+0 0x2 +[ 1] 0+1 0x3 +[ 2] 2+2 0x6 +[ 3] 3+3 0xc +[ 4] 2+4 0xf +[ 5] 5+5 0x1e +[ 6] 6+6 0x3c +[ 7] 7+7 0x78 +[ 8] 8+8 0xf0 +[ 9] 5+9 0xff +[ 10] 10+10 0x1fe +[ 11] 11+11 0x3fc +[ 12] 2+12 0x3ff +[ 13] 13+13 0x7fe +[ 14] 14+14 0xffc +[ 15] 15+15 0x1ff8 +[ 16] 16+16 0x3ff0 +[ 17] 17+17 0x7fe0 +[ 18] 18+18 0xffc0 +[ 19] 19+19 0x1ff80 +[ 20] 20+20 0x3ff00 +[ 21] 21+21 0x7fe00 +[ 22] 22+22 0xffc00 +[ 23] 13+23 0xfffff +[ 24] 24+24 0x1ffffe +[ 25] 25+25 0x3ffffc +[ 26] 26+26 0x7ffff8 +[ 27] 27+27 0xfffff0 +[ 28] 28+28 0x1ffffe0 +[ 29] 29+29 0x3ffffc0 +[ 30] 30+30 0x7ffff80 +[ 31] 31+31 0xfffff00 +[ 32] 32+32 0x1ffffe00 +[ 33] 33+33 0x3ffffc00 +[ 34] 13+34 0x3fffffff +[ 35] 35+35 0x7ffffffe +[ 36] 36+36 0xfffffffc +[ 37] 37+37 0x1fffffff8 +[ 38] 38+38 0x3fffffff0 +[ 39] 39+39 0x7ffffffe0 +[ 40] 40+40 0xfffffffc0 +[ 41] 41+41 0x1fffffff80 +[ 42] 42+42 0x3fffffff00 +[ 43] 43+43 0x7ffffffe00 +[ 44] 44+44 0xfffffffc00 +[ 45] 45+45 0x1fffffff800 +[ 46] 46+46 0x3fffffff000 +[ 47] 47+47 0x7ffffffe000 +[ 48] 48+48 0xfffffffc000 +[ 49] 49+49 0x1fffffff8000 +[ 50] 50+50 0x3fffffff0000 +[ 51] 51+51 0x7ffffffe0000 +[ 52] 52+52 0xfffffffc0000 +[ 53] 53+53 0x1fffffff80000 +[ 54] 54+54 0x3fffffff00000 +[ 55] 55+55 0x7ffffffe00000 +[ 56] 56+56 0xfffffffc00000 +[ 57] 57+57 0x1fffffff800000 +[ 58] 58+58 0x3fffffff000000 +[ 59] 59+59 0x7ffffffe000000 +[ 60] 60+60 0xfffffffc000000 +[ 61] 61+61 0x1fffffff8000000 +[ 62] 62+62 0x3fffffff0000000 +[ 63] 63+63 0x7ffffffe0000000 +[ 64] 64+64 0xfffffffc0000000 +[ 65] 35+65 0xfffffffffffffff +[ 66] 66+66 0x1ffffffffffffffe +[ 67] 67+67 0x3ffffffffffffffc +[ 68] 68+68 0x7ffffffffffffff8 +[ 69] 69+69 0xfffffffffffffff0 +[ 70] 70+70 0x1ffffffffffffffe0 +[ 71] 71+71 0x3ffffffffffffffc0 +[ 72] 72+72 0x7ffffffffffffff80 +[ 73] 73+73 0xfffffffffffffff00 +[ 74] 74+74 0x1ffffffffffffffe00 +[ 75] 75+75 0x3ffffffffffffffc00 +[ 76] 76+76 0x7ffffffffffffff800 +[ 77] 77+77 0xfffffffffffffff000 +[ 78] 78+78 0x1ffffffffffffffe000 +[ 79] 79+79 0x3ffffffffffffffc000 +[ 80] 80+80 0x7ffffffffffffff8000 +[ 81] 81+81 0xfffffffffffffff0000 +[ 82] 82+82 0x1ffffffffffffffe0000 +[ 83] 83+83 0x3ffffffffffffffc0000 +[ 84] 84+84 0x7ffffffffffffff80000 +[ 85] 85+85 0xfffffffffffffff00000 +[ 86] 86+86 0x1ffffffffffffffe00000 +[ 87] 87+87 0x3ffffffffffffffc00000 +[ 88] 88+88 0x7ffffffffffffff800000 +[ 89] 89+89 0xfffffffffffffff000000 +[ 90] 90+90 0x1ffffffffffffffe000000 +[ 91] 91+91 0x3ffffffffffffffc000000 +[ 92] 92+92 0x7ffffffffffffff8000000 +[ 93] 93+93 0xfffffffffffffff0000000 +[ 94] 94+94 0x1ffffffffffffffe0000000 +[ 95] 95+95 0x3ffffffffffffffc0000000 +[ 96] 96+96 0x7ffffffffffffff80000000 +[ 97] 97+97 0xfffffffffffffff00000000 +[ 98] 98+98 0x1ffffffffffffffe00000000 +[ 99] 99+99 0x3ffffffffffffffc00000000 +[100] 100+100 0x7ffffffffffffff800000000 +[101] 101+101 0xfffffffffffffff000000000 +[102] 102+102 0x1ffffffffffffffe000000000 +[103] 103+103 0x3ffffffffffffffc000000000 +[104] 104+104 0x7ffffffffffffff8000000000 +[105] 105+105 0xfffffffffffffff0000000000 +[106] 106+106 0x1ffffffffffffffe0000000000 +[107] 107+107 0x3ffffffffffffffc0000000000 +[108] 108+108 0x7ffffffffffffff80000000000 +[109] 109+109 0xfffffffffffffff00000000000 +[110] 110+110 0x1ffffffffffffffe00000000000 +[111] 111+111 0x3ffffffffffffffc00000000000 +[112] 112+112 0x7ffffffffffffff800000000000 +[113] 113+113 0xfffffffffffffff000000000000 +[114] 114+114 0x1ffffffffffffffe000000000000 +[115] 115+115 0x3ffffffffffffffc000000000000 +[116] 116+116 0x7ffffffffffffff8000000000000 +[117] 117+117 0xfffffffffffffff0000000000000 +[118] 118+118 0x1ffffffffffffffe0000000000000 +[119] 119+119 0x3ffffffffffffffc0000000000000 +[120] 120+120 0x7ffffffffffffff80000000000000 +[121] 121+121 0xfffffffffffffff00000000000000 +[122] 122+122 0x1ffffffffffffffe00000000000000 +[123] 123+123 0x3ffffffffffffffc00000000000000 +[124] 124+124 0x7ffffffffffffff800000000000000 +[125] 125+125 0xfffffffffffffff000000000000000 +[126] 66+126 0xffffffffffffffffffffffffffffff +[127] 127+127 0x1fffffffffffffffffffffffffffffe +[128] 128+128 0x3fffffffffffffffffffffffffffffc +[129] 129+129 0x7fffffffffffffffffffffffffffff8 +[130] 130+130 0xffffffffffffffffffffffffffffff0 +[131] 131+131 0x1fffffffffffffffffffffffffffffe0 +[132] 132+132 0x3fffffffffffffffffffffffffffffc0 +[133] 133+133 0x7fffffffffffffffffffffffffffff80 +[134] 134+134 0xffffffffffffffffffffffffffffff00 +[135] 135+135 0x1fffffffffffffffffffffffffffffe00 +[136] 136+136 0x3fffffffffffffffffffffffffffffc00 +[137] 137+137 0x7fffffffffffffffffffffffffffff800 +[138] 138+138 0xffffffffffffffffffffffffffffff000 +[139] 139+139 0x1fffffffffffffffffffffffffffffe000 +[140] 140+140 0x3fffffffffffffffffffffffffffffc000 +[141] 141+141 0x7fffffffffffffffffffffffffffff8000 +[142] 142+142 0xffffffffffffffffffffffffffffff0000 +[143] 143+143 0x1fffffffffffffffffffffffffffffe0000 +[144] 144+144 0x3fffffffffffffffffffffffffffffc0000 +[145] 145+145 0x7fffffffffffffffffffffffffffff80000 +[146] 146+146 0xffffffffffffffffffffffffffffff00000 +[147] 147+147 0x1fffffffffffffffffffffffffffffe00000 +[148] 148+148 0x3fffffffffffffffffffffffffffffc00000 +[149] 149+149 0x7fffffffffffffffffffffffffffff800000 +[150] 150+150 0xffffffffffffffffffffffffffffff000000 +[151] 151+151 0x1fffffffffffffffffffffffffffffe000000 +[152] 152+152 0x3fffffffffffffffffffffffffffffc000000 +[153] 153+153 0x7fffffffffffffffffffffffffffff8000000 +[154] 154+154 0xffffffffffffffffffffffffffffff0000000 +[155] 155+155 0x1fffffffffffffffffffffffffffffe0000000 +[156] 156+156 0x3fffffffffffffffffffffffffffffc0000000 +[157] 157+157 0x7fffffffffffffffffffffffffffff80000000 +[158] 158+158 0xffffffffffffffffffffffffffffff00000000 +[159] 159+159 0x1fffffffffffffffffffffffffffffe00000000 +[160] 160+160 0x3fffffffffffffffffffffffffffffc00000000 +[161] 161+161 0x7fffffffffffffffffffffffffffff800000000 +[162] 162+162 0xffffffffffffffffffffffffffffff000000000 +[163] 163+163 0x1fffffffffffffffffffffffffffffe000000000 +[164] 164+164 0x3fffffffffffffffffffffffffffffc000000000 +[165] 165+165 0x7fffffffffffffffffffffffffffff8000000000 +[166] 166+166 0xffffffffffffffffffffffffffffff0000000000 +[167] 167+167 0x1fffffffffffffffffffffffffffffe0000000000 +[168] 168+168 0x3fffffffffffffffffffffffffffffc0000000000 +[169] 169+169 0x7fffffffffffffffffffffffffffff80000000000 +[170] 170+170 0xffffffffffffffffffffffffffffff00000000000 +[171] 171+171 0x1fffffffffffffffffffffffffffffe00000000000 +[172] 172+172 0x3fffffffffffffffffffffffffffffc00000000000 +[173] 173+173 0x7fffffffffffffffffffffffffffff800000000000 +[174] 174+174 0xffffffffffffffffffffffffffffff000000000000 +[175] 175+175 0x1fffffffffffffffffffffffffffffe000000000000 +[176] 176+176 0x3fffffffffffffffffffffffffffffc000000000000 +[177] 177+177 0x7fffffffffffffffffffffffffffff8000000000000 +[178] 178+178 0xffffffffffffffffffffffffffffff0000000000000 +[179] 179+179 0x1fffffffffffffffffffffffffffffe0000000000000 +[180] 180+180 0x3fffffffffffffffffffffffffffffc0000000000000 +[181] 181+181 0x7fffffffffffffffffffffffffffff80000000000000 +[182] 182+182 0xffffffffffffffffffffffffffffff00000000000000 +[183] 183+183 0x1fffffffffffffffffffffffffffffe00000000000000 +[184] 184+184 0x3fffffffffffffffffffffffffffffc00000000000000 +[185] 185+185 0x7fffffffffffffffffffffffffffff800000000000000 +[186] 186+186 0xffffffffffffffffffffffffffffff000000000000000 +[187] 187+187 0x1fffffffffffffffffffffffffffffe000000000000000 +[188] 188+188 0x3fffffffffffffffffffffffffffffc000000000000000 +[189] 189+189 0x7fffffffffffffffffffffffffffff8000000000000000 +[190] 190+190 0xffffffffffffffffffffffffffffff0000000000000000 +[191] 191+191 0x1fffffffffffffffffffffffffffffe0000000000000000 +[192] 192+192 0x3fffffffffffffffffffffffffffffc0000000000000000 +[193] 193+193 0x7fffffffffffffffffffffffffffff80000000000000000 +[194] 194+194 0xffffffffffffffffffffffffffffff00000000000000000 +[195] 195+195 0x1fffffffffffffffffffffffffffffe00000000000000000 +[196] 196+196 0x3fffffffffffffffffffffffffffffc00000000000000000 +[197] 197+197 0x7fffffffffffffffffffffffffffff800000000000000000 +[198] 198+198 0xffffffffffffffffffffffffffffff000000000000000000 +[199] 199+199 0x1fffffffffffffffffffffffffffffe000000000000000000 +[200] 200+200 0x3fffffffffffffffffffffffffffffc000000000000000000 +[201] 201+201 0x7fffffffffffffffffffffffffffff8000000000000000000 +[202] 202+202 0xffffffffffffffffffffffffffffff0000000000000000000 +[203] 203+203 0x1fffffffffffffffffffffffffffffe0000000000000000000 +[204] 204+204 0x3fffffffffffffffffffffffffffffc0000000000000000000 +[205] 205+205 0x7fffffffffffffffffffffffffffff80000000000000000000 +[206] 206+206 0xffffffffffffffffffffffffffffff00000000000000000000 +[207] 207+207 0x1fffffffffffffffffffffffffffffe00000000000000000000 +[208] 208+208 0x3fffffffffffffffffffffffffffffc00000000000000000000 +[209] 209+209 0x7fffffffffffffffffffffffffffff800000000000000000000 +[210] 210+210 0xffffffffffffffffffffffffffffff000000000000000000000 +[211] 211+211 0x1fffffffffffffffffffffffffffffe000000000000000000000 +[212] 212+212 0x3fffffffffffffffffffffffffffffc000000000000000000000 +[213] 213+213 0x7fffffffffffffffffffffffffffff8000000000000000000000 +[214] 214+214 0xffffffffffffffffffffffffffffff0000000000000000000000 +[215] 215+215 0x1fffffffffffffffffffffffffffffe0000000000000000000000 +[216] 216+216 0x3fffffffffffffffffffffffffffffc0000000000000000000000 +[217] 217+217 0x7fffffffffffffffffffffffffffff80000000000000000000000 +[218] 218+218 0xffffffffffffffffffffffffffffff00000000000000000000000 +[219] 219+219 0x1fffffffffffffffffffffffffffffe00000000000000000000000 +[220] 220+220 0x3fffffffffffffffffffffffffffffc00000000000000000000000 +[221] 221+221 0x7fffffffffffffffffffffffffffff800000000000000000000000 +[222] 222+222 0xffffffffffffffffffffffffffffff000000000000000000000000 +[223] 223+223 0x1fffffffffffffffffffffffffffffe000000000000000000000000 +[224] 224+224 0x3fffffffffffffffffffffffffffffc000000000000000000000000 +[225] 225+225 0x7fffffffffffffffffffffffffffff8000000000000000000000000 +[226] 226+226 0xffffffffffffffffffffffffffffff0000000000000000000000000 +[227] 227+227 0x1fffffffffffffffffffffffffffffe0000000000000000000000000 +[228] 228+228 0x3fffffffffffffffffffffffffffffc0000000000000000000000000 +[229] 229+229 0x7fffffffffffffffffffffffffffff80000000000000000000000000 +[230] 230+230 0xffffffffffffffffffffffffffffff00000000000000000000000000 +[231] 231+231 0x1fffffffffffffffffffffffffffffe00000000000000000000000000 +[232] 232+232 0x3fffffffffffffffffffffffffffffc00000000000000000000000000 +[233] 233+233 0x7fffffffffffffffffffffffffffff800000000000000000000000000 +[234] 234+234 0xffffffffffffffffffffffffffffff000000000000000000000000000 +[235] 235+235 0x1fffffffffffffffffffffffffffffe000000000000000000000000000 +[236] 236+236 0x3fffffffffffffffffffffffffffffc000000000000000000000000000 +[237] 237+237 0x7fffffffffffffffffffffffffffff8000000000000000000000000000 +[238] 238+238 0xffffffffffffffffffffffffffffff0000000000000000000000000000 +[239] 239+239 0x1fffffffffffffffffffffffffffffe0000000000000000000000000000 +[240] 240+240 0x3fffffffffffffffffffffffffffffc0000000000000000000000000000 +[241] 241+241 0x7fffffffffffffffffffffffffffff80000000000000000000000000000 +[242] 242+242 0xffffffffffffffffffffffffffffff00000000000000000000000000000 +[243] 243+243 0x1fffffffffffffffffffffffffffffe00000000000000000000000000000 +[244] 244+244 0x3fffffffffffffffffffffffffffffc00000000000000000000000000000 +[245] 245+245 0x7fffffffffffffffffffffffffffff800000000000000000000000000000 +[246] 246+246 0xffffffffffffffffffffffffffffff000000000000000000000000000000 +[247] 127+247 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +[248] 248+248 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe +[249] 249+249 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc +[250] 250+250 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8 +[251] 251+251 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0 +[252] 252+252 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0 +[253] 253+253 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0 +[254] 254+254 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80 +[255] 255+255 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +[256] 256+256 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00 +[257] 257+257 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00 +[258] 13+258 0x3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +[259] 259+259 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe +[260] 260+260 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc +[261] 0+261 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd +[262] 262+262 0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa +[263] 263+263 0x3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4 +[264] 264+264 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe8 +[265] 2+265 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb +``` + +
+ +### script + +``` +{{- format .Script -}} +``` + +
+Output of script template + +``` +_10 = 2*1 +_11 = 1 + _10 +_1100 = _11 << 2 +_1111 = _11 + _1100 +_11110000 = _1111 << 4 +_11111111 = _1111 + _11110000 +x10 = _11111111 << 2 + _11 +x20 = x10 << 10 + x10 +x30 = x20 << 10 + x10 +x60 = x30 << 30 + x30 +x120 = x60 << 60 + x60 +x240 = x120 << 120 + x120 +x250 = x240 << 10 + x10 +return (x250 << 2 + 1) << 3 + _11 +``` + +
+ diff --git a/internal/cli/util.go b/internal/cli/util.go index 406b9ed..c57f569 100644 --- a/internal/cli/util.go +++ b/internal/cli/util.go @@ -14,3 +14,19 @@ func OpenInput(filename string) (string, io.ReadCloser, error) { f, err := os.Open(filename) return filename, f, err } + +// OpenOutput is a convenience for possibly opening an output file, or otherwise returning standard out. +func OpenOutput(filename string) (string, io.WriteCloser, error) { + if filename == "" { + return "", nopwritercloser{os.Stdout}, nil + } + f, err := os.Create(filename) + return filename, f, err +} + +// nopwritercloser wraps an io.Writer and provides a no-op Close() method. +type nopwritercloser struct { + io.Writer +} + +func (nopwritercloser) Close() error { return nil } diff --git a/internal/examples/fp25519/00-search.out b/internal/examples/fp25519/00-search.out new file mode 100644 index 0000000..e33ab1c --- /dev/null +++ b/internal/examples/fp25519/00-search.out @@ -0,0 +1,5 @@ +addchain: expr: "2^255 - 19 - 2" +addchain: hex: 7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb +addchain: dec: 57896044618658097711785492504343953926634992332820282019728792003956564819947 +addchain: best: opt(runs(continued_fractions(dichotomic))) +addchain: cost: 266 diff --git a/internal/examples/fp25519/00-search.sh b/internal/examples/fp25519/00-search.sh new file mode 100644 index 0000000..8de9e0b --- /dev/null +++ b/internal/examples/fp25519/00-search.sh @@ -0,0 +1 @@ +addchain search '2^255 - 19 - 2' > inv.acc diff --git a/internal/examples/fp25519/01-listing.out b/internal/examples/fp25519/01-listing.out new file mode 100644 index 0000000..91b2ad0 --- /dev/null +++ b/internal/examples/fp25519/01-listing.out @@ -0,0 +1,25 @@ +tmp t0 t1 t2 +double z x +add z x z +shift t0 z 2 +add t0 z t0 +shift t1 t0 4 +add t0 t0 t1 +shift t0 t0 2 +add t0 z t0 +shift t1 t0 10 +add t1 t0 t1 +shift t1 t1 10 +add t1 t0 t1 +shift t2 t1 30 +add t1 t1 t2 +shift t2 t1 60 +add t1 t1 t2 +shift t2 t1 120 +add t1 t1 t2 +shift t1 t1 10 +add t0 t0 t1 +shift t0 t0 2 +add t0 x t0 +shift t0 t0 3 +add z z t0 diff --git a/internal/examples/fp25519/01-listing.sh b/internal/examples/fp25519/01-listing.sh new file mode 100644 index 0000000..4816a09 --- /dev/null +++ b/internal/examples/fp25519/01-listing.sh @@ -0,0 +1 @@ +addchain gen inv.acc diff --git a/internal/examples/fp25519/02-generate.out b/internal/examples/fp25519/02-generate.out new file mode 100644 index 0000000..e69de29 diff --git a/internal/examples/fp25519/02-generate.sh b/internal/examples/fp25519/02-generate.sh new file mode 100644 index 0000000..3436b64 --- /dev/null +++ b/internal/examples/fp25519/02-generate.sh @@ -0,0 +1 @@ +addchain gen -tmpl inv.tmpl inv.acc | gofmt > inv.go diff --git a/internal/examples/fp25519/fp.go b/internal/examples/fp25519/fp.go new file mode 100644 index 0000000..4002d35 --- /dev/null +++ b/internal/examples/fp25519/fp.go @@ -0,0 +1,37 @@ +package fp25519 + +import "math/big" + +// p is the field prime modulus. +var p, _ = new(big.Int).SetString("57896044618658097711785492504343953926634992332820282019728792003956564819949", 10) + +// Elt is an element of the field modulo 2²⁵⁵-19. +type Elt struct{ n big.Int } + +// SetInt sets z = x (mod p) and returns it. +func (z *Elt) SetInt(x *big.Int) *Elt { + z.n.Set(x) + return z.modp() +} + +// Int returns z as a big integer. +func (z *Elt) Int() *big.Int { + return new(big.Int).Set(&z.n) +} + +// Mul computes z = x*y (mod p) and returns it. +func (z *Elt) Mul(x, y *Elt) *Elt { + z.n.Mul(&x.n, &y.n) + return z.modp() +} + +// Sqr computes z = x² (mod p) and returns it. +func (z *Elt) Sqr(x *Elt) *Elt { + return z.Mul(x, x) +} + +// modp reduces z modulo p, ensuring it's in the range [0, p). +func (z *Elt) modp() *Elt { + z.n.Mod(&z.n, p) + return z +} diff --git a/internal/examples/fp25519/fp_test.go b/internal/examples/fp25519/fp_test.go new file mode 100644 index 0000000..b414335 --- /dev/null +++ b/internal/examples/fp25519/fp_test.go @@ -0,0 +1,31 @@ +package fp25519 + +import ( + "crypto/rand" + "math/big" + "testing" +) + +func RandElt(t *testing.T) *Elt { + t.Helper() + one := new(big.Int).SetInt64(1) + max := new(big.Int).Sub(p, one) + x, err := rand.Int(rand.Reader, max) + if err != nil { + t.Fatal(err) + } + x.Add(x, one) + return new(Elt).SetInt(x) +} + +func TestInv(t *testing.T) { + const trials = 1 << 12 + for trial := 0; trial < trials; trial++ { + x := RandElt(t) + got := new(Elt).Inv(x) + expect := new(big.Int).ModInverse(x.Int(), p) + if got.Int().Cmp(expect) != 0 { + t.FailNow() + } + } +} diff --git a/internal/examples/fp25519/inv.acc b/internal/examples/fp25519/inv.acc new file mode 100644 index 0000000..a5c8d8d --- /dev/null +++ b/internal/examples/fp25519/inv.acc @@ -0,0 +1,14 @@ +_10 = 2*1 +_11 = 1 + _10 +_1100 = _11 << 2 +_1111 = _11 + _1100 +_11110000 = _1111 << 4 +_11111111 = _1111 + _11110000 +x10 = _11111111 << 2 + _11 +x20 = x10 << 10 + x10 +x30 = x20 << 10 + x10 +x60 = x30 << 30 + x30 +x120 = x60 << 60 + x60 +x240 = x120 << 120 + x120 +x250 = x240 << 10 + x10 +return (x250 << 2 + 1) << 3 + _11 diff --git a/internal/examples/fp25519/inv.go b/internal/examples/fp25519/inv.go new file mode 100644 index 0000000..b3f8ada --- /dev/null +++ b/internal/examples/fp25519/inv.go @@ -0,0 +1,136 @@ +// Code generated by addchain. DO NOT EDIT. + +package fp25519 + +// Inv computes z = 1/x (mod p) and returns it. +func (z *Elt) Inv(x *Elt) *Elt { + // Inversion computation is derived from the addition chain: + // + // _10 = 2*1 + // _11 = 1 + _10 + // _1100 = _11 << 2 + // _1111 = _11 + _1100 + // _11110000 = _1111 << 4 + // _11111111 = _1111 + _11110000 + // x10 = _11111111 << 2 + _11 + // x20 = x10 << 10 + x10 + // x30 = x20 << 10 + x10 + // x60 = x30 << 30 + x30 + // x120 = x60 << 60 + x60 + // x240 = x120 << 120 + x120 + // x250 = x240 << 10 + x10 + // return (x250 << 2 + 1) << 3 + _11 + // + // Operations: 254 squares 12 multiplies + // + // Generated by github.com/mmcloughlin/addchain v0.3.0. + + // Allocate Temporaries. + var ( + t0 = new(Elt) + t1 = new(Elt) + t2 = new(Elt) + ) + + // Step 1: z = x^0x2 + z.Sqr(x) + + // Step 2: z = x^0x3 + z.Mul(x, z) + + // Step 4: t0 = x^0xc + t0.Sqr(z) + for s := 1; s < 2; s++ { + t0.Sqr(t0) + } + + // Step 5: t0 = x^0xf + t0.Mul(z, t0) + + // Step 9: t1 = x^0xf0 + t1.Sqr(t0) + for s := 1; s < 4; s++ { + t1.Sqr(t1) + } + + // Step 10: t0 = x^0xff + t0.Mul(t0, t1) + + // Step 12: t0 = x^0x3fc + for s := 0; s < 2; s++ { + t0.Sqr(t0) + } + + // Step 13: t0 = x^0x3ff + t0.Mul(z, t0) + + // Step 23: t1 = x^0xffc00 + t1.Sqr(t0) + for s := 1; s < 10; s++ { + t1.Sqr(t1) + } + + // Step 24: t1 = x^0xfffff + t1.Mul(t0, t1) + + // Step 34: t1 = x^0x3ffffc00 + for s := 0; s < 10; s++ { + t1.Sqr(t1) + } + + // Step 35: t1 = x^0x3fffffff + t1.Mul(t0, t1) + + // Step 65: t2 = x^0xfffffffc0000000 + t2.Sqr(t1) + for s := 1; s < 30; s++ { + t2.Sqr(t2) + } + + // Step 66: t1 = x^0xfffffffffffffff + t1.Mul(t1, t2) + + // Step 126: t2 = x^0xfffffffffffffff000000000000000 + t2.Sqr(t1) + for s := 1; s < 60; s++ { + t2.Sqr(t2) + } + + // Step 127: t1 = x^0xffffffffffffffffffffffffffffff + t1.Mul(t1, t2) + + // Step 247: t2 = x^0xffffffffffffffffffffffffffffff000000000000000000000000000000 + t2.Sqr(t1) + for s := 1; s < 120; s++ { + t2.Sqr(t2) + } + + // Step 248: t1 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + t1.Mul(t1, t2) + + // Step 258: t1 = x^0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00 + for s := 0; s < 10; s++ { + t1.Sqr(t1) + } + + // Step 259: t0 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + t0.Mul(t0, t1) + + // Step 261: t0 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc + for s := 0; s < 2; s++ { + t0.Sqr(t0) + } + + // Step 262: t0 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd + t0.Mul(x, t0) + + // Step 265: t0 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe8 + for s := 0; s < 3; s++ { + t0.Sqr(t0) + } + + // Step 266: z = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb + z.Mul(z, t0) + + return z +} diff --git a/internal/examples/fp25519/inv.tmpl b/internal/examples/fp25519/inv.tmpl new file mode 100644 index 0000000..cae637a --- /dev/null +++ b/internal/examples/fp25519/inv.tmpl @@ -0,0 +1,46 @@ +// Code generated by {{ .Meta.Name }}. DO NOT EDIT. + +package fp25519 + +// Inv computes z = 1/x (mod p) and returns it. +func (z *Elt) Inv(x *Elt) *Elt { + // Inversion computation is derived from the addition chain: + // + {{- range lines (format .Script) }} + // {{ . }} + {{- end }} + // + // Operations: {{ .Ops.Doubles }} squares {{ .Ops.Adds }} multiplies + // + // Generated by {{ .Meta.Module }} {{ .Meta.ReleaseTag }}. + + // Allocate Temporaries. + var ( + {{- range .Program.Temporaries }} + {{ . }} = new(Elt) + {{- end -}} + ) + + {{ range $i := .Program.Instructions }} + // {{ printf "Step %d: %s = x^%#x" $i.Output.Index $i.Output (index $.Chain $i.Output.Index) }} + {{- with add $i.Op }} + {{ $i.Output }}.Mul({{ .X }}, {{ .Y }}) + {{ end -}} + + {{- with double $i.Op }} + {{ $i.Output }}.Sqr({{ .X }}) + {{ end -}} + + {{- with shift $i.Op -}} + {{- $first := 0 -}} + {{- if ne $i.Output.Identifier .X.Identifier }} + {{ $i.Output }}.Sqr({{ .X }}) + {{- $first = 1 -}} + {{- end }} + for s := {{ $first }}; s < {{ .S }}; s++ { + {{ $i.Output }}.Sqr({{ $i.Output }}) + } + {{ end -}} + {{- end }} + return z +} diff --git a/internal/examples/cli/output b/internal/examples/search/cmd.out similarity index 100% rename from internal/examples/cli/output rename to internal/examples/search/cmd.out diff --git a/internal/examples/cli/cmd.sh b/internal/examples/search/cmd.sh similarity index 100% rename from internal/examples/cli/cmd.sh rename to internal/examples/search/cmd.sh diff --git a/internal/gen/functions.go b/internal/gen/functions.go new file mode 100644 index 0000000..ec37483 --- /dev/null +++ b/internal/gen/functions.go @@ -0,0 +1,88 @@ +package gen + +import ( + "bufio" + "reflect" + "strings" + + "github.com/mmcloughlin/addchain/acc/ir" + "github.com/mmcloughlin/addchain/acc/printer" +) + +// Function is a function provided to templates. +type Function struct { + Name string + Description string + Func interface{} +} + +// Signature returns the function signature. +func (f *Function) Signature() string { + return reflect.ValueOf(f.Func).Type().String() +} + +// Functions is the list of functions provided to templates. +var Functions = []*Function{ + { + Name: "add", + Description: "If the input operation is an `ir.Add` then return it, otherwise return `nil`", + Func: func(op ir.Op) ir.Op { + if a, ok := op.(ir.Add); ok { + return a + } + return nil + }, + }, + { + Name: "double", + Description: "If the input operation is an `ir.Double` then return it, otherwise return `nil`", + Func: func(op ir.Op) ir.Op { + if d, ok := op.(ir.Double); ok { + return d + } + return nil + }, + }, + { + Name: "shift", + Description: "If the input operation is an `ir.Shift` then return it, otherwise return `nil`", + Func: func(op ir.Op) ir.Op { + if s, ok := op.(ir.Shift); ok { + return s + } + return nil + }, + }, + { + Name: "inc", + Description: "Increment an integer", + Func: func(n int) int { return n + 1 }, + }, + { + Name: "format", + Description: "Formats an addition chain script (`*ast.Chain`) as a string", + Func: printer.String, + }, + { + Name: "split", + Description: "Calls `strings.Split`", + Func: strings.Split, + }, + { + Name: "join", + Description: "Calls `strings.Join`", + Func: strings.Join, + }, + { + Name: "lines", + Description: "Split input string into lines", + Func: func(s string) []string { + var lines []string + scanner := bufio.NewScanner(strings.NewReader(s)) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + return lines + }, + }, +} diff --git a/internal/gen/functions_test.go b/internal/gen/functions_test.go new file mode 100644 index 0000000..45da035 --- /dev/null +++ b/internal/gen/functions_test.go @@ -0,0 +1,26 @@ +package gen + +import "testing" + +func TestFunctionSignature(t *testing.T) { + f := &Function{ + Name: "sig", + Description: "Test for function signature", + Func: func(x, y int) int { return x + y }, + } + expect := "func(int, int) int" + if f.Signature() != expect { + t.FailNow() + } +} + +func TestFunctionsLint(t *testing.T) { + for _, f := range Functions { + if f.Name == "" { + t.Fatalf("nameless function") + } + if f.Description == "" { + t.Errorf("%s: missing description", f.Name) + } + } +} diff --git a/internal/gen/gen.go b/internal/gen/gen.go new file mode 100644 index 0000000..46a7775 --- /dev/null +++ b/internal/gen/gen.go @@ -0,0 +1,90 @@ +// Package gen provides templated output generation from addition chain +// programs. +package gen + +import ( + "io" + "text/template" + + "github.com/mmcloughlin/addchain" + "github.com/mmcloughlin/addchain/acc" + "github.com/mmcloughlin/addchain/acc/ast" + "github.com/mmcloughlin/addchain/acc/ir" + "github.com/mmcloughlin/addchain/acc/pass" + "github.com/mmcloughlin/addchain/meta" +) + +// Data provided to templates. +type Data struct { + // Chain is the addition chain as a list of integers. + Chain addchain.Chain + + // Ops is the complete sequence of addition operations required to compute + // the addition chain. + Ops addchain.Program + + // Script is the condensed representation of the addition chain computation + // in the "addition chain calculator" language. + Script *ast.Chain + + // Program is the intermediate representation of the addition chain + // computation. This representation is likely the most convenient for code + // generation. It contains a sequence of add, double and shift (repeated + // doubling) instructions required to compute the chain. Temporary variable + // allocation has been performed and the list of required temporaries + // populated. + Program *ir.Program + + // Metadata about the addchain project and the specific release parameters. + // Please use this to include a reference or citation back to the addchain + // project in your generated output. + Meta *meta.Properties +} + +// Config for template input generation. +type Config struct { + // Allocator for temporary variables. This configuration determines variable + // naming. + Allocator pass.Allocator +} + +// PrepareData builds input template data for the given addition chain script. +func PrepareData(cfg Config, s *ast.Chain) (*Data, error) { + // Translate to IR. + p, err := acc.Translate(s) + if err != nil { + return nil, err + } + + // Apply processing passes: temporary variable allocation, and computing the + // full addition chain sequence and operations. + if err := pass.Exec(p, cfg.Allocator, pass.Func(pass.Eval)); err != nil { + return nil, err + } + + return &Data{ + Chain: p.Chain, + Ops: p.Program, + Script: s, + Program: p, + Meta: meta.Meta, + }, nil +} + +// Generate templated output for the given data, writing to w. +func Generate(w io.Writer, tmpl string, d *Data) error { + // Custom template functions. + funcs := template.FuncMap{} + for _, f := range Functions { + funcs[f.Name] = f.Func + } + + // Parse template. + t, err := template.New("").Funcs(funcs).Parse(tmpl) + if err != nil { + return err + } + + // Execute. + return t.Execute(w, d) +} diff --git a/internal/gen/gen_test.go b/internal/gen/gen_test.go new file mode 100644 index 0000000..7e93276 --- /dev/null +++ b/internal/gen/gen_test.go @@ -0,0 +1,76 @@ +package gen + +import ( + "bytes" + "io/ioutil" + "path/filepath" + "testing" + + "github.com/mmcloughlin/addchain/acc/parse" + "github.com/mmcloughlin/addchain/acc/pass" + "github.com/mmcloughlin/addchain/internal/test" +) + +func TestBuiltinTemplatesGolden(t *testing.T) { + d := LoadTestData(t) + for _, name := range BuiltinTemplateNames() { + name := name // scopelint + t.Run(name, func(t *testing.T) { + // Load the template. + tmpl, err := BuiltinTemplate(name) + if err != nil { + t.Fatal(err) + } + + // Generate output. + var buf bytes.Buffer + if err := Generate(&buf, tmpl, d); err != nil { + t.Fatal(err) + } + got := buf.Bytes() + + // Compare to golden case. + filename := test.GoldenName(filepath.Join("builtin", name)) + + if test.Golden() { + if err := ioutil.WriteFile(filename, got, 0644); err != nil { + t.Fatalf("write golden file: %v", err) + } + } + + expect, err := ioutil.ReadFile(filename) + if err != nil { + t.Fatalf("read golden file: %v", err) + } + + if !bytes.Equal(got, expect) { + t.Fatal("output does not match golden file") + } + }) + } +} + +func LoadTestData(t *testing.T) *Data { + t.Helper() + + // Prepare data for a fixed test input. + s, err := parse.File("testdata/input.acc") + if err != nil { + t.Fatal(err) + } + + cfg := Config{ + Allocator: pass.Allocator{ + Input: "x", + Output: "z", + Format: "t%d", + }, + } + + d, err := PrepareData(cfg, s) + if err != nil { + t.Fatal(err) + } + + return d +} diff --git a/internal/gen/templates.go b/internal/gen/templates.go new file mode 100644 index 0000000..609f027 --- /dev/null +++ b/internal/gen/templates.go @@ -0,0 +1,53 @@ +package gen + +import ( + "embed" + "fmt" + "path" + "strings" +) + +//go:embed templates +var templates embed.FS + +// Template file extension. +const templateext = ".tmpl" + +// BuiltinTemplate loads the named template. Returns an error if the template is +// unknown. +func BuiltinTemplate(name string) (string, error) { + path := fmt.Sprintf("templates/%s%s", name, templateext) + b, err := templates.ReadFile(path) + if err != nil { + return "", fmt.Errorf("unknown template %q", name) + } + return string(b), nil +} + +// BuiltinTemplateNames returns all builtin template names. +func BuiltinTemplateNames() []string { + entries, err := templates.ReadDir("templates") + if err != nil { + panic("gen: could not read embedded templates") + } + var names []string + for _, entry := range entries { + filename := entry.Name() + if path.Ext(filename) != templateext { + panic("gen: builtin template has wrong extension") + } + name := strings.TrimSuffix(filename, templateext) + names = append(names, name) + } + return names +} + +// IsBuiltinTemplate reports whether name is a builtin template name. +func IsBuiltinTemplate(name string) bool { + for _, builtin := range BuiltinTemplateNames() { + if builtin == name { + return true + } + } + return false +} diff --git a/internal/gen/templates/chain.tmpl b/internal/gen/templates/chain.tmpl new file mode 100644 index 0000000..25cc47e --- /dev/null +++ b/internal/gen/templates/chain.tmpl @@ -0,0 +1,3 @@ +{{- range $n, $value := .Chain -}} +{{- printf "%3d: %#x\n" (inc $n) $value -}} +{{- end -}} diff --git a/internal/gen/templates/listing.tmpl b/internal/gen/templates/listing.tmpl new file mode 100644 index 0000000..79545c0 --- /dev/null +++ b/internal/gen/templates/listing.tmpl @@ -0,0 +1,16 @@ +{{ printf "tmp\t%s" (join .Program.Temporaries "\t") }} +{{ range $i := .Program.Instructions -}} + +{{- with add $i.Op -}} +{{ printf "add\t%s\t%s\t%s" $i.Output .X .Y }} +{{ end -}} + +{{- with double $i.Op -}} +{{ printf "double\t%s\t%s" $i.Output .X }} +{{ end -}} + +{{- with shift $i.Op -}} +{{ printf "shift\t%s\t%s\t%d" $i.Output .X .S }} +{{ end -}} + +{{- end -}} diff --git a/internal/gen/templates/ops.tmpl b/internal/gen/templates/ops.tmpl new file mode 100644 index 0000000..8981d9d --- /dev/null +++ b/internal/gen/templates/ops.tmpl @@ -0,0 +1,3 @@ +{{- range $n, $op := .Ops -}} +{{- printf "[%3d] %4d+%-4d %#x\n" $n $op.I $op.J (index $.Chain (inc $n)) -}} +{{- end -}} diff --git a/internal/gen/templates/script.tmpl b/internal/gen/templates/script.tmpl new file mode 100644 index 0000000..f5858a1 --- /dev/null +++ b/internal/gen/templates/script.tmpl @@ -0,0 +1 @@ +{{- format .Script -}} diff --git a/internal/gen/testdata/builtin/chain.golden b/internal/gen/testdata/builtin/chain.golden new file mode 100644 index 0000000..62c63d3 --- /dev/null +++ b/internal/gen/testdata/builtin/chain.golden @@ -0,0 +1,267 @@ + 1: 0x1 + 2: 0x2 + 3: 0x3 + 4: 0x6 + 5: 0xc + 6: 0xf + 7: 0x1e + 8: 0x3c + 9: 0x78 + 10: 0xf0 + 11: 0xff + 12: 0x1fe + 13: 0x3fc + 14: 0x3ff + 15: 0x7fe + 16: 0xffc + 17: 0x1ff8 + 18: 0x3ff0 + 19: 0x7fe0 + 20: 0xffc0 + 21: 0x1ff80 + 22: 0x3ff00 + 23: 0x7fe00 + 24: 0xffc00 + 25: 0xfffff + 26: 0x1ffffe + 27: 0x3ffffc + 28: 0x7ffff8 + 29: 0xfffff0 + 30: 0x1ffffe0 + 31: 0x3ffffc0 + 32: 0x7ffff80 + 33: 0xfffff00 + 34: 0x1ffffe00 + 35: 0x3ffffc00 + 36: 0x3fffffff + 37: 0x7ffffffe + 38: 0xfffffffc + 39: 0x1fffffff8 + 40: 0x3fffffff0 + 41: 0x7ffffffe0 + 42: 0xfffffffc0 + 43: 0x1fffffff80 + 44: 0x3fffffff00 + 45: 0x7ffffffe00 + 46: 0xfffffffc00 + 47: 0x1fffffff800 + 48: 0x3fffffff000 + 49: 0x7ffffffe000 + 50: 0xfffffffc000 + 51: 0x1fffffff8000 + 52: 0x3fffffff0000 + 53: 0x7ffffffe0000 + 54: 0xfffffffc0000 + 55: 0x1fffffff80000 + 56: 0x3fffffff00000 + 57: 0x7ffffffe00000 + 58: 0xfffffffc00000 + 59: 0x1fffffff800000 + 60: 0x3fffffff000000 + 61: 0x7ffffffe000000 + 62: 0xfffffffc000000 + 63: 0x1fffffff8000000 + 64: 0x3fffffff0000000 + 65: 0x7ffffffe0000000 + 66: 0xfffffffc0000000 + 67: 0xfffffffffffffff + 68: 0x1ffffffffffffffe + 69: 0x3ffffffffffffffc + 70: 0x7ffffffffffffff8 + 71: 0xfffffffffffffff0 + 72: 0x1ffffffffffffffe0 + 73: 0x3ffffffffffffffc0 + 74: 0x7ffffffffffffff80 + 75: 0xfffffffffffffff00 + 76: 0x1ffffffffffffffe00 + 77: 0x3ffffffffffffffc00 + 78: 0x7ffffffffffffff800 + 79: 0xfffffffffffffff000 + 80: 0x1ffffffffffffffe000 + 81: 0x3ffffffffffffffc000 + 82: 0x7ffffffffffffff8000 + 83: 0xfffffffffffffff0000 + 84: 0x1ffffffffffffffe0000 + 85: 0x3ffffffffffffffc0000 + 86: 0x7ffffffffffffff80000 + 87: 0xfffffffffffffff00000 + 88: 0x1ffffffffffffffe00000 + 89: 0x3ffffffffffffffc00000 + 90: 0x7ffffffffffffff800000 + 91: 0xfffffffffffffff000000 + 92: 0x1ffffffffffffffe000000 + 93: 0x3ffffffffffffffc000000 + 94: 0x7ffffffffffffff8000000 + 95: 0xfffffffffffffff0000000 + 96: 0x1ffffffffffffffe0000000 + 97: 0x3ffffffffffffffc0000000 + 98: 0x7ffffffffffffff80000000 + 99: 0xfffffffffffffff00000000 +100: 0x1ffffffffffffffe00000000 +101: 0x3ffffffffffffffc00000000 +102: 0x7ffffffffffffff800000000 +103: 0xfffffffffffffff000000000 +104: 0x1ffffffffffffffe000000000 +105: 0x3ffffffffffffffc000000000 +106: 0x7ffffffffffffff8000000000 +107: 0xfffffffffffffff0000000000 +108: 0x1ffffffffffffffe0000000000 +109: 0x3ffffffffffffffc0000000000 +110: 0x7ffffffffffffff80000000000 +111: 0xfffffffffffffff00000000000 +112: 0x1ffffffffffffffe00000000000 +113: 0x3ffffffffffffffc00000000000 +114: 0x7ffffffffffffff800000000000 +115: 0xfffffffffffffff000000000000 +116: 0x1ffffffffffffffe000000000000 +117: 0x3ffffffffffffffc000000000000 +118: 0x7ffffffffffffff8000000000000 +119: 0xfffffffffffffff0000000000000 +120: 0x1ffffffffffffffe0000000000000 +121: 0x3ffffffffffffffc0000000000000 +122: 0x7ffffffffffffff80000000000000 +123: 0xfffffffffffffff00000000000000 +124: 0x1ffffffffffffffe00000000000000 +125: 0x3ffffffffffffffc00000000000000 +126: 0x7ffffffffffffff800000000000000 +127: 0xfffffffffffffff000000000000000 +128: 0xffffffffffffffffffffffffffffff +129: 0x1fffffffffffffffffffffffffffffe +130: 0x3fffffffffffffffffffffffffffffc +131: 0x7fffffffffffffffffffffffffffff8 +132: 0xffffffffffffffffffffffffffffff0 +133: 0x1fffffffffffffffffffffffffffffe0 +134: 0x3fffffffffffffffffffffffffffffc0 +135: 0x7fffffffffffffffffffffffffffff80 +136: 0xffffffffffffffffffffffffffffff00 +137: 0x1fffffffffffffffffffffffffffffe00 +138: 0x3fffffffffffffffffffffffffffffc00 +139: 0x7fffffffffffffffffffffffffffff800 +140: 0xffffffffffffffffffffffffffffff000 +141: 0x1fffffffffffffffffffffffffffffe000 +142: 0x3fffffffffffffffffffffffffffffc000 +143: 0x7fffffffffffffffffffffffffffff8000 +144: 0xffffffffffffffffffffffffffffff0000 +145: 0x1fffffffffffffffffffffffffffffe0000 +146: 0x3fffffffffffffffffffffffffffffc0000 +147: 0x7fffffffffffffffffffffffffffff80000 +148: 0xffffffffffffffffffffffffffffff00000 +149: 0x1fffffffffffffffffffffffffffffe00000 +150: 0x3fffffffffffffffffffffffffffffc00000 +151: 0x7fffffffffffffffffffffffffffff800000 +152: 0xffffffffffffffffffffffffffffff000000 +153: 0x1fffffffffffffffffffffffffffffe000000 +154: 0x3fffffffffffffffffffffffffffffc000000 +155: 0x7fffffffffffffffffffffffffffff8000000 +156: 0xffffffffffffffffffffffffffffff0000000 +157: 0x1fffffffffffffffffffffffffffffe0000000 +158: 0x3fffffffffffffffffffffffffffffc0000000 +159: 0x7fffffffffffffffffffffffffffff80000000 +160: 0xffffffffffffffffffffffffffffff00000000 +161: 0x1fffffffffffffffffffffffffffffe00000000 +162: 0x3fffffffffffffffffffffffffffffc00000000 +163: 0x7fffffffffffffffffffffffffffff800000000 +164: 0xffffffffffffffffffffffffffffff000000000 +165: 0x1fffffffffffffffffffffffffffffe000000000 +166: 0x3fffffffffffffffffffffffffffffc000000000 +167: 0x7fffffffffffffffffffffffffffff8000000000 +168: 0xffffffffffffffffffffffffffffff0000000000 +169: 0x1fffffffffffffffffffffffffffffe0000000000 +170: 0x3fffffffffffffffffffffffffffffc0000000000 +171: 0x7fffffffffffffffffffffffffffff80000000000 +172: 0xffffffffffffffffffffffffffffff00000000000 +173: 0x1fffffffffffffffffffffffffffffe00000000000 +174: 0x3fffffffffffffffffffffffffffffc00000000000 +175: 0x7fffffffffffffffffffffffffffff800000000000 +176: 0xffffffffffffffffffffffffffffff000000000000 +177: 0x1fffffffffffffffffffffffffffffe000000000000 +178: 0x3fffffffffffffffffffffffffffffc000000000000 +179: 0x7fffffffffffffffffffffffffffff8000000000000 +180: 0xffffffffffffffffffffffffffffff0000000000000 +181: 0x1fffffffffffffffffffffffffffffe0000000000000 +182: 0x3fffffffffffffffffffffffffffffc0000000000000 +183: 0x7fffffffffffffffffffffffffffff80000000000000 +184: 0xffffffffffffffffffffffffffffff00000000000000 +185: 0x1fffffffffffffffffffffffffffffe00000000000000 +186: 0x3fffffffffffffffffffffffffffffc00000000000000 +187: 0x7fffffffffffffffffffffffffffff800000000000000 +188: 0xffffffffffffffffffffffffffffff000000000000000 +189: 0x1fffffffffffffffffffffffffffffe000000000000000 +190: 0x3fffffffffffffffffffffffffffffc000000000000000 +191: 0x7fffffffffffffffffffffffffffff8000000000000000 +192: 0xffffffffffffffffffffffffffffff0000000000000000 +193: 0x1fffffffffffffffffffffffffffffe0000000000000000 +194: 0x3fffffffffffffffffffffffffffffc0000000000000000 +195: 0x7fffffffffffffffffffffffffffff80000000000000000 +196: 0xffffffffffffffffffffffffffffff00000000000000000 +197: 0x1fffffffffffffffffffffffffffffe00000000000000000 +198: 0x3fffffffffffffffffffffffffffffc00000000000000000 +199: 0x7fffffffffffffffffffffffffffff800000000000000000 +200: 0xffffffffffffffffffffffffffffff000000000000000000 +201: 0x1fffffffffffffffffffffffffffffe000000000000000000 +202: 0x3fffffffffffffffffffffffffffffc000000000000000000 +203: 0x7fffffffffffffffffffffffffffff8000000000000000000 +204: 0xffffffffffffffffffffffffffffff0000000000000000000 +205: 0x1fffffffffffffffffffffffffffffe0000000000000000000 +206: 0x3fffffffffffffffffffffffffffffc0000000000000000000 +207: 0x7fffffffffffffffffffffffffffff80000000000000000000 +208: 0xffffffffffffffffffffffffffffff00000000000000000000 +209: 0x1fffffffffffffffffffffffffffffe00000000000000000000 +210: 0x3fffffffffffffffffffffffffffffc00000000000000000000 +211: 0x7fffffffffffffffffffffffffffff800000000000000000000 +212: 0xffffffffffffffffffffffffffffff000000000000000000000 +213: 0x1fffffffffffffffffffffffffffffe000000000000000000000 +214: 0x3fffffffffffffffffffffffffffffc000000000000000000000 +215: 0x7fffffffffffffffffffffffffffff8000000000000000000000 +216: 0xffffffffffffffffffffffffffffff0000000000000000000000 +217: 0x1fffffffffffffffffffffffffffffe0000000000000000000000 +218: 0x3fffffffffffffffffffffffffffffc0000000000000000000000 +219: 0x7fffffffffffffffffffffffffffff80000000000000000000000 +220: 0xffffffffffffffffffffffffffffff00000000000000000000000 +221: 0x1fffffffffffffffffffffffffffffe00000000000000000000000 +222: 0x3fffffffffffffffffffffffffffffc00000000000000000000000 +223: 0x7fffffffffffffffffffffffffffff800000000000000000000000 +224: 0xffffffffffffffffffffffffffffff000000000000000000000000 +225: 0x1fffffffffffffffffffffffffffffe000000000000000000000000 +226: 0x3fffffffffffffffffffffffffffffc000000000000000000000000 +227: 0x7fffffffffffffffffffffffffffff8000000000000000000000000 +228: 0xffffffffffffffffffffffffffffff0000000000000000000000000 +229: 0x1fffffffffffffffffffffffffffffe0000000000000000000000000 +230: 0x3fffffffffffffffffffffffffffffc0000000000000000000000000 +231: 0x7fffffffffffffffffffffffffffff80000000000000000000000000 +232: 0xffffffffffffffffffffffffffffff00000000000000000000000000 +233: 0x1fffffffffffffffffffffffffffffe00000000000000000000000000 +234: 0x3fffffffffffffffffffffffffffffc00000000000000000000000000 +235: 0x7fffffffffffffffffffffffffffff800000000000000000000000000 +236: 0xffffffffffffffffffffffffffffff000000000000000000000000000 +237: 0x1fffffffffffffffffffffffffffffe000000000000000000000000000 +238: 0x3fffffffffffffffffffffffffffffc000000000000000000000000000 +239: 0x7fffffffffffffffffffffffffffff8000000000000000000000000000 +240: 0xffffffffffffffffffffffffffffff0000000000000000000000000000 +241: 0x1fffffffffffffffffffffffffffffe0000000000000000000000000000 +242: 0x3fffffffffffffffffffffffffffffc0000000000000000000000000000 +243: 0x7fffffffffffffffffffffffffffff80000000000000000000000000000 +244: 0xffffffffffffffffffffffffffffff00000000000000000000000000000 +245: 0x1fffffffffffffffffffffffffffffe00000000000000000000000000000 +246: 0x3fffffffffffffffffffffffffffffc00000000000000000000000000000 +247: 0x7fffffffffffffffffffffffffffff800000000000000000000000000000 +248: 0xffffffffffffffffffffffffffffff000000000000000000000000000000 +249: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +250: 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe +251: 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc +252: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8 +253: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0 +254: 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0 +255: 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0 +256: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80 +257: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +258: 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00 +259: 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00 +260: 0x3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +261: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe +262: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc +263: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd +264: 0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa +265: 0x3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4 +266: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe8 +267: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb diff --git a/internal/gen/testdata/builtin/listing.golden b/internal/gen/testdata/builtin/listing.golden new file mode 100644 index 0000000..91b2ad0 --- /dev/null +++ b/internal/gen/testdata/builtin/listing.golden @@ -0,0 +1,25 @@ +tmp t0 t1 t2 +double z x +add z x z +shift t0 z 2 +add t0 z t0 +shift t1 t0 4 +add t0 t0 t1 +shift t0 t0 2 +add t0 z t0 +shift t1 t0 10 +add t1 t0 t1 +shift t1 t1 10 +add t1 t0 t1 +shift t2 t1 30 +add t1 t1 t2 +shift t2 t1 60 +add t1 t1 t2 +shift t2 t1 120 +add t1 t1 t2 +shift t1 t1 10 +add t0 t0 t1 +shift t0 t0 2 +add t0 x t0 +shift t0 t0 3 +add z z t0 diff --git a/internal/gen/testdata/builtin/ops.golden b/internal/gen/testdata/builtin/ops.golden new file mode 100644 index 0000000..a5571c3 --- /dev/null +++ b/internal/gen/testdata/builtin/ops.golden @@ -0,0 +1,266 @@ +[ 0] 0+0 0x2 +[ 1] 0+1 0x3 +[ 2] 2+2 0x6 +[ 3] 3+3 0xc +[ 4] 2+4 0xf +[ 5] 5+5 0x1e +[ 6] 6+6 0x3c +[ 7] 7+7 0x78 +[ 8] 8+8 0xf0 +[ 9] 5+9 0xff +[ 10] 10+10 0x1fe +[ 11] 11+11 0x3fc +[ 12] 2+12 0x3ff +[ 13] 13+13 0x7fe +[ 14] 14+14 0xffc +[ 15] 15+15 0x1ff8 +[ 16] 16+16 0x3ff0 +[ 17] 17+17 0x7fe0 +[ 18] 18+18 0xffc0 +[ 19] 19+19 0x1ff80 +[ 20] 20+20 0x3ff00 +[ 21] 21+21 0x7fe00 +[ 22] 22+22 0xffc00 +[ 23] 13+23 0xfffff +[ 24] 24+24 0x1ffffe +[ 25] 25+25 0x3ffffc +[ 26] 26+26 0x7ffff8 +[ 27] 27+27 0xfffff0 +[ 28] 28+28 0x1ffffe0 +[ 29] 29+29 0x3ffffc0 +[ 30] 30+30 0x7ffff80 +[ 31] 31+31 0xfffff00 +[ 32] 32+32 0x1ffffe00 +[ 33] 33+33 0x3ffffc00 +[ 34] 13+34 0x3fffffff +[ 35] 35+35 0x7ffffffe +[ 36] 36+36 0xfffffffc +[ 37] 37+37 0x1fffffff8 +[ 38] 38+38 0x3fffffff0 +[ 39] 39+39 0x7ffffffe0 +[ 40] 40+40 0xfffffffc0 +[ 41] 41+41 0x1fffffff80 +[ 42] 42+42 0x3fffffff00 +[ 43] 43+43 0x7ffffffe00 +[ 44] 44+44 0xfffffffc00 +[ 45] 45+45 0x1fffffff800 +[ 46] 46+46 0x3fffffff000 +[ 47] 47+47 0x7ffffffe000 +[ 48] 48+48 0xfffffffc000 +[ 49] 49+49 0x1fffffff8000 +[ 50] 50+50 0x3fffffff0000 +[ 51] 51+51 0x7ffffffe0000 +[ 52] 52+52 0xfffffffc0000 +[ 53] 53+53 0x1fffffff80000 +[ 54] 54+54 0x3fffffff00000 +[ 55] 55+55 0x7ffffffe00000 +[ 56] 56+56 0xfffffffc00000 +[ 57] 57+57 0x1fffffff800000 +[ 58] 58+58 0x3fffffff000000 +[ 59] 59+59 0x7ffffffe000000 +[ 60] 60+60 0xfffffffc000000 +[ 61] 61+61 0x1fffffff8000000 +[ 62] 62+62 0x3fffffff0000000 +[ 63] 63+63 0x7ffffffe0000000 +[ 64] 64+64 0xfffffffc0000000 +[ 65] 35+65 0xfffffffffffffff +[ 66] 66+66 0x1ffffffffffffffe +[ 67] 67+67 0x3ffffffffffffffc +[ 68] 68+68 0x7ffffffffffffff8 +[ 69] 69+69 0xfffffffffffffff0 +[ 70] 70+70 0x1ffffffffffffffe0 +[ 71] 71+71 0x3ffffffffffffffc0 +[ 72] 72+72 0x7ffffffffffffff80 +[ 73] 73+73 0xfffffffffffffff00 +[ 74] 74+74 0x1ffffffffffffffe00 +[ 75] 75+75 0x3ffffffffffffffc00 +[ 76] 76+76 0x7ffffffffffffff800 +[ 77] 77+77 0xfffffffffffffff000 +[ 78] 78+78 0x1ffffffffffffffe000 +[ 79] 79+79 0x3ffffffffffffffc000 +[ 80] 80+80 0x7ffffffffffffff8000 +[ 81] 81+81 0xfffffffffffffff0000 +[ 82] 82+82 0x1ffffffffffffffe0000 +[ 83] 83+83 0x3ffffffffffffffc0000 +[ 84] 84+84 0x7ffffffffffffff80000 +[ 85] 85+85 0xfffffffffffffff00000 +[ 86] 86+86 0x1ffffffffffffffe00000 +[ 87] 87+87 0x3ffffffffffffffc00000 +[ 88] 88+88 0x7ffffffffffffff800000 +[ 89] 89+89 0xfffffffffffffff000000 +[ 90] 90+90 0x1ffffffffffffffe000000 +[ 91] 91+91 0x3ffffffffffffffc000000 +[ 92] 92+92 0x7ffffffffffffff8000000 +[ 93] 93+93 0xfffffffffffffff0000000 +[ 94] 94+94 0x1ffffffffffffffe0000000 +[ 95] 95+95 0x3ffffffffffffffc0000000 +[ 96] 96+96 0x7ffffffffffffff80000000 +[ 97] 97+97 0xfffffffffffffff00000000 +[ 98] 98+98 0x1ffffffffffffffe00000000 +[ 99] 99+99 0x3ffffffffffffffc00000000 +[100] 100+100 0x7ffffffffffffff800000000 +[101] 101+101 0xfffffffffffffff000000000 +[102] 102+102 0x1ffffffffffffffe000000000 +[103] 103+103 0x3ffffffffffffffc000000000 +[104] 104+104 0x7ffffffffffffff8000000000 +[105] 105+105 0xfffffffffffffff0000000000 +[106] 106+106 0x1ffffffffffffffe0000000000 +[107] 107+107 0x3ffffffffffffffc0000000000 +[108] 108+108 0x7ffffffffffffff80000000000 +[109] 109+109 0xfffffffffffffff00000000000 +[110] 110+110 0x1ffffffffffffffe00000000000 +[111] 111+111 0x3ffffffffffffffc00000000000 +[112] 112+112 0x7ffffffffffffff800000000000 +[113] 113+113 0xfffffffffffffff000000000000 +[114] 114+114 0x1ffffffffffffffe000000000000 +[115] 115+115 0x3ffffffffffffffc000000000000 +[116] 116+116 0x7ffffffffffffff8000000000000 +[117] 117+117 0xfffffffffffffff0000000000000 +[118] 118+118 0x1ffffffffffffffe0000000000000 +[119] 119+119 0x3ffffffffffffffc0000000000000 +[120] 120+120 0x7ffffffffffffff80000000000000 +[121] 121+121 0xfffffffffffffff00000000000000 +[122] 122+122 0x1ffffffffffffffe00000000000000 +[123] 123+123 0x3ffffffffffffffc00000000000000 +[124] 124+124 0x7ffffffffffffff800000000000000 +[125] 125+125 0xfffffffffffffff000000000000000 +[126] 66+126 0xffffffffffffffffffffffffffffff +[127] 127+127 0x1fffffffffffffffffffffffffffffe +[128] 128+128 0x3fffffffffffffffffffffffffffffc +[129] 129+129 0x7fffffffffffffffffffffffffffff8 +[130] 130+130 0xffffffffffffffffffffffffffffff0 +[131] 131+131 0x1fffffffffffffffffffffffffffffe0 +[132] 132+132 0x3fffffffffffffffffffffffffffffc0 +[133] 133+133 0x7fffffffffffffffffffffffffffff80 +[134] 134+134 0xffffffffffffffffffffffffffffff00 +[135] 135+135 0x1fffffffffffffffffffffffffffffe00 +[136] 136+136 0x3fffffffffffffffffffffffffffffc00 +[137] 137+137 0x7fffffffffffffffffffffffffffff800 +[138] 138+138 0xffffffffffffffffffffffffffffff000 +[139] 139+139 0x1fffffffffffffffffffffffffffffe000 +[140] 140+140 0x3fffffffffffffffffffffffffffffc000 +[141] 141+141 0x7fffffffffffffffffffffffffffff8000 +[142] 142+142 0xffffffffffffffffffffffffffffff0000 +[143] 143+143 0x1fffffffffffffffffffffffffffffe0000 +[144] 144+144 0x3fffffffffffffffffffffffffffffc0000 +[145] 145+145 0x7fffffffffffffffffffffffffffff80000 +[146] 146+146 0xffffffffffffffffffffffffffffff00000 +[147] 147+147 0x1fffffffffffffffffffffffffffffe00000 +[148] 148+148 0x3fffffffffffffffffffffffffffffc00000 +[149] 149+149 0x7fffffffffffffffffffffffffffff800000 +[150] 150+150 0xffffffffffffffffffffffffffffff000000 +[151] 151+151 0x1fffffffffffffffffffffffffffffe000000 +[152] 152+152 0x3fffffffffffffffffffffffffffffc000000 +[153] 153+153 0x7fffffffffffffffffffffffffffff8000000 +[154] 154+154 0xffffffffffffffffffffffffffffff0000000 +[155] 155+155 0x1fffffffffffffffffffffffffffffe0000000 +[156] 156+156 0x3fffffffffffffffffffffffffffffc0000000 +[157] 157+157 0x7fffffffffffffffffffffffffffff80000000 +[158] 158+158 0xffffffffffffffffffffffffffffff00000000 +[159] 159+159 0x1fffffffffffffffffffffffffffffe00000000 +[160] 160+160 0x3fffffffffffffffffffffffffffffc00000000 +[161] 161+161 0x7fffffffffffffffffffffffffffff800000000 +[162] 162+162 0xffffffffffffffffffffffffffffff000000000 +[163] 163+163 0x1fffffffffffffffffffffffffffffe000000000 +[164] 164+164 0x3fffffffffffffffffffffffffffffc000000000 +[165] 165+165 0x7fffffffffffffffffffffffffffff8000000000 +[166] 166+166 0xffffffffffffffffffffffffffffff0000000000 +[167] 167+167 0x1fffffffffffffffffffffffffffffe0000000000 +[168] 168+168 0x3fffffffffffffffffffffffffffffc0000000000 +[169] 169+169 0x7fffffffffffffffffffffffffffff80000000000 +[170] 170+170 0xffffffffffffffffffffffffffffff00000000000 +[171] 171+171 0x1fffffffffffffffffffffffffffffe00000000000 +[172] 172+172 0x3fffffffffffffffffffffffffffffc00000000000 +[173] 173+173 0x7fffffffffffffffffffffffffffff800000000000 +[174] 174+174 0xffffffffffffffffffffffffffffff000000000000 +[175] 175+175 0x1fffffffffffffffffffffffffffffe000000000000 +[176] 176+176 0x3fffffffffffffffffffffffffffffc000000000000 +[177] 177+177 0x7fffffffffffffffffffffffffffff8000000000000 +[178] 178+178 0xffffffffffffffffffffffffffffff0000000000000 +[179] 179+179 0x1fffffffffffffffffffffffffffffe0000000000000 +[180] 180+180 0x3fffffffffffffffffffffffffffffc0000000000000 +[181] 181+181 0x7fffffffffffffffffffffffffffff80000000000000 +[182] 182+182 0xffffffffffffffffffffffffffffff00000000000000 +[183] 183+183 0x1fffffffffffffffffffffffffffffe00000000000000 +[184] 184+184 0x3fffffffffffffffffffffffffffffc00000000000000 +[185] 185+185 0x7fffffffffffffffffffffffffffff800000000000000 +[186] 186+186 0xffffffffffffffffffffffffffffff000000000000000 +[187] 187+187 0x1fffffffffffffffffffffffffffffe000000000000000 +[188] 188+188 0x3fffffffffffffffffffffffffffffc000000000000000 +[189] 189+189 0x7fffffffffffffffffffffffffffff8000000000000000 +[190] 190+190 0xffffffffffffffffffffffffffffff0000000000000000 +[191] 191+191 0x1fffffffffffffffffffffffffffffe0000000000000000 +[192] 192+192 0x3fffffffffffffffffffffffffffffc0000000000000000 +[193] 193+193 0x7fffffffffffffffffffffffffffff80000000000000000 +[194] 194+194 0xffffffffffffffffffffffffffffff00000000000000000 +[195] 195+195 0x1fffffffffffffffffffffffffffffe00000000000000000 +[196] 196+196 0x3fffffffffffffffffffffffffffffc00000000000000000 +[197] 197+197 0x7fffffffffffffffffffffffffffff800000000000000000 +[198] 198+198 0xffffffffffffffffffffffffffffff000000000000000000 +[199] 199+199 0x1fffffffffffffffffffffffffffffe000000000000000000 +[200] 200+200 0x3fffffffffffffffffffffffffffffc000000000000000000 +[201] 201+201 0x7fffffffffffffffffffffffffffff8000000000000000000 +[202] 202+202 0xffffffffffffffffffffffffffffff0000000000000000000 +[203] 203+203 0x1fffffffffffffffffffffffffffffe0000000000000000000 +[204] 204+204 0x3fffffffffffffffffffffffffffffc0000000000000000000 +[205] 205+205 0x7fffffffffffffffffffffffffffff80000000000000000000 +[206] 206+206 0xffffffffffffffffffffffffffffff00000000000000000000 +[207] 207+207 0x1fffffffffffffffffffffffffffffe00000000000000000000 +[208] 208+208 0x3fffffffffffffffffffffffffffffc00000000000000000000 +[209] 209+209 0x7fffffffffffffffffffffffffffff800000000000000000000 +[210] 210+210 0xffffffffffffffffffffffffffffff000000000000000000000 +[211] 211+211 0x1fffffffffffffffffffffffffffffe000000000000000000000 +[212] 212+212 0x3fffffffffffffffffffffffffffffc000000000000000000000 +[213] 213+213 0x7fffffffffffffffffffffffffffff8000000000000000000000 +[214] 214+214 0xffffffffffffffffffffffffffffff0000000000000000000000 +[215] 215+215 0x1fffffffffffffffffffffffffffffe0000000000000000000000 +[216] 216+216 0x3fffffffffffffffffffffffffffffc0000000000000000000000 +[217] 217+217 0x7fffffffffffffffffffffffffffff80000000000000000000000 +[218] 218+218 0xffffffffffffffffffffffffffffff00000000000000000000000 +[219] 219+219 0x1fffffffffffffffffffffffffffffe00000000000000000000000 +[220] 220+220 0x3fffffffffffffffffffffffffffffc00000000000000000000000 +[221] 221+221 0x7fffffffffffffffffffffffffffff800000000000000000000000 +[222] 222+222 0xffffffffffffffffffffffffffffff000000000000000000000000 +[223] 223+223 0x1fffffffffffffffffffffffffffffe000000000000000000000000 +[224] 224+224 0x3fffffffffffffffffffffffffffffc000000000000000000000000 +[225] 225+225 0x7fffffffffffffffffffffffffffff8000000000000000000000000 +[226] 226+226 0xffffffffffffffffffffffffffffff0000000000000000000000000 +[227] 227+227 0x1fffffffffffffffffffffffffffffe0000000000000000000000000 +[228] 228+228 0x3fffffffffffffffffffffffffffffc0000000000000000000000000 +[229] 229+229 0x7fffffffffffffffffffffffffffff80000000000000000000000000 +[230] 230+230 0xffffffffffffffffffffffffffffff00000000000000000000000000 +[231] 231+231 0x1fffffffffffffffffffffffffffffe00000000000000000000000000 +[232] 232+232 0x3fffffffffffffffffffffffffffffc00000000000000000000000000 +[233] 233+233 0x7fffffffffffffffffffffffffffff800000000000000000000000000 +[234] 234+234 0xffffffffffffffffffffffffffffff000000000000000000000000000 +[235] 235+235 0x1fffffffffffffffffffffffffffffe000000000000000000000000000 +[236] 236+236 0x3fffffffffffffffffffffffffffffc000000000000000000000000000 +[237] 237+237 0x7fffffffffffffffffffffffffffff8000000000000000000000000000 +[238] 238+238 0xffffffffffffffffffffffffffffff0000000000000000000000000000 +[239] 239+239 0x1fffffffffffffffffffffffffffffe0000000000000000000000000000 +[240] 240+240 0x3fffffffffffffffffffffffffffffc0000000000000000000000000000 +[241] 241+241 0x7fffffffffffffffffffffffffffff80000000000000000000000000000 +[242] 242+242 0xffffffffffffffffffffffffffffff00000000000000000000000000000 +[243] 243+243 0x1fffffffffffffffffffffffffffffe00000000000000000000000000000 +[244] 244+244 0x3fffffffffffffffffffffffffffffc00000000000000000000000000000 +[245] 245+245 0x7fffffffffffffffffffffffffffff800000000000000000000000000000 +[246] 246+246 0xffffffffffffffffffffffffffffff000000000000000000000000000000 +[247] 127+247 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +[248] 248+248 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe +[249] 249+249 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc +[250] 250+250 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8 +[251] 251+251 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0 +[252] 252+252 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0 +[253] 253+253 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0 +[254] 254+254 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80 +[255] 255+255 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +[256] 256+256 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00 +[257] 257+257 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00 +[258] 13+258 0x3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +[259] 259+259 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe +[260] 260+260 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc +[261] 0+261 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd +[262] 262+262 0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa +[263] 263+263 0x3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4 +[264] 264+264 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe8 +[265] 2+265 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb diff --git a/internal/gen/testdata/builtin/script.golden b/internal/gen/testdata/builtin/script.golden new file mode 100644 index 0000000..a5c8d8d --- /dev/null +++ b/internal/gen/testdata/builtin/script.golden @@ -0,0 +1,14 @@ +_10 = 2*1 +_11 = 1 + _10 +_1100 = _11 << 2 +_1111 = _11 + _1100 +_11110000 = _1111 << 4 +_11111111 = _1111 + _11110000 +x10 = _11111111 << 2 + _11 +x20 = x10 << 10 + x10 +x30 = x20 << 10 + x10 +x60 = x30 << 30 + x30 +x120 = x60 << 60 + x60 +x240 = x120 << 120 + x120 +x250 = x240 << 10 + x10 +return (x250 << 2 + 1) << 3 + _11 diff --git a/internal/gen/testdata/input.acc b/internal/gen/testdata/input.acc new file mode 100644 index 0000000..a5c8d8d --- /dev/null +++ b/internal/gen/testdata/input.acc @@ -0,0 +1,14 @@ +_10 = 2*1 +_11 = 1 + _10 +_1100 = _11 << 2 +_1111 = _11 + _1100 +_11110000 = _1111 << 4 +_11111111 = _1111 + _11110000 +x10 = _11111111 << 2 + _11 +x20 = x10 << 10 + x10 +x30 = x20 << 10 + x10 +x60 = x30 << 30 + x30 +x120 = x60 << 60 + x60 +x240 = x120 << 120 + x120 +x250 = x240 << 10 + x10 +return (x250 << 2 + 1) << 3 + _11 diff --git a/internal/tools/docgen/main.go b/internal/tools/docgen/main.go index b2cc332..7a36f09 100644 --- a/internal/tools/docgen/main.go +++ b/internal/tools/docgen/main.go @@ -9,12 +9,15 @@ import ( "fmt" "io/ioutil" "log" + "net/url" "os" "path" + "path/filepath" "regexp" "strings" "text/template" + "github.com/mmcloughlin/addchain/internal/gen" "github.com/mmcloughlin/addchain/internal/results" "github.com/mmcloughlin/addchain/meta" ) @@ -44,11 +47,10 @@ func mainerr() (err error) { t := template.New("doc") t.Funcs(template.FuncMap{ + "link": rellink(*output), "include": include, "snippet": snippet, "anchor": anchor, - "pkg": pkg, - "sym": sym, "bibentry": bibentry, "biburl": biburl, "toc": toc, @@ -57,6 +59,9 @@ func mainerr() (err error) { "sum": symbol('\u2211'), }) + t.Funcs(pkgfuncs("", meta.Meta.Module())) + t.Funcs(pkgfuncs("std", "")) + // Load template. s, err := load() if err != nil { @@ -72,6 +77,9 @@ func mainerr() (err error) { "Meta": meta.Meta, "Results": results.Results, "Bibliography": bibliography, + + "BuiltinTemplateNames": gen.BuiltinTemplateNames(), + "TemplateFunctions": gen.Functions, } // Execute. @@ -127,6 +135,17 @@ func load() (string, error) { return string(b), nil } +// link to a file in the repository. +func rellink(output string) func(string) (string, error) { + base := filepath.Dir(output) + return func(filename string) (string, error) { + if _, err := os.Stat(filename); err != nil { + return "", err + } + return filepath.Rel(base, filename) + } +} + // include template function. func include(filename string) (string, error) { b, err := ioutil.ReadFile(filename) @@ -181,19 +200,34 @@ func anchor(heading string) string { return r.Replace(strings.ToLower((heading))) } -// pkg returns markdown for a package with a link to documentation. -func pkg(name string) string { - return fmt.Sprintf("[`%s`](%s)", name, pkgurl(name)) -} - -// sym returns markdown for a symbol with a link to documentation. -func sym(pkg, name string) string { - return fmt.Sprintf("[`%s.%s`](%s#%s)", path.Base(pkg), name, pkgurl(pkg), name) +// pkgfuncs builds template functions for references to packages linked to +// documentation. +func pkgfuncs(prefix, mod string) template.FuncMap { + return template.FuncMap{ + // pkgurl returns url to package documentation. + prefix + "pkgurl": func(pkg string) string { + return pkgurl(mod, pkg, "") + }, + // pkg returns markdown for a package with a link to documentation. + prefix + "pkg": func(pkg string) string { + return fmt.Sprintf("[`%s`](%s)", pkg, pkgurl(mod, pkg, "")) + }, + // sym returns markdown for a symbol with a link to documentation. + prefix + "sym": func(pkg, name string) string { + return fmt.Sprintf("[`%s.%s`](%s)", path.Base(pkg), name, pkgurl(mod, pkg, name)) + }, + } } -// pkgurl returns url to go.dev documentation on the given sub-package. -func pkgurl(name string) string { - return "https://pkg.go.dev/" + path.Join("github.com/mmcloughlin/addchain", name) +// pkgurl returns url to go.dev documentation for a given package. +func pkgurl(mod, pkg, fragment string) string { + u := url.URL{ + Scheme: "https", + Host: "pkg.go.dev", + Path: path.Join(mod, pkg), + Fragment: fragment, + } + return u.String() } // bibentry returns formatted bibliography entry for the given citation name. diff --git a/internal/tools/docgen/templates/gen.tmpl b/internal/tools/docgen/templates/gen.tmpl new file mode 100644 index 0000000..61f88d5 --- /dev/null +++ b/internal/tools/docgen/templates/gen.tmpl @@ -0,0 +1,106 @@ +# Output Generation + +{{ toc }} + +{{- $templatereference := "Template Reference" -}} +{{- $builtins := "Builtin Templates" }} + +## Example + +Let's show an example of generating code for curve25519 field inversion. Search +for the best addition chain and save the result: + +```sh +{{ include "internal/examples/fp25519/00-search.sh" -}} +``` + +Now we can use the `{{ .Meta.Name }}` generate command to generate code to +execute the addition chain. By default, the generate command will show us a +concise listing of the instructions required to compute the addition chain. + +```sh +{{ include "internal/examples/fp25519/01-listing.sh" -}} +``` +Output: +``` +{{ include "internal/examples/fp25519/01-listing.out" -}} +``` + +This listing is intended to be a simple text format that could directly be +turned into code. The directives mean: + +* `tmp v ...`: declare temporary variables `v ...` +* `add z x y`: execute addition `z = x+y` +* `double z x`: execute doubling `z = 2*x` +* `shift z x n`: execute repeated doubling z = 2n*x + +Under the hood, `{{ .Meta.Name }}` has processed the addition chain into the {{ +sym "acc/ir" "Program" }} intermediate representation and used an allocation +pass to assign the minimum number of temporary variables. The listing format is +intended be a convient and easy-to-parse text format to use as input to other +tools. + +In addition, `{{ .Meta.Name }}` also offers templated output. In fact, the +listing is actually produced by the [listing](#listing) builtin template. See +below for details of the [templating language](#{{ anchor $templatereference }}) +and [builtin template examples](#{{ anchor $builtins }}). The following template +can be used to directly produce Go code to execute the inversion chain: + +``` +{{ include "internal/examples/fp25519/inv.tmpl" -}} +``` + +Generate code by passing the template to `{{ .Meta.Name }}`: +```sh +{{ include "internal/examples/fp25519/02-generate.sh" -}} +``` +The end product: +```go +{{ include "internal/examples/fp25519/inv.go" -}} +``` + +This code is part of a [full working example]({{ link +"internal/examples/fp25519" }}) that passes tests. + +## {{ $templatereference }} + +Templates use Go {{ stdpkg "text/template" }} syntax. The data structure passed +to the template is: + +```go +{{ snippet "internal/gen/gen.go" "type Data" "^}" -}} +``` + +In addition to the [builtin functions]({{ stdpkgurl "text/template" }}#hdr-Functions), +templates may use: + +| Name | Signature | Description | +| ---- | --------- | ----------- | +{{ range .TemplateFunctions -}} +| **`{{ .Name }}`** | `{{ .Signature }}` | {{ .Description }} | +{{ end }} + +## {{ $builtins }} + +Example output for each builtin template is generated from the chain: + +``` +{{ include "internal/gen/testdata/input.acc" -}} +``` + +{{ range .BuiltinTemplateNames }} +### {{ . }} + +``` +{{ include (printf "internal/gen/templates/%s.tmpl" .) -}} +``` + +
+Output of {{ . }} template + +``` +{{ include (printf "internal/gen/testdata/builtin/%s.golden" .) -}} +``` + +
+{{ end }} diff --git a/internal/tools/docgen/templates/readme.tmpl b/internal/tools/docgen/templates/readme.tmpl index f21002d..ae6e6c3 100644 --- a/internal/tools/docgen/templates/readme.tmpl +++ b/internal/tools/docgen/templates/readme.tmpl @@ -21,6 +21,7 @@ generators. * Generic optimization methods eliminate redundant operations * Simple domain-specific language for addition chain computations * Command-line interface or library +* Code generation and templated output support {{ toc }} @@ -80,12 +81,12 @@ delta from the library result. | ---- | -----------: | ---------: | ----: | {{ range .Results -}} {{- if gt .BestKnown 0 -}} -| [{{ .Name }}](doc/results.md#{{ anchor .Name }}) | {{ .Length }} | {{ .BestKnown }} | {{ if le .Delta 0 }}**{{ printf "%+d" .Delta }}**{{ else }}{{ printf "%+d" .Delta }}{{ end }} | +| [{{ .Name }}]({{ link "doc/results.md" }}#{{ anchor .Name }}) | {{ .Length }} | {{ .BestKnown }} | {{ if le .Delta 0 }}**{{ printf "%+d" .Delta }}**{{ else }}{{ printf "%+d" .Delta }}{{ end }} | {{ end -}} {{ end }} -See [full results listing](doc/results.md) for more detail and results for -less common exponents. +See [full results listing]({{ link "doc/results.md" }}) for more detail and +results for less common exponents. These results demonstrate that `addchain` is competitive with hand-optimized chains, often with equivalent or better performance. Even when `addchain` is @@ -113,15 +114,17 @@ go install {{ .Meta.Module }}/cmd/addchain@latest Search for a curve25519 field inversion addition chain with: ```sh -{{ include "internal/examples/cli/cmd.sh" -}} +{{ include "internal/examples/search/cmd.sh" -}} ``` Output: ``` -{{ include "internal/examples/cli/output" -}} +{{ include "internal/examples/search/cmd.out" -}} ``` +Next, you can [generate code from this addition chain]({{ link "doc/gen.md" }}). + ### Library Install: diff --git a/script/generate b/script/generate index 7348668..5456770 100755 --- a/script/generate +++ b/script/generate @@ -2,19 +2,17 @@ set -exuo pipefail -# Parse options. -all="false" -while getopts "a" opt; do - case "${opt}" in - a) all="true" ;; - esac -done +# Run examples. +go install ./cmd/addchain -# Run example program. -if [ "${all}" = "true" ]; then - go install ./cmd/addchain - bash ./internal/examples/cli/cmd.sh 2>&1 | tee ./internal/examples/cli/output -fi +for example in ./internal/examples/*; do + cd "${example}" + for script in *.sh; do + root="${script%.sh}" + bash "${script}" > "${root}.out" 2>&1 + done + cd - +done # go generate go generate -x ./... @@ -25,6 +23,7 @@ bib generate -bib doc/references.bib -type markdown -output doc/bibliography.md # Documentation. go run ./internal/tools/docgen -type readme -tocmax 3 -output README.md go run ./internal/tools/docgen -type results -output doc/results.md +go run ./internal/tools/docgen -type gen -tocmax 3 -output doc/gen.md go run ./internal/tools/docgen -type cff -output CITATION.cff go run ./internal/tools/docgen -type bibtex -output CITATION.bib go run ./internal/tools/docgen -type zenodo -output .zenodo.json