
This commit adds support for software vectoring in the PLIC interrupt. The interrupt table is created by the compiler, which leads to very compact code while retaining the flexibility that the interrupt API provides.
100 строки
3 КиБ
Go
100 строки
3 КиБ
Go
package transform
|
|
|
|
import (
|
|
"reflect"
|
|
|
|
"tinygo.org/x/go-llvm"
|
|
)
|
|
|
|
// Return a list of values (actually, instructions) where this value is used as
|
|
// an operand.
|
|
func getUses(value llvm.Value) []llvm.Value {
|
|
if value.IsNil() {
|
|
return nil
|
|
}
|
|
var uses []llvm.Value
|
|
use := value.FirstUse()
|
|
for !use.IsNil() {
|
|
uses = append(uses, use.User())
|
|
use = use.NextUse()
|
|
}
|
|
return uses
|
|
}
|
|
|
|
// hasUses returns whether the given value has any uses. It is equivalent to
|
|
// getUses(value) != nil but faster.
|
|
func hasUses(value llvm.Value) bool {
|
|
if value.IsNil() {
|
|
return false
|
|
}
|
|
return !value.FirstUse().IsNil()
|
|
}
|
|
|
|
// makeGlobalArray creates a new LLVM global with the given name and integers as
|
|
// contents, and returns the global.
|
|
// Note that it is left with the default linkage etc., you should set
|
|
// linkage/constant/etc properties yourself.
|
|
func makeGlobalArray(mod llvm.Module, bufItf interface{}, name string, elementType llvm.Type) llvm.Value {
|
|
buf := reflect.ValueOf(bufItf)
|
|
globalType := llvm.ArrayType(elementType, buf.Len())
|
|
global := llvm.AddGlobal(mod, globalType, name)
|
|
value := llvm.Undef(globalType)
|
|
for i := 0; i < buf.Len(); i++ {
|
|
ch := buf.Index(i).Uint()
|
|
value = llvm.ConstInsertValue(value, llvm.ConstInt(elementType, ch, false), []uint32{uint32(i)})
|
|
}
|
|
global.SetInitializer(value)
|
|
return global
|
|
}
|
|
|
|
// getGlobalBytes returns the slice contained in the array of the provided
|
|
// global. It can recover the bytes originally created using makeGlobalArray, if
|
|
// makeGlobalArray was given a byte slice.
|
|
func getGlobalBytes(global llvm.Value) []byte {
|
|
value := global.Initializer()
|
|
buf := make([]byte, value.Type().ArrayLength())
|
|
for i := range buf {
|
|
buf[i] = byte(llvm.ConstExtractValue(value, []uint32{uint32(i)}).ZExtValue())
|
|
}
|
|
return buf
|
|
}
|
|
|
|
// replaceGlobalByteWithArray replaces a global integer type in the module with
|
|
// an integer array, using a GEP to make the types match. It is a convenience
|
|
// function used for creating reflection sidetables, for example.
|
|
func replaceGlobalIntWithArray(mod llvm.Module, name string, buf interface{}) llvm.Value {
|
|
oldGlobal := mod.NamedGlobal(name)
|
|
global := makeGlobalArray(mod, buf, name+".tmp", oldGlobal.Type().ElementType())
|
|
gep := llvm.ConstGEP(global, []llvm.Value{
|
|
llvm.ConstInt(mod.Context().Int32Type(), 0, false),
|
|
llvm.ConstInt(mod.Context().Int32Type(), 0, false),
|
|
})
|
|
oldGlobal.ReplaceAllUsesWith(gep)
|
|
oldGlobal.EraseFromParentAsGlobal()
|
|
global.SetName(name)
|
|
return global
|
|
}
|
|
|
|
// typeHasPointers returns whether this type is a pointer or contains pointers.
|
|
// If the type is an aggregate type, it will check whether there is a pointer
|
|
// inside.
|
|
func typeHasPointers(t llvm.Type) bool {
|
|
switch t.TypeKind() {
|
|
case llvm.PointerTypeKind:
|
|
return true
|
|
case llvm.StructTypeKind:
|
|
for _, subType := range t.StructElementTypes() {
|
|
if typeHasPointers(subType) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
case llvm.ArrayTypeKind:
|
|
if typeHasPointers(t.ElementType()) {
|
|
return true
|
|
}
|
|
return false
|
|
default:
|
|
return false
|
|
}
|
|
}
|