github.com/axw/llgo@v0.0.0-20160805011314-95b5fe4dca20/irgen/attribute.go (about) 1 //===- attribute.go - attribute processor ---------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file processes llgo and //extern attributes. 11 // 12 //===----------------------------------------------------------------------===// 13 14 package irgen 15 16 import ( 17 "fmt" 18 "go/ast" 19 "llvm.org/llvm/bindings/go/llvm" 20 "strings" 21 ) 22 23 const AttributeCommentPrefix = "#llgo " 24 25 // Attribute represents an attribute associated with a 26 // global variable or function. 27 type Attribute interface { 28 Apply(llvm.Value) 29 } 30 31 // parseAttribute parses zero or more #llgo comment attributes associated with 32 // a global variable or function. The comment group provided will be processed 33 // one line at a time using parseAttribute. 34 func parseAttributes(doc *ast.CommentGroup) []Attribute { 35 var attributes []Attribute 36 if doc == nil { 37 return attributes 38 } 39 for _, comment := range doc.List { 40 if strings.HasPrefix(comment.Text, "//extern ") { 41 nameattr := nameAttribute(strings.TrimSpace(comment.Text[9:])) 42 attributes = append(attributes, nameattr) 43 continue 44 } 45 text := comment.Text[2:] 46 if strings.HasPrefix(comment.Text, "/*") { 47 text = text[:len(text)-2] 48 } 49 attr := parseAttribute(strings.TrimSpace(text)) 50 if attr != nil { 51 attributes = append(attributes, attr) 52 } 53 } 54 return attributes 55 } 56 57 // parseAttribute parses a single #llgo comment attribute associated with 58 // a global variable or function. The string provided will be parsed 59 // if it begins with AttributeCommentPrefix, otherwise nil is returned. 60 func parseAttribute(line string) Attribute { 61 if !strings.HasPrefix(line, AttributeCommentPrefix) { 62 return nil 63 } 64 line = strings.TrimSpace(line[len(AttributeCommentPrefix):]) 65 colon := strings.IndexRune(line, ':') 66 var key, value string 67 if colon == -1 { 68 key = line 69 } else { 70 key, value = line[:colon], line[colon+1:] 71 } 72 switch key { 73 case "linkage": 74 return parseLinkageAttribute(value) 75 case "name": 76 return nameAttribute(strings.TrimSpace(value)) 77 case "attr": 78 return parseLLVMAttribute(strings.TrimSpace(value)) 79 case "thread_local": 80 return tlsAttribute{} 81 default: 82 // FIXME decide what to do here. return error? log warning? 83 panic("unknown attribute key: " + key) 84 } 85 return nil 86 } 87 88 type linkageAttribute llvm.Linkage 89 90 func (a linkageAttribute) Apply(v llvm.Value) { 91 v.SetLinkage(llvm.Linkage(a)) 92 } 93 94 func parseLinkageAttribute(value string) linkageAttribute { 95 var result linkageAttribute 96 value = strings.Replace(value, ",", " ", -1) 97 for _, field := range strings.Fields(value) { 98 switch strings.ToLower(field) { 99 case "private": 100 result |= linkageAttribute(llvm.PrivateLinkage) 101 case "internal": 102 result |= linkageAttribute(llvm.InternalLinkage) 103 case "available_externally": 104 result |= linkageAttribute(llvm.AvailableExternallyLinkage) 105 case "linkonce": 106 result |= linkageAttribute(llvm.LinkOnceAnyLinkage) 107 case "common": 108 result |= linkageAttribute(llvm.CommonLinkage) 109 case "weak": 110 result |= linkageAttribute(llvm.WeakAnyLinkage) 111 case "appending": 112 result |= linkageAttribute(llvm.AppendingLinkage) 113 case "extern_weak": 114 result |= linkageAttribute(llvm.ExternalWeakLinkage) 115 case "linkonce_odr": 116 result |= linkageAttribute(llvm.LinkOnceODRLinkage) 117 case "weak_odr": 118 result |= linkageAttribute(llvm.WeakODRLinkage) 119 case "external": 120 result |= linkageAttribute(llvm.ExternalLinkage) 121 } 122 } 123 return result 124 } 125 126 type nameAttribute string 127 128 func (a nameAttribute) Apply(v llvm.Value) { 129 if !v.IsAFunction().IsNil() { 130 name := string(a) 131 curr := v.GlobalParent().NamedFunction(name) 132 if !curr.IsNil() && curr != v { 133 if curr.BasicBlocksCount() != 0 { 134 panic(fmt.Errorf("Want to take the name %s from a function that has a body!", name)) 135 } 136 curr.SetName(name + "_llgo_replaced") 137 curr.ReplaceAllUsesWith(llvm.ConstBitCast(v, curr.Type())) 138 } 139 v.SetName(name) 140 } else { 141 v.SetName(string(a)) 142 } 143 } 144 145 func parseLLVMAttribute(value string) llvmAttribute { 146 var result llvmAttribute 147 value = strings.Replace(value, ",", " ", -1) 148 for _, field := range strings.Fields(value) { 149 switch strings.ToLower(field) { 150 case "noreturn": 151 result |= llvmAttribute(llvm.NoReturnAttribute) 152 case "nounwind": 153 result |= llvmAttribute(llvm.NoUnwindAttribute) 154 case "noinline": 155 result |= llvmAttribute(llvm.NoInlineAttribute) 156 case "alwaysinline": 157 result |= llvmAttribute(llvm.AlwaysInlineAttribute) 158 } 159 } 160 return result 161 } 162 163 type llvmAttribute llvm.Attribute 164 165 func (a llvmAttribute) Apply(v llvm.Value) { 166 if !v.IsAFunction().IsNil() { 167 v.AddFunctionAttr(llvm.Attribute(a)) 168 } else { 169 v.AddAttribute(llvm.Attribute(a)) 170 } 171 } 172 173 type tlsAttribute struct{} 174 175 func (tlsAttribute) Apply(v llvm.Value) { 176 v.SetThreadLocal(true) 177 }