// indexExpr lowers the given index expression to LLVM IR, emitting code to f. func (m *Module) indexExpr(f *Function, n *ast.IndexExpr) value.Value { index := m.expr(f, n.Index) // Extend the index to a 64-bit integer. if !irtypes.Equal(index.Type(), irtypes.I64) { index = m.convert(f, index, irtypes.I64) } typ := m.typeOf(n.Name) array := m.valueFromIdent(f, n.Name) // Dereference pointer pointer. elem := typ addr := array zero := constZero(irtypes.I64) indices := []value.Value{zero, index} if typ, ok := typ.(*irtypes.Pointer); ok { elem = typ.Elem() // Emit load instruction. // TODO: Validate typ against array.Elem(). loadInst, err := instruction.NewLoad(array) if err != nil { panic(fmt.Sprintf("unable to create load instruction; %v", err)) } addr = f.emitInst(loadInst) indices = []value.Value{index} } // Emit getelementptr instruction. if m.isGlobal(n.Name) { var is []constant.Constant for _, index := range indices { i, ok := index.(constant.Constant) if !ok { break } is = append(is, i) } if len(is) == len(indices) { // In accordance with Clang, emit getelementptr constant expressions // for global variables. gepExpr, err := constant.NewGetElementPtr(elem, addr, is) if err != nil { panic(fmt.Sprintf("unable to create getelementptr expression; %v", err)) } return gepExpr } } // TODO: Validate elem against array.Elem(). gepInst, err := instruction.NewGetElementPtr(addr, indices) if err != nil { panic(fmt.Sprintf("unable to create getelementptr instruction; %v", err)) } return f.emitInst(gepInst) }
// indexExprUse lowers the given index expression usage to LLVM IR, emitting // code to f. func (m *Module) indexExprUse(f *Function, n *ast.IndexExpr) value.Value { v := m.indexExpr(f, n) typ := m.typeOf(n) if isRef(typ) { return v } // TODO: Validate typ against v.Elem(). loadInst, err := instruction.NewLoad(v) if err != nil { panic(fmt.Sprintf("unable to create load instruction; %v", err)) } // Emit load instruction. return f.emitInst(loadInst) }
// identUse lowers the given identifier usage to LLVM IR, emitting code to f. func (m *Module) identUse(f *Function, ident *ast.Ident) value.Value { v := m.ident(f, ident) typ := m.typeOf(ident) if isRef(typ) { return v } // TODO: Validate typ against v.Elem() loadInst, err := instruction.NewLoad(v) if err != nil { panic(fmt.Sprintf("unable to create load instruction; %v", err)) } // Emit load instruction. return f.emitInst(loadInst) }
// NewLoadInst returns a new load instruction based on the given type and // address. func NewLoadInst(typ, srcAddrType, srcAddr interface{}) (*instruction.Load, error) { if typ, ok := typ.(types.Type); ok { srcAddr, err := NewValue(srcAddrType, srcAddr) if err != nil { return nil, errutil.Err(err) } srcAddrType, ok := srcAddr.Type().(*types.Pointer) if !ok { return nil, errutil.Newf("invalid source address pointer type; expected *types.Pointer, got %T", srcAddr.Type()) } if !types.Equal(typ, srcAddrType.Elem()) { return nil, errutil.Newf("type mismatch between element type (%v) and source address element type (%v)", typ, srcAddrType.Elem()) } return instruction.NewLoad(srcAddr) } return nil, errutil.Newf("invalid operand type; expected types.Type, got %T", typ) }
// ident lowers the given identifier to LLVM IR, emitting code to f. func (m *Module) ident(f *Function, ident *ast.Ident) value.Value { switch typ := m.typeOf(ident).(type) { case *irtypes.Array: array := m.valueFromIdent(f, ident) zero := constZero(irtypes.I64) indices := []value.Value{zero, zero} // Emit getelementptr instruction. if m.isGlobal(ident) { var is []constant.Constant for _, index := range indices { i, ok := index.(constant.Constant) if !ok { break } is = append(is, i) } if len(is) == len(indices) { // In accordance with Clang, emit getelementptr constant expressions // for global variables. gepExpr, err := constant.NewGetElementPtr(typ, array, is) if err != nil { panic(fmt.Sprintf("unable to create getelementptr expression; %v", err)) } return gepExpr } } gepInst, err := instruction.NewGetElementPtr(array, indices) if err != nil { panic(fmt.Sprintf("unable to create getelementptr instruction; %v", err)) } return f.emitInst(gepInst) case *irtypes.Pointer: // Emit load instruction. // TODO: Validate typ against srcAddr.Elem(). loadInst, err := instruction.NewLoad(m.valueFromIdent(f, ident)) if err != nil { panic(fmt.Sprintf("unable to create load instruction; %v", err)) } return f.emitInst(loadInst) default: return m.valueFromIdent(f, ident) } }
// 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") } }