github.com/llir/llvm@v0.3.6/asm/helper.go (about) 1 package asm 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 8 "github.com/llir/ll/ast" 9 asmenum "github.com/llir/llvm/asm/enum" 10 "github.com/llir/llvm/internal/enc" 11 "github.com/llir/llvm/ir" 12 "github.com/llir/llvm/ir/constant" 13 "github.com/llir/llvm/ir/enum" 14 "github.com/llir/llvm/ir/metadata" 15 "github.com/llir/llvm/ir/types" 16 "github.com/llir/llvm/ir/value" 17 "github.com/pkg/errors" 18 ) 19 20 // === [ Identifiers ] ========================================================= 21 22 // --- [ Global identifiers ] -------------------------------------------------- 23 24 // globalIdent returns the identifier (without '@' prefix) of the given global 25 // identifier. 26 func globalIdent(old ast.GlobalIdent) ir.GlobalIdent { 27 ident := old.Text() 28 const prefix = "@" 29 if !strings.HasPrefix(ident, prefix) { 30 panic(fmt.Errorf("invalid global identifier %q; missing '%s' prefix", ident, prefix)) 31 } 32 ident = ident[len(prefix):] 33 // positive integer -> ID 34 // everything else (including negative integer) -> Name 35 if id, err := strconv.ParseInt(ident, 10, 64); err == nil && id >= 0 { 36 return ir.GlobalIdent{GlobalID: id} 37 } 38 // Unquote after trying to parse as ID, since @"42" is recognized as named 39 // and not unnamed. 40 ident = unquote(ident) 41 return ir.GlobalIdent{GlobalName: ident} 42 } 43 44 // --- [ Local identifiers ] --------------------------------------------------- 45 46 // localIdent returns the identifier (without '%' prefix) of the given local 47 // identifier. 48 func localIdent(old ast.LocalIdent) ir.LocalIdent { 49 ident := old.Text() 50 const prefix = "%" 51 if !strings.HasPrefix(ident, prefix) { 52 panic(fmt.Errorf("invalid local identifier %q; missing '%s' prefix", ident, prefix)) 53 } 54 ident = ident[len(prefix):] 55 // positive integer -> ID 56 // everything else (including negative integer) -> Name 57 if id, err := strconv.ParseInt(ident, 10, 64); err == nil && id >= 0 { 58 return ir.LocalIdent{LocalID: id} 59 } 60 // Unquote after trying to parse as ID, since %"42" is recognized as named 61 // and not unnamed. 62 ident = unquote(ident) 63 return ir.LocalIdent{LocalName: ident} 64 } 65 66 // --- [ Label identifiers ] --------------------------------------------------- 67 68 // labelIdent returns the identifier (without ':' suffix) of the given label 69 // identifier. 70 func labelIdent(old ast.LabelIdent) ir.LocalIdent { 71 ident := old.Text() 72 const suffix = ":" 73 if !strings.HasSuffix(ident, suffix) { 74 panic(fmt.Errorf("invalid label identifier %q; missing '%s' suffix", ident, suffix)) 75 } 76 ident = ident[:len(ident)-len(suffix)] 77 // positive integer -> ID 78 // everything else (including negative integer) -> Name 79 if id, err := strconv.ParseInt(ident, 10, 64); err == nil && id >= 0 { 80 return ir.LocalIdent{LocalID: id} 81 } 82 // Unquote after trying to parse as ID, since %"42" is recognized as named 83 // and not unnamed. 84 ident = unquote(ident) 85 return ir.LocalIdent{LocalName: ident} 86 } 87 88 // --- [ Attribute group identifiers ] ----------------------------------------- 89 90 // attrGroupID returns the ID (without '#' prefix) of the given attribute group 91 // ID. 92 func attrGroupID(old ast.AttrGroupID) int64 { 93 text := old.Text() 94 const prefix = "#" 95 if !strings.HasPrefix(text, prefix) { 96 panic(fmt.Errorf("invalid attribute group ID %q; missing '%s' prefix", text, prefix)) 97 } 98 text = text[len(prefix):] 99 id, err := strconv.ParseInt(text, 10, 64) 100 if err != nil { 101 panic(fmt.Errorf("unable to parse attribute group ID %q; %v", text, err)) 102 } 103 return id 104 } 105 106 // --- [ Comdat identifiers ] -------------------------------------------------- 107 108 // comdatName returns the name (without '%' prefix) of the given comdat name. 109 func comdatName(old ast.ComdatName) string { 110 name := old.Text() 111 const prefix = "$" 112 if !strings.HasPrefix(name, prefix) { 113 panic(fmt.Errorf("invalid comdat name %q; missing '%s' prefix", name, prefix)) 114 } 115 name = name[len(prefix):] 116 return unquote(name) 117 } 118 119 // --- [ Metadata identifiers ] ------------------------------------------------ 120 121 // metadataName returns the name (without '!' prefix) of the given metadata 122 // name. 123 func metadataName(old ast.MetadataName) string { 124 name := old.Text() 125 const prefix = "!" 126 if !strings.HasPrefix(name, prefix) { 127 panic(fmt.Errorf("invalid metadata name %q; missing '%s' prefix", name, prefix)) 128 } 129 name = name[len(prefix):] 130 return string(enc.Unescape(name)) 131 } 132 133 // metadataID returns the ID (without '!' prefix) of the given metadata ID. 134 func metadataID(old ast.MetadataID) int64 { 135 text := old.Text() 136 const prefix = "!" 137 if !strings.HasPrefix(text, prefix) { 138 panic(fmt.Errorf("invalid metadata ID %q; missing '%s' prefix", text, prefix)) 139 } 140 text = text[len(prefix):] 141 id, err := strconv.ParseInt(text, 10, 64) 142 if err != nil { 143 panic(fmt.Errorf("unable to parse metadata ID %q; %v", text, err)) 144 } 145 return id 146 } 147 148 // === [ Literals ] ============================================================ 149 150 // --- [ Integer literals ] ---------------------------------------------------- 151 152 // boolLit returns the boolean value corresponding to the given boolean literal. 153 func boolLit(old ast.BoolLit) bool { 154 text := old.Text() 155 switch text { 156 case "true": 157 return true 158 case "false": 159 return false 160 default: 161 panic(fmt.Errorf(`invalid boolean literal; expected "true" or "false", got %q`, text)) 162 } 163 } 164 165 // uintLit returns the unsigned integer value corresponding to the given 166 // unsigned integer literal. 167 func uintLit(old ast.UintLit) uint64 { 168 text := old.Text() 169 var x uint64 170 var err error 171 switch { 172 // unsigned hexadecimal integer literal 173 case strings.HasPrefix(text, "u0x"): 174 text = text[len("u0x"):] 175 x, err = strconv.ParseUint(text, 16, 64) 176 // signed hexadecimal integer literal 177 case strings.HasPrefix(text, "s0x"): 178 panic(fmt.Errorf("invalid use of signed hexadecimal integer literal %q; grammar for ast.UintLit denotes unsigned integer literal", text)) 179 default: 180 x, err = strconv.ParseUint(text, 10, 64) 181 } 182 if err != nil { 183 panic(fmt.Errorf("unable to parse unsigned integer literal %q; %v", text, err)) 184 } 185 return x 186 } 187 188 // uintSlice returns the slice of unsigned integer value corresponding to the given 189 // unsigned integer slice. 190 func uintSlice(olds []ast.UintLit) []uint64 { 191 xs := make([]uint64, len(olds)) 192 for i, old := range olds { 193 x := uintLit(old) 194 xs[i] = x 195 } 196 return xs 197 } 198 199 // intLit returns the integer value corresponding to the given integer literal. 200 func intLit(old ast.IntLit) int64 { 201 text := old.Text() 202 var x int64 203 var err error 204 switch { 205 // unsigned hexadecimal integer literal 206 case strings.HasPrefix(text, "u0x"): 207 text = text[len("u0x"):] 208 x, err = strconv.ParseInt(text, 16, 64) 209 // signed hexadecimal integer literal 210 case strings.HasPrefix(text, "s0x"): 211 // Note: the grammar uses ast.IntLit only for two purposes: 212 // 213 // 1) integer constants 214 // 2) signed integers of specialized metadata fields 215 // 216 // Integer constants are not parsed here, they are parsed by irIntConst 217 // using constant.NewIntFromString. 218 // 219 // In particular, we need to know the underlying type (bit size) associated 220 // with the integer literal to be able to parse signed values, as they are 221 // represented in two's complement hexadecimal notation. 222 // 223 // Type information is available when parsing integer constant values, as 224 // values are denoted by type-value pairs, so constant.NewIntFromString 225 // has all required information. 226 // 227 // However, when parsing signed values used for specialized metadata fields, 228 // this information is not available. As such, rather than potentially loosing 229 // information, we choose to panic and report the ambiguous use of "s0x" 230 // notation in specialized metadata fields, where `-42` would suffice. 231 panic(fmt.Errorf(`ambiguous use of signed hexadecimal integer literal %q, no type information available; consider using signed integer literal representation instead (e.g. "-42")`, text)) 232 default: 233 x, err = strconv.ParseInt(text, 10, 64) 234 } 235 if err != nil { 236 panic(fmt.Errorf("unable to parse integer literal %q; %v", text, err)) 237 } 238 return x 239 } 240 241 // --- [ String literals ] ----------------------------------------------------- 242 243 // stringLit returns the string corresponding to the given string literal. 244 func stringLit(old ast.StringLit) string { 245 return unquote(old.Text()) 246 } 247 248 // ___ [ Helpers ] _____________________________________________________________ 249 250 // irAddrSpace returns the IR address space corresponding to the given AST 251 // address space. 252 func irAddrSpace(old ast.AddrSpace) types.AddrSpace { 253 return types.AddrSpace(uintLit(old.N())) 254 } 255 256 // irAlign returns the IR alignment corresponding to the given AST alignment. 257 func irAlign(old ast.Align) ir.Align { 258 return ir.Align(uintLit(old.N())) 259 } 260 261 // irArg returns the IR argument corresponding to the given AST argument. 262 func (fgen *funcGen) irArg(old ast.Arg) (value.Value, error) { 263 typ, err := fgen.gen.irType(old.Typ()) 264 if err != nil { 265 return nil, errors.WithStack(err) 266 } 267 switch oldVal := old.Val().(type) { 268 case ast.Value: 269 x, err := fgen.irValue(typ, oldVal) 270 if err != nil { 271 return nil, errors.WithStack(err) 272 } 273 // (optional) Parameter attributes. 274 if oldAttrs := old.Attrs(); len(oldAttrs) > 0 { 275 attrs := make([]ir.ParamAttribute, len(oldAttrs)) 276 for i, oldAttr := range old.Attrs() { 277 attr, err := fgen.gen.irParamAttribute(oldAttr) 278 if err != nil { 279 return nil, errors.WithStack(err) 280 } 281 attrs[i] = attr 282 } 283 return &ir.Arg{Attrs: attrs, Value: x}, nil 284 } 285 return x, nil 286 case ast.Metadata: 287 md, err := fgen.irMetadata(oldVal) 288 if err != nil { 289 return nil, errors.WithStack(err) 290 } 291 return &metadata.Value{Value: md}, nil 292 default: 293 panic(fmt.Errorf("support for value %T not yet implemented", oldVal)) 294 } 295 } 296 297 // irBlock returns the IR basic block corresponding to the given AST label. 298 func (fgen *funcGen) irBlock(old ast.Label) (*ir.Block, error) { 299 ident := localIdent(old.Name()) 300 v, ok := fgen.locals[ident] 301 if !ok { 302 return nil, errors.Errorf("unable to locate local identifier %q", ident.Ident()) 303 } 304 block, ok := v.(*ir.Block) 305 if !ok { 306 return nil, errors.Errorf("invalid basic block type; expected *ir.Block, got %T", v) 307 } 308 return block, nil 309 } 310 311 // irCallingConv returns the IR calling convention corresponding to the given 312 // AST calling convention. 313 func irCallingConv(old ast.CallingConv) enum.CallingConv { 314 switch old := old.(type) { 315 case *ast.CallingConvEnum: 316 return asmenum.CallingConvFromString(old.Text()) 317 case *ast.CallingConvInt: 318 cc := uintLit(old.UintLit()) 319 switch cc { 320 case 0: 321 // Note, C calling convention is defined as 0 in LLVM. To have the zero-value 322 // calling convention mean no calling convention, re-define C calling 323 // convention as 1, and use 0 for none. 324 return enum.CallingConvC 325 default: 326 return enum.CallingConv(cc) 327 } 328 default: 329 panic(fmt.Errorf("support for calling convention type %T not yet implemented", old)) 330 } 331 } 332 333 // irCase returns the IR switch case corresponding to the given AST switch case. 334 func (fgen *funcGen) irCase(n ast.Case) (*ir.Case, error) { 335 // Case comparand. 336 x, err := fgen.gen.irTypeConst(n.X()) 337 if err != nil { 338 return nil, errors.WithStack(err) 339 } 340 // Case target branch. 341 target, err := fgen.irBlock(n.Target()) 342 if err != nil { 343 return nil, errors.WithStack(err) 344 } 345 return ir.NewCase(x, target), nil 346 } 347 348 // irClause returns the IR clause corresponding to the given AST clause. 349 func (fgen *funcGen) irClause(n ast.Clause) (*ir.Clause, error) { 350 x, err := fgen.irTypeValue(n.X()) 351 if err != nil { 352 return nil, errors.WithStack(err) 353 } 354 clauseType := asmenum.ClauseTypeFromString(n.ClauseType().Text()) 355 return ir.NewClause(clauseType, x), nil 356 } 357 358 // irExceptionArg returns the IR exception argument corresponding to the given 359 // AST exception argument. 360 func (fgen *funcGen) irExceptionArg(old ast.ExceptionArg) (value.Value, error) { 361 typ, err := fgen.gen.irType(old.Typ()) 362 if err != nil { 363 return nil, errors.WithStack(err) 364 } 365 switch val := old.Val().(type) { 366 case ast.Value: 367 return fgen.irValue(typ, val) 368 case ast.Metadata: 369 md, err := fgen.irMetadata(val) 370 if err != nil { 371 return nil, errors.WithStack(err) 372 } 373 return &metadata.Value{Value: md}, nil 374 default: 375 panic(fmt.Errorf("spport for exception argument value %T not yet implemented", val)) 376 } 377 } 378 379 // irExceptionPad returns the IR exception pad corresponding to the given AST 380 // exception pad. 381 func (fgen *funcGen) irExceptionPad(old ast.ExceptionPad) (ir.ExceptionPad, error) { 382 switch old := old.(type) { 383 case *ast.NoneConst: 384 return constant.None, nil 385 case *ast.LocalIdent: 386 ident := localIdent(*old) 387 v, ok := fgen.locals[ident] 388 if !ok { 389 return nil, errors.Errorf("unable to locate local identifier %q", ident.Ident()) 390 } 391 return v, nil 392 default: 393 panic(fmt.Errorf("spport for exception pad %T not yet implemented", old)) 394 } 395 } 396 397 // irFastMathFlags returns the IR fast math flags corresponding to the given AST 398 // fast math flags. 399 func irFastMathFlags(olds []ast.FastMathFlag) []enum.FastMathFlag { 400 if len(olds) == 0 { 401 return nil 402 } 403 flags := make([]enum.FastMathFlag, len(olds)) 404 for i, old := range olds { 405 flag := asmenum.FastMathFlagFromString(old.Text()) 406 flags[i] = flag 407 } 408 return flags 409 } 410 411 // irFuncAttribute returns the IR function attribute corresponding to the given 412 // AST function attribute. 413 func (gen *generator) irFuncAttribute(old ast.FuncAttribute) ir.FuncAttribute { 414 switch old := old.(type) { 415 case *ast.AttrString: 416 return ir.AttrString(unquote(old.Text())) 417 case *ast.AttrPair: 418 return ir.AttrPair{ 419 Key: unquote(old.Key().Text()), 420 Value: unquote(old.Val().Text()), 421 } 422 case *ast.AttrGroupID: 423 id := attrGroupID(*old) 424 def, ok := gen.new.attrGroupDefs[id] 425 if !ok { 426 // Attribute group definition for ID not found. 427 // 428 // The input file should have contained this definition, but seeing as 429 // the LLVM test suite contains several LLVM IR files which omit the 430 // attribute group definitions, we will play nice and add an empty 431 // definition instead of panicking. 432 // 433 // This issue is tracked at: https://github.com/llir/llvm/issues/37 434 def = &ir.AttrGroupDef{ID: id} 435 gen.new.attrGroupDefs[id] = def 436 } 437 return def 438 // TODO: add support for Align. 439 //case *ast.Align: 440 // return ir.Align(uintLit(old.N())) 441 case *ast.AlignPair: 442 return ir.Align(uintLit(old.N())) 443 case *ast.AlignStack: 444 return ir.AlignStack(uintLit(old.N())) 445 case *ast.AlignStackPair: 446 return ir.AlignStack(uintLit(old.N())) 447 case *ast.AllocSize: 448 elemSizeIndex := int(uintLit(old.ElemSizeIndex())) 449 if nElemsIndex, ok := old.NElemsIndex(); ok { 450 return ir.AllocSize{ 451 ElemSizeIndex: elemSizeIndex, 452 NElemsIndex: int(uintLit(nElemsIndex)), 453 } 454 } 455 return ir.AllocSize{ 456 ElemSizeIndex: elemSizeIndex, 457 NElemsIndex: -1, 458 } 459 case *ast.FuncAttr: 460 return asmenum.FuncAttrFromString(old.Text()) 461 case *ast.Preallocated: 462 typ, err := gen.irType(old.Typ()) 463 if err != nil { 464 panic(err.Error()) 465 } 466 return ir.Preallocated{Typ: typ} 467 case *ast.VScaleRange: 468 min := int(uintLit(old.Min())) 469 if max, ok := old.Max(); ok { 470 return ir.VectorScaleRange{ 471 Min: min, 472 Max: int(uintLit(max)), 473 } 474 } 475 return ir.VectorScaleRange{ 476 Min: -1, // NOTE: using -1 to denote omitted value. 477 Max: min, // NOTE: Min denotes Max if Max is not present. 478 } 479 default: 480 panic(fmt.Errorf("support for function attribute %T not yet implemented", old)) 481 } 482 } 483 484 // irImmutable returns the immutable boolean (constant or global) corresponding 485 // to the given AST immutable. 486 func irImmutable(old ast.Immutable) bool { 487 text := old.Text() 488 switch text { 489 case "constant": 490 return true 491 case "global": 492 return false 493 default: 494 panic(fmt.Errorf("support for immutable %q not yet implemented", text)) 495 } 496 } 497 498 // irIncoming returns the incoming value corresponding to the given AST incoming 499 // value. 500 func (fgen *funcGen) irIncoming(xType types.Type, oldX ast.Value, oldPred ast.LocalIdent) (*ir.Incoming, error) { 501 x, err := fgen.irValue(xType, oldX) 502 if err != nil { 503 return nil, errors.WithStack(err) 504 } 505 predIdent := localIdent(oldPred) 506 v, ok := fgen.locals[predIdent] 507 if !ok { 508 return nil, errors.Errorf("unable to locate local identifier %q", predIdent.Ident()) 509 } 510 pred, ok := v.(*ir.Block) 511 if !ok { 512 return nil, errors.Errorf("invalid basic block type; expected *ir.Block, got %T", v) 513 } 514 return ir.NewIncoming(x, pred), nil 515 } 516 517 // irIndirectSymbol returns the IR indirect symbol corresponding to the given 518 // AST indirect symbol. 519 func (gen *generator) irIndirectSymbol(typ *types.PointerType, old ast.IndirectSymbol) (constant.Constant, error) { 520 switch old := old.(type) { 521 case *ast.TypeConst: 522 symbol, err := gen.irTypeConst(*old) 523 if err != nil { 524 return nil, errors.WithStack(err) 525 } 526 return symbol, nil 527 case *ast.BitCastExpr: 528 symbol, err := gen.irConstant(typ, old) 529 if err != nil { 530 return nil, errors.WithStack(err) 531 } 532 return symbol, nil 533 case *ast.GetElementPtrExpr: 534 symbol, err := gen.irConstant(typ, old) 535 if err != nil { 536 return nil, errors.WithStack(err) 537 } 538 return symbol, nil 539 case *ast.AddrSpaceCastExpr: 540 symbol, err := gen.irConstant(typ, old) 541 if err != nil { 542 return nil, errors.WithStack(err) 543 } 544 return symbol, nil 545 case *ast.IntToPtrExpr: 546 symbol, err := gen.irConstant(typ, old) 547 if err != nil { 548 return nil, errors.WithStack(err) 549 } 550 return symbol, nil 551 default: 552 panic(fmt.Errorf("support for indirect symbol %T not yet implemented", old)) 553 } 554 } 555 556 // irInlineAsm translates the AST inline assembler expression into an equivalent 557 // IR inline assembler expression. 558 func irInlineAsm(typ types.Type, old *ast.InlineAsm) *ir.InlineAsm { 559 // Assembly instructions. 560 asm := stringLit(old.Asm()) 561 // Constraints. 562 constraint := stringLit(old.Constraints()) 563 v := ir.NewInlineAsm(typ, asm, constraint) 564 // (optional) Side effect. 565 _, v.SideEffect = old.SideEffect() 566 // (optional) Stack alignment. 567 _, v.AlignStack = old.AlignStackTok() 568 // (optional) Intel dialect. 569 _, v.IntelDialect = old.IntelDialect() 570 return v 571 } 572 573 // irOperandBundle returns the IR operand bundle corresponding to the given AST 574 // operand bundle. 575 func (fgen *funcGen) irOperandBundle(old ast.OperandBundle) (*ir.OperandBundle, error) { 576 // Tag. 577 tag := stringLit(old.Tag()) 578 // Inputs. 579 var inputs []value.Value 580 for _, oldInput := range old.Inputs() { 581 input, err := fgen.irTypeValue(oldInput) 582 if err != nil { 583 return nil, errors.WithStack(err) 584 } 585 inputs = append(inputs, input) 586 } 587 return ir.NewOperandBundle(tag, inputs...), nil 588 } 589 590 // irOverflowFlags returns the IR overflow flags corresponding to the given AST 591 // overflow flags. 592 func irOverflowFlags(olds []ast.OverflowFlag) []enum.OverflowFlag { 593 if len(olds) == 0 { 594 return nil 595 } 596 flags := make([]enum.OverflowFlag, len(olds)) 597 for i, old := range olds { 598 flag := asmenum.OverflowFlagFromString(old.Text()) 599 flags[i] = flag 600 } 601 return flags 602 } 603 604 // irParamAttribute returns the IR parameter attribute corresponding to the given 605 // AST parameter attribute. 606 func (gen *generator) irParamAttribute(old ast.ParamAttribute) (ir.ParamAttribute, error) { 607 switch old := old.(type) { 608 case *ast.AttrString: 609 return ir.AttrString(unquote(old.Text())), nil 610 case *ast.AttrPair: 611 return ir.AttrPair{ 612 Key: unquote(old.Key().Text()), 613 Value: unquote(old.Val().Text()), 614 }, nil 615 case *ast.Align: 616 return ir.Align(uintLit(old.N())), nil 617 case *ast.AlignStack: 618 return ir.AlignStack(uintLit(old.N())), nil 619 case *ast.ByRefAttr: 620 typ, err := gen.irType(old.Typ()) 621 if err != nil { 622 return nil, errors.WithStack(err) 623 } 624 return ir.ByRef{Typ: typ}, nil 625 case *ast.Byval: 626 if t, ok := old.Typ(); ok { 627 typ, err := gen.irType(t) 628 if err != nil { 629 return nil, errors.WithStack(err) 630 } 631 return ir.Byval{Typ: typ}, nil 632 } 633 return ir.Byval{}, nil 634 case *ast.Dereferenceable: 635 return ir.Dereferenceable{N: uintLit(old.N())}, nil 636 case *ast.DereferenceableOrNull: 637 return ir.Dereferenceable{ 638 N: uintLit(old.N()), 639 DerefOrNull: true, 640 }, nil 641 case *ast.ElementType: 642 typ, err := gen.irType(old.Typ()) 643 if err != nil { 644 return nil, errors.WithStack(err) 645 } 646 return ir.ElementType{Typ: typ}, nil 647 case *ast.InAlloca: 648 typ, err := gen.irType(old.Typ()) 649 if err != nil { 650 return nil, err 651 } 652 return ir.InAlloca{Typ: typ}, nil 653 case *ast.ParamAttr: 654 return asmenum.ParamAttrFromString(old.Text()), nil 655 case *ast.Preallocated: 656 typ, err := gen.irType(old.Typ()) 657 if err != nil { 658 return nil, err 659 } 660 return ir.Preallocated{Typ: typ}, nil 661 case *ast.StructRetAttr: 662 typ, err := gen.irType(old.Typ()) 663 if err != nil { 664 return nil, err 665 } 666 return ir.SRet{Typ: typ}, nil 667 default: 668 panic(fmt.Errorf("support for parameter attribute %T not yet implemented", old)) 669 } 670 } 671 672 // irReturnAttribute returns the IR return attribute corresponding to the given 673 // AST return attribute. 674 func irReturnAttribute(old ast.ReturnAttribute) ir.ReturnAttribute { 675 switch old := old.(type) { 676 // TODO: add support for AttrString. 677 //case *ast.AttrString: 678 // return ir.AttrString(unquote(old.Text())) 679 // TODO: add support for AttrPair. 680 //case *ast.AttrPair: 681 // return ir.AttrPair{ 682 // Key: unquote(old.Key().Text()), 683 // Value: unquote(old.Val().Text()), 684 // } 685 // TODO: re-enable 686 //case *ast.Align: 687 // return ir.Align(uintLit(old.N())) 688 case *ast.Dereferenceable: 689 return ir.Dereferenceable{N: uintLit(old.N())} 690 case *ast.DereferenceableOrNull: 691 return ir.Dereferenceable{ 692 N: uintLit(old.N()), 693 DerefOrNull: true, 694 } 695 case *ast.ReturnAttr: 696 return asmenum.ReturnAttrFromString(old.Text()) 697 default: 698 panic(fmt.Errorf("support for return attribute %T not yet implemented", old)) 699 } 700 } 701 702 // irTLSModelFromThreadLocal returns the IR TLS model corresponding to the given 703 // AST thread local storage. 704 func irTLSModelFromThreadLocal(old ast.ThreadLocal) enum.TLSModel { 705 if n, ok := old.Model(); ok { 706 // e.g. thread_local(initialexec) 707 return asmenum.TLSModelFromString(n.Text()) 708 } 709 // If no explicit model is given, the "general dynamic" model is used. 710 // thread_local 711 return enum.TLSModelGeneric 712 } 713 714 // irUnwindTarget returns the IR unwind target corresponding to the given AST 715 // unwind target. 716 func (fgen *funcGen) irUnwindTarget(n ast.UnwindTarget) (*ir.Block, error) { 717 switch n := n.(type) { 718 case *ast.Label: 719 return fgen.irBlock(*n) 720 case *ast.UnwindToCaller: 721 // A nil unwind target basic block indicates "unwind to caller". 722 return nil, nil 723 default: 724 panic(fmt.Errorf("support for unwind target %T not yet implemented", n)) 725 } 726 } 727 728 // irUseListOrder returns the IR use-list order corresponding to the given AST 729 // use-list order. 730 func (fgen *funcGen) irUseListOrder(old ast.UseListOrder) (*ir.UseListOrder, error) { 731 // Value. 732 val, err := fgen.irTypeValue(old.Val()) 733 if err != nil { 734 return nil, errors.WithStack(err) 735 } 736 // Indices. 737 indices := uintSlice(old.Indices()) 738 useListOrder := &ir.UseListOrder{ 739 Value: val, 740 Indices: indices, 741 } 742 return useListOrder, nil 743 } 744 745 // ### [ Helpers ] ############################################################# 746 747 // unquote returns the unquoted version of s if quoted, and the original string 748 // otherwise. 749 func unquote(s string) string { 750 if len(s) >= 2 && strings.HasPrefix(s, `"`) && strings.HasSuffix(s, `"`) { 751 return string(enc.Unquote(s)) 752 } 753 return s 754 } 755 756 // text returns the text of the given node. 757 func text(n ast.LlvmNode) string { 758 if n := n.LlvmNode(); n.IsValid() { 759 return n.Text() 760 } 761 return "" 762 } 763 764 // findBlock returns the basic block with the given local identifier in the 765 // function. 766 func findBlock(f *ir.Func, blockIdent ir.LocalIdent) (*ir.Block, error) { 767 for _, block := range f.Blocks { 768 if block.LocalIdent == blockIdent { 769 return block, nil 770 } 771 } 772 return nil, errors.Errorf("unable to locate basic block %q of function %q", blockIdent.Ident(), f.Ident()) 773 }