| // Copyright 2015 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package ssa |
| |
| import ( |
| "fmt" |
| "html" |
| "strings" |
| ) |
| |
| func (v *Value) HTML() string { |
| // TODO: Using the value ID as the class ignores the fact |
| // that value IDs get recycled and that some values |
| // are transmuted into other values. |
| s := v.String() |
| return fmt.Sprintf("<span class=\"%s ssa-value\">%s</span>", s, s) |
| } |
| |
| func (v *Value) LongHTML() string { |
| // TODO: Any intra-value formatting? |
| // I'm wary of adding too much visual noise, |
| // but a little bit might be valuable. |
| // We already have visual noise in the form of punctuation |
| // maybe we could replace some of that with formatting. |
| s := fmt.Sprintf("<span class=\"%s ssa-long-value\">", v.String()) |
| |
| linenumber := "<span class=\"no-line-number\">(?)</span>" |
| if v.Pos.IsKnown() { |
| linenumber = fmt.Sprintf("<span class=\"l%v line-number\">(%s)</span>", v.Pos.LineNumber(), v.Pos.LineNumberHTML()) |
| } |
| |
| s += fmt.Sprintf("%s %s = %s", v.HTML(), linenumber, v.Op.String()) |
| |
| s += " <" + html.EscapeString(v.Type.String()) + ">" |
| s += html.EscapeString(v.AuxString()) |
| for _, a := range v.Args { |
| s += fmt.Sprintf(" %s", a.HTML()) |
| } |
| r := v.Block.Func.RegAlloc |
| if int(v.ID) < len(r) && r[v.ID] != nil { |
| s += " : " + html.EscapeString(r[v.ID].String()) |
| } |
| if reg := v.Block.Func.TempRegs[v.ID]; reg != nil { |
| s += " tmp=" + reg.String() |
| } |
| var names []string |
| for name, values := range v.Block.Func.NamedValues { |
| for _, value := range values { |
| if value == v { |
| names = append(names, name.String()) |
| break // drop duplicates. |
| } |
| } |
| } |
| if len(names) != 0 { |
| s += " (" + strings.Join(names, ", ") + ")" |
| } |
| |
| s += "</span>" |
| return s |
| } |
| |
| func (b *Block) HTML() string { |
| // TODO: Using the value ID as the class ignores the fact |
| // that value IDs get recycled and that some values |
| // are transmuted into other values. |
| s := html.EscapeString(b.String()) |
| return fmt.Sprintf("<span class=\"%s ssa-block\">%s</span>", s, s) |
| } |
| |
| func (b *Block) LongHTML() string { |
| // TODO: improve this for HTML? |
| s := fmt.Sprintf("<span class=\"%s ssa-block\">%s</span>", html.EscapeString(b.String()), html.EscapeString(b.Kind.String())) |
| if b.Aux != nil { |
| s += html.EscapeString(fmt.Sprintf(" {%v}", b.Aux)) |
| } |
| if t := b.AuxIntString(); t != "" { |
| s += html.EscapeString(fmt.Sprintf(" [%v]", t)) |
| } |
| for _, c := range b.ControlValues() { |
| s += fmt.Sprintf(" %s", c.HTML()) |
| } |
| if len(b.Succs) > 0 { |
| s += " →" // right arrow |
| for _, e := range b.Succs { |
| c := e.B |
| s += " " + c.HTML() |
| } |
| } |
| switch b.Likely { |
| case BranchUnlikely: |
| s += " (unlikely)" |
| case BranchLikely: |
| s += " (likely)" |
| } |
| if b.Pos.IsKnown() { |
| // TODO does not begin to deal with the full complexity of line numbers. |
| // Maybe we want a string/slice instead, of outer-inner when inlining. |
| s += fmt.Sprintf(" <span class=\"l%v line-number\">(%s)</span>", b.Pos.LineNumber(), b.Pos.LineNumberHTML()) |
| } |
| return s |
| } |
| |
| func (b *Block) UnlikelyIndex() int { |
| switch b.Likely { |
| case BranchLikely: |
| return 1 |
| case BranchUnlikely: |
| return 0 |
| } |
| return -1 |
| } |