Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 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 
24
 *
25
 */
26
#include "radeon_llvm_emit.h"
27
#include "util/u_memory.h"
28
 
29
#include 
30
#include 
31
 
32
#include 
33
#include 
34
#include 
35
#include 
36
#include 
37
 
38
#define CPU_STRING_LEN 30
39
#define FS_STRING_LEN 30
40
#define TRIPLE_STRING_LEN 7
41
 
42
/**
43
 * Set the shader type we want to compile
44
 *
45
 * @param type shader type to set
46
 */
47
void radeon_llvm_shader_type(LLVMValueRef F, unsigned type)
48
{
49
  char Str[2];
50
  sprintf(Str, "%1d", type);
51
 
52
  LLVMAddTargetDependentFunctionAttr(F, "ShaderType", Str);
53
}
54
 
55
static void init_r600_target() {
56
	static unsigned initialized = 0;
57
	if (!initialized) {
58
		LLVMInitializeR600TargetInfo();
59
		LLVMInitializeR600Target();
60
		LLVMInitializeR600TargetMC();
61
		LLVMInitializeR600AsmPrinter();
62
		initialized = 1;
63
	}
64
}
65
 
66
static LLVMTargetRef get_r600_target() {
67
	LLVMTargetRef target = NULL;
68
 
69
	for (target = LLVMGetFirstTarget(); target;
70
					target = LLVMGetNextTarget(target)) {
71
		if (!strncmp(LLVMGetTargetName(target), "r600", 4)) {
72
			break;
73
		}
74
	}
75
 
76
	if (!target) {
77
		fprintf(stderr, "Can't find target r600\n");
78
		return NULL;
79
	}
80
	return target;
81
}
82
 
83
/**
84
 * Compile an LLVM module to machine code.
85
 *
86
 * @returns 0 for success, 1 for failure
87
 */
88
unsigned radeon_llvm_compile(LLVMModuleRef M, struct radeon_llvm_binary *binary,
89
					  const char * gpu_family, unsigned dump) {
90
 
91
	LLVMTargetRef target;
92
	LLVMTargetMachineRef tm;
93
	char cpu[CPU_STRING_LEN];
94
	char fs[FS_STRING_LEN];
95
	char *err;
96
	LLVMMemoryBufferRef out_buffer;
97
	unsigned buffer_size;
98
	const char *buffer_data;
99
	char triple[TRIPLE_STRING_LEN];
100
	char *elf_buffer;
101
	Elf *elf;
102
	Elf_Scn *section = NULL;
103
	size_t section_str_index;
104
	LLVMBool r;
105
 
106
	init_r600_target();
107
 
108
	target = get_r600_target();
109
	if (!target) {
110
		return 1;
111
	}
112
 
113
	strncpy(cpu, gpu_family, CPU_STRING_LEN);
114
	memset(fs, 0, sizeof(fs));
115
	if (dump) {
116
		LLVMDumpModule(M);
117
		strncpy(fs, "+DumpCode", FS_STRING_LEN);
118
	}
119
	strncpy(triple, "r600--", TRIPLE_STRING_LEN);
120
	tm = LLVMCreateTargetMachine(target, triple, cpu, fs,
121
				  LLVMCodeGenLevelDefault, LLVMRelocDefault,
122
						  LLVMCodeModelDefault);
123
 
124
	r = LLVMTargetMachineEmitToMemoryBuffer(tm, M, LLVMObjectFile, &err,
125
								 &out_buffer);
126
	if (r) {
127
		fprintf(stderr, "%s", err);
128
		FREE(err);
129
		return 1;
130
	}
131
 
132
	buffer_size = LLVMGetBufferSize(out_buffer);
133
	buffer_data = LLVMGetBufferStart(out_buffer);
134
 
135
	/* One of the libelf implementations
136
	 * (http://www.mr511.de/software/english.htm) requires calling
137
	 * elf_version() before elf_memory().
138
	 */
139
	elf_version(EV_CURRENT);
140
	elf_buffer = MALLOC(buffer_size);
141
	memcpy(elf_buffer, buffer_data, buffer_size);
142
 
143
	elf = elf_memory(elf_buffer, buffer_size);
144
 
145
	elf_getshdrstrndx(elf, §ion_str_index);
146
 
147
	while ((section = elf_nextscn(elf, section))) {
148
		const char *name;
149
		Elf_Data *section_data = NULL;
150
		GElf_Shdr section_header;
151
		if (gelf_getshdr(section, §ion_header) != §ion_header) {
152
			fprintf(stderr, "Failed to read ELF section header\n");
153
			return 1;
154
		}
155
		name = elf_strptr(elf, section_str_index, section_header.sh_name);
156
		if (!strcmp(name, ".text")) {
157
			section_data = elf_getdata(section, section_data);
158
			binary->code_size = section_data->d_size;
159
			binary->code = MALLOC(binary->code_size * sizeof(unsigned char));
160
			memcpy(binary->code, section_data->d_buf, binary->code_size);
161
		} else if (!strcmp(name, ".AMDGPU.config")) {
162
			section_data = elf_getdata(section, section_data);
163
			binary->config_size = section_data->d_size;
164
			binary->config = MALLOC(binary->config_size * sizeof(unsigned char));
165
			memcpy(binary->config, section_data->d_buf, binary->config_size);
166
		}
167
	}
168
 
169
	LLVMDisposeMemoryBuffer(out_buffer);
170
	LLVMDisposeTargetMachine(tm);
171
	return 0;
172
}