purego_target.go raw

   1  //go:build purego
   2  
   3  package llvm
   4  
   5  import (
   6  	"errors"
   7  	"fmt"
   8  	"os"
   9  	"runtime"
  10  	"unsafe"
  11  
  12  	"github.com/ebitengine/purego"
  13  )
  14  
  15  type (
  16  	TargetData      struct{ C uintptr }
  17  	Target          struct{ C uintptr }
  18  	TargetMachine   struct{ C uintptr }
  19  	ByteOrdering    int
  20  	RelocMode       int
  21  	CodeGenOptLevel int
  22  	CodeGenFileType int
  23  	CodeModel       int
  24  )
  25  
  26  func (td TargetData) IsNil() bool    { return td.C == 0 }
  27  func (t Target) IsNil() bool         { return t.C == 0 }
  28  func (tm TargetMachine) IsNil() bool { return tm.C == 0 }
  29  
  30  const (
  31  	BigEndian    ByteOrdering = 0
  32  	LittleEndian ByteOrdering = 1
  33  )
  34  
  35  const (
  36  	RelocDefault      RelocMode = 0
  37  	RelocStatic       RelocMode = 1
  38  	RelocPIC          RelocMode = 2
  39  	RelocDynamicNoPic RelocMode = 3
  40  )
  41  
  42  const (
  43  	CodeGenLevelNone       CodeGenOptLevel = 0
  44  	CodeGenLevelLess       CodeGenOptLevel = 1
  45  	CodeGenLevelDefault    CodeGenOptLevel = 2
  46  	CodeGenLevelAggressive CodeGenOptLevel = 3
  47  )
  48  
  49  const (
  50  	CodeModelDefault    CodeModel = 0
  51  	CodeModelJITDefault CodeModel = 1
  52  	CodeModelTiny       CodeModel = 2
  53  	CodeModelSmall      CodeModel = 3
  54  	CodeModelKernel     CodeModel = 4
  55  	CodeModelMedium     CodeModel = 5
  56  	CodeModelLarge      CodeModel = 6
  57  )
  58  
  59  const (
  60  	AssemblyFile CodeGenFileType = 0
  61  	ObjectFile   CodeGenFileType = 1
  62  )
  63  
  64  var (
  65  	// Per-target init (inline functions in C headers aren't exported)
  66  	targetInits []uintptr
  67  
  68  	// Target lookup
  69  	symGetTargetFromTriple   uintptr
  70  	symGetFirstTarget        uintptr
  71  	symGetNextTarget         uintptr
  72  	symGetTargetName         uintptr
  73  	symGetTargetDescription  uintptr
  74  	symGetDefaultTargetTriple uintptr
  75  
  76  	// TargetMachine
  77  	symCreateTargetMachine       uintptr
  78  	symCreateTargetDataLayout    uintptr
  79  	symGetTargetMachineTriple    uintptr
  80  	symTargetMachineEmitToMemBuf uintptr
  81  	symAddAnalysisPasses         uintptr
  82  	symDisposeTargetMachine      uintptr
  83  
  84  	// TargetData
  85  	symCreateTargetData          uintptr
  86  	symCopyStringRepOfTargetData uintptr
  87  	symByteOrder                 uintptr
  88  	symPointerSize               uintptr
  89  	symIntPtrType                uintptr
  90  	symSizeOfTypeInBits          uintptr
  91  	symStoreSizeOfType           uintptr
  92  	symABISizeOfType             uintptr
  93  	symABIAlignOfType            uintptr
  94  	symCallFrameAlignOfType      uintptr
  95  	symPrefAlignOfType           uintptr
  96  	symPrefAlignOfGlobal         uintptr
  97  	symElementAtOffset           uintptr
  98  	symOffsetOfElement           uintptr
  99  	symDisposeTargetData         uintptr
 100  
 101  	// MemoryBuffer
 102  	symGetBufferStart        uintptr
 103  	symGetBufferSize         uintptr
 104  	symDisposeMemoryBuffer   uintptr
 105  	symCreateMemBufWithRange uintptr
 106  
 107  	// Bitcode
 108  	symWriteBitcodeToFD         uintptr
 109  	symWriteBitcodeToMemBuf     uintptr
 110  	symCreateMemBufWithFile     uintptr
 111  	symParseBitcodeInCtx2       uintptr
 112  
 113  	// IR Reader
 114  	symParseIRInContext uintptr
 115  
 116  	// Linker
 117  	symLinkModules2 uintptr
 118  
 119  	// PassManager
 120  	symCreatePassManager  uintptr
 121  	symDisposePassManager uintptr
 122  	symRunPassManager     uintptr
 123  
 124  	// Thin LTO (glue)
 125  	symGoWriteThinLTOBitcode uintptr
 126  )
 127  
 128  func registerTarget() {
 129  	// LLVMInitializeAll* are inline C functions, not exported symbols.
 130  	// We call per-target init functions directly.
 131  	targets := []string{"X86", "AArch64", "ARM", "WebAssembly", "RISCV", "Mips", "AMDGPU"}
 132  	suffixes := []string{"TargetInfo", "Target", "TargetMC", "AsmParser", "AsmPrinter"}
 133  	for _, t := range targets {
 134  		for _, s := range suffixes {
 135  			sym := trySym(libLLVM, "LLVMInitialize"+t+s)
 136  			if sym != 0 {
 137  				targetInits = append(targetInits, sym)
 138  			}
 139  		}
 140  	}
 141  
 142  	symGetTargetFromTriple = mustSym(libLLVM, "LLVMGetTargetFromTriple")
 143  	symGetFirstTarget = mustSym(libLLVM, "LLVMGetFirstTarget")
 144  	symGetNextTarget = mustSym(libLLVM, "LLVMGetNextTarget")
 145  	symGetTargetName = mustSym(libLLVM, "LLVMGetTargetName")
 146  	symGetTargetDescription = mustSym(libLLVM, "LLVMGetTargetDescription")
 147  	symGetDefaultTargetTriple = mustSym(libLLVM, "LLVMGetDefaultTargetTriple")
 148  
 149  	symCreateTargetMachine = mustSym(libLLVM, "LLVMCreateTargetMachine")
 150  	symCreateTargetDataLayout = mustSym(libLLVM, "LLVMCreateTargetDataLayout")
 151  	symGetTargetMachineTriple = mustSym(libLLVM, "LLVMGetTargetMachineTriple")
 152  	symTargetMachineEmitToMemBuf = mustSym(libLLVM, "LLVMTargetMachineEmitToMemoryBuffer")
 153  	symAddAnalysisPasses = mustSym(libLLVM, "LLVMAddAnalysisPasses")
 154  	symDisposeTargetMachine = mustSym(libLLVM, "LLVMDisposeTargetMachine")
 155  
 156  	symCreateTargetData = mustSym(libLLVM, "LLVMCreateTargetData")
 157  	symCopyStringRepOfTargetData = mustSym(libLLVM, "LLVMCopyStringRepOfTargetData")
 158  	symByteOrder = mustSym(libLLVM, "LLVMByteOrder")
 159  	symPointerSize = mustSym(libLLVM, "LLVMPointerSize")
 160  	symIntPtrType = mustSym(libLLVM, "LLVMIntPtrType")
 161  	symSizeOfTypeInBits = mustSym(libLLVM, "LLVMSizeOfTypeInBits")
 162  	symStoreSizeOfType = mustSym(libLLVM, "LLVMStoreSizeOfType")
 163  	symABISizeOfType = mustSym(libLLVM, "LLVMABISizeOfType")
 164  	symABIAlignOfType = mustSym(libLLVM, "LLVMABIAlignmentOfType")
 165  	symCallFrameAlignOfType = mustSym(libLLVM, "LLVMCallFrameAlignmentOfType")
 166  	symPrefAlignOfType = mustSym(libLLVM, "LLVMPreferredAlignmentOfType")
 167  	symPrefAlignOfGlobal = mustSym(libLLVM, "LLVMPreferredAlignmentOfGlobal")
 168  	symElementAtOffset = mustSym(libLLVM, "LLVMElementAtOffset")
 169  	symOffsetOfElement = mustSym(libLLVM, "LLVMOffsetOfElement")
 170  	symDisposeTargetData = mustSym(libLLVM, "LLVMDisposeTargetData")
 171  
 172  	symGetBufferStart = mustSym(libLLVM, "LLVMGetBufferStart")
 173  	symGetBufferSize = mustSym(libLLVM, "LLVMGetBufferSize")
 174  	symDisposeMemoryBuffer = mustSym(libLLVM, "LLVMDisposeMemoryBuffer")
 175  	symCreateMemBufWithRange = mustSym(libLLVM, "LLVMCreateMemoryBufferWithMemoryRangeCopy")
 176  
 177  	symWriteBitcodeToFD = mustSym(libLLVM, "LLVMWriteBitcodeToFD")
 178  	symWriteBitcodeToMemBuf = mustSym(libLLVM, "LLVMWriteBitcodeToMemoryBuffer")
 179  	symCreateMemBufWithFile = mustSym(libLLVM, "LLVMCreateMemoryBufferWithContentsOfFile")
 180  	symParseBitcodeInCtx2 = mustSym(libLLVM, "LLVMParseBitcodeInContext2")
 181  
 182  	symParseIRInContext = mustSym(libLLVM, "LLVMParseIRInContext")
 183  
 184  	symLinkModules2 = mustSym(libLLVM, "LLVMLinkModules2")
 185  
 186  	symCreatePassManager = mustSym(libLLVM, "LLVMCreatePassManager")
 187  	symDisposePassManager = mustSym(libLLVM, "LLVMDisposePassManager")
 188  	symRunPassManager = mustSym(libLLVM, "LLVMRunPassManager")
 189  
 190  	if libGlue != 0 {
 191  		symGoWriteThinLTOBitcode = trySym(libGlue, "LLVMGoWriteThinLTOBitcodeToMemoryBuffer")
 192  	}
 193  }
 194  
 195  // ---- Target initialization ----
 196  
 197  var targetsInitialized bool
 198  
 199  func InitializeAllTargets() {
 200  	if targetsInitialized {
 201  		return
 202  	}
 203  	targetsInitialized = true
 204  	for _, sym := range targetInits {
 205  		purego.SyscallN(sym)
 206  	}
 207  }
 208  
 209  func InitializeAllTargetInfos() { InitializeAllTargets() }
 210  func InitializeAllTargetMCs()   { InitializeAllTargets() }
 211  func InitializeAllAsmParsers()  { InitializeAllTargets() }
 212  func InitializeAllAsmPrinters() { InitializeAllTargets() }
 213  
 214  // ---- Target lookup ----
 215  
 216  func GetTargetFromTriple(triple string) (Target, error) {
 217  	ctriple := cString(triple)
 218  	var target uintptr
 219  	var errMsg uintptr
 220  	r, _, _ := purego.SyscallN(symGetTargetFromTriple, ctriple, uintptr(unsafe.Pointer(&target)), uintptr(unsafe.Pointer(&errMsg)))
 221  	runtime.KeepAlive(triple)
 222  	if r != 0 {
 223  		s := goString(errMsg)
 224  		purego.SyscallN(symDisposeMessage, errMsg)
 225  		return Target{}, fmt.Errorf("%s", s)
 226  	}
 227  	return Target{target}, nil
 228  }
 229  
 230  func FirstTarget() Target {
 231  	r, _, _ := purego.SyscallN(symGetFirstTarget)
 232  	return Target{r}
 233  }
 234  
 235  func (t Target) NextTarget() Target {
 236  	r, _, _ := purego.SyscallN(symGetNextTarget, t.C)
 237  	return Target{r}
 238  }
 239  
 240  func (t Target) Name() string {
 241  	r, _, _ := purego.SyscallN(symGetTargetName, t.C)
 242  	return goString(r)
 243  }
 244  
 245  func (t Target) Description() string {
 246  	r, _, _ := purego.SyscallN(symGetTargetDescription, t.C)
 247  	return goString(r)
 248  }
 249  
 250  func DefaultTargetTriple() string {
 251  	r, _, _ := purego.SyscallN(symGetDefaultTargetTriple)
 252  	s := goString(r)
 253  	purego.SyscallN(symDisposeMessage, r)
 254  	return s
 255  }
 256  
 257  // ---- TargetMachine ----
 258  
 259  func (t Target) CreateTargetMachine(triple, cpu, features string, level CodeGenOptLevel, reloc RelocMode, codeModel CodeModel) TargetMachine {
 260  	ctriple := cString(triple)
 261  	ccpu := cString(cpu)
 262  	cfeatures := cString(features)
 263  	r, _, _ := purego.SyscallN(symCreateTargetMachine, t.C, ctriple, ccpu, cfeatures, uintptr(level), uintptr(reloc), uintptr(codeModel))
 264  	runtime.KeepAlive(triple)
 265  	runtime.KeepAlive(cpu)
 266  	runtime.KeepAlive(features)
 267  	return TargetMachine{r}
 268  }
 269  
 270  func (tm TargetMachine) CreateTargetData() TargetData {
 271  	r, _, _ := purego.SyscallN(symCreateTargetDataLayout, tm.C)
 272  	return TargetData{r}
 273  }
 274  
 275  func (tm TargetMachine) Triple() string {
 276  	r, _, _ := purego.SyscallN(symGetTargetMachineTriple, tm.C)
 277  	s := goString(r)
 278  	purego.SyscallN(symDisposeMessage, r)
 279  	return s
 280  }
 281  
 282  func (tm TargetMachine) EmitToMemoryBuffer(m Module, ft CodeGenFileType) (MemoryBuffer, error) {
 283  	var errMsg uintptr
 284  	var mb uintptr
 285  	r, _, _ := purego.SyscallN(symTargetMachineEmitToMemBuf, tm.C, m.C, uintptr(ft), uintptr(unsafe.Pointer(&errMsg)), uintptr(unsafe.Pointer(&mb)))
 286  	if r != 0 {
 287  		s := goString(errMsg)
 288  		purego.SyscallN(symDisposeMessage, errMsg)
 289  		return MemoryBuffer{}, fmt.Errorf("%s", s)
 290  	}
 291  	return MemoryBuffer{mb}, nil
 292  }
 293  
 294  func (tm TargetMachine) AddAnalysisPasses(pm PassManager) {
 295  	purego.SyscallN(symAddAnalysisPasses, tm.C, pm.C)
 296  }
 297  
 298  func (tm TargetMachine) Dispose() {
 299  	purego.SyscallN(symDisposeTargetMachine, tm.C)
 300  }
 301  
 302  // ---- TargetData ----
 303  
 304  func NewTargetData(rep string) TargetData {
 305  	crep := cString(rep)
 306  	r, _, _ := purego.SyscallN(symCreateTargetData, crep)
 307  	runtime.KeepAlive(rep)
 308  	return TargetData{r}
 309  }
 310  
 311  func (td TargetData) String() string {
 312  	r, _, _ := purego.SyscallN(symCopyStringRepOfTargetData, td.C)
 313  	s := goString(r)
 314  	purego.SyscallN(symDisposeMessage, r)
 315  	return s
 316  }
 317  
 318  func (td TargetData) ByteOrder() ByteOrdering {
 319  	r, _, _ := purego.SyscallN(symByteOrder, td.C)
 320  	return ByteOrdering(r)
 321  }
 322  
 323  func (td TargetData) PointerSize() int {
 324  	r, _, _ := purego.SyscallN(symPointerSize, td.C)
 325  	return int(r)
 326  }
 327  
 328  func (td TargetData) IntPtrType() Type {
 329  	r, _, _ := purego.SyscallN(symIntPtrType, td.C)
 330  	return Type{r}
 331  }
 332  
 333  func (td TargetData) TypeSizeInBits(t Type) uint64 {
 334  	r, _, _ := purego.SyscallN(symSizeOfTypeInBits, td.C, t.C)
 335  	return uint64(r)
 336  }
 337  
 338  func (td TargetData) TypeStoreSize(t Type) uint64 {
 339  	r, _, _ := purego.SyscallN(symStoreSizeOfType, td.C, t.C)
 340  	return uint64(r)
 341  }
 342  
 343  func (td TargetData) TypeAllocSize(t Type) uint64 {
 344  	r, _, _ := purego.SyscallN(symABISizeOfType, td.C, t.C)
 345  	return uint64(r)
 346  }
 347  
 348  func (td TargetData) ABITypeAlignment(t Type) int {
 349  	r, _, _ := purego.SyscallN(symABIAlignOfType, td.C, t.C)
 350  	return int(r)
 351  }
 352  
 353  func (td TargetData) CallFrameTypeAlignment(t Type) int {
 354  	r, _, _ := purego.SyscallN(symCallFrameAlignOfType, td.C, t.C)
 355  	return int(r)
 356  }
 357  
 358  func (td TargetData) PrefTypeAlignment(t Type) int {
 359  	r, _, _ := purego.SyscallN(symPrefAlignOfType, td.C, t.C)
 360  	return int(r)
 361  }
 362  
 363  func (td TargetData) PreferredAlignment(g Value) int {
 364  	r, _, _ := purego.SyscallN(symPrefAlignOfGlobal, td.C, g.C)
 365  	return int(r)
 366  }
 367  
 368  func (td TargetData) ElementContainingOffset(t Type, offset uint64) int {
 369  	r, _, _ := purego.SyscallN(symElementAtOffset, td.C, t.C, uintptr(offset))
 370  	return int(r)
 371  }
 372  
 373  func (td TargetData) ElementOffset(t Type, element int) uint64 {
 374  	r, _, _ := purego.SyscallN(symOffsetOfElement, td.C, t.C, uintptr(element))
 375  	return uint64(r)
 376  }
 377  
 378  func (td TargetData) Dispose() {
 379  	purego.SyscallN(symDisposeTargetData, td.C)
 380  }
 381  
 382  // ---- MemoryBuffer ----
 383  
 384  func (mb MemoryBuffer) Bytes() []byte {
 385  	start, _, _ := purego.SyscallN(symGetBufferStart, mb.C)
 386  	size, _, _ := purego.SyscallN(symGetBufferSize, mb.C)
 387  	if start == 0 || size == 0 {
 388  		return nil
 389  	}
 390  	return (*[1 << 30]byte)(unsafe.Pointer(start))[:int(size):int(size)]
 391  }
 392  
 393  func (mb MemoryBuffer) Dispose() {
 394  	purego.SyscallN(symDisposeMemoryBuffer, mb.C)
 395  }
 396  
 397  func NewMemoryBufferFromBytes(data []byte, name string) MemoryBuffer {
 398  	cname := cString(name)
 399  	r, _, _ := purego.SyscallN(symCreateMemBufWithRange,
 400  		uintptr(unsafe.Pointer(&data[0])), uintptr(len(data)), cname, 1)
 401  	runtime.KeepAlive(data)
 402  	runtime.KeepAlive(name)
 403  	return MemoryBuffer{C: r}
 404  }
 405  
 406  func (c Context) ParseIR(buf MemoryBuffer) (Module, error) {
 407  	var mod uintptr
 408  	var errMsg uintptr
 409  	r, _, _ := purego.SyscallN(symParseIRInContext, c.C, buf.C,
 410  		uintptr(unsafe.Pointer(&mod)), uintptr(unsafe.Pointer(&errMsg)))
 411  	if r != 0 {
 412  		s := goString(errMsg)
 413  		purego.SyscallN(symDisposeMessage, errMsg)
 414  		return Module{}, fmt.Errorf("ParseIR: %s", s)
 415  	}
 416  	return Module{mod}, nil
 417  }
 418  
 419  // ---- Bitcode ----
 420  
 421  var writeBitcodeToFileErr = errors.New("Failed to write bitcode to file")
 422  
 423  func WriteBitcodeToFile(m Module, file *os.File) error {
 424  	r, _, _ := purego.SyscallN(symWriteBitcodeToFD, m.C, uintptr(file.Fd()), 0, 0)
 425  	if r != 0 {
 426  		return writeBitcodeToFileErr
 427  	}
 428  	return nil
 429  }
 430  
 431  func WriteBitcodeToMemoryBuffer(m Module) MemoryBuffer {
 432  	r, _, _ := purego.SyscallN(symWriteBitcodeToMemBuf, m.C)
 433  	return MemoryBuffer{C: r}
 434  }
 435  
 436  func WriteThinLTOBitcodeToMemoryBuffer(m Module) MemoryBuffer {
 437  	if symGoWriteThinLTOBitcode == 0 {
 438  		return WriteBitcodeToMemoryBuffer(m)
 439  	}
 440  	r, _, _ := purego.SyscallN(symGoWriteThinLTOBitcode, m.C)
 441  	return MemoryBuffer{C: r}
 442  }
 443  
 444  func (c Context) ParseBitcodeFile(name string) (Module, error) {
 445  	cname := cString(name)
 446  	var membuf uintptr
 447  	var errMsg uintptr
 448  	r, _, _ := purego.SyscallN(symCreateMemBufWithFile, cname, uintptr(unsafe.Pointer(&membuf)), uintptr(unsafe.Pointer(&errMsg)))
 449  	runtime.KeepAlive(name)
 450  	if r != 0 {
 451  		s := goString(errMsg)
 452  		purego.SyscallN(symDisposeMessage, errMsg)
 453  		return Module{}, fmt.Errorf("read %s: %s", name, s)
 454  	}
 455  
 456  	var mod uintptr
 457  	r, _, _ = purego.SyscallN(symParseBitcodeInCtx2, c.C, membuf, uintptr(unsafe.Pointer(&mod)))
 458  	if r != 0 {
 459  		return Module{}, fmt.Errorf("parse bitcode %s failed", name)
 460  	}
 461  	return Module{mod}, nil
 462  }
 463  
 464  // ---- Module linking ----
 465  
 466  func LinkModules(dest, src Module) error {
 467  	r, _, _ := purego.SyscallN(symLinkModules2, dest.C, src.C)
 468  	if r != 0 {
 469  		return fmt.Errorf("link modules failed")
 470  	}
 471  	return nil
 472  }
 473  
 474  // ---- PassManager ----
 475  
 476  func NewPassManager() PassManager {
 477  	r, _, _ := purego.SyscallN(symCreatePassManager)
 478  	return PassManager{r}
 479  }
 480  
 481  func (pm PassManager) Dispose() {
 482  	purego.SyscallN(symDisposePassManager, pm.C)
 483  }
 484  
 485  func (pm PassManager) Run(m Module) bool {
 486  	r, _, _ := purego.SyscallN(symRunPassManager, pm.C, m.C)
 487  	return r != 0
 488  }
 489