github.com/llir/llvm@v0.3.6/asm/global.go (about) 1 package asm 2 3 import ( 4 "fmt" 5 6 "github.com/llir/ll/ast" 7 asmenum "github.com/llir/llvm/asm/enum" 8 "github.com/llir/llvm/internal/enc" 9 "github.com/llir/llvm/internal/gep" 10 "github.com/llir/llvm/ir" 11 "github.com/llir/llvm/ir/constant" 12 "github.com/llir/llvm/ir/types" 13 "github.com/pkg/errors" 14 ) 15 16 // === [ Create and index IR ] ================================================= 17 18 // createGlobalEntities indexes global identifiers and creates scaffolding IR 19 // global declarations and definitions, indirect symbol definitions (aliases and 20 // indirect functions), and function declarations and definitions (without 21 // bodies but with types) of the given module. 22 // 23 // post-condition: gen.new.globals maps from global identifier (without '@' 24 // prefix) to corresponding skeleton IR value. 25 func (gen *generator) createGlobalEntities() error { 26 // 4a1. Index global identifiers and create scaffolding IR global 27 // declarations and definitions, indirect symbol definitions (aliases 28 // and indirect functions), and function declarations and definitions 29 // (without bodies but with types). 30 for ident, old := range gen.old.globals { 31 new, err := gen.newGlobalEntity(ident, old) 32 if err != nil { 33 return errors.WithStack(err) 34 } 35 gen.new.globals[ident] = new 36 } 37 return nil 38 } 39 40 // newGlobalEntity returns a new scaffolding IR value (without body but with 41 // type) based on the given AST global declaration or definition, indirect 42 // symbol definitions (aliases and indirect functions), or function declaration 43 // or definition. 44 func (gen *generator) newGlobalEntity(ident ir.GlobalIdent, old ast.LlvmNode) (constant.Constant, error) { 45 switch old := old.(type) { 46 case *ast.GlobalDecl: 47 oldAddrSpace, _ := old.AddrSpace() 48 return gen.newGlobal(ident, old.ContentType(), oldAddrSpace) 49 case *ast.IndirectSymbolDef: 50 return gen.newIndirectSymbol(ident, old) 51 case *ast.FuncDecl: 52 return gen.newFunc(ident, old.Header()) 53 case *ast.FuncDef: 54 return gen.newFunc(ident, old.Header()) 55 default: 56 panic(fmt.Errorf("support for global variable, indirect symbol or function %T not yet implemented", old)) 57 } 58 } 59 60 // newGlobal returns a new IR global variable declaration or definition (without 61 // body but with type) based on the given AST content type and optional address 62 // space. 63 func (gen *generator) newGlobal(ident ir.GlobalIdent, oldContentType ast.Type, oldAddrSpace ast.AddrSpace) (*ir.Global, error) { 64 // Content type. 65 contentType, err := gen.irType(oldContentType) 66 if err != nil { 67 return nil, errors.WithStack(err) 68 } 69 typ := types.NewPointer(contentType) 70 // (optional) Address space. 71 var addrSpace types.AddrSpace 72 if oldAddrSpace.IsValid() { 73 addrSpace = irAddrSpace(oldAddrSpace) 74 typ.AddrSpace = addrSpace 75 } 76 return &ir.Global{GlobalIdent: ident, ContentType: contentType, Typ: typ, AddrSpace: addrSpace}, nil 77 } 78 79 // newIndirectSymbol returns a new IR indirect symbol definition (without body 80 // but with type) based on the given AST indirect symbol. 81 func (gen *generator) newIndirectSymbol(ident ir.GlobalIdent, old *ast.IndirectSymbolDef) (constant.Constant, error) { 82 // Content type. 83 contentType, err := gen.irType(old.ContentType()) 84 if err != nil { 85 return nil, errors.WithStack(err) 86 } 87 typ := types.NewPointer(contentType) 88 // Infer address space of pointer type from indirect symbol as no explicit 89 // type/value pair is given for the indirect symbol when aliasee is a 90 // constant expression. 91 var symbolType types.Type 92 switch oldSymbol := old.IndirectSymbol().(type) { 93 case *ast.AddrSpaceCastExpr: 94 to, err := gen.irType(oldSymbol.To()) 95 if err != nil { 96 return nil, errors.WithStack(err) 97 } 98 symbolType = to 99 case *ast.BitCastExpr: 100 to, err := gen.irType(oldSymbol.To()) 101 if err != nil { 102 return nil, errors.WithStack(err) 103 } 104 symbolType = to 105 case *ast.GetElementPtrExpr: 106 symType, err := gen.gepExprType(oldSymbol) 107 if err != nil { 108 return nil, errors.WithStack(err) 109 } 110 symbolType = symType 111 case *ast.IntToPtrExpr: 112 to, err := gen.irType(oldSymbol.To()) 113 if err != nil { 114 return nil, errors.WithStack(err) 115 } 116 symbolType = to 117 case *ast.TypeConst: 118 symType, err := gen.irType(oldSymbol.Typ()) 119 if err != nil { 120 return nil, errors.WithStack(err) 121 } 122 symbolType = symType 123 default: 124 panic(fmt.Errorf("support for indirect symbol type %T not yet implemented", oldSymbol)) 125 } 126 switch symbolType := symbolType.(type) { 127 case *types.PointerType: 128 typ.AddrSpace = symbolType.AddrSpace 129 default: 130 panic(fmt.Errorf("support for indirect symbol type %T not yet implemented", symbolType)) 131 } 132 // Indirect symbol kind. 133 kind := old.IndirectSymbolKind().Text() 134 switch kind { 135 case "alias": 136 return &ir.Alias{GlobalIdent: ident, Typ: typ}, nil 137 case "ifunc": 138 return &ir.IFunc{GlobalIdent: ident, Typ: typ}, nil 139 default: 140 panic(fmt.Errorf("support for indirect symbol kind %q not yet implemented", kind)) 141 } 142 } 143 144 // newFunc returns a new IR function declaration or definition (without body but 145 // with type) based on the given AST function header. 146 func (gen *generator) newFunc(ident ir.GlobalIdent, hdr ast.FuncHeader) (*ir.Func, error) { 147 // Function signature. 148 sig, err := gen.irSigFromHeader(hdr) 149 if err != nil { 150 return nil, errors.WithStack(err) 151 } 152 typ := types.NewPointer(sig) 153 // (optional) Address space. 154 var addrSpace types.AddrSpace 155 if n, ok := hdr.AddrSpace(); ok { 156 addrSpace = irAddrSpace(n) 157 typ.AddrSpace = addrSpace 158 } 159 return &ir.Func{GlobalIdent: ident, Sig: sig, Typ: typ, AddrSpace: addrSpace, Parent: gen.m}, nil 160 } 161 162 // ### [ Helper functions ] #################################################### 163 164 // irSigFromHeader translates the AST function signature to an equivalent IR 165 // function type. 166 func (gen *generator) irSigFromHeader(old ast.FuncHeader) (*types.FuncType, error) { 167 // Return type. 168 sig := &types.FuncType{} 169 retType, err := gen.irType(old.RetType()) 170 if err != nil { 171 return nil, errors.WithStack(err) 172 } 173 sig.RetType = retType 174 // Function parameters. 175 ps := old.Params() 176 if oldParams := ps.Params(); len(oldParams) > 0 { 177 sig.Params = make([]types.Type, len(oldParams)) 178 for i, oldParam := range oldParams { 179 param, err := gen.irType(oldParam.Typ()) 180 if err != nil { 181 return nil, errors.WithStack(err) 182 } 183 sig.Params[i] = param 184 } 185 } 186 // Variadic. 187 _, sig.Variadic = ps.Variadic() 188 return sig, nil 189 } 190 191 // === [ Translate AST to IR ] ================================================= 192 193 // translateGlobalEntities translate AST global declarations and definitions, 194 // indirect symbol definitions, and function declarations and definitions to IR. 195 func (gen *generator) translateGlobalEntities() error { 196 // TODO: make concurrent and benchmark difference in walltime. 197 198 // 4b1. Translate AST global declarations and definitions, indirect symbol 199 // definitions, and function declarations and definitions to IR. 200 for ident, old := range gen.old.globals { 201 v, ok := gen.new.globals[ident] 202 if !ok { 203 panic(fmt.Errorf("unable to locate global identifier %q", ident.Ident())) 204 } 205 switch old := old.(type) { 206 case *ast.GlobalDecl: 207 new, ok := v.(*ir.Global) 208 if !ok { 209 panic(fmt.Errorf("invalid global declaration type; expected *ir.Global, got %T", v)) 210 } 211 if err := gen.irGlobal(new, old); err != nil { 212 return errors.WithStack(err) 213 } 214 case *ast.IndirectSymbolDef: 215 kind := old.IndirectSymbolKind().Text() 216 switch kind { 217 case "alias": 218 new, ok := v.(*ir.Alias) 219 if !ok { 220 panic(fmt.Errorf("invalid alias definition type; expected *ir.Alias, got %T", v)) 221 } 222 if err := gen.irAlias(new, old); err != nil { 223 return errors.WithStack(err) 224 } 225 case "ifunc": 226 new, ok := v.(*ir.IFunc) 227 if !ok { 228 panic(fmt.Errorf("invalid IFunc definition type; expected *ir.IFunc, got %T", v)) 229 } 230 if err := gen.irIFunc(new, old); err != nil { 231 return errors.WithStack(err) 232 } 233 default: 234 panic(fmt.Errorf("support for indirect symbol kind %q not yet implemented", kind)) 235 } 236 case *ast.FuncDecl: 237 new, ok := v.(*ir.Func) 238 if !ok { 239 panic(fmt.Errorf("invalid function declaration type; expected *ir.Func, got %T", v)) 240 } 241 if err := gen.irFuncDecl(new, old); err != nil { 242 return errors.WithStack(err) 243 } 244 case *ast.FuncDef: 245 new, ok := v.(*ir.Func) 246 if !ok { 247 panic(fmt.Errorf("invalid function definition type; expected *ir.Func, got %T", v)) 248 } 249 if err := gen.irFuncDef(new, old); err != nil { 250 return errors.WithStack(err) 251 } 252 default: 253 panic(fmt.Errorf("support for global variable, indirect symbol or function %T not yet implemented", old)) 254 } 255 } 256 return nil 257 } 258 259 // --- [ Global declarations ] ------------------------------------------------- 260 261 // irGlobal translates the AST global declaration into an equivalent IR 262 // global declaration. 263 func (gen *generator) irGlobal(new *ir.Global, old *ast.GlobalDecl) error { 264 // (optional) Linkage. 265 if n, ok := old.Linkage(); ok { 266 new.Linkage = asmenum.LinkageFromString(n.LlvmNode().Text()) 267 } 268 // (optional) Preemption. 269 if n, ok := old.Preemption(); ok { 270 new.Preemption = asmenum.PreemptionFromString(n.Text()) 271 } 272 // (optional) Visibility. 273 if n, ok := old.Visibility(); ok { 274 new.Visibility = asmenum.VisibilityFromString(n.Text()) 275 } 276 // (optional) DLL storage class. 277 if n, ok := old.DLLStorageClass(); ok { 278 new.DLLStorageClass = asmenum.DLLStorageClassFromString(n.Text()) 279 } 280 // (optional) Thread local storage model. 281 if n, ok := old.ThreadLocal(); ok { 282 new.TLSModel = irTLSModelFromThreadLocal(n) 283 } 284 // (optional) Unnamed address. 285 if n, ok := old.UnnamedAddr(); ok { 286 new.UnnamedAddr = asmenum.UnnamedAddrFromString(n.Text()) 287 } 288 // (optional) Address space: handled in newGlobalEntity. 289 // (optional) Externally initialized. 290 _, new.ExternallyInitialized = old.ExternallyInitialized() 291 // Immutability of global variable (constant or global). 292 new.Immutable = irImmutable(old.Immutable()) 293 // Content type: handled in newGlobalEntity. 294 // Initial value (only used in global variable definitions). 295 if n, ok := old.Init(); ok { 296 init, err := gen.irConstant(new.ContentType, n) 297 if err != nil { 298 return errors.WithStack(err) 299 } 300 new.Init = init 301 } 302 for _, globalField := range old.GlobalFields() { 303 switch globalField := globalField.(type) { 304 // (optional) Section name. 305 case *ast.Section: 306 new.Section = stringLit(globalField.Name()) 307 // (optional) Partition name. 308 case *ast.Partition: 309 new.Partition = stringLit(globalField.Name()) 310 // (optional) Comdat. 311 case *ast.Comdat: 312 // When comdat name is omitted, the global name is used as an implicit 313 // comdat name. 314 name := new.Name() 315 if n, ok := globalField.Name(); ok { 316 name = comdatName(n) 317 } 318 def, ok := gen.new.comdatDefs[name] 319 if !ok { 320 return errors.Errorf("unable to locate comdat identifier %q used in global declaration of %q", enc.ComdatName(name), new.Ident()) 321 } 322 new.Comdat = def 323 // (optional) Alignment. 324 case *ast.Align: 325 new.Align = irAlign(*globalField) 326 } 327 } 328 // (optional) Metadata. 329 md, err := gen.irMetadataAttachments(old.Metadata()) 330 if err != nil { 331 return errors.WithStack(err) 332 } 333 new.Metadata = md 334 // (optional) Function attributes. 335 if oldFuncAttrs := old.FuncAttrs(); len(oldFuncAttrs) > 0 { 336 new.FuncAttrs = make([]ir.FuncAttribute, len(oldFuncAttrs)) 337 for i, oldFuncAttr := range oldFuncAttrs { 338 funcAttr := gen.irFuncAttribute(oldFuncAttr) 339 new.FuncAttrs[i] = funcAttr 340 } 341 } 342 return nil 343 } 344 345 // --- [ Alias definitions ] --------------------------------------------------- 346 347 // irAlias translates the AST indirect symbol definition (alias) into an 348 // equivalent IR alias definition. 349 func (gen *generator) irAlias(new *ir.Alias, old *ast.IndirectSymbolDef) error { 350 // (optional) Linkage. 351 if n, ok := old.Linkage(); ok { 352 new.Linkage = asmenum.LinkageFromString(n.Text()) 353 } 354 if n, ok := old.ExternLinkage(); ok { 355 new.Linkage = asmenum.LinkageFromString(n.Text()) 356 } 357 // (optional) Preemption. 358 if n, ok := old.Preemption(); ok { 359 new.Preemption = asmenum.PreemptionFromString(n.Text()) 360 } 361 // (optional) Visibility. 362 if n, ok := old.Visibility(); ok { 363 new.Visibility = asmenum.VisibilityFromString(n.Text()) 364 } 365 // (optional) DLL storage class. 366 if n, ok := old.DLLStorageClass(); ok { 367 new.DLLStorageClass = asmenum.DLLStorageClassFromString(n.Text()) 368 } 369 // (optional) Thread local storage model. 370 if n, ok := old.ThreadLocal(); ok { 371 new.TLSModel = irTLSModelFromThreadLocal(n) 372 } 373 // (optional) Unnamed address. 374 if n, ok := old.UnnamedAddr(); ok { 375 new.UnnamedAddr = asmenum.UnnamedAddrFromString(n.Text()) 376 } 377 // Content type: handled in newGlobalEntity. 378 // Aliasee. 379 aliasee, err := gen.irIndirectSymbol(new.Typ, old.IndirectSymbol()) 380 if err != nil { 381 return errors.WithStack(err) 382 } 383 new.Aliasee = aliasee 384 // (optional) Partition name. 385 for _, partition := range old.Partitions() { 386 new.Partition = stringLit(partition.Name()) 387 } 388 return nil 389 } 390 391 // --- [ IFunc definitions ] --------------------------------------------------- 392 393 // irIFunc translates the AST indirect symbol definition (IFunc) into an 394 // equivalent IR indirect function definition. 395 func (gen *generator) irIFunc(new *ir.IFunc, old *ast.IndirectSymbolDef) error { 396 // (optional) Linkage. 397 if n, ok := old.Linkage(); ok { 398 new.Linkage = asmenum.LinkageFromString(n.Text()) 399 } 400 if n, ok := old.ExternLinkage(); ok { 401 new.Linkage = asmenum.LinkageFromString(n.Text()) 402 } 403 // (optional) Preemption. 404 if n, ok := old.Preemption(); ok { 405 new.Preemption = asmenum.PreemptionFromString(n.Text()) 406 } 407 // (optional) Visibility. 408 if n, ok := old.Visibility(); ok { 409 new.Visibility = asmenum.VisibilityFromString(n.Text()) 410 } 411 // (optional) DLL storage class. 412 if n, ok := old.DLLStorageClass(); ok { 413 new.DLLStorageClass = asmenum.DLLStorageClassFromString(n.Text()) 414 } 415 // (optional) Thread local storage model. 416 if n, ok := old.ThreadLocal(); ok { 417 new.TLSModel = irTLSModelFromThreadLocal(n) 418 } 419 // (optional) Unnamed address. 420 if n, ok := old.UnnamedAddr(); ok { 421 new.UnnamedAddr = asmenum.UnnamedAddrFromString(n.Text()) 422 } 423 // Content type: handled in newGlobalEntity. 424 // Resolver. 425 resolver, err := gen.irIndirectSymbol(new.Typ, old.IndirectSymbol()) 426 if err != nil { 427 return errors.WithStack(err) 428 } 429 new.Resolver = resolver 430 // (optional) Partition name. 431 for _, partition := range old.Partitions() { 432 new.Partition = stringLit(partition.Name()) 433 } 434 return nil 435 } 436 437 // --- [ Function declarations ] ----------------------------------------------- 438 439 // irFuncDecl translates the AST function declaration into an equivalent IR 440 // function declaration. 441 func (gen *generator) irFuncDecl(new *ir.Func, old *ast.FuncDecl) error { 442 // (optional) Metadata. 443 md, err := gen.irMetadataAttachments(old.Metadata()) 444 if err != nil { 445 return errors.WithStack(err) 446 } 447 new.Metadata = md 448 // Function header. 449 return gen.irFuncHeader(new, old.Header()) 450 } 451 452 // --- [ Function definitions ] ------------------------------------------------ 453 454 // irFuncDef translates the AST function definition into an equivalent IR 455 // function definition. 456 func (gen *generator) irFuncDef(new *ir.Func, old *ast.FuncDef) error { 457 // Function header. 458 if err := gen.irFuncHeader(new, old.Header()); err != nil { 459 return errors.WithStack(err) 460 } 461 // (optional) Metadata. 462 md, err := gen.irMetadataAttachments(old.Metadata()) 463 if err != nil { 464 return errors.WithStack(err) 465 } 466 new.Metadata = md 467 // Basic blocks. 468 fgen := newFuncGen(gen, new) 469 oldBody := old.Body() 470 if err := fgen.resolveLocals(oldBody); err != nil { 471 return errors.WithStack(err) 472 } 473 // (optional) Use list orders. 474 if oldUseListOrders := oldBody.UseListOrders(); len(oldUseListOrders) > 0 { 475 new.UseListOrders = make([]*ir.UseListOrder, len(oldUseListOrders)) 476 for i, oldUseListOrder := range oldUseListOrders { 477 useListOrder, err := fgen.irUseListOrder(oldUseListOrder) 478 if err != nil { 479 return errors.WithStack(err) 480 } 481 new.UseListOrders[i] = useListOrder 482 } 483 } 484 return nil 485 } 486 487 // ~~~ [ Function headers ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 488 489 // irFuncHeader translates the AST function header into an equivalent IR 490 // function. 491 func (gen *generator) irFuncHeader(new *ir.Func, old ast.FuncHeader) error { 492 // (optional) Linkage. 493 if n, ok := old.Linkage(); ok { 494 new.Linkage = asmenum.LinkageFromString(n.Text()) 495 } 496 if n, ok := old.ExternLinkage(); ok { 497 new.Linkage = asmenum.LinkageFromString(n.Text()) 498 } 499 // (optional) Preemption. 500 if n, ok := old.Preemption(); ok { 501 new.Preemption = asmenum.PreemptionFromString(n.Text()) 502 } 503 // (optional) Visibility. 504 if n, ok := old.Visibility(); ok { 505 new.Visibility = asmenum.VisibilityFromString(n.Text()) 506 } 507 // (optional) DLL storage class. 508 if n, ok := old.DLLStorageClass(); ok { 509 new.DLLStorageClass = asmenum.DLLStorageClassFromString(n.Text()) 510 } 511 // (optional) Calling convention. 512 if n, ok := old.CallingConv(); ok { 513 new.CallingConv = irCallingConv(n) 514 } 515 // (optional) Return attributes. 516 if oldReturnAttrs := old.ReturnAttrs(); len(oldReturnAttrs) > 0 { 517 new.ReturnAttrs = make([]ir.ReturnAttribute, len(oldReturnAttrs)) 518 for i, oldRetAttr := range oldReturnAttrs { 519 retAttr := irReturnAttribute(oldRetAttr) 520 new.ReturnAttrs[i] = retAttr 521 } 522 } 523 // Return type: handled in newGlobalEntity. 524 // Function parameters. 525 ps := old.Params() 526 if oldParams := ps.Params(); len(oldParams) > 0 { 527 new.Params = make([]*ir.Param, len(oldParams)) 528 for i, oldParam := range oldParams { 529 // Type. 530 typ, err := gen.irType(oldParam.Typ()) 531 if err != nil { 532 return errors.WithStack(err) 533 } 534 // Name. 535 param := ir.NewParam("", typ) 536 if n, ok := oldParam.Name(); ok { 537 ident := localIdent(n) 538 param.LocalIdent = ident 539 } 540 // (optional) Parameter attributes. 541 if oldParamAttrs := oldParam.Attrs(); len(oldParamAttrs) > 0 { 542 param.Attrs = make([]ir.ParamAttribute, len(oldParamAttrs)) 543 for j, oldParamAttr := range oldParamAttrs { 544 paramAttr, err := gen.irParamAttribute(oldParamAttr) 545 if err != nil { 546 return errors.WithStack(err) 547 } 548 param.Attrs[j] = paramAttr 549 } 550 } 551 new.Params[i] = param 552 } 553 } 554 // (optional) Unnamed address. 555 if n, ok := old.UnnamedAddr(); ok { 556 new.UnnamedAddr = asmenum.UnnamedAddrFromString(n.Text()) 557 } 558 // (optional) Address space: handled in newGlobalEntity. 559 for _, funcHdrField := range old.FuncHdrFields() { 560 switch funcHdrField := funcHdrField.(type) { 561 // (optional) Function attributes. 562 case ast.FuncAttribute: 563 funcAttr := gen.irFuncAttribute(funcHdrField) 564 new.FuncAttrs = append(new.FuncAttrs, funcAttr) 565 // (optional) Alignment. 566 case *ast.Align: 567 new.Align = irAlign(*funcHdrField) 568 // (optional) Section name. 569 case *ast.Section: 570 new.Section = stringLit(funcHdrField.Name()) 571 // (optional) Partition name. 572 case *ast.Partition: 573 new.Partition = stringLit(funcHdrField.Name()) 574 // (optional) Comdat. 575 case *ast.Comdat: 576 // When comdat name is omitted, the function name is used as an implicit 577 // comdat name. 578 name := new.Name() 579 if n, ok := funcHdrField.Name(); ok { 580 name = comdatName(n) 581 } 582 def, ok := gen.new.comdatDefs[name] 583 if !ok { 584 return errors.Errorf("unable to locate comdat identifier %q used in function header of %q", enc.ComdatName(name), new.Ident()) 585 } 586 new.Comdat = def 587 // (optional) Garbage collection. 588 case *ast.GCNode: 589 new.GC = stringLit(funcHdrField.Name()) 590 // (optional) Prefix. 591 case *ast.Prefix: 592 prefix, err := gen.irTypeConst(funcHdrField.TypeConst()) 593 if err != nil { 594 return errors.WithStack(err) 595 } 596 new.Prefix = prefix 597 // (optional) Prologue. 598 case *ast.Prologue: 599 prologue, err := gen.irTypeConst(funcHdrField.TypeConst()) 600 if err != nil { 601 return errors.WithStack(err) 602 } 603 new.Prologue = prologue 604 // (optional) Prefix. 605 case *ast.Personality: 606 personality, err := gen.irTypeConst(funcHdrField.TypeConst()) 607 if err != nil { 608 return errors.WithStack(err) 609 } 610 new.Personality = personality 611 } 612 } 613 return nil 614 } 615 616 // ### [ Helper functions ] #################################################### 617 618 // gepExprType computes the result type of a getelementptr constant expression. 619 // 620 // getelementptr ElemType, Src, Indices 621 // 622 // Notably, gepExprType returns the type of the gep expression without resolving 623 // the underlying src value. As such gepExprType may be invoked before 624 // completing global identifier resolution. This is needed to correctly resolve 625 // the optional address space of indirect symbols (i.e. aliases and ifuncs). 626 func (gen *generator) gepExprType(old *ast.GetElementPtrExpr) (types.Type, error) { 627 elemType, err := gen.irType(old.ElemType()) 628 if err != nil { 629 return nil, errors.WithStack(err) 630 } 631 src, err := gen.irType(old.Src().Typ()) 632 if err != nil { 633 return nil, errors.WithStack(err) 634 } 635 var idxs []gep.Index 636 for _, index := range old.Indices() { 637 indexVal := index.Index().Val() 638 idx := gen.getIndex(indexVal) 639 idxs = append(idxs, idx) 640 } 641 return gep.ResultType(elemType, src, idxs), nil 642 }