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  }