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