blob: 82f264e26e74b9297b8d9e8e9f7adcef76fefa06 [file] [log] [blame]
Peter Collingbournead9841e2014-11-27 00:06:42 +00001//===- 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
14package irgen
15
16import (
17 "fmt"
18 "go/ast"
19 "llvm.org/llvm/bindings/go/llvm"
20 "strings"
21)
22
23const AttributeCommentPrefix = "#llgo "
24
25// Attribute represents an attribute associated with a
26// global variable or function.
27type 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.
34func 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.
60func 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))
Peter Collingbournead9841e2014-11-27 00:06:42 +000077 case "thread_local":
78 return tlsAttribute{}
79 default:
80 // FIXME decide what to do here. return error? log warning?
81 panic("unknown attribute key: " + key)
82 }
83 return nil
84}
85
86type linkageAttribute llvm.Linkage
87
88func (a linkageAttribute) Apply(v llvm.Value) {
89 v.SetLinkage(llvm.Linkage(a))
90}
91
92func parseLinkageAttribute(value string) linkageAttribute {
93 var result linkageAttribute
94 value = strings.Replace(value, ",", " ", -1)
95 for _, field := range strings.Fields(value) {
96 switch strings.ToLower(field) {
97 case "private":
98 result |= linkageAttribute(llvm.PrivateLinkage)
99 case "internal":
100 result |= linkageAttribute(llvm.InternalLinkage)
101 case "available_externally":
102 result |= linkageAttribute(llvm.AvailableExternallyLinkage)
103 case "linkonce":
104 result |= linkageAttribute(llvm.LinkOnceAnyLinkage)
105 case "common":
106 result |= linkageAttribute(llvm.CommonLinkage)
107 case "weak":
108 result |= linkageAttribute(llvm.WeakAnyLinkage)
109 case "appending":
110 result |= linkageAttribute(llvm.AppendingLinkage)
111 case "extern_weak":
112 result |= linkageAttribute(llvm.ExternalWeakLinkage)
113 case "linkonce_odr":
114 result |= linkageAttribute(llvm.LinkOnceODRLinkage)
115 case "weak_odr":
116 result |= linkageAttribute(llvm.WeakODRLinkage)
117 case "external":
118 result |= linkageAttribute(llvm.ExternalLinkage)
119 }
120 }
121 return result
122}
123
124type nameAttribute string
125
126func (a nameAttribute) Apply(v llvm.Value) {
127 if !v.IsAFunction().IsNil() {
128 name := string(a)
129 curr := v.GlobalParent().NamedFunction(name)
130 if !curr.IsNil() && curr != v {
131 if curr.BasicBlocksCount() != 0 {
132 panic(fmt.Errorf("Want to take the name %s from a function that has a body!", name))
133 }
134 curr.SetName(name + "_llgo_replaced")
135 curr.ReplaceAllUsesWith(llvm.ConstBitCast(v, curr.Type()))
136 }
137 v.SetName(name)
138 } else {
139 v.SetName(string(a))
140 }
141}
142
Peter Collingbournead9841e2014-11-27 00:06:42 +0000143type tlsAttribute struct{}
144
145func (tlsAttribute) Apply(v llvm.Value) {
146 v.SetThreadLocal(true)
147}