// SetAlias creates a type alias between the given name and type. func (ctx *Context) SetAlias(name string, typ Type) error { if _, ok := ctx.structs[name]; ok { return fmt.Errorf("redefinition of identified structure %q as type alias (%q)", enc.Local(name), typ) } if old, ok := ctx.alias[name]; ok { return fmt.Errorf("redefinition of type alias %q; old mapping %q, new mapping %q", enc.Local(name), old, typ) } ctx.alias[name] = typ return nil }
// String returns the string representation of the instruction. func (term *Br) String() string { cond := term.Cond() trueBranch, falseBranch := term.TrueBranch(), term.FalseBranch() // TODO: Make use of ValueString rather than enc.Local for trueBranch and // falseBranch. return fmt.Sprintf("br %s %s, label %s, label %s", cond.Type(), cond.ValueString(), enc.Local(trueBranch.Name()), enc.Local(falseBranch.Name())) }
func TestLocal(t *testing.T) { golden := []struct { s string want string }{ // i=0 {s: "foo", want: "%foo"}, // i=1 {s: "a b", want: `%a\20b`}, // i=2 {s: "$a", want: "%$a"}, // i=3 {s: "-a", want: "%-a"}, // i=4 {s: ".a", want: "%.a"}, // i=5 {s: "_a", want: "%_a"}, // i=6 {s: "#a", want: `%\23a`}, // i=7 {s: "a b#c", want: `%a\20b\23c`}, // i=8 {s: "2", want: "%2"}, // i=9 {s: "foo世bar", want: `%foo\E4\B8\96bar`}, } for i, g := range golden { got := enc.Local(g.s) if got != g.want { t.Errorf("i=%d: name mismatch; expected %q, got %q", i, g.want, got) } } }
// assignIDs assigns unique IDs to unnamed basic blocks and local variable // definitions. func (block *BasicBlock) assignIDs() error { f := block.Parent() // Named represents a named basic block or local variable definition. type Named interface { Name() string SetName(name string) } // setName assigns unique local IDs to unnamed basic blocks and local // variable definitions. setName := func(n Named) error { // TODO: Ensure that global variables cannot be mixed up with local // variables. This should be easy, as global variables may not be unnamed. // Check that global variables are always given a name during creation. if name := n.Name(); len(name) == 0 { n.SetName(f.nextID()) } else if isLocalID(name) { // Validate that explicitly named local IDs conform to the localID // counter and update the localID counter to keep explicitly and // implicitly named local IDs in sync. if want := f.nextID(); name != want { return errutil.Newf("invalid local ID; expected %s, got %s", enc.Local(want), enc.Local(name)) } } return nil } // Assign unique local IDs to unnamed basic blocks. if err := setName(block); err != nil { return errutil.Err(err) } // Assign unique local IDs to unnamed local variable definitions. for _, inst := range block.Insts() { if def, ok := inst.(*instruction.LocalVarDef); ok { if !types.IsVoid(def.ValInst().RetType()) { if err := setName(def); err != nil { return errutil.Err(err) } } } } return nil }
// Validate validates the type context by verifying that all identified // structures have been assigned bodies. func (ctx *Context) Validate() error { for _, t := range ctx.structs { if t.typ == nil { return fmt.Errorf("empty body of identified structure %q", enc.Local(t.Name())) } } return nil }
// String returns a string representation of the module. func (m *Module) String() string { // Data layout; e.g. // target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" buf := new(bytes.Buffer) if len(m.Layout) > 0 { fmt.Fprintf(buf, "target datalayout = %q\n", m.Layout) } // Target triple; e.g. // target triple = "x86_64-unknown-linux-gnu" if len(m.Triple) > 0 { fmt.Fprintf(buf, "target triple = %q\n", m.Triple) } // Type definitions; e.g. // %foo = type {i32} for _, typ := range m.Types { fmt.Fprintf(buf, "%v = type %v\n", enc.Local(typ.Name()), typ.Struct()) } // Global variables; e.g. // @x = global i32 42 for _, global := range m.Globals { fmt.Fprintln(buf, global) } // Function declarations; e.g. // declare i32 @printf(i8*, ...) // // Function definitions; e.g. // define i32 @main() { // ret i32 42 // } for _, f := range m.Funcs { fmt.Fprintln(buf, f) } // TODO: Print named metadata. // TODO: Print metadata. return buf.String() }
// String returns the string representation of the instruction. func (term *Jmp) String() string { return fmt.Sprintf("br label %s", enc.Local(term.target.Name())) }
func BenchmarkLocalReplace(b *testing.B) { for i := 0; i < b.N; i++ { enc.Local("$foo bar#baz") } }
// ValueString returns a string representation of the value. func (block *BasicBlock) ValueString() string { return enc.Local(block.Name()) }
// ValueString returns a string representation of the value. func (t *Param) ValueString() string { return enc.Local(t.Name()) }
// String returns a string representation of the function parameter type. func (t *Param) String() string { if len(t.name) > 0 { return fmt.Sprintf("%v %v", t.typ, enc.Local(t.name)) } return t.typ.String() }
// Struct returns the identified structure of the given name. If no such // structure exists, a new identified structure is created. To enable recursive // and forward references, identified structures are initially created without // bodies. It is the caller's responsibility to populate the body of the // identified structure. func (ctx *Context) Struct(name string) (*NamedStruct, error) { if old, ok := ctx.alias[name]; ok { return nil, fmt.Errorf("redefinition of type alias %q (%q) as identified structure", enc.Local(name), old) } t, ok := ctx.structs[name] if !ok { t = &NamedStruct{name: name} ctx.structs[name] = t } return t, nil }
// String returns a string representation of the identified structure type. // // As identified structure types may include recursive references, they are // always printed by their type names. func (t *NamedStruct) String() string { // e.g. "%regset" return enc.Local(t.Name()) }
// SetStruct sets the underlying structure type definition of the identified // structure. func (t *NamedStruct) SetStruct(typ *Struct) error { if typ == nil { t.typ = typ } else if !t.typ.Equal(typ) { return fmt.Errorf("redefinition of identified structure %q; old definition %v, new definition %v", enc.Local(t.Name()), t.typ, typ) } return nil }
// ValueString returns a string representation of the value. func (def *LocalVarDef) ValueString() string { return enc.Local(def.Name()) }