target.go raw

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