// 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) }
// 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) } }
// NewValue returns a new value based on the given type and value. func NewValue(typ, val interface{}) (value.Value, error) { // TODO: Verify type equality between typ and val.Type(). // * handled by constant.NewInt // * ... if typ, ok := typ.(types.Type); ok { switch val := val.(type) { case *LocalDummy: return val, nil case *Global: // TODO: Retreive type from val.typ once support for forward reference // of global variable declarations have been added. // TODO: Add type-check between ptrType and val.typ. if typ, ok := typ.(*types.Pointer); ok { return constant.NewPointer(typ, val.name) } return nil, errutil.Newf("invalid global type; expected *types.Pointer, got %T", typ) case *IntConst: return constant.NewInt(typ, val.val) case *NullPointerConst: if typ, ok := typ.(*types.Pointer); ok { return constant.NewNullPointer(typ) } return nil, errutil.Newf("invalid null pointer type; expected *types.Pointer, got %T", typ) case *CharArrayConst: return constant.NewCharArray(typ, val.val) case *ZeroInitializer: return constant.NewZeroInitializer(typ), nil case *GetElementPtrExpr: return constant.NewGetElementPtr(val.elem, val.addr, val.indices) default: pretty.Println(val) panic(fmt.Sprintf("support for value type %T not yet implemented", val)) } } return nil, errutil.Newf("invalid value type; expected types.Type, got %T", typ) }