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 }