github.com/llir/llvm@v0.3.6/asm/inst_other.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/ir" 9 "github.com/llir/llvm/ir/types" 10 "github.com/llir/llvm/ir/value" 11 "github.com/pkg/errors" 12 ) 13 14 // === [ Create IR ] =========================================================== 15 16 // newICmpInst returns a new IR icmp instruction (without body but with type) 17 // based on the given AST icmp instruction. 18 func (fgen *funcGen) newICmpInst(ident ir.LocalIdent, old *ast.ICmpInst) (*ir.InstICmp, error) { 19 xType, err := fgen.gen.irType(old.X().Typ()) 20 if err != nil { 21 return nil, errors.WithStack(err) 22 } 23 var typ types.Type 24 switch xType := xType.(type) { 25 case *types.IntType, *types.PointerType: 26 typ = types.I1 27 case *types.VectorType: 28 typ = types.NewVector(xType.Len, types.I1) 29 default: 30 panic(fmt.Errorf("invalid icmp operand type; expected *types.IntType, *types.PointerType or *types.VectorType, got %T", xType)) 31 } 32 return &ir.InstICmp{LocalIdent: ident, Typ: typ}, nil 33 } 34 35 // newFCmpInst returns a new IR fcmp instruction (without body but with type) 36 // based on the given AST fcmp instruction. 37 func (fgen *funcGen) newFCmpInst(ident ir.LocalIdent, old *ast.FCmpInst) (*ir.InstFCmp, error) { 38 xType, err := fgen.gen.irType(old.X().Typ()) 39 if err != nil { 40 return nil, errors.WithStack(err) 41 } 42 var typ types.Type 43 switch xType := xType.(type) { 44 case *types.FloatType: 45 typ = types.I1 46 case *types.VectorType: 47 typ = types.NewVector(xType.Len, types.I1) 48 default: 49 panic(fmt.Errorf("invalid fcmp operand type; expected *types.FloatType or *types.VectorType, got %T", xType)) 50 } 51 return &ir.InstFCmp{LocalIdent: ident, Typ: typ}, nil 52 } 53 54 // newPhiInst returns a new IR phi instruction (without body but with type) 55 // based on the given AST phi instruction. 56 func (fgen *funcGen) newPhiInst(ident ir.LocalIdent, old *ast.PhiInst) (*ir.InstPhi, error) { 57 typ, err := fgen.gen.irType(old.Typ()) 58 if err != nil { 59 return nil, errors.WithStack(err) 60 } 61 return &ir.InstPhi{LocalIdent: ident, Typ: typ, FastMathFlags: irFastMathFlags(old.FastMathFlags())}, nil 62 } 63 64 // newSelectInst returns a new IR select instruction (without body but with 65 // type) based on the given AST select instruction. 66 func (fgen *funcGen) newSelectInst(ident ir.LocalIdent, old *ast.SelectInst) (*ir.InstSelect, error) { 67 typ, err := fgen.gen.irType(old.ValueTrue().Typ()) 68 if err != nil { 69 return nil, errors.WithStack(err) 70 } 71 return &ir.InstSelect{LocalIdent: ident, Typ: typ}, nil 72 } 73 74 // newFreezeInst returns a new IR freeze instruction (without body but with 75 // type) based on the given AST freeze instruction. 76 func (fgen *funcGen) newFreezeInst(ident ir.LocalIdent, old *ast.FreezeInst) (*ir.InstFreeze, error) { 77 typ, err := fgen.gen.irType(old.X().Typ()) 78 if err != nil { 79 return nil, errors.WithStack(err) 80 } 81 return &ir.InstFreeze{LocalIdent: ident, Typ: typ}, nil 82 } 83 84 // newCallInst returns a new IR call instruction (without body but with type) 85 // based on the given AST call instruction. 86 func (fgen *funcGen) newCallInst(ident ir.LocalIdent, old *ast.CallInst) (*ir.InstCall, error) { 87 // Note: the type of call instructions must be determined before assigning 88 // local IDs, as they may be values or non-values based on return type. 89 typ, err := fgen.gen.irType(old.Typ()) 90 if err != nil { 91 return nil, errors.WithStack(err) 92 } 93 // Resolve return type of variadic functions; e.g. 94 // 95 // call void (...) @foo() 96 if funcType, ok := typ.(*types.FuncType); ok { 97 typ = funcType.RetType 98 } 99 return &ir.InstCall{LocalIdent: ident, Typ: typ}, nil 100 } 101 102 // newVAArgInst returns a new IR vaarg instruction (without body but with type) 103 // based on the given AST vaarg instruction. 104 func (fgen *funcGen) newVAArgInst(ident ir.LocalIdent, old *ast.VAArgInst) (*ir.InstVAArg, error) { 105 argType, err := fgen.gen.irType(old.ArgType()) 106 if err != nil { 107 return nil, errors.WithStack(err) 108 } 109 return &ir.InstVAArg{LocalIdent: ident, ArgType: argType}, nil 110 } 111 112 // newLandingPadInst returns a new IR landingpad instruction (without body but 113 // with type) based on the given AST landingpad instruction. 114 func (fgen *funcGen) newLandingPadInst(ident ir.LocalIdent, old *ast.LandingPadInst) (*ir.InstLandingPad, error) { 115 resultType, err := fgen.gen.irType(old.ResultType()) 116 if err != nil { 117 return nil, errors.WithStack(err) 118 } 119 return &ir.InstLandingPad{LocalIdent: ident, ResultType: resultType}, nil 120 } 121 122 // === [ Translate AST to IR ] ================================================= 123 124 // --- [ icmp ] ---------------------------------------------------------------- 125 126 // irICmpInst translates the given AST icmp instruction into an equivalent IR 127 // instruction. 128 func (fgen *funcGen) irICmpInst(new ir.Instruction, old *ast.ICmpInst) error { 129 inst, ok := new.(*ir.InstICmp) 130 if !ok { 131 panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstICmp, got %T", new)) 132 } 133 // Integer comparison predicate. 134 inst.Pred = asmenum.IPredFromString(old.Pred().Text()) 135 // X operand. 136 x, err := fgen.irTypeValue(old.X()) 137 if err != nil { 138 return errors.WithStack(err) 139 } 140 inst.X = x 141 // Y operand. 142 y, err := fgen.irValue(x.Type(), old.Y()) 143 if err != nil { 144 return errors.WithStack(err) 145 } 146 inst.Y = y 147 // (optional) Metadata. 148 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 149 if err != nil { 150 return errors.WithStack(err) 151 } 152 inst.Metadata = md 153 return nil 154 } 155 156 // --- [ fcmp ] ---------------------------------------------------------------- 157 158 // irFCmpInst translates the given AST fcmp instruction into an equivalent IR 159 // instruction. 160 func (fgen *funcGen) irFCmpInst(new ir.Instruction, old *ast.FCmpInst) error { 161 inst, ok := new.(*ir.InstFCmp) 162 if !ok { 163 panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFCmp, got %T", new)) 164 } 165 // Floating-point comparison predicate. 166 inst.Pred = asmenum.FPredFromString(old.Pred().Text()) 167 // X operand. 168 x, err := fgen.irTypeValue(old.X()) 169 if err != nil { 170 return errors.WithStack(err) 171 } 172 inst.X = x 173 // Y operand. 174 y, err := fgen.irValue(x.Type(), old.Y()) 175 if err != nil { 176 return errors.WithStack(err) 177 } 178 inst.Y = y 179 // (optional) Fast math flags. 180 inst.FastMathFlags = irFastMathFlags(old.FastMathFlags()) 181 // (optional) Metadata. 182 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 183 if err != nil { 184 return errors.WithStack(err) 185 } 186 inst.Metadata = md 187 return nil 188 } 189 190 // --- [ phi ] ----------------------------------------------------------------- 191 192 // irPhiInst translates the given AST phi instruction into an equivalent IR 193 // instruction. 194 func (fgen *funcGen) irPhiInst(new ir.Instruction, old *ast.PhiInst) error { 195 inst, ok := new.(*ir.InstPhi) 196 if !ok { 197 panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstPhi, got %T", new)) 198 } 199 // Type of incoming values. 200 typ, err := fgen.gen.irType(old.Typ()) 201 if err != nil { 202 return errors.WithStack(err) 203 } 204 // Incoming values. 205 if oldIncs := old.Incs(); len(oldIncs) > 0 { 206 inst.Incs = make([]*ir.Incoming, len(oldIncs)) 207 for i, oldInc := range oldIncs { 208 inc, err := fgen.irIncoming(typ, oldInc.X(), oldInc.Pred()) 209 if err != nil { 210 return errors.WithStack(err) 211 } 212 inst.Incs[i] = inc 213 } 214 } 215 // (optional) Metadata. 216 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 217 if err != nil { 218 return errors.WithStack(err) 219 } 220 inst.Metadata = md 221 return nil 222 } 223 224 // --- [ select ] -------------------------------------------------------------- 225 226 // irSelectInst translates the given AST select instruction into an equivalent 227 // IR instruction. 228 func (fgen *funcGen) irSelectInst(new ir.Instruction, old *ast.SelectInst) error { 229 inst, ok := new.(*ir.InstSelect) 230 if !ok { 231 panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSelect, got %T", new)) 232 } 233 // Selection condition. 234 cond, err := fgen.irTypeValue(old.Cond()) 235 if err != nil { 236 return errors.WithStack(err) 237 } 238 inst.Cond = cond 239 // True condition value. 240 valueTrue, err := fgen.irTypeValue(old.ValueTrue()) 241 if err != nil { 242 return errors.WithStack(err) 243 } 244 inst.ValueTrue = valueTrue 245 // False condition value. 246 valueFalse, err := fgen.irTypeValue(old.ValueFalse()) 247 if err != nil { 248 return errors.WithStack(err) 249 } 250 inst.ValueFalse = valueFalse 251 // (optional) Fast math flags. 252 inst.FastMathFlags = irFastMathFlags(old.FastMathFlags()) 253 // (optional) Metadata. 254 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 255 if err != nil { 256 return errors.WithStack(err) 257 } 258 inst.Metadata = md 259 return nil 260 } 261 262 // --- [ freeze ] ---------------------------------------------------------- 263 264 // irFreezeInst translates the given AST freeze instruction into an 265 // equivalent IR instruction. 266 func (fgen *funcGen) irFreezeInst(new ir.Instruction, old *ast.FreezeInst) error { 267 inst, ok := new.(*ir.InstFreeze) 268 if !ok { 269 panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFreeze, got %T", new)) 270 } 271 x, err := fgen.irTypeValue(old.X()) 272 if err != nil { 273 return errors.WithStack(err) 274 } 275 inst.X = x 276 return nil 277 } 278 279 // --- [ call ] ---------------------------------------------------------------- 280 281 // irCallInst translates the given AST call instruction into an equivalent IR 282 // instruction. 283 func (fgen *funcGen) irCallInst(new ir.Instruction, old *ast.CallInst) error { 284 inst, ok := new.(*ir.InstCall) 285 if !ok { 286 panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstCall, got %T", new)) 287 } 288 // Function arguments. 289 if oldArgs := old.Args().Args(); len(oldArgs) > 0 { 290 inst.Args = make([]value.Value, len(oldArgs)) 291 for i, oldArg := range oldArgs { 292 arg, err := fgen.irArg(oldArg) 293 if err != nil { 294 return errors.WithStack(err) 295 } 296 inst.Args[i] = arg 297 } 298 } 299 // Callee. 300 typ, err := fgen.gen.irType(old.Typ()) 301 if err != nil { 302 return errors.WithStack(err) 303 } 304 sig, ok := typ.(*types.FuncType) 305 if !ok { 306 // Preliminary function signature. Only used by fgen.irValue for inline 307 // assembly callees and constrant expressions. 308 var paramTypes []types.Type 309 if len(inst.Args) > 0 { 310 paramTypes = make([]types.Type, len(inst.Args)) 311 for i, arg := range inst.Args { 312 paramTypes[i] = arg.Type() 313 } 314 } 315 sig = types.NewFunc(typ, paramTypes...) 316 } 317 // The callee type is always pointer to function type. 318 ptrToSig := types.NewPointer(sig) 319 callee, err := fgen.irValue(ptrToSig, old.Callee()) 320 if err != nil { 321 return errors.WithStack(err) 322 } 323 inst.Callee = callee 324 // (optional) Tail. 325 if n, ok := old.Tail(); ok { 326 inst.Tail = asmenum.TailFromString(n.Text()) 327 } 328 // (optional) Fast math flags. 329 inst.FastMathFlags = irFastMathFlags(old.FastMathFlags()) 330 // (optional) Calling convention. 331 if n, ok := old.CallingConv(); ok { 332 inst.CallingConv = irCallingConv(n) 333 } 334 // (optional) Return attributes. 335 if oldReturnAttrs := old.ReturnAttrs(); len(oldReturnAttrs) > 0 { 336 inst.ReturnAttrs = make([]ir.ReturnAttribute, len(oldReturnAttrs)) 337 for i, oldRetAttr := range oldReturnAttrs { 338 retAttr := irReturnAttribute(oldRetAttr) 339 inst.ReturnAttrs[i] = retAttr 340 } 341 } 342 // (optional) Address space. 343 if n, ok := old.AddrSpace(); ok { 344 inst.AddrSpace = irAddrSpace(n) 345 } 346 // (optional) Function attributes. 347 if oldFuncAttrs := old.FuncAttrs(); len(oldFuncAttrs) > 0 { 348 inst.FuncAttrs = make([]ir.FuncAttribute, len(oldFuncAttrs)) 349 for i, oldFuncAttr := range oldFuncAttrs { 350 funcAttr := fgen.gen.irFuncAttribute(oldFuncAttr) 351 inst.FuncAttrs[i] = funcAttr 352 } 353 } 354 // (optional) Operand bundles. 355 if oldOperandBundles := old.OperandBundles(); len(oldOperandBundles) > 0 { 356 inst.OperandBundles = make([]*ir.OperandBundle, len(oldOperandBundles)) 357 for i, oldOperandBundle := range oldOperandBundles { 358 operandBundle, err := fgen.irOperandBundle(oldOperandBundle) 359 if err != nil { 360 return errors.WithStack(err) 361 } 362 inst.OperandBundles[i] = operandBundle 363 } 364 } 365 // (optional) Metadata. 366 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 367 if err != nil { 368 return errors.WithStack(err) 369 } 370 inst.Metadata = md 371 return nil 372 } 373 374 // --- [ va_arg ] -------------------------------------------------------------- 375 376 // irVAArgInst translates the given AST vaarg instruction into an equivalent IR 377 // instruction. 378 func (fgen *funcGen) irVAArgInst(new ir.Instruction, old *ast.VAArgInst) error { 379 inst, ok := new.(*ir.InstVAArg) 380 if !ok { 381 panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstVAArg, got %T", new)) 382 } 383 // Variable argument list. 384 argList, err := fgen.irTypeValue(old.ArgList()) 385 if err != nil { 386 return errors.WithStack(err) 387 } 388 inst.ArgList = argList 389 // Argument type. 390 argType, err := fgen.gen.irType(old.ArgType()) 391 if err != nil { 392 return errors.WithStack(err) 393 } 394 inst.ArgType = argType 395 // (optional) Metadata. 396 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 397 if err != nil { 398 return errors.WithStack(err) 399 } 400 inst.Metadata = md 401 return nil 402 } 403 404 // --- [ landingpad ] ---------------------------------------------------------- 405 406 // irLandingPadInst translates the given AST landingpad instruction into an 407 // equivalent IR instruction. 408 func (fgen *funcGen) irLandingPadInst(new ir.Instruction, old *ast.LandingPadInst) error { 409 inst, ok := new.(*ir.InstLandingPad) 410 if !ok { 411 panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstLandingPad, got %T", new)) 412 } 413 // Result type. 414 resultType, err := fgen.gen.irType(old.ResultType()) 415 if err != nil { 416 return errors.WithStack(err) 417 } 418 inst.ResultType = resultType 419 // (optional) Cleanup landing pad. 420 _, inst.Cleanup = old.Cleanup() 421 // Filter and catch clauses. 422 if oldClauses := old.Clauses(); len(oldClauses) > 0 { 423 inst.Clauses = make([]*ir.Clause, len(oldClauses)) 424 for i, oldClause := range oldClauses { 425 clause, err := fgen.irClause(oldClause) 426 if err != nil { 427 return errors.WithStack(err) 428 } 429 inst.Clauses[i] = clause 430 } 431 } 432 // (optional) Metadata. 433 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 434 if err != nil { 435 return errors.WithStack(err) 436 } 437 inst.Metadata = md 438 return nil 439 } 440 441 // --- [ catchpad ] ------------------------------------------------------------ 442 443 // irCatchPadInst translates the given AST catchpad instruction into an 444 // equivalent IR instruction. 445 func (fgen *funcGen) irCatchPadInst(new ir.Instruction, old *ast.CatchPadInst) error { 446 inst, ok := new.(*ir.InstCatchPad) 447 if !ok { 448 panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstCatchPad, got %T", new)) 449 } 450 // Exception scope. 451 ident := localIdent(old.CatchSwitch()) 452 v, ok := fgen.locals[ident] 453 if !ok { 454 return errors.Errorf("unable to locate local identifier %q", ident.Ident()) 455 } 456 catchSwitch, ok := v.(*ir.TermCatchSwitch) 457 if !ok { 458 return errors.Errorf("invalid parent catchswitch type; expected *ir.TermCatchSwitch, got %T", v) 459 } 460 inst.CatchSwitch = catchSwitch 461 // Exception arguments. 462 if oldArgs := old.Args(); len(oldArgs) > 0 { 463 inst.Args = make([]value.Value, len(oldArgs)) 464 for i, oldArg := range oldArgs { 465 arg, err := fgen.irExceptionArg(oldArg) 466 if err != nil { 467 return errors.WithStack(err) 468 } 469 inst.Args[i] = arg 470 } 471 } 472 // (optional) Metadata. 473 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 474 if err != nil { 475 return errors.WithStack(err) 476 } 477 inst.Metadata = md 478 return nil 479 } 480 481 // --- [ cleanuppad ] ---------------------------------------------------------- 482 483 // irCleanupPadInst translates the given AST cleanuppad instruction into an 484 // equivalent IR instruction. 485 func (fgen *funcGen) irCleanupPadInst(new ir.Instruction, old *ast.CleanupPadInst) error { 486 inst, ok := new.(*ir.InstCleanupPad) 487 if !ok { 488 panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstCleanupPad, got %T", new)) 489 } 490 // Exception scope. 491 parentPad, err := fgen.irExceptionPad(old.ParentPad()) 492 if err != nil { 493 return errors.WithStack(err) 494 } 495 inst.ParentPad = parentPad 496 // Exception arguments. 497 if oldArgs := old.Args(); len(oldArgs) > 0 { 498 inst.Args = make([]value.Value, len(oldArgs)) 499 for i, oldArg := range oldArgs { 500 arg, err := fgen.irExceptionArg(oldArg) 501 if err != nil { 502 return errors.WithStack(err) 503 } 504 inst.Args[i] = arg 505 } 506 } 507 // (optional) Metadata. 508 md, err := fgen.gen.irMetadataAttachments(old.Metadata()) 509 if err != nil { 510 return errors.WithStack(err) 511 } 512 inst.Metadata = md 513 return nil 514 }