github.com/llir/llvm@v0.3.6/asm/term.go (about) 1 package asm 2 3 import ( 4 "fmt" 5 6 "github.com/llir/ll/ast" 7 "github.com/llir/llvm/ir" 8 "github.com/llir/llvm/ir/types" 9 "github.com/llir/llvm/ir/value" 10 "github.com/pkg/errors" 11 ) 12 13 // === [ Create IR ] =========================================================== 14 15 // newTerm returns a new IR terminator (without body but with type) based on the 16 // given AST terminator. 17 func (fgen *funcGen) newTerm(old ast.Terminator) (ir.Terminator, error) { 18 switch old := old.(type) { 19 // Value terminators. 20 case *ast.LocalDefTerm: 21 ident := localIdent(old.Name()) 22 return fgen.newValueTerm(ident, old.Term()) 23 case ast.ValueTerminator: 24 unnamed := ir.LocalIdent{} 25 return fgen.newValueTerm(unnamed, old) 26 // Non-value terminators. 27 case *ast.RetTerm: 28 return &ir.TermRet{}, nil 29 case *ast.BrTerm: 30 return &ir.TermBr{}, nil 31 case *ast.CondBrTerm: 32 return &ir.TermCondBr{}, nil 33 case *ast.SwitchTerm: 34 return &ir.TermSwitch{}, nil 35 case *ast.IndirectBrTerm: 36 return &ir.TermIndirectBr{}, nil 37 case *ast.ResumeTerm: 38 return &ir.TermResume{}, nil 39 case *ast.CatchRetTerm: 40 return &ir.TermCatchRet{}, nil 41 case *ast.CleanupRetTerm: 42 return &ir.TermCleanupRet{}, nil 43 case *ast.UnreachableTerm: 44 return &ir.TermUnreachable{}, nil 45 default: 46 panic(fmt.Errorf("support for terminator %T not yet implemented", old)) 47 } 48 } 49 50 // newValueTerm returns a new IR value terminator (without body but with type) 51 // based on the given AST value terminator. 52 func (fgen *funcGen) newValueTerm(ident ir.LocalIdent, old ast.ValueTerminator) (ir.Terminator, error) { 53 switch old := old.(type) { 54 case *ast.InvokeTerm: 55 return fgen.newInvokeTerm(ident, old) 56 case *ast.CallBrTerm: 57 return fgen.newCallBrTerm(ident, old) 58 case *ast.CatchSwitchTerm: 59 // Result type is always token. 60 return &ir.TermCatchSwitch{LocalIdent: ident}, nil 61 default: 62 panic(fmt.Errorf("support for value terminator %T not yet implemented", old)) 63 } 64 } 65 66 // newInvokeTerm returns a new IR invoke terminator (without body but with type) 67 // based on the given AST invoke terminator. 68 func (fgen *funcGen) newInvokeTerm(ident ir.LocalIdent, old *ast.InvokeTerm) (*ir.TermInvoke, error) { 69 typ, err := fgen.gen.irType(old.Typ()) 70 if err != nil { 71 return nil, errors.WithStack(err) 72 } 73 // Resolve return type of variadic functions. 74 if funcType, ok := typ.(*types.FuncType); ok { 75 typ = funcType.RetType 76 } 77 return &ir.TermInvoke{LocalIdent: ident, Typ: typ}, nil 78 } 79 80 // newCallBrTerm returns a new IR callbr terminator (without body but with type) 81 // based on the given AST callbr terminator. 82 func (fgen *funcGen) newCallBrTerm(ident ir.LocalIdent, old *ast.CallBrTerm) (*ir.TermCallBr, error) { 83 typ, err := fgen.gen.irType(old.Typ()) 84 if err != nil { 85 return nil, errors.WithStack(err) 86 } 87 // Resolve return type of variadic functions. 88 if funcType, ok := typ.(*types.FuncType); ok { 89 typ = funcType.RetType 90 } 91 return &ir.TermCallBr{LocalIdent: ident, Typ: typ}, nil 92 } 93 94 // === [ Translate AST to IR ] ================================================= 95 96 // translateTerms translates the AST terminators of the given function to IR. 97 func (fgen *funcGen) translateTerms(oldBlocks []ast.BasicBlock) error { 98 for i, oldBlock := range oldBlocks { 99 block := fgen.f.Blocks[i] 100 old := oldBlock.Term() 101 if err := fgen.irTerm(block.Term, old); err != nil { 102 return errors.WithStack(err) 103 } 104 } 105 return nil 106 } 107 108 // irTerm translates the AST terminator into an equivalent IR terminator. 109 func (fgen *funcGen) irTerm(new ir.Terminator, old ast.Terminator) error { 110 switch old := old.(type) { 111 // Value terminators. 112 case *ast.LocalDefTerm: 113 return fgen.irValueTerm(new, old.Term()) 114 case ast.ValueTerminator: 115 return fgen.irValueTerm(new, old) 116 // Non-value terminators. 117 case *ast.RetTerm: 118 return fgen.irRetTerm(new, old) 119 case *ast.BrTerm: 120 return fgen.irBrTerm(new, old) 121 case *ast.CondBrTerm: 122 return fgen.irCondBrTerm(new, old) 123 case *ast.SwitchTerm: 124 return fgen.irSwitchTerm(new, old) 125 case *ast.IndirectBrTerm: 126 return fgen.irIndirectBrTerm(new, old) 127 case *ast.ResumeTerm: 128 return fgen.irResumeTerm(new, old) 129 case *ast.CatchRetTerm: 130 return fgen.irCatchRetTerm(new, old) 131 case *ast.CleanupRetTerm: 132 return fgen.irCleanupRetTerm(new, old) 133 case *ast.UnreachableTerm: 134 return fgen.irUnreachableTerm(new, old) 135 default: 136 panic(fmt.Errorf("support for terminator %T not yet implemented", old)) 137 } 138 } 139 140 // irValueTerm translates the AST value terminator into an equivalent IR value 141 // terminator. 142 func (fgen *funcGen) irValueTerm(new ir.Terminator, old ast.ValueTerminator) error { 143 switch old := old.(type) { 144 case *ast.InvokeTerm: 145 return fgen.irInvokeTerm(new, old) 146 case *ast.CallBrTerm: 147 return fgen.irCallBrTerm(new, old) 148 case *ast.CatchSwitchTerm: 149 return fgen.irCatchSwitchTerm(new, old) 150 default: 151 panic(fmt.Errorf("support for value terminator %T not yet implemented", old)) 152 } 153 } 154 155 // --- [ ret ] ----------------------------------------------------------------- 156 157 // irRetTerm translates the AST ret terminator into an equivalent IR terminator. 158 func (fgen *funcGen) irRetTerm(new ir.Terminator, old *ast.RetTerm) error { 159 term, ok := new.(*ir.TermRet) 160 if !ok { 161 panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermRet, got %T", new)) 162 } 163 // Return type. 164 typ, err := fgen.gen.irType(old.XTyp()) 165 if err != nil { 166 return errors.WithStack(err) 167 } 168 // Check if non-void return. 169 if n, ok := old.X(); ok { 170 // Return value. 171 x, err := fgen.irValue(typ, n) 172 if err != nil { 173 return errors.WithStack(err) 174 } 175 term.X = x 176 } 177 // (optional) Metadata. 178 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 179 if err != nil { 180 return errors.WithStack(err) 181 } 182 term.Metadata = md 183 return nil 184 } 185 186 // --- [ br ] ------------------------------------------------------------------ 187 188 // irBrTerm translates the AST br terminator into an equivalent IR terminator. 189 func (fgen *funcGen) irBrTerm(new ir.Terminator, old *ast.BrTerm) error { 190 term, ok := new.(*ir.TermBr) 191 if !ok { 192 panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermBr, got %T", new)) 193 } 194 // Target. 195 target, err := fgen.irBlock(old.Target()) 196 if err != nil { 197 return errors.WithStack(err) 198 } 199 term.Target = target 200 // (optional) Metadata. 201 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 202 if err != nil { 203 return errors.WithStack(err) 204 } 205 term.Metadata = md 206 return nil 207 } 208 209 // --- [ condbr ] -------------------------------------------------------------- 210 211 // irCondBrTerm translates the AST condbr terminator into an equivalent IR 212 // terminator. 213 func (fgen *funcGen) irCondBrTerm(new ir.Terminator, old *ast.CondBrTerm) error { 214 term, ok := new.(*ir.TermCondBr) 215 if !ok { 216 panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermCondBr, got %T", new)) 217 } 218 // Branching condition. 219 ct := old.CondTyp() 220 condType, err := fgen.gen.irType(&ct) 221 if err != nil { 222 return errors.WithStack(err) 223 } 224 cond, err := fgen.irValue(condType, old.Cond()) 225 if err != nil { 226 return errors.WithStack(err) 227 } 228 term.Cond = cond 229 // Target true. 230 targetTrue, err := fgen.irBlock(old.TargetTrue()) 231 if err != nil { 232 return errors.WithStack(err) 233 } 234 term.TargetTrue = targetTrue 235 // Target false. 236 targetFalse, err := fgen.irBlock(old.TargetFalse()) 237 if err != nil { 238 return errors.WithStack(err) 239 } 240 term.TargetFalse = targetFalse 241 // (optional) Metadata. 242 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 243 if err != nil { 244 return errors.WithStack(err) 245 } 246 term.Metadata = md 247 return nil 248 } 249 250 // --- [ switch ] -------------------------------------------------------------- 251 252 // irSwitchTerm translates the AST switch terminator into an equivalent IR 253 // terminator. 254 func (fgen *funcGen) irSwitchTerm(new ir.Terminator, old *ast.SwitchTerm) error { 255 term, ok := new.(*ir.TermSwitch) 256 if !ok { 257 panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermSwitch, got %T", new)) 258 } 259 // Control variable. 260 x, err := fgen.irTypeValue(old.X()) 261 if err != nil { 262 return errors.WithStack(err) 263 } 264 term.X = x 265 // Default target. 266 targetDefault, err := fgen.irBlock(old.Default()) 267 if err != nil { 268 return errors.WithStack(err) 269 } 270 term.TargetDefault = targetDefault 271 // Switch cases. 272 if oldCases := old.Cases(); len(oldCases) > 0 { 273 term.Cases = make([]*ir.Case, len(oldCases)) 274 for i, oldCase := range oldCases { 275 c, err := fgen.irCase(oldCase) 276 if err != nil { 277 return errors.WithStack(err) 278 } 279 term.Cases[i] = c 280 } 281 } 282 // (optional) Metadata. 283 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 284 if err != nil { 285 return errors.WithStack(err) 286 } 287 term.Metadata = md 288 return nil 289 } 290 291 // --- [ indirectbr ] ---------------------------------------------------------- 292 293 // irIndirectBrTerm translates the AST indirectbr terminator into an equivalent 294 // IR terminator. 295 func (fgen *funcGen) irIndirectBrTerm(new ir.Terminator, old *ast.IndirectBrTerm) error { 296 term, ok := new.(*ir.TermIndirectBr) 297 if !ok { 298 panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermIndirectBr, got %T", new)) 299 } 300 // Target address. 301 addr, err := fgen.irTypeValue(old.Addr()) 302 if err != nil { 303 return errors.WithStack(err) 304 } 305 term.Addr = addr 306 // Valid targets. 307 if oldValidTargets := old.ValidTargets(); len(oldValidTargets) > 0 { 308 term.ValidTargets = make([]value.Value, len(oldValidTargets)) 309 for i, oldValidTarget := range oldValidTargets { 310 validTarget, err := fgen.irBlock(oldValidTarget) 311 if err != nil { 312 return errors.WithStack(err) 313 } 314 term.ValidTargets[i] = validTarget 315 } 316 } 317 // (optional) Metadata. 318 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 319 if err != nil { 320 return errors.WithStack(err) 321 } 322 term.Metadata = md 323 return nil 324 } 325 326 // --- [ invoke ] -------------------------------------------------------------- 327 328 // irInvokeTerm translates the AST invoke terminator into an equivalent IR 329 // terminator. 330 func (fgen *funcGen) irInvokeTerm(new ir.Terminator, old *ast.InvokeTerm) error { 331 term, ok := new.(*ir.TermInvoke) 332 if !ok { 333 panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermInvoke, got %T", new)) 334 } 335 // Function arguments. 336 if oldArgs := old.Args().Args(); len(oldArgs) > 0 { 337 term.Args = make([]value.Value, len(oldArgs)) 338 for i, oldArg := range oldArgs { 339 arg, err := fgen.irArg(oldArg) 340 if err != nil { 341 return errors.WithStack(err) 342 } 343 term.Args[i] = arg 344 } 345 } 346 // Invokee. 347 typ, err := fgen.gen.irType(old.Typ()) 348 if err != nil { 349 return errors.WithStack(err) 350 } 351 sig, ok := typ.(*types.FuncType) 352 if !ok { 353 // Preliminary function signature. Only used by fgen.irValue for inline 354 // assembly invokees and constrant expressions. 355 var paramTypes []types.Type 356 if len(term.Args) > 0 { 357 paramTypes = make([]types.Type, len(term.Args)) 358 for i, arg := range term.Args { 359 paramTypes[i] = arg.Type() 360 } 361 } 362 sig = types.NewFunc(typ, paramTypes...) 363 } 364 // The invokee type is always pointer to function type. 365 ptrToSig := types.NewPointer(sig) 366 invokee, err := fgen.irValue(ptrToSig, old.Invokee()) 367 if err != nil { 368 return errors.WithStack(err) 369 } 370 term.Invokee = invokee 371 // Normal control flow return point. 372 normalRetTarget, err := fgen.irBlock(old.NormalRetTarget()) 373 if err != nil { 374 return errors.WithStack(err) 375 } 376 term.NormalRetTarget = normalRetTarget 377 // Exception control flow return point. 378 exceptionRetTarget, err := fgen.irBlock(old.ExceptionRetTarget()) 379 if err != nil { 380 return errors.WithStack(err) 381 } 382 term.ExceptionRetTarget = exceptionRetTarget 383 // (optional) Calling convention. 384 if n, ok := old.CallingConv(); ok { 385 term.CallingConv = irCallingConv(n) 386 } 387 // (optional) Return attributes. 388 if oldReturnAttrs := old.ReturnAttrs(); len(oldReturnAttrs) > 0 { 389 term.ReturnAttrs = make([]ir.ReturnAttribute, len(oldReturnAttrs)) 390 for i, oldRetAttr := range oldReturnAttrs { 391 retAttr := irReturnAttribute(oldRetAttr) 392 term.ReturnAttrs[i] = retAttr 393 } 394 } 395 // (optional) Address space. 396 if n, ok := old.AddrSpace(); ok { 397 term.AddrSpace = irAddrSpace(n) 398 } 399 // (optional) Function attributes. 400 if oldFuncAttrs := old.FuncAttrs(); len(oldFuncAttrs) > 0 { 401 term.FuncAttrs = make([]ir.FuncAttribute, len(oldFuncAttrs)) 402 for i, oldFuncAttr := range oldFuncAttrs { 403 funcAttr := fgen.gen.irFuncAttribute(oldFuncAttr) 404 term.FuncAttrs[i] = funcAttr 405 } 406 } 407 // (optional) Operand bundles. 408 if oldOperandBundles := old.OperandBundles(); len(oldOperandBundles) > 0 { 409 term.OperandBundles = make([]*ir.OperandBundle, len(oldOperandBundles)) 410 for i, oldOperandBundle := range oldOperandBundles { 411 operandBundle, err := fgen.irOperandBundle(oldOperandBundle) 412 if err != nil { 413 return errors.WithStack(err) 414 } 415 term.OperandBundles[i] = operandBundle 416 } 417 } 418 // (optional) Metadata. 419 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 420 if err != nil { 421 return errors.WithStack(err) 422 } 423 term.Metadata = md 424 return nil 425 } 426 427 // --- [ callbr ] -------------------------------------------------------------- 428 429 // irCallBrTerm translates the AST callbr terminator into an equivalent IR 430 // terminator. 431 func (fgen *funcGen) irCallBrTerm(new ir.Terminator, old *ast.CallBrTerm) error { 432 term, ok := new.(*ir.TermCallBr) 433 if !ok { 434 panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermCallBr, got %T", new)) 435 } 436 // Function arguments. 437 if oldArgs := old.Args().Args(); len(oldArgs) > 0 { 438 term.Args = make([]value.Value, len(oldArgs)) 439 for i, oldArg := range oldArgs { 440 arg, err := fgen.irArg(oldArg) 441 if err != nil { 442 return errors.WithStack(err) 443 } 444 term.Args[i] = arg 445 } 446 } 447 // Callee. 448 typ, err := fgen.gen.irType(old.Typ()) 449 if err != nil { 450 return errors.WithStack(err) 451 } 452 sig, ok := typ.(*types.FuncType) 453 if !ok { 454 // Preliminary function signature. Only used by fgen.irValue for inline 455 // assembly callees and constrant expressions. 456 var paramTypes []types.Type 457 if len(term.Args) > 0 { 458 paramTypes = make([]types.Type, len(term.Args)) 459 for i, arg := range term.Args { 460 paramTypes[i] = arg.Type() 461 } 462 } 463 sig = types.NewFunc(typ, paramTypes...) 464 } 465 // The callee type is always pointer to function type. 466 ptrToSig := types.NewPointer(sig) 467 callee, err := fgen.irValue(ptrToSig, old.Callee()) 468 if err != nil { 469 return errors.WithStack(err) 470 } 471 term.Callee = callee 472 // Normal control flow return point. 473 normalRetTarget, err := fgen.irBlock(old.NormalRetTarget()) 474 if err != nil { 475 return errors.WithStack(err) 476 } 477 term.NormalRetTarget = normalRetTarget 478 // Exception control flow return point. 479 for _, oldOtherRetTarget := range old.OtherRetTargets() { 480 otherRetTarget, err := fgen.irBlock(oldOtherRetTarget) 481 if err != nil { 482 return errors.WithStack(err) 483 } 484 term.OtherRetTargets = append(term.OtherRetTargets, otherRetTarget) 485 } 486 // (optional) Calling convention. 487 if n, ok := old.CallingConv(); ok { 488 term.CallingConv = irCallingConv(n) 489 } 490 // (optional) Return attributes. 491 if oldReturnAttrs := old.ReturnAttrs(); len(oldReturnAttrs) > 0 { 492 term.ReturnAttrs = make([]ir.ReturnAttribute, len(oldReturnAttrs)) 493 for i, oldRetAttr := range oldReturnAttrs { 494 retAttr := irReturnAttribute(oldRetAttr) 495 term.ReturnAttrs[i] = retAttr 496 } 497 } 498 // (optional) Address space. 499 if n, ok := old.AddrSpace(); ok { 500 term.AddrSpace = irAddrSpace(n) 501 } 502 // (optional) Function attributes. 503 if oldFuncAttrs := old.FuncAttrs(); len(oldFuncAttrs) > 0 { 504 term.FuncAttrs = make([]ir.FuncAttribute, len(oldFuncAttrs)) 505 for i, oldFuncAttr := range oldFuncAttrs { 506 funcAttr := fgen.gen.irFuncAttribute(oldFuncAttr) 507 term.FuncAttrs[i] = funcAttr 508 } 509 } 510 // (optional) Operand bundles. 511 if oldOperandBundles := old.OperandBundles(); len(oldOperandBundles) > 0 { 512 term.OperandBundles = make([]*ir.OperandBundle, len(oldOperandBundles)) 513 for i, oldOperandBundle := range oldOperandBundles { 514 operandBundle, err := fgen.irOperandBundle(oldOperandBundle) 515 if err != nil { 516 return errors.WithStack(err) 517 } 518 term.OperandBundles[i] = operandBundle 519 } 520 } 521 // (optional) Metadata. 522 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 523 if err != nil { 524 return errors.WithStack(err) 525 } 526 term.Metadata = md 527 return nil 528 } 529 530 // --- [ resume ] -------------------------------------------------------------- 531 532 // irResumeTerm translates the AST resume terminator into an equivalent IR 533 // terminator. 534 func (fgen *funcGen) irResumeTerm(new ir.Terminator, old *ast.ResumeTerm) error { 535 term, ok := new.(*ir.TermResume) 536 if !ok { 537 panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermResume, got %T", new)) 538 } 539 // Exception argument to propagate. 540 x, err := fgen.irTypeValue(old.X()) 541 if err != nil { 542 return errors.WithStack(err) 543 } 544 term.X = x 545 // (optional) Metadata. 546 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 547 if err != nil { 548 return errors.WithStack(err) 549 } 550 term.Metadata = md 551 return nil 552 } 553 554 // --- [ catchswitch ] --------------------------------------------------------- 555 556 // irCatchSwitchTerm translates the AST catchswitch terminator into an 557 // equivalent IR terminator. 558 func (fgen *funcGen) irCatchSwitchTerm(new ir.Terminator, old *ast.CatchSwitchTerm) error { 559 term, ok := new.(*ir.TermCatchSwitch) 560 if !ok { 561 panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermCatchSwitch, got %T", new)) 562 } 563 // Parent exception pad. 564 parentPad, err := fgen.irExceptionPad(old.ParentPad()) 565 if err != nil { 566 return errors.WithStack(err) 567 } 568 term.ParentPad = parentPad 569 // Exception handlers. 570 if oldHandlers := old.Handlers().Labels(); len(oldHandlers) > 0 { 571 term.Handlers = make([]value.Value, len(oldHandlers)) 572 for i, oldHandler := range oldHandlers { 573 handler, err := fgen.irBlock(oldHandler) 574 if err != nil { 575 return errors.WithStack(err) 576 } 577 term.Handlers[i] = handler 578 } 579 } 580 // Optional default unwind target basic block; if nil unwind to caller. 581 defaultUnwindTarget, err := fgen.irUnwindTarget(old.DefaultUnwindTarget()) 582 if err != nil { 583 return errors.WithStack(err) 584 } 585 if defaultUnwindTarget != nil { 586 // Note: since DefaultUnwindTarget is an interface we have to be careful 587 // with typed nil values (e.g. `(*ir.Block)(nil)`). This is to ensure that 588 // DefaultUnwindTarget is nil and not `{Type: ir.Block, Value: nil}`. 589 // 590 // ref: https://golang.org/doc/faq#nil_error 591 term.DefaultUnwindTarget = defaultUnwindTarget 592 } 593 // (optional) Metadata. 594 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 595 if err != nil { 596 return errors.WithStack(err) 597 } 598 term.Metadata = md 599 return nil 600 } 601 602 // --- [ catchret ] ------------------------------------------------------------ 603 604 // irCatchRetTerm translates the AST catchret terminator into an equivalent IR 605 // terminator. 606 func (fgen *funcGen) irCatchRetTerm(new ir.Terminator, old *ast.CatchRetTerm) error { 607 term, ok := new.(*ir.TermCatchRet) 608 if !ok { 609 panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermCatchRet, got %T", new)) 610 } 611 // Exit catchpad. 612 v, err := fgen.irValue(types.Token, old.CatchPad()) 613 if err != nil { 614 return errors.WithStack(err) 615 } 616 catchpad, ok := v.(*ir.InstCatchPad) 617 if !ok { 618 return errors.Errorf("invalid catchpad type; expected *ir.InstCatchPad, got %T", v) 619 } 620 term.CatchPad = catchpad 621 // Target basic block to transfer control flow to. 622 target, err := fgen.irBlock(old.Target()) 623 if err != nil { 624 return errors.WithStack(err) 625 } 626 term.Target = target 627 // (optional) Metadata. 628 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 629 if err != nil { 630 return errors.WithStack(err) 631 } 632 term.Metadata = md 633 return nil 634 } 635 636 // --- [ cleanupret ] ---------------------------------------------------------- 637 638 // irCleanupRetTerm translates the AST cleanupret terminator into an equivalent 639 // IR terminator. 640 func (fgen *funcGen) irCleanupRetTerm(new ir.Terminator, old *ast.CleanupRetTerm) error { 641 term, ok := new.(*ir.TermCleanupRet) 642 if !ok { 643 panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermCleanupRet, got %T", new)) 644 } 645 // Exit cleanuppad. 646 v, err := fgen.irValue(types.Token, old.CleanupPad()) 647 if err != nil { 648 return errors.WithStack(err) 649 } 650 cleanuppad, ok := v.(*ir.InstCleanupPad) 651 if !ok { 652 return errors.Errorf("invalid cleanuppad type; expected *ir.InstCleanupPad, got %T", v) 653 } 654 term.CleanupPad = cleanuppad 655 // Optional unwind target basic block; if nil unwind to caller. 656 unwindTarget, err := fgen.irUnwindTarget(old.UnwindTarget()) 657 if err != nil { 658 return errors.WithStack(err) 659 } 660 if unwindTarget != nil { 661 // Note: since UnwindTarget is an interface we have to be careful 662 // with typed nil values (e.g. `(*ir.Block)(nil)`). This is to ensure that 663 // UnwindTarget is nil and not `{Type: ir.Block, Value: nil}`. 664 // 665 // ref: https://golang.org/doc/faq#nil_error 666 term.UnwindTarget = unwindTarget 667 } 668 // (optional) Metadata. 669 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 670 if err != nil { 671 return errors.WithStack(err) 672 } 673 term.Metadata = md 674 return nil 675 } 676 677 // --- [ unreachable ] --------------------------------------------------------- 678 679 // irUnreachableTerm translates the AST unreachable terminator into an 680 // equivalent IR terminator. 681 func (fgen *funcGen) irUnreachableTerm(new ir.Terminator, old *ast.UnreachableTerm) error { 682 term, ok := new.(*ir.TermUnreachable) 683 if !ok { 684 panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermUnreachable, got %T", new)) 685 } 686 // (optional) Metadata. 687 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 688 if err != nil { 689 return errors.WithStack(err) 690 } 691 term.Metadata = md 692 return nil 693 }