github.com/llir/llvm@v0.3.6/ir/helper.go (about) 1 package ir 2 3 import ( 4 "fmt" 5 "io" 6 "strconv" 7 "strings" 8 9 "github.com/llir/llvm/internal/enc" 10 "github.com/llir/llvm/ir/enum" 11 "github.com/llir/llvm/ir/metadata" 12 "github.com/llir/llvm/ir/types" 13 "github.com/llir/llvm/ir/value" 14 ) 15 16 // Align is a memory alignment attribute. 17 type Align uint64 18 19 // String returns the string representation of the alignment attribute. 20 func (align Align) String() string { 21 // Note, alignment is printed as `align = 8` in attribute groups. 22 return fmt.Sprintf("align %d", uint64(align)) 23 } 24 25 // AlignStack is a stack alignment attribute. 26 type AlignStack uint64 27 28 // String returns the string representation of the stack alignment attribute. 29 func (align AlignStack) String() string { 30 // Note, stack alignment is printed as `alignstack = 8` in attribute groups. 31 return fmt.Sprintf("alignstack(%d)", uint64(align)) 32 } 33 34 // AllocSize is an attribute for functions like malloc. If the second parameter 35 // is omitted, NElemsIndex will be -1. 36 type AllocSize struct { 37 // Element size parameter index. 38 ElemSizeIndex int 39 // Number of elements parameter index; -1 if not present. 40 NElemsIndex int 41 } 42 43 // String returns the string representation of the allocsize attribute. 44 func (a AllocSize) String() string { 45 if a.NElemsIndex == -1 { 46 return fmt.Sprintf("allocsize(%d)", a.ElemSizeIndex) 47 } 48 return fmt.Sprintf("allocsize(%d, %d)", a.ElemSizeIndex, a.NElemsIndex) 49 } 50 51 // Arg is a function argument with optional parameter attributes. 52 type Arg struct { 53 // Argument value. 54 value.Value 55 // (optional) Parameter attributes. 56 Attrs []ParamAttribute 57 } 58 59 // NewArg returns a new function argument based on the given value and parameter 60 // attributes. 61 func NewArg(x value.Value, attrs ...ParamAttribute) *Arg { 62 return &Arg{Value: x, Attrs: attrs} 63 } 64 65 // String returns a string representation of the function argument. 66 func (arg *Arg) String() string { 67 // Typ=ConcreteType Attrs=ParamAttribute* Val=Value 68 buf := &strings.Builder{} 69 buf.WriteString(arg.Type().String()) 70 for _, attr := range arg.Attrs { 71 fmt.Fprintf(buf, " %s", attr) 72 } 73 fmt.Fprintf(buf, " %s", arg.Ident()) 74 return buf.String() 75 } 76 77 // AttrPair is an attribute key-value pair (used in function, parameter and 78 // return attributes). 79 type AttrPair struct { 80 Key string 81 Value string 82 } 83 84 // String returns the string representation of the attribute key-value pair. 85 func (a AttrPair) String() string { 86 // Key=StringLit '=' Val=StringLit 87 return fmt.Sprintf("%s=%s", quote(a.Key), quote(a.Value)) 88 } 89 90 // AttrString is an attribute string (used in function, parameter and return 91 // attributes). 92 type AttrString string 93 94 // String returns the string representation of the attribute string. 95 func (a AttrString) String() string { 96 return quote(string(a)) 97 } 98 99 // ByRef is a byref parameter attribute. 100 type ByRef struct { 101 // Parameter type. 102 Typ types.Type 103 } 104 105 // String returns the string representation of the byref parameter attribute. 106 func (b ByRef) String() string { 107 // 'byref' '(' Typ=Type ')' 108 return fmt.Sprintf("byref(%s)", b.Typ) 109 } 110 111 // Byval is a byval parameter attribute. 112 type Byval struct { 113 // (optional) Parameter type. 114 Typ types.Type 115 } 116 117 // String returns the string representation of the byval parameter attribute. 118 func (b Byval) String() string { 119 // 'byval' 120 // 121 // 'byval' '(' Typ=Type ')' 122 if b.Typ != nil { 123 return fmt.Sprintf("byval(%s)", b.Typ) 124 } 125 return "byval" 126 } 127 128 // Dereferenceable is a dereferenceable memory attribute. 129 type Dereferenceable struct { 130 // Number of bytes known to be dereferenceable. 131 N uint64 132 // (optional) Either dereferenceable or null if set. 133 DerefOrNull bool 134 } 135 136 // String returns the string representation of the dereferenceable memory 137 // attribute. 138 func (d Dereferenceable) String() string { 139 // 'dereferenceable' '(' N=UintLit ')' 140 // 141 // 'dereferenceable_or_null' '(' N=UintLit ')' 142 if d.DerefOrNull { 143 return fmt.Sprintf("dereferenceable_or_null(%d)", d.N) 144 } 145 return fmt.Sprintf("dereferenceable(%d)", d.N) 146 } 147 148 // ElementType is a elementtype parameter attribute. 149 type ElementType struct { 150 // Parameter type. 151 Typ types.Type 152 } 153 154 // String returns the string representation of the elementtype parameter 155 // attribute. 156 func (b ElementType) String() string { 157 // 'elementtype' '(' Typ=Type ')' 158 return fmt.Sprintf("elementtype(%s)", b.Typ) 159 } 160 161 // InAlloca is a param attribute. 162 type InAlloca struct { 163 Typ types.Type 164 } 165 166 // String returns a string representation of the InAlloca attribute. 167 func (p InAlloca) String() string { 168 return fmt.Sprintf("inalloca(%v)", p.Typ) 169 } 170 171 // Preallocated is a func/param attribute. 172 type Preallocated struct { 173 Typ types.Type 174 } 175 176 // String returns a string representation of the Preallocated attribute. 177 func (p Preallocated) String() string { 178 return fmt.Sprintf("preallocated(%v)", p.Typ) 179 } 180 181 // VectorScaleRange denotes the min/max vector scale value of a given function. If 182 // the second parameter is omitted, Min will be -1. 183 type VectorScaleRange struct { 184 // Min value. 185 Min int 186 // Max value. 187 Max int 188 } 189 190 // String returns the string representation of the vscale_range attribute. 191 func (a VectorScaleRange) String() string { 192 if a.Min == -1 { 193 return fmt.Sprintf("vscale_range(%d)", a.Max) 194 } 195 return fmt.Sprintf("vscale_range(%d, %d)", a.Min, a.Max) 196 } 197 198 // TODO: check if *ir.InstLandingPad is a valid ExceptionPad. 199 200 // ExceptionPad is an exception pad or the none token. 201 // 202 // An ExceptionPad has one of the following underlying types. 203 // 204 // *ir.InstCatchPad 205 // *ir.InstCleanupPad 206 // *constant.NoneToken 207 type ExceptionPad interface { 208 value.Value 209 } 210 211 // FuncAttribute is a function attribute. 212 // 213 // A FuncAttribute has one of the following underlying types. 214 // 215 // ir.AttrString 216 // ir.AttrPair 217 // *ir.AttrGroupDef 218 // ir.Align 219 // ir.AlignStack 220 // ir.AllocSize 221 // enum.FuncAttr 222 type FuncAttribute interface { 223 fmt.Stringer 224 // IsFuncAttribute ensures that only function attributes can be assigned to 225 // the ir.FuncAttribute interface. 226 IsFuncAttribute() 227 } 228 229 // GlobalIdent is a global identifier. 230 type GlobalIdent struct { 231 GlobalName string 232 GlobalID int64 233 } 234 235 // Ident returns the identifier associated with the global identifier. 236 func (i GlobalIdent) Ident() string { 237 if i.IsUnnamed() { 238 return enc.GlobalID(i.GlobalID) 239 } 240 return enc.GlobalName(i.GlobalName) 241 } 242 243 // Name returns the name of the global identifier. 244 // 245 // If unnamed, the global ID is returned. To distinguish numeric names from 246 // unnamed IDs, numeric names are quoted. 247 func (i GlobalIdent) Name() string { 248 if i.IsUnnamed() { 249 return strconv.FormatInt(i.GlobalID, 10) 250 } 251 if x, err := strconv.ParseInt(i.GlobalName, 10, 64); err == nil { 252 // Print GlobalName with quotes if it is a number; e.g. "42". 253 return fmt.Sprintf(`"%d"`, x) 254 } 255 return i.GlobalName 256 } 257 258 // SetName sets the name of the global identifier. 259 func (i *GlobalIdent) SetName(name string) { 260 i.GlobalName = name 261 i.GlobalID = 0 262 } 263 264 // ID returns the ID of the global identifier. 265 func (i GlobalIdent) ID() int64 { 266 return i.GlobalID 267 } 268 269 // SetID sets the ID of the global identifier. 270 func (i *GlobalIdent) SetID(id int64) { 271 i.GlobalID = id 272 } 273 274 // IsUnnamed reports whether the global identifier is unnamed. 275 func (i GlobalIdent) IsUnnamed() bool { 276 return len(i.GlobalName) == 0 277 } 278 279 // LocalIdent is a local identifier. 280 type LocalIdent struct { 281 LocalName string 282 LocalID int64 283 } 284 285 // NewLocalIdent returns a new local identifier based on the given string. An 286 // unnamed local ID is used if ident is an integer, and a local name otherwise. 287 func NewLocalIdent(ident string) LocalIdent { 288 if id, err := strconv.ParseInt(ident, 10, 64); err == nil { 289 return LocalIdent{LocalID: id} 290 } 291 return LocalIdent{LocalName: ident} 292 } 293 294 // Ident returns the identifier associated with the local identifier. 295 func (i LocalIdent) Ident() string { 296 if i.IsUnnamed() { 297 return enc.LocalID(i.LocalID) 298 } 299 return enc.LocalName(i.LocalName) 300 } 301 302 // Name returns the name of the local identifier. 303 // 304 // If unnamed, the local ID is returned. To distinguish numeric names from 305 // unnamed IDs, numeric names are quoted. 306 func (i LocalIdent) Name() string { 307 if i.IsUnnamed() { 308 return strconv.FormatInt(i.LocalID, 10) 309 } 310 if x, err := strconv.ParseInt(i.LocalName, 10, 64); err == nil { 311 // Print LocalName with quotes if it is a number; e.g. "42". 312 return fmt.Sprintf(`"%d"`, x) 313 } 314 return i.LocalName 315 } 316 317 // SetName sets the name of the local identifier. 318 func (i *LocalIdent) SetName(name string) { 319 i.LocalName = name 320 i.LocalID = 0 321 } 322 323 // ID returns the ID of the local identifier. 324 func (i LocalIdent) ID() int64 { 325 return i.LocalID 326 } 327 328 // SetID sets the ID of the local identifier. 329 func (i *LocalIdent) SetID(id int64) { 330 i.LocalID = id 331 } 332 333 // IsUnnamed reports whether the local identifier is unnamed. 334 func (i LocalIdent) IsUnnamed() bool { 335 return len(i.LocalName) == 0 336 } 337 338 // Metadata is a list of metadata attachments. 339 type Metadata []*metadata.Attachment 340 341 // MDAttachments returns the metadata attachments of the value. 342 func (mds Metadata) MDAttachments() []*metadata.Attachment { 343 return mds 344 } 345 346 // OperandBundle is a tagged set of SSA values associated with a call-site. 347 type OperandBundle struct { 348 Tag string 349 Inputs []value.Value 350 } 351 352 // NewOperandBundle returns a new operand bundle based on the given tag and 353 // input values. 354 func NewOperandBundle(tag string, inputs ...value.Value) *OperandBundle { 355 return &OperandBundle{Tag: tag, Inputs: inputs} 356 } 357 358 // String returns a string representation of the operand bundle. 359 func (o *OperandBundle) String() string { 360 // Tag=StringLit '(' Inputs=(TypeValue separator ',')* ')' 361 buf := &strings.Builder{} 362 fmt.Fprintf(buf, "%s(", quote(o.Tag)) 363 for i, input := range o.Inputs { 364 if i != 0 { 365 buf.WriteString(", ") 366 } 367 buf.WriteString(input.String()) 368 } 369 buf.WriteString(")") 370 return buf.String() 371 } 372 373 // ParamAttribute is a parameter attribute. 374 // 375 // A ParamAttribute has one of the following underlying types. 376 // 377 // ir.AttrString 378 // ir.AttrPair 379 // ir.Align 380 // ir.Dereferenceable 381 // enum.ParamAttr 382 type ParamAttribute interface { 383 fmt.Stringer 384 // IsParamAttribute ensures that only parameter attributes can be assigned to 385 // the ir.ParamAttribute interface. 386 IsParamAttribute() 387 } 388 389 // ReturnAttribute is a return attribute. 390 // 391 // A ReturnAttribute has one of the following underlying types. 392 // 393 // ir.AttrString 394 // ir.AttrPair 395 // ir.Align 396 // ir.Dereferenceable 397 // enum.ReturnAttr 398 type ReturnAttribute interface { 399 fmt.Stringer 400 // IsReturnAttribute ensures that only return attributes can be assigned to 401 // the ir.ReturnAttribute interface. 402 IsReturnAttribute() 403 } 404 405 // ___ [ Function parameter ] __________________________________________________ 406 407 // Param is an LLVM IR function parameter. 408 type Param struct { 409 // (optional) Parameter name (without '%' prefix). 410 LocalIdent 411 // Parameter type. 412 Typ types.Type 413 414 // extra. 415 416 // (optional) Parameter attributes. 417 Attrs []ParamAttribute 418 } 419 420 // NewParam returns a new function parameter based on the given name and type. 421 func NewParam(name string, typ types.Type) *Param { 422 return &Param{ 423 LocalIdent: LocalIdent{LocalName: name}, 424 Typ: typ, 425 } 426 } 427 428 // String returns the LLVM syntax representation of the function parameter as a 429 // type-value pair. 430 func (p *Param) String() string { 431 return fmt.Sprintf("%s %s", p.Type(), p.Ident()) 432 } 433 434 // Type returns the type of the function parameter. 435 func (p *Param) Type() types.Type { 436 return p.Typ 437 } 438 439 // LLString returns the LLVM syntax representation of the function parameter. 440 // 441 // Typ=Type Attrs=ParamAttribute* Name=LocalIdent? 442 func (p *Param) LLString() string { 443 buf := &strings.Builder{} 444 buf.WriteString(p.Typ.String()) 445 for _, attr := range p.Attrs { 446 fmt.Fprintf(buf, " %s", attr) 447 } 448 fmt.Fprintf(buf, " %s", p.Ident()) 449 return buf.String() 450 } 451 452 // SRet is an sret parameter attribute. 453 type SRet struct { 454 Typ types.Type 455 } 456 457 // String returns the string representation of the sret parameter attribute. 458 func (s SRet) String() string { 459 // 'sret' '(' Typ=Type ')' 460 return fmt.Sprintf("sret(%s)", s.Typ) 461 } 462 463 // ### [ Helper functions ] #################################################### 464 465 // quote returns s as a double-quoted string literal. 466 func quote(s string) string { 467 return enc.Quote([]byte(s)) 468 } 469 470 // callingConvString returns the string representation of the given calling 471 // convention. 472 func callingConvString(callingConv enum.CallingConv) string { 473 s := callingConv.String() 474 cc := uint(callingConv) 475 if unknown := fmt.Sprintf("CallingConv(%d)", cc); s == unknown { 476 return fmt.Sprintf("cc %d", cc) 477 } 478 return s 479 } 480 481 // tlsModelString returns the string representation of the given thread local 482 // storage model. 483 func tlsModelString(model enum.TLSModel) string { 484 if model == enum.TLSModelGeneric { 485 return "thread_local" 486 } 487 return fmt.Sprintf("thread_local(%s)", model) 488 } 489 490 // --- [ Formatted I/O writer ] ------------------------------------------------ 491 492 // fmtWriter is a formatted I/O writer. 493 // 494 // A formatted I/O writer keeps track of the total number of bytes written to w 495 // and the first non-nil error encountered. 496 type fmtWriter struct { 497 // underlying io.Writer. 498 w io.Writer 499 // Number of bytes written to w. 500 size int64 501 // First non-nil error encountered. 502 err error 503 } 504 505 // Fprint formats using the default formats for its operands and writes to w. 506 // Spaces are added between operands when neither is a string. It returns the 507 // number of bytes written and any write error encountered. 508 func (fw *fmtWriter) Fprint(a ...interface{}) (n int, err error) { 509 if fw.err != nil { 510 // early return if a previous error has been encountered. 511 return 0, nil 512 } 513 n, err = fmt.Fprint(fw.w, a...) 514 fw.size += int64(n) 515 fw.err = err 516 return n, err 517 } 518 519 // Fprintf formats according to a format specifier and writes to w. It returns 520 // the number of bytes written and any write error encountered. 521 func (fw *fmtWriter) Fprintf(format string, a ...interface{}) (n int, err error) { 522 if fw.err != nil { 523 // early return if a previous error has been encountered. 524 return 0, nil 525 } 526 n, err = fmt.Fprintf(fw.w, format, a...) 527 fw.size += int64(n) 528 fw.err = err 529 return n, err 530 } 531 532 // Fprintln formats using the default formats for its operands and writes to w. 533 // Spaces are always added between operands and a newline is appended. It 534 // returns the number of bytes written and any write error encountered. 535 func (fw *fmtWriter) Fprintln(a ...interface{}) (n int, err error) { 536 if fw.err != nil { 537 // early return if a previous error has been encountered. 538 return 0, nil 539 } 540 n, err = fmt.Fprintln(fw.w, a...) 541 fw.size += int64(n) 542 fw.err = err 543 return n, err 544 } 545 546 // namedVar is a named variable. 547 type namedVar interface { 548 value.Named 549 // ID returns the ID of the local identifier. 550 ID() int64 551 // SetID sets the ID of the local identifier. 552 SetID(id int64) 553 // IsUnnamed reports whether the local identifier is unnamed. 554 IsUnnamed() bool 555 }