// NewPHIInst returns a new phi instruction based on the given type and incoming // values. func NewPHIInst(typ, incList interface{}) (*instruction.PHI, error) { if typ, ok := typ.(types.Type); ok { if incList, ok := incList.([]*Incoming); ok { var incs []*instruction.Incoming for _, inc := range incList { val, err := NewValue(typ, inc.val) if err != nil { return nil, errutil.Err(err) } inc, err := instruction.NewIncoming(val, inc.pred) if err != nil { return nil, errutil.Err(err) } incs = append(incs, inc) } return instruction.NewPHI(incs) } return nil, errutil.Newf("invalid incoming values type; expected []*Incoming, got %T", incList) } return nil, errutil.Newf("invalid operand type; expected types.Type, got %T", typ) }
// fixValueInst replaces dummy values within the given value instruction with // their corresponding local variables. func (m dummyMap) fixValueInst(oldValInst instruction.ValueInst) instruction.ValueInst { switch oldValInst := oldValInst.(type) { // Binary Operations case *instruction.Add: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewAdd(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FAdd: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewFAdd(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.Sub: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewSub(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FSub: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewFSub(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.Mul: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewMul(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FMul: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewFMul(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.UDiv: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewUDiv(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.SDiv: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewSDiv(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FDiv: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewFDiv(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.URem: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewURem(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.SRem: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewSRem(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FRem: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewFRem(x, y) if err != nil { panic(errutil.Err(err)) } return inst // Bitwise Binary Operations case *instruction.ShL: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewShL(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.LShR: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewLShR(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.AShR: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewAShR(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.And: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewAnd(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.Or: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewOr(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.Xor: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewXor(x, y) if err != nil { panic(errutil.Err(err)) } return inst // Vector Operations case *instruction.ExtractElement: panic("irx.dummyMap.fixValueInst: ExtractElement not yet implemented") case *instruction.InsertElement: panic("irx.dummyMap.fixValueInst: InsertElement not yet implemented") case *instruction.ShuffleVector: panic("irx.dummyMap.fixValueInst: ShuffleVector not yet implemented") // Aggregate Operations case *instruction.ExtractValue: panic("irx.dummyMap.fixValueInst: ExtractValue not yet implemented") case *instruction.InsertValue: panic("irx.dummyMap.fixValueInst: InsertValue not yet implemented") // Memory Access and Addressing Operations case *instruction.Alloca: // Nothing to do; alloca contains no dummy values. return oldValInst case *instruction.Load: srcAddr := m.fixValue(oldValInst.SrcAddr()) inst, err := instruction.NewLoad(srcAddr) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.CmpXchg: panic("irx.dummyMap.fixValueInst: CmpXchg not yet implemented") case *instruction.AtomicRMW: panic("irx.dummyMap.fixValueInst: AtomicRMW not yet implemented") case *instruction.GetElementPtr: srcAddr := m.fixValue(oldValInst.SrcAddr()) var indices []value.Value for _, oldIndex := range oldValInst.Indices() { index := m.fixValue(oldIndex) indices = append(indices, index) } inst, err := instruction.NewGetElementPtr(srcAddr, indices) if err != nil { panic(errutil.Err(err)) } return inst // Conversion Operations case *instruction.Trunc: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewTrunc(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.ZExt: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewZExt(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.SExt: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewSExt(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FPTrunc: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewFPTrunc(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FPExt: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewFPExt(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FPToUI: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewFPToUI(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FPToSI: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewFPToSI(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.UIToFP: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewUIToFP(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.SIToFP: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewSIToFP(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.PtrToInt: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewPtrToInt(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.IntToPtr: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewIntToPtr(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.BitCast: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewBitCast(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.AddrSpaceCast: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewAddrSpaceCast(from, to) if err != nil { panic(errutil.Err(err)) } return inst // Other Operations case *instruction.ICmp: cond := oldValInst.Cond() x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewICmp(cond, x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FCmp: panic("irx.dummyMap.fixValueInst: FCmp not yet implemented") case *instruction.PHI: oldIncs := oldValInst.Incs() var incs []*instruction.Incoming for _, oldInc := range oldIncs { val := m.fixValue(oldInc.Value()) pred := m.fixNamedValue(oldInc.Pred()) inc, err := instruction.NewIncoming(val, pred) if err != nil { panic(errutil.Err(err)) } incs = append(incs, inc) } inst, err := instruction.NewPHI(incs) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.Select: cond := m.fixValue(oldValInst.Cond()) x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewSelect(cond, x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.Call: result := oldValInst.RetType() // TODO: Fix value of callee if the type of Callee changes from string to // value.Value. callee := oldValInst.Callee() var args []value.Value for _, oldArg := range oldValInst.Args() { arg := m.fixValue(oldArg) args = append(args, arg) } inst, err := instruction.NewCall(result, callee, args) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.VAArg: panic("irx.dummyMap.fixValueInst: VAArg not yet implemented") case *instruction.LandingPad: panic("irx.dummyMap.fixValueInst: LandingPad not yet implemented") case *instruction.CatchPad: panic("irx.dummyMap.fixValueInst: CatchPad not yet implemented") case *instruction.CleanupPad: panic("irx.dummyMap.fixValueInst: CleanupPad not yet implemented") default: panic("irx.dummyMap.fixValueInst: not yet implemented") } }
// binaryExpr lowers the given binary expression to LLVM IR, emitting code to f. func (m *Module) binaryExpr(f *Function, n *ast.BinaryExpr) value.Value { switch n.Op { // + case token.Add: x, y := m.expr(f, n.X), m.expr(f, n.Y) x, y = m.implicitConversion(f, x, y) addInst, err := instruction.NewAdd(x, y) if err != nil { panic(fmt.Sprintf("unable to create add instruction; %v", err)) } // Emit add instruction. return f.emitInst(addInst) // - case token.Sub: x, y := m.expr(f, n.X), m.expr(f, n.Y) x, y = m.implicitConversion(f, x, y) subInst, err := instruction.NewSub(x, y) if err != nil { panic(fmt.Sprintf("unable to create sub instruction; %v", err)) } // Emit sub instruction. return f.emitInst(subInst) // * case token.Mul: x, y := m.expr(f, n.X), m.expr(f, n.Y) x, y = m.implicitConversion(f, x, y) mulInst, err := instruction.NewMul(x, y) if err != nil { panic(fmt.Sprintf("unable to create mul instruction; %v", err)) } // Emit mul instruction. return f.emitInst(mulInst) // / case token.Div: x, y := m.expr(f, n.X), m.expr(f, n.Y) x, y = m.implicitConversion(f, x, y) // TODO: Add support for unsigned division. sdivInst, err := instruction.NewSDiv(x, y) if err != nil { panic(fmt.Sprintf("unable to create sdiv instruction; %v", err)) } // Emit sdiv instruction. return f.emitInst(sdivInst) // < case token.Lt: x, y := m.expr(f, n.X), m.expr(f, n.Y) x, y = m.implicitConversion(f, x, y) icmpInst, err := instruction.NewICmp(instruction.ICondSLT, x, y) if err != nil { panic(fmt.Sprintf("unable to create icmp instruction; %v", err)) } // Emit icmp instruction. return f.emitInst(icmpInst) // > case token.Gt: x, y := m.expr(f, n.X), m.expr(f, n.Y) x, y = m.implicitConversion(f, x, y) icmpInst, err := instruction.NewICmp(instruction.ICondSGT, x, y) if err != nil { panic(fmt.Sprintf("unable to create icmp instruction; %v", err)) } // Emit icmp instruction. return f.emitInst(icmpInst) // <= case token.Le: x, y := m.expr(f, n.X), m.expr(f, n.Y) x, y = m.implicitConversion(f, x, y) icmpInst, err := instruction.NewICmp(instruction.ICondSLE, x, y) if err != nil { panic(fmt.Sprintf("unable to create icmp instruction; %v", err)) } // Emit icmp instruction. return f.emitInst(icmpInst) // >= case token.Ge: x, y := m.expr(f, n.X), m.expr(f, n.Y) x, y = m.implicitConversion(f, x, y) icmpInst, err := instruction.NewICmp(instruction.ICondSGE, x, y) if err != nil { panic(fmt.Sprintf("unable to create icmp instruction; %v", err)) } // Emit icmp instruction. return f.emitInst(icmpInst) // != case token.Ne: x, y := m.expr(f, n.X), m.expr(f, n.Y) x, y = m.implicitConversion(f, x, y) icmpInst, err := instruction.NewICmp(instruction.ICondNE, x, y) if err != nil { panic(fmt.Sprintf("unable to create icmp instruction; %v", err)) } // Emit icmp instruction. return f.emitInst(icmpInst) // == case token.Eq: x, y := m.expr(f, n.X), m.expr(f, n.Y) x, y = m.implicitConversion(f, x, y) icmpInst, err := instruction.NewICmp(instruction.ICondEQ, x, y) if err != nil { panic(fmt.Sprintf("unable to create icmp instruction; %v", err)) } // Emit icmp instruction. return f.emitInst(icmpInst) // && case token.Land: x := m.cond(f, n.X) start := f.curBlock trueBranch := f.NewBasicBlock("") end := f.NewBasicBlock("") term, err := instruction.NewBr(x, trueBranch, end) if err != nil { panic(fmt.Sprintf("unable to create br terminator; %v", err)) } f.curBlock.SetTerm(term) f.curBlock = trueBranch y := m.cond(f, n.Y) trueBranch.emitJmp(end) f.curBlock = end var incs []*instruction.Incoming zero := constZero(irtypes.I1) inc, err := instruction.NewIncoming(zero, start) if err != nil { panic(fmt.Sprintf("unable to create incoming value; %v", err)) } incs = append(incs, inc) inc, err = instruction.NewIncoming(y, trueBranch) if err != nil { panic(fmt.Sprintf("unable to create incoming value; %v", err)) } incs = append(incs, inc) phiInst, err := instruction.NewPHI(incs) if err != nil { panic(fmt.Sprintf("unable to create br terminator; %v", err)) } // Emit phi instruction. return f.emitInst(phiInst) // = case token.Assign: y := m.expr(f, n.Y) switch expr := n.X.(type) { case *ast.Ident: m.identDef(f, expr, y) case *ast.IndexExpr: m.indexExprDef(f, expr, y) default: panic(fmt.Sprintf("support for assignment to type %T not yet implemented", expr)) } return y default: panic(fmt.Sprintf("support for binary operator %v not yet implemented", n.Op)) } }