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