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  }