github.com/llir/llvm@v0.3.6/ir/func.go (about) 1 package ir 2 3 import ( 4 "fmt" 5 "strings" 6 "sync" 7 8 "github.com/llir/llvm/internal/enc" 9 "github.com/llir/llvm/ir/constant" 10 "github.com/llir/llvm/ir/enum" 11 "github.com/llir/llvm/ir/types" 12 "github.com/pkg/errors" 13 ) 14 15 // === [ Functions ] =========================================================== 16 17 // Func is an LLVM IR function. The body of a function definition consists of a 18 // set of basic blocks, interconnected by terminator control flow instructions. 19 type Func struct { 20 // Function name (without '@' prefix). 21 GlobalIdent 22 // Function signature. 23 Sig *types.FuncType 24 // Function parameters. 25 Params []*Param 26 // Basic blocks. 27 Blocks []*Block // nil if declaration. 28 29 // extra. 30 31 // Pointer type to function, including an optional address space. If Typ is 32 // nil, the first invocation of Type stores a pointer type with Sig as 33 // element. 34 Typ *types.PointerType 35 // (optional) Linkage. 36 Linkage enum.Linkage 37 // (optional) Preemption; zero value if not present. 38 Preemption enum.Preemption 39 // (optional) Visibility; zero value if not present. 40 Visibility enum.Visibility 41 // (optional) DLL storage class; zero value if not present. 42 DLLStorageClass enum.DLLStorageClass 43 // (optional) Calling convention; zero value if not present. 44 CallingConv enum.CallingConv 45 // (optional) Return attributes. 46 ReturnAttrs []ReturnAttribute 47 // (optional) Unnamed address. 48 UnnamedAddr enum.UnnamedAddr 49 // (optional) Address space; zero if not present. 50 AddrSpace types.AddrSpace 51 // (optional) Function attributes. 52 FuncAttrs []FuncAttribute 53 // (optional) Section name; empty if not present. 54 Section string 55 // (optional) Partition name; empty if not present. 56 Partition string 57 // (optional) Comdat; nil if not present. 58 Comdat *ComdatDef 59 // (optional) Alignment; zero if not present. 60 Align Align 61 // (optional) Garbage collection; empty if not present. 62 GC string 63 // (optional) Prefix; nil if not present. 64 Prefix constant.Constant 65 // (optional) Prologue; nil if not present. 66 Prologue constant.Constant 67 // (optional) Personality; nil if not present. 68 Personality constant.Constant 69 // (optional) Use list orders. 70 UseListOrders []*UseListOrder 71 // (optional) Metadata. 72 Metadata 73 74 // Parent module; field set by ir.Module.NewFunc. 75 Parent *Module `json:"-"` 76 77 // mu prevents races on AssignIDs. 78 mu sync.Mutex 79 } 80 81 // NewFunc returns a new function based on the given function name, return type 82 // and function parameters. 83 func NewFunc(name string, retType types.Type, params ...*Param) *Func { 84 paramTypes := make([]types.Type, len(params)) 85 for i, param := range params { 86 paramTypes[i] = param.Type() 87 } 88 sig := types.NewFunc(retType, paramTypes...) 89 f := &Func{Sig: sig, Params: params} 90 f.SetName(name) 91 // Compute type. 92 f.Type() 93 return f 94 } 95 96 // String returns the LLVM syntax representation of the function as a type-value 97 // pair. 98 func (f *Func) String() string { 99 return fmt.Sprintf("%s %s", f.Type(), f.Ident()) 100 } 101 102 // Type returns the type of the function. 103 func (f *Func) Type() types.Type { 104 // Cache type if not present. 105 if f.Typ == nil { 106 f.Typ = types.NewPointer(f.Sig) 107 f.Typ.AddrSpace = f.AddrSpace 108 } 109 return f.Typ 110 } 111 112 // LLString returns the LLVM syntax representation of the function definition or 113 // declaration. 114 // 115 // Function declaration. 116 // 117 // 'declare' Metadata=MetadataAttachment* Header=FuncHeader 118 // 119 // Function definition. 120 // 121 // 'define' Header=FuncHeader Metadata=MetadataAttachment* Body=FuncBody 122 func (f *Func) LLString() string { 123 if err := f.AssignIDs(); err != nil { 124 panic(fmt.Errorf("unable to assign IDs of function %q; %v", f.Ident(), err)) 125 } 126 buf := &strings.Builder{} 127 if len(f.Blocks) == 0 { 128 // Function declaration. 129 buf.WriteString("declare") 130 for _, md := range f.Metadata { 131 fmt.Fprintf(buf, " %s", md) 132 } 133 if f.Linkage != enum.LinkageNone { 134 fmt.Fprintf(buf, " %s", f.Linkage) 135 } 136 buf.WriteString(headerString(f)) 137 return buf.String() 138 } else { 139 // Function definition. 140 buf.WriteString("define") 141 if f.Linkage != enum.LinkageNone { 142 fmt.Fprintf(buf, " %s", f.Linkage) 143 } 144 buf.WriteString(headerString(f)) 145 for _, md := range f.Metadata { 146 fmt.Fprintf(buf, " %s", md) 147 } 148 fmt.Fprintf(buf, " %s", bodyString(f)) 149 return buf.String() 150 } 151 } 152 153 // AssignIDs assigns IDs to unnamed local variables. 154 func (f *Func) AssignIDs() error { 155 f.mu.Lock() 156 defer f.mu.Unlock() 157 id := int64(0) 158 setName := func(n namedVar) error { 159 if n.IsUnnamed() { 160 if n.ID() != 0 && id != n.ID() { 161 want := id 162 got := n.ID() 163 return errors.Errorf("invalid local ID in function %q, expected %s, got %s", f.Ident(), enc.LocalID(want), enc.LocalID(got)) 164 } 165 n.SetID(id) 166 id++ 167 } 168 return nil 169 } 170 for _, param := range f.Params { 171 // Assign local IDs to unnamed parameters of function definitions. 172 if err := setName(param); err != nil { 173 return errors.WithStack(err) 174 } 175 } 176 for _, block := range f.Blocks { 177 // Assign local IDs to unnamed basic blocks. 178 if err := setName(block); err != nil { 179 return errors.WithStack(err) 180 } 181 for _, inst := range block.Insts { 182 n, ok := inst.(namedVar) 183 if !ok { 184 continue 185 } 186 // Skip void instructions (call with void return). 187 if types.Equal(n.Type(), types.Void) { 188 continue 189 } 190 // Assign local IDs to unnamed local variables. 191 if err := setName(n); err != nil { 192 return errors.WithStack(err) 193 } 194 } 195 n, ok := block.Term.(namedVar) 196 if !ok { 197 continue 198 } 199 // Skip void terminators (invoke, callbr with void return). 200 if types.Equal(n.Type(), types.Void) { 201 continue 202 } 203 if err := setName(n); err != nil { 204 return errors.WithStack(err) 205 } 206 } 207 return nil 208 } 209 210 // ### [ Helper functions ] #################################################### 211 212 // headerString returns the string representation of the function header. 213 func headerString(f *Func) string { 214 // (Linkage | ExternLinkage)? Preemptionopt Visibilityopt DLLStorageClassopt CallingConvopt ReturnAttrs=ReturnAttribute* RetType=Type Name=GlobalIdent '(' Params ')' UnnamedAddropt AddrSpaceopt FuncAttrs=FuncAttribute* Sectionopt Partitionopt Comdatopt Alignopt GCopt Prefixopt Prologueopt Personalityopt 215 buf := &strings.Builder{} 216 if f.Preemption != enum.PreemptionNone { 217 fmt.Fprintf(buf, " %s", f.Preemption) 218 } 219 if f.Visibility != enum.VisibilityNone { 220 fmt.Fprintf(buf, " %s", f.Visibility) 221 } 222 if f.DLLStorageClass != enum.DLLStorageClassNone { 223 fmt.Fprintf(buf, " %s", f.DLLStorageClass) 224 } 225 if f.CallingConv != enum.CallingConvNone { 226 fmt.Fprintf(buf, " %s", callingConvString(f.CallingConv)) 227 } 228 for _, attr := range f.ReturnAttrs { 229 fmt.Fprintf(buf, " %s", attr) 230 } 231 fmt.Fprintf(buf, " %s", f.Sig.RetType) 232 fmt.Fprintf(buf, " %s(", f.Ident()) 233 for i, param := range f.Params { 234 if i != 0 { 235 buf.WriteString(", ") 236 } 237 buf.WriteString(param.LLString()) 238 } 239 if f.Sig.Variadic { 240 if len(f.Params) > 0 { 241 buf.WriteString(", ") 242 } 243 buf.WriteString("...") 244 } 245 buf.WriteString(")") 246 if f.UnnamedAddr != enum.UnnamedAddrNone { 247 fmt.Fprintf(buf, " %s", f.UnnamedAddr) 248 } 249 if f.AddrSpace != 0 { 250 fmt.Fprintf(buf, " %s", f.AddrSpace) 251 } 252 for _, attr := range f.FuncAttrs { 253 fmt.Fprintf(buf, " %s", attr) 254 } 255 if len(f.Section) > 0 { 256 fmt.Fprintf(buf, " section %s", quote(f.Section)) 257 } 258 if len(f.Partition) > 0 { 259 fmt.Fprintf(buf, " partition %s", quote(f.Partition)) 260 } 261 if f.Comdat != nil { 262 if f.Comdat.Name == f.Name() { 263 buf.WriteString(" comdat") 264 } else { 265 fmt.Fprintf(buf, " %s", f.Comdat) 266 } 267 } 268 if f.Align != 0 { 269 fmt.Fprintf(buf, " %s", f.Align) 270 } 271 if len(f.GC) > 0 { 272 fmt.Fprintf(buf, " gc %s", quote(f.GC)) 273 } 274 if f.Prefix != nil { 275 fmt.Fprintf(buf, " prefix %s", f.Prefix) 276 } 277 if f.Prologue != nil { 278 fmt.Fprintf(buf, " prologue %s", f.Prologue) 279 } 280 if f.Personality != nil { 281 fmt.Fprintf(buf, " personality %s", f.Personality) 282 } 283 return buf.String() 284 } 285 286 // bodyString returns the string representation of the function body. 287 func bodyString(body *Func) string { 288 // '{' Blocks=Block+ UseListOrders=UseListOrder* '}' 289 buf := &strings.Builder{} 290 buf.WriteString("{\n") 291 for i, block := range body.Blocks { 292 if i != 0 { 293 buf.WriteString("\n") 294 } 295 fmt.Fprintf(buf, "%s\n", block.LLString()) 296 } 297 if len(body.UseListOrders) > 0 { 298 buf.WriteString("\n") 299 } 300 for _, u := range body.UseListOrders { 301 fmt.Fprintf(buf, "\t%s\n", u) 302 } 303 buf.WriteString("}") 304 return buf.String() 305 }