Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5564 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 "radeon_elf_util.h"
28
#include "util/u_memory.h"
29
#include "pipe/p_shader_tokens.h"
30
 
31
#include 
32
#include 
33
#include 
34
 
35
#include 
36
#include 
37
#include 
38
 
39
#define CPU_STRING_LEN 30
40
#define FS_STRING_LEN 30
41
#define TRIPLE_STRING_LEN 7
42
 
43
/**
44
 * Shader types for the LLVM backend.
45
 */
46
enum radeon_llvm_shader_type {
47
	RADEON_LLVM_SHADER_PS = 0,
48
	RADEON_LLVM_SHADER_VS = 1,
49
	RADEON_LLVM_SHADER_GS = 2,
50
	RADEON_LLVM_SHADER_CS = 3,
51
};
52
 
53
/**
54
 * Set the shader type we want to compile
55
 *
56
 * @param type shader type to set
57
 */
58
void radeon_llvm_shader_type(LLVMValueRef F, unsigned type)
59
{
60
	char Str[2];
61
	enum radeon_llvm_shader_type llvm_type;
62
 
63
	switch (type) {
64
	case TGSI_PROCESSOR_VERTEX:
65
		llvm_type = RADEON_LLVM_SHADER_VS;
66
		break;
67
	case TGSI_PROCESSOR_GEOMETRY:
68
		llvm_type = RADEON_LLVM_SHADER_GS;
69
		break;
70
	case TGSI_PROCESSOR_FRAGMENT:
71
		llvm_type = RADEON_LLVM_SHADER_PS;
72
		break;
73
	case TGSI_PROCESSOR_COMPUTE:
74
		llvm_type = RADEON_LLVM_SHADER_CS;
75
		break;
76
	default:
77
		assert(0);
78
	}
79
 
80
	sprintf(Str, "%1d", llvm_type);
81
 
82
	LLVMAddTargetDependentFunctionAttr(F, "ShaderType", Str);
83
}
84
 
85
static void init_r600_target()
86
{
87
	static unsigned initialized = 0;
88
	if (!initialized) {
89
		LLVMInitializeR600TargetInfo();
90
		LLVMInitializeR600Target();
91
		LLVMInitializeR600TargetMC();
92
		LLVMInitializeR600AsmPrinter();
93
		initialized = 1;
94
	}
95
}
96
 
97
LLVMTargetRef radeon_llvm_get_r600_target(const char *triple)
98
{
99
	LLVMTargetRef target = NULL;
100
	char *err_message = NULL;
101
 
102
	init_r600_target();
103
 
104
	if (LLVMGetTargetFromTriple(triple, &target, &err_message)) {
105
		fprintf(stderr, "Cannot find target for triple %s ", triple);
106
		if (err_message) {
107
			fprintf(stderr, "%s\n", err_message);
108
		}
109
		LLVMDisposeMessage(err_message);
110
		return NULL;
111
	}
112
	return target;
113
}
114
 
115
#if HAVE_LLVM >= 0x0305
116
 
117
static void radeonDiagnosticHandler(LLVMDiagnosticInfoRef di, void *context)
118
{
119
	if (LLVMGetDiagInfoSeverity(di) == LLVMDSError) {
120
		unsigned int *diagnosticflag = (unsigned int *)context;
121
		char *diaginfo_message = LLVMGetDiagInfoDescription(di);
122
 
123
		*diagnosticflag = 1;
124
		fprintf(stderr,"LLVM triggered Diagnostic Handler: %s\n", diaginfo_message);
125
		LLVMDisposeMessage(diaginfo_message);
126
	}
127
}
128
 
129
#endif
130
 
131
/**
132
 * Compile an LLVM module to machine code.
133
 *
134
 * @returns 0 for success, 1 for failure
135
 */
136
unsigned radeon_llvm_compile(LLVMModuleRef M, struct radeon_shader_binary *binary,
137
			  const char *gpu_family, unsigned dump, LLVMTargetMachineRef tm)
138
{
139
 
140
	char cpu[CPU_STRING_LEN];
141
	char fs[FS_STRING_LEN];
142
	char *err;
143
	bool dispose_tm = false;
144
	LLVMContextRef llvm_ctx;
145
	unsigned rval = 0;
146
	LLVMMemoryBufferRef out_buffer;
147
	unsigned buffer_size;
148
	const char *buffer_data;
149
	char triple[TRIPLE_STRING_LEN];
150
	LLVMBool mem_err;
151
 
152
	if (!tm) {
153
		strncpy(triple, "r600--", TRIPLE_STRING_LEN);
154
		LLVMTargetRef target = radeon_llvm_get_r600_target(triple);
155
		if (!target) {
156
			return 1;
157
		}
158
		strncpy(cpu, gpu_family, CPU_STRING_LEN);
159
		memset(fs, 0, sizeof(fs));
160
		if (dump) {
161
			strncpy(fs, "+DumpCode", FS_STRING_LEN);
162
		}
163
		tm = LLVMCreateTargetMachine(target, triple, cpu, fs,
164
				  LLVMCodeGenLevelDefault, LLVMRelocDefault,
165
						  LLVMCodeModelDefault);
166
		dispose_tm = true;
167
	}
168
	if (dump) {
169
		LLVMDumpModule(M);
170
	}
171
	/* Setup Diagnostic Handler*/
172
	llvm_ctx = LLVMGetModuleContext(M);
173
 
174
#if HAVE_LLVM >= 0x0305
175
	LLVMContextSetDiagnosticHandler(llvm_ctx, radeonDiagnosticHandler, &rval);
176
#endif
177
	rval = 0;
178
 
179
	/* Compile IR*/
180
	mem_err = LLVMTargetMachineEmitToMemoryBuffer(tm, M, LLVMObjectFile, &err,
181
								 &out_buffer);
182
 
183
	/* Process Errors/Warnings */
184
	if (mem_err) {
185
		fprintf(stderr, "%s: %s", __FUNCTION__, err);
186
		FREE(err);
187
		LLVMDisposeTargetMachine(tm);
188
		return 1;
189
	}
190
 
191
	if (0 != rval) {
192
		fprintf(stderr, "%s: Processing Diag Flag\n", __FUNCTION__);
193
	}
194
 
195
	/* Extract Shader Code*/
196
	buffer_size = LLVMGetBufferSize(out_buffer);
197
	buffer_data = LLVMGetBufferStart(out_buffer);
198
 
199
	radeon_elf_read(buffer_data, buffer_size, binary, dump);
200
 
201
	/* Clean up */
202
	LLVMDisposeMemoryBuffer(out_buffer);
203
 
204
	if (dispose_tm) {
205
		LLVMDisposeTargetMachine(tm);
206
	}
207
	return rval;
208
}