github.com/llir/llvm@v0.3.6/ir/module.go (about)

     1  package ir
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"strings"
     7  	"sync"
     8  
     9  	"github.com/llir/llvm/internal/enc"
    10  	"github.com/llir/llvm/internal/natsort"
    11  	"github.com/llir/llvm/ir/enum"
    12  	"github.com/llir/llvm/ir/metadata"
    13  	"github.com/llir/llvm/ir/types"
    14  	"github.com/llir/llvm/ir/value"
    15  	"github.com/pkg/errors"
    16  )
    17  
    18  // === [ Modules ] =============================================================
    19  
    20  // Module is an LLVM IR module, which consists of top-level declarations and
    21  // definitions.
    22  type Module struct {
    23  	// Type definitions.
    24  	TypeDefs []types.Type
    25  	// Global variable declarations and definitions.
    26  	Globals []*Global
    27  	// Function declarations and definitions.
    28  	Funcs []*Func
    29  
    30  	// extra.
    31  
    32  	// (optional) Source filename; or empty if not present.
    33  	SourceFilename string
    34  	// (optional) Data layout; or empty if not present.
    35  	DataLayout string
    36  	// (optional) Target triple; or empty if not present.
    37  	TargetTriple string
    38  	// (optional) Module-level inline assembly.
    39  	ModuleAsms []string
    40  	// (optional) Comdat definitions.
    41  	ComdatDefs []*ComdatDef
    42  	// (optional) Aliases.
    43  	Aliases []*Alias
    44  	// (optional) IFuncs.
    45  	IFuncs []*IFunc
    46  	// (optional) Attribute group definitions.
    47  	AttrGroupDefs []*AttrGroupDef
    48  	// (optional) Named metadata definitions.
    49  	NamedMetadataDefs map[string]*metadata.NamedDef
    50  	// (optional) Metadata definitions.
    51  	MetadataDefs []metadata.Definition
    52  	// (optional) Use-list order directives.
    53  	UseListOrders []*UseListOrder
    54  	// (optional) Basic block specific use-list order directives.
    55  	UseListOrderBBs []*UseListOrderBB
    56  
    57  	// mu prevents races on AssignGlobalIDs and AssignMetadataIDs.
    58  	mu sync.Mutex
    59  }
    60  
    61  // NewModule returns a new LLVM IR module.
    62  func NewModule() *Module {
    63  	return &Module{
    64  		NamedMetadataDefs: make(map[string]*metadata.NamedDef),
    65  	}
    66  }
    67  
    68  // String returns the string representation of the module in LLVM IR assembly
    69  // syntax.
    70  func (m *Module) String() string {
    71  	buf := &strings.Builder{}
    72  	if _, err := m.WriteTo(buf); err != nil {
    73  		panic(fmt.Errorf("unable to write to string buffer; %v", err))
    74  	}
    75  	return buf.String()
    76  }
    77  
    78  // WriteTo write the string representation of the module in LLVM IR assembly
    79  // syntax to w.
    80  func (m *Module) WriteTo(w io.Writer) (n int64, err error) {
    81  	fw := &fmtWriter{w: w}
    82  	// Assign global IDs.
    83  	if err := m.AssignGlobalIDs(); err != nil {
    84  		panic(fmt.Errorf("unable to assign globals IDs of module; %v", err))
    85  	}
    86  	// Assign metadata IDs.
    87  	if err := m.AssignMetadataIDs(); err != nil {
    88  		panic(fmt.Errorf("unable to assign metadata IDs of module; %v", err))
    89  	}
    90  	// Source filename.
    91  	if len(m.SourceFilename) > 0 {
    92  		// 'source_filename' '=' Name=StringLit
    93  		fw.Fprintf("source_filename = %s\n", quote(m.SourceFilename))
    94  	}
    95  	// Data layout.
    96  	if len(m.DataLayout) > 0 {
    97  		// 'target' 'datalayout' '=' DataLayout=StringLit
    98  		fw.Fprintf("target datalayout = %s\n", quote(m.DataLayout))
    99  	}
   100  	// Target triple.
   101  	if len(m.TargetTriple) > 0 {
   102  		// 'target' 'triple' '=' TargetTriple=StringLit
   103  		fw.Fprintf("target triple = %s\n", quote(m.TargetTriple))
   104  	}
   105  	// Module-level inline assembly.
   106  	if len(m.ModuleAsms) > 0 && fw.size > 0 {
   107  		fw.Fprint("\n")
   108  	}
   109  	for _, asm := range m.ModuleAsms {
   110  		// 'module' 'asm' Asm=StringLit
   111  		fw.Fprintf("module asm %s\n", quote(asm))
   112  	}
   113  	// Type definitions.
   114  	if len(m.TypeDefs) > 0 && fw.size > 0 {
   115  		fw.Fprint("\n")
   116  	}
   117  	for _, t := range m.TypeDefs {
   118  		// Name=LocalIdent '=' 'type' Typ=OpaqueType
   119  		//
   120  		// Name=LocalIdent '=' 'type' Typ=Type
   121  		fw.Fprintf("%s = type %s\n", t, t.LLString())
   122  	}
   123  	// Comdat definitions.
   124  	if len(m.ComdatDefs) > 0 && fw.size > 0 {
   125  		fw.Fprint("\n")
   126  	}
   127  	for _, def := range m.ComdatDefs {
   128  		fw.Fprintln(def.LLString())
   129  	}
   130  	// Global declarations and definitions.
   131  	if len(m.Globals) > 0 && fw.size > 0 {
   132  		fw.Fprint("\n")
   133  	}
   134  	for _, g := range m.Globals {
   135  		fw.Fprintln(g.LLString())
   136  	}
   137  	// Aliases.
   138  	if len(m.Aliases) > 0 && fw.size > 0 {
   139  		fw.Fprint("\n")
   140  	}
   141  	for _, alias := range m.Aliases {
   142  		fw.Fprintln(alias.LLString())
   143  	}
   144  	// IFuncs.
   145  	if len(m.IFuncs) > 0 && fw.size > 0 {
   146  		fw.Fprint("\n")
   147  	}
   148  	for _, ifunc := range m.IFuncs {
   149  		fw.Fprintln(ifunc.LLString())
   150  	}
   151  	// Function declarations and definitions.
   152  	if len(m.Funcs) > 0 && fw.size > 0 {
   153  		fw.Fprint("\n")
   154  	}
   155  	for i, f := range m.Funcs {
   156  		if i != 0 {
   157  			fw.Fprint("\n")
   158  		}
   159  		fw.Fprintln(f.LLString())
   160  	}
   161  	// Attribute group definitions.
   162  	if len(m.AttrGroupDefs) > 0 && fw.size > 0 {
   163  		fw.Fprint("\n")
   164  	}
   165  	for _, a := range m.AttrGroupDefs {
   166  		fw.Fprintln(a.LLString())
   167  	}
   168  	// Named metadata definitions; output in natural sorting order.
   169  	var mdNames []string
   170  	for mdName := range m.NamedMetadataDefs {
   171  		mdNames = append(mdNames, mdName)
   172  	}
   173  	natsort.Strings(mdNames)
   174  	if len(m.NamedMetadataDefs) > 0 && fw.size > 0 {
   175  		fw.Fprint("\n")
   176  	}
   177  	for _, mdName := range mdNames {
   178  		// Name=MetadataName '=' '!' '{' MDNodes=(MetadataNode separator ',')* '}'
   179  		md := m.NamedMetadataDefs[mdName]
   180  		fw.Fprintf("%s = %s\n", md.Ident(), md.LLString())
   181  	}
   182  	// Metadata definitions.
   183  	if len(m.MetadataDefs) > 0 && fw.size > 0 {
   184  		fw.Fprint("\n")
   185  	}
   186  	for _, md := range m.MetadataDefs {
   187  		// ID=MetadataID '=' Distinctopt MDNode=MDTuple
   188  		//
   189  		// ID=MetadataID '=' Distinctopt MDNode=SpecializedMDNode
   190  		fw.Fprintf("%s = %s\n", md.Ident(), md.LLString())
   191  	}
   192  	// Use-list orders.
   193  	if len(m.UseListOrders) > 0 && fw.size > 0 {
   194  		fw.Fprint("\n")
   195  	}
   196  	for _, u := range m.UseListOrders {
   197  		fw.Fprintln(u)
   198  	}
   199  	// Basic block specific use-list orders.
   200  	if len(m.UseListOrderBBs) > 0 && fw.size > 0 {
   201  		fw.Fprint("\n")
   202  	}
   203  	for _, u := range m.UseListOrderBBs {
   204  		fw.Fprintln(u)
   205  	}
   206  	return fw.size, fw.err
   207  }
   208  
   209  // ~~~ [ Comdat Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   210  
   211  // ComdatDef is a comdat definition top-level entity.
   212  type ComdatDef struct {
   213  	// Comdat name (without '$' prefix).
   214  	Name string
   215  	// Comdat kind.
   216  	Kind enum.SelectionKind
   217  }
   218  
   219  // String returns the string representation of the Comdat definition.
   220  func (c *ComdatDef) String() string {
   221  	return fmt.Sprintf("comdat(%s)", enc.ComdatName(c.Name))
   222  }
   223  
   224  // LLString returns the LLVM syntax representation of the Comdat definition.
   225  //
   226  // Name=ComdatName '=' 'comdat' Kind=SelectionKind
   227  func (c *ComdatDef) LLString() string {
   228  	return fmt.Sprintf("%s = comdat %s", enc.ComdatName(c.Name), c.Kind)
   229  }
   230  
   231  // ~~~ [ Attribute Group Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   232  
   233  // AttrGroupDef is an attribute group definition.
   234  type AttrGroupDef struct {
   235  	// Attribute group ID (without '#' prefix).
   236  	ID int64
   237  	// Function attributes.
   238  	FuncAttrs []FuncAttribute
   239  }
   240  
   241  // String returns the string representation of the attribute group definition.
   242  func (a *AttrGroupDef) String() string {
   243  	return enc.AttrGroupID(a.ID)
   244  }
   245  
   246  // LLString returns the LLVM syntax representation of the attribute group
   247  // definition.
   248  //
   249  // 'attributes' ID=AttrGroupID '=' '{' FuncAttrs=FuncAttribute* '}'
   250  func (a *AttrGroupDef) LLString() string {
   251  	buf := &strings.Builder{}
   252  	fmt.Fprintf(buf, "attributes %s = { ", enc.AttrGroupID(a.ID))
   253  	for i, attr := range a.FuncAttrs {
   254  		if i != 0 {
   255  			buf.WriteString(" ")
   256  		}
   257  		switch attr := attr.(type) {
   258  		case Align:
   259  			// Note, alignment is printed as `align = 8` in attribute groups.
   260  			fmt.Fprintf(buf, "align = %d", uint64(attr))
   261  		case AlignStack:
   262  			// Note, stack alignment is printed as `alignstack = 8` in attribute
   263  			// groups.
   264  			fmt.Fprintf(buf, "alignstack = %d", uint64(attr))
   265  		default:
   266  			buf.WriteString(attr.String())
   267  		}
   268  	}
   269  	buf.WriteString(" }")
   270  	return buf.String()
   271  }
   272  
   273  // ~~~ [ Use-list Order Directives ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   274  
   275  // UseListOrder is a use-list order directive.
   276  type UseListOrder struct {
   277  	// Value.
   278  	Value value.Value
   279  	// Use-list order.
   280  	Indices []uint64
   281  }
   282  
   283  // String returns the string representation of the use-list order directive
   284  // definition.
   285  func (u *UseListOrder) String() string {
   286  	//  'uselistorder' TypeValue ',' '{' Indices=(UintLit separator ',')+ '}'
   287  	buf := &strings.Builder{}
   288  	fmt.Fprintf(buf, "uselistorder %s, { ", u.Value)
   289  	for i, index := range u.Indices {
   290  		if i != 0 {
   291  			buf.WriteString(", ")
   292  		}
   293  		fmt.Fprintf(buf, "%d", index)
   294  	}
   295  	buf.WriteString(" }")
   296  	return buf.String()
   297  }
   298  
   299  // UseListOrderBB is a basic block specific use-list order directive.
   300  type UseListOrderBB struct {
   301  	// Function.
   302  	Func *Func
   303  	// Basic block.
   304  	Block *Block
   305  	// Use-list order.
   306  	Indices []uint64
   307  }
   308  
   309  // String returns the string representation of the basic block specific use-
   310  // list order directive definition.
   311  func (u *UseListOrderBB) String() string {
   312  	//  'uselistorder_bb' Func=GlobalIdent ',' Block=LocalIdent ',' '{'
   313  	//  Indices=(UintLit separator ',')+ '}'
   314  	buf := &strings.Builder{}
   315  	fmt.Fprintf(buf, "uselistorder_bb %s, %s, { ", u.Func.Ident(), u.Block.Ident())
   316  	for i, index := range u.Indices {
   317  		if i != 0 {
   318  			buf.WriteString(", ")
   319  		}
   320  		fmt.Fprintf(buf, "%d", index)
   321  	}
   322  	buf.WriteString(" }")
   323  	return buf.String()
   324  }
   325  
   326  // ### [ Helper functions ] ####################################################
   327  
   328  // AssignGlobalIDs assigns IDs to unnamed global variables.
   329  func (m *Module) AssignGlobalIDs() error {
   330  	m.mu.Lock()
   331  	defer m.mu.Unlock()
   332  	id := int64(0)
   333  	setName := func(n namedVar) error {
   334  		if n.IsUnnamed() {
   335  			if n.ID() != 0 && id != n.ID() {
   336  				want := id
   337  				got := n.ID()
   338  				return errors.Errorf("invalid global ID, expected %s, got %s", enc.GlobalID(want), enc.GlobalID(got))
   339  			}
   340  			n.SetID(id)
   341  			id++
   342  		}
   343  		return nil
   344  	}
   345  	// Assign global IDs to unnamed global variables.
   346  	for _, n := range m.Globals {
   347  		if err := setName(n); err != nil {
   348  			return errors.WithStack(err)
   349  		}
   350  	}
   351  	// Assign global IDs to unnamed aliases.
   352  	for _, n := range m.Aliases {
   353  		if err := setName(n); err != nil {
   354  			return errors.WithStack(err)
   355  		}
   356  	}
   357  	// Assign global IDs to unnamed IFuncs.
   358  	for _, n := range m.IFuncs {
   359  		if err := setName(n); err != nil {
   360  			return errors.WithStack(err)
   361  		}
   362  	}
   363  	// Assign global IDs to unnamed functions.
   364  	for _, n := range m.Funcs {
   365  		if err := setName(n); err != nil {
   366  			return errors.WithStack(err)
   367  		}
   368  	}
   369  	return nil
   370  }
   371  
   372  // AssignMetadataIDs assigns metadata IDs to the unnamed metadata definitions of
   373  // the module.
   374  func (m *Module) AssignMetadataIDs() error {
   375  	m.mu.Lock()
   376  	defer m.mu.Unlock()
   377  	// Index used IDs.
   378  	used := make(map[int64]bool)
   379  	for _, md := range m.MetadataDefs {
   380  		id := md.ID()
   381  		if id != -1 {
   382  			if _, ok := used[id]; ok {
   383  				return errors.Errorf("metadata ID %s already in use", enc.MetadataID(id))
   384  			}
   385  			used[id] = true
   386  		}
   387  	}
   388  	// nextID returns the next unused metdata ID.
   389  	curID := int64(-1)
   390  	nextID := func() int64 {
   391  		for {
   392  			curID++
   393  			if !used[curID] {
   394  				return curID
   395  			}
   396  		}
   397  	}
   398  	// Assign IDs to unnamed metadata definitions.
   399  	for _, md := range m.MetadataDefs {
   400  		id := md.ID()
   401  		if id != -1 {
   402  			// Metadata definition already has ID.
   403  			continue
   404  		}
   405  		newID := nextID()
   406  		md.SetID(newID)
   407  	}
   408  	return nil
   409  }