radeon/llvm: Factor elf parsing code out into its own function
[mesa.git] / src / gallium / drivers / radeon / radeon_llvm_emit.c
1 /*
2 * Copyright 2011 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors: Tom Stellard <thomas.stellard@amd.com>
24 *
25 */
26 #include "radeon_llvm_emit.h"
27 #include "radeon_elf_util.h"
28 #include "util/u_memory.h"
29
30 #include <llvm-c/Target.h>
31 #include <llvm-c/TargetMachine.h>
32
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36
37 #define CPU_STRING_LEN 30
38 #define FS_STRING_LEN 30
39 #define TRIPLE_STRING_LEN 7
40
41 /**
42 * Set the shader type we want to compile
43 *
44 * @param type shader type to set
45 */
46 void radeon_llvm_shader_type(LLVMValueRef F, unsigned type)
47 {
48 char Str[2];
49 sprintf(Str, "%1d", type);
50
51 LLVMAddTargetDependentFunctionAttr(F, "ShaderType", Str);
52 }
53
54 static void init_r600_target() {
55 static unsigned initialized = 0;
56 if (!initialized) {
57 LLVMInitializeR600TargetInfo();
58 LLVMInitializeR600Target();
59 LLVMInitializeR600TargetMC();
60 LLVMInitializeR600AsmPrinter();
61 initialized = 1;
62 }
63 }
64
65 static LLVMTargetRef get_r600_target() {
66 LLVMTargetRef target = NULL;
67
68 for (target = LLVMGetFirstTarget(); target;
69 target = LLVMGetNextTarget(target)) {
70 if (!strncmp(LLVMGetTargetName(target), "r600", 4)) {
71 break;
72 }
73 }
74
75 if (!target) {
76 fprintf(stderr, "Can't find target r600\n");
77 return NULL;
78 }
79 return target;
80 }
81
82 /**
83 * Compile an LLVM module to machine code.
84 *
85 * @returns 0 for success, 1 for failure
86 */
87 unsigned radeon_llvm_compile(LLVMModuleRef M, struct radeon_shader_binary *binary,
88 const char * gpu_family, unsigned dump) {
89
90 LLVMTargetRef target;
91 LLVMTargetMachineRef tm;
92 char cpu[CPU_STRING_LEN];
93 char fs[FS_STRING_LEN];
94 char *err;
95 LLVMMemoryBufferRef out_buffer;
96 unsigned buffer_size;
97 const char *buffer_data;
98 char triple[TRIPLE_STRING_LEN];
99 LLVMBool r;
100
101 init_r600_target();
102
103 target = get_r600_target();
104 if (!target) {
105 return 1;
106 }
107
108 strncpy(cpu, gpu_family, CPU_STRING_LEN);
109 memset(fs, 0, sizeof(fs));
110 if (dump) {
111 LLVMDumpModule(M);
112 strncpy(fs, "+DumpCode", FS_STRING_LEN);
113 }
114 strncpy(triple, "r600--", TRIPLE_STRING_LEN);
115 tm = LLVMCreateTargetMachine(target, triple, cpu, fs,
116 LLVMCodeGenLevelDefault, LLVMRelocDefault,
117 LLVMCodeModelDefault);
118
119 r = LLVMTargetMachineEmitToMemoryBuffer(tm, M, LLVMObjectFile, &err,
120 &out_buffer);
121 if (r) {
122 fprintf(stderr, "%s", err);
123 FREE(err);
124 return 1;
125 }
126
127 buffer_size = LLVMGetBufferSize(out_buffer);
128 buffer_data = LLVMGetBufferStart(out_buffer);
129
130 radeon_elf_read(buffer_data, buffer_size, binary, dump);
131
132 LLVMDisposeMemoryBuffer(out_buffer);
133 LLVMDisposeTargetMachine(tm);
134 return 0;
135 }