forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			147 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
//===- attribute.go - attribute processor ---------------------------------===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
//
 | 
						|
// This file processes llgo and //extern attributes.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
package irgen
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"go/ast"
 | 
						|
	"llvm.org/llvm/bindings/go/llvm"
 | 
						|
	"strings"
 | 
						|
)
 | 
						|
 | 
						|
const AttributeCommentPrefix = "#llgo "
 | 
						|
 | 
						|
// Attribute represents an attribute associated with a
 | 
						|
// global variable or function.
 | 
						|
type Attribute interface {
 | 
						|
	Apply(llvm.Value)
 | 
						|
}
 | 
						|
 | 
						|
// parseAttribute parses zero or more #llgo comment attributes associated with
 | 
						|
// a global variable or function. The comment group provided will be processed
 | 
						|
// one line at a time using parseAttribute.
 | 
						|
func parseAttributes(doc *ast.CommentGroup) []Attribute {
 | 
						|
	var attributes []Attribute
 | 
						|
	if doc == nil {
 | 
						|
		return attributes
 | 
						|
	}
 | 
						|
	for _, comment := range doc.List {
 | 
						|
		if strings.HasPrefix(comment.Text, "//extern ") {
 | 
						|
			nameattr := nameAttribute(strings.TrimSpace(comment.Text[9:]))
 | 
						|
			attributes = append(attributes, nameattr)
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		text := comment.Text[2:]
 | 
						|
		if strings.HasPrefix(comment.Text, "/*") {
 | 
						|
			text = text[:len(text)-2]
 | 
						|
		}
 | 
						|
		attr := parseAttribute(strings.TrimSpace(text))
 | 
						|
		if attr != nil {
 | 
						|
			attributes = append(attributes, attr)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return attributes
 | 
						|
}
 | 
						|
 | 
						|
// parseAttribute parses a single #llgo comment attribute associated with
 | 
						|
// a global variable or function. The string provided will be parsed
 | 
						|
// if it begins with AttributeCommentPrefix, otherwise nil is returned.
 | 
						|
func parseAttribute(line string) Attribute {
 | 
						|
	if !strings.HasPrefix(line, AttributeCommentPrefix) {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	line = strings.TrimSpace(line[len(AttributeCommentPrefix):])
 | 
						|
	colon := strings.IndexRune(line, ':')
 | 
						|
	var key, value string
 | 
						|
	if colon == -1 {
 | 
						|
		key = line
 | 
						|
	} else {
 | 
						|
		key, value = line[:colon], line[colon+1:]
 | 
						|
	}
 | 
						|
	switch key {
 | 
						|
	case "linkage":
 | 
						|
		return parseLinkageAttribute(value)
 | 
						|
	case "name":
 | 
						|
		return nameAttribute(strings.TrimSpace(value))
 | 
						|
	case "thread_local":
 | 
						|
		return tlsAttribute{}
 | 
						|
	default:
 | 
						|
		// FIXME decide what to do here. return error? log warning?
 | 
						|
		panic("unknown attribute key: " + key)
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
type linkageAttribute llvm.Linkage
 | 
						|
 | 
						|
func (a linkageAttribute) Apply(v llvm.Value) {
 | 
						|
	v.SetLinkage(llvm.Linkage(a))
 | 
						|
}
 | 
						|
 | 
						|
func parseLinkageAttribute(value string) linkageAttribute {
 | 
						|
	var result linkageAttribute
 | 
						|
	value = strings.Replace(value, ",", " ", -1)
 | 
						|
	for _, field := range strings.Fields(value) {
 | 
						|
		switch strings.ToLower(field) {
 | 
						|
		case "private":
 | 
						|
			result |= linkageAttribute(llvm.PrivateLinkage)
 | 
						|
		case "internal":
 | 
						|
			result |= linkageAttribute(llvm.InternalLinkage)
 | 
						|
		case "available_externally":
 | 
						|
			result |= linkageAttribute(llvm.AvailableExternallyLinkage)
 | 
						|
		case "linkonce":
 | 
						|
			result |= linkageAttribute(llvm.LinkOnceAnyLinkage)
 | 
						|
		case "common":
 | 
						|
			result |= linkageAttribute(llvm.CommonLinkage)
 | 
						|
		case "weak":
 | 
						|
			result |= linkageAttribute(llvm.WeakAnyLinkage)
 | 
						|
		case "appending":
 | 
						|
			result |= linkageAttribute(llvm.AppendingLinkage)
 | 
						|
		case "extern_weak":
 | 
						|
			result |= linkageAttribute(llvm.ExternalWeakLinkage)
 | 
						|
		case "linkonce_odr":
 | 
						|
			result |= linkageAttribute(llvm.LinkOnceODRLinkage)
 | 
						|
		case "weak_odr":
 | 
						|
			result |= linkageAttribute(llvm.WeakODRLinkage)
 | 
						|
		case "external":
 | 
						|
			result |= linkageAttribute(llvm.ExternalLinkage)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return result
 | 
						|
}
 | 
						|
 | 
						|
type nameAttribute string
 | 
						|
 | 
						|
func (a nameAttribute) Apply(v llvm.Value) {
 | 
						|
	if !v.IsAFunction().IsNil() {
 | 
						|
		name := string(a)
 | 
						|
		curr := v.GlobalParent().NamedFunction(name)
 | 
						|
		if !curr.IsNil() && curr != v {
 | 
						|
			if curr.BasicBlocksCount() != 0 {
 | 
						|
				panic(fmt.Errorf("Want to take the name %s from a function that has a body!", name))
 | 
						|
			}
 | 
						|
			curr.SetName(name + "_llgo_replaced")
 | 
						|
			curr.ReplaceAllUsesWith(llvm.ConstBitCast(v, curr.Type()))
 | 
						|
		}
 | 
						|
		v.SetName(name)
 | 
						|
	} else {
 | 
						|
		v.SetName(string(a))
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type tlsAttribute struct{}
 | 
						|
 | 
						|
func (tlsAttribute) Apply(v llvm.Value) {
 | 
						|
	v.SetThreadLocal(true)
 | 
						|
}
 |