• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 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
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sub license, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
15  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
16  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
17  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
18  * USE OR OTHER DEALINGS IN THE SOFTWARE.
19  *
20  * The above copyright notice and this permission notice (including the
21  * next paragraph) shall be included in all copies or substantial portions
22  * of the Software.
23  *
24  */
25 /* based on pieces from si_pipe.c and radeon_llvm_emit.c */
26 #include "ac_llvm_util.h"
27 #include "util/bitscan.h"
28 #include <llvm-c/Core.h>
29 #include <llvm-c/Support.h>
30 #include "c11/threads.h"
31 
32 #include <assert.h>
33 #include <stdio.h>
34 #include <string.h>
35 
ac_init_llvm_target()36 static void ac_init_llvm_target()
37 {
38 	LLVMInitializeAMDGPUTargetInfo();
39 	LLVMInitializeAMDGPUTarget();
40 	LLVMInitializeAMDGPUTargetMC();
41 	LLVMInitializeAMDGPUAsmPrinter();
42 
43 	/* For inline assembly. */
44 	LLVMInitializeAMDGPUAsmParser();
45 
46 	/* Workaround for bug in llvm 4.0 that causes image intrinsics
47 	 * to disappear.
48 	 * https://reviews.llvm.org/D26348
49 	 */
50 	if (HAVE_LLVM >= 0x0400) {
51 		/* "mesa" is the prefix for error messages */
52 		const char *argv[2] = { "mesa", "-simplifycfg-sink-common=false" };
53 		LLVMParseCommandLineOptions(2, argv, NULL);
54 	}
55 }
56 
57 static once_flag ac_init_llvm_target_once_flag = ONCE_FLAG_INIT;
58 
ac_get_llvm_target(const char * triple)59 LLVMTargetRef ac_get_llvm_target(const char *triple)
60 {
61 	LLVMTargetRef target = NULL;
62 	char *err_message = NULL;
63 
64 	call_once(&ac_init_llvm_target_once_flag, ac_init_llvm_target);
65 
66 	if (LLVMGetTargetFromTriple(triple, &target, &err_message)) {
67 		fprintf(stderr, "Cannot find target for triple %s ", triple);
68 		if (err_message) {
69 			fprintf(stderr, "%s\n", err_message);
70 		}
71 		LLVMDisposeMessage(err_message);
72 		return NULL;
73 	}
74 	return target;
75 }
76 
ac_get_llvm_processor_name(enum radeon_family family)77 const char *ac_get_llvm_processor_name(enum radeon_family family)
78 {
79 	switch (family) {
80 	case CHIP_TAHITI:
81 		return "tahiti";
82 	case CHIP_PITCAIRN:
83 		return "pitcairn";
84 	case CHIP_VERDE:
85 		return "verde";
86 	case CHIP_OLAND:
87 		return "oland";
88 	case CHIP_HAINAN:
89 		return "hainan";
90 	case CHIP_BONAIRE:
91 		return "bonaire";
92 	case CHIP_KABINI:
93 		return "kabini";
94 	case CHIP_KAVERI:
95 		return "kaveri";
96 	case CHIP_HAWAII:
97 		return "hawaii";
98 	case CHIP_MULLINS:
99 		return "mullins";
100 	case CHIP_TONGA:
101 		return "tonga";
102 	case CHIP_ICELAND:
103 		return "iceland";
104 	case CHIP_CARRIZO:
105 		return "carrizo";
106 	case CHIP_FIJI:
107 		return "fiji";
108 	case CHIP_STONEY:
109 		return "stoney";
110 	case CHIP_POLARIS10:
111 		return "polaris10";
112 	case CHIP_POLARIS11:
113 	case CHIP_POLARIS12:
114 		return "polaris11";
115 	case CHIP_VEGA10:
116 	case CHIP_RAVEN:
117 		return "gfx900";
118 	default:
119 		return "";
120 	}
121 }
122 
ac_create_target_machine(enum radeon_family family,enum ac_target_machine_options tm_options)123 LLVMTargetMachineRef ac_create_target_machine(enum radeon_family family, enum ac_target_machine_options tm_options)
124 {
125 	assert(family >= CHIP_TAHITI);
126 	char features[256];
127 	const char *triple = (tm_options & AC_TM_SUPPORTS_SPILL) ? "amdgcn-mesa-mesa3d" : "amdgcn--";
128 	LLVMTargetRef target = ac_get_llvm_target(triple);
129 
130 	snprintf(features, sizeof(features),
131 		 "+DumpCode,+vgpr-spilling,-fp32-denormals,+fp64-denormals%s%s%s%s",
132 		 tm_options & AC_TM_SISCHED ? ",+si-scheduler" : "",
133 		 tm_options & AC_TM_FORCE_ENABLE_XNACK ? ",+xnack" : "",
134 		 tm_options & AC_TM_FORCE_DISABLE_XNACK ? ",-xnack" : "",
135 		 tm_options & AC_TM_PROMOTE_ALLOCA_TO_SCRATCH ? ",-promote-alloca" : "");
136 
137 	LLVMTargetMachineRef tm = LLVMCreateTargetMachine(
138 	                             target,
139 	                             triple,
140 	                             ac_get_llvm_processor_name(family),
141 				     features,
142 	                             LLVMCodeGenLevelDefault,
143 	                             LLVMRelocDefault,
144 	                             LLVMCodeModelDefault);
145 
146 	return tm;
147 }
148 
149 
150 #if HAVE_LLVM < 0x0400
ac_attr_to_llvm_attr(enum ac_func_attr attr)151 static LLVMAttribute ac_attr_to_llvm_attr(enum ac_func_attr attr)
152 {
153    switch (attr) {
154    case AC_FUNC_ATTR_ALWAYSINLINE: return LLVMAlwaysInlineAttribute;
155    case AC_FUNC_ATTR_BYVAL: return LLVMByValAttribute;
156    case AC_FUNC_ATTR_INREG: return LLVMInRegAttribute;
157    case AC_FUNC_ATTR_NOALIAS: return LLVMNoAliasAttribute;
158    case AC_FUNC_ATTR_NOUNWIND: return LLVMNoUnwindAttribute;
159    case AC_FUNC_ATTR_READNONE: return LLVMReadNoneAttribute;
160    case AC_FUNC_ATTR_READONLY: return LLVMReadOnlyAttribute;
161    default:
162 	   fprintf(stderr, "Unhandled function attribute: %x\n", attr);
163 	   return 0;
164    }
165 }
166 
167 #else
168 
attr_to_str(enum ac_func_attr attr)169 static const char *attr_to_str(enum ac_func_attr attr)
170 {
171    switch (attr) {
172    case AC_FUNC_ATTR_ALWAYSINLINE: return "alwaysinline";
173    case AC_FUNC_ATTR_BYVAL: return "byval";
174    case AC_FUNC_ATTR_INREG: return "inreg";
175    case AC_FUNC_ATTR_NOALIAS: return "noalias";
176    case AC_FUNC_ATTR_NOUNWIND: return "nounwind";
177    case AC_FUNC_ATTR_READNONE: return "readnone";
178    case AC_FUNC_ATTR_READONLY: return "readonly";
179    case AC_FUNC_ATTR_WRITEONLY: return "writeonly";
180    case AC_FUNC_ATTR_INACCESSIBLE_MEM_ONLY: return "inaccessiblememonly";
181    case AC_FUNC_ATTR_CONVERGENT: return "convergent";
182    default:
183 	   fprintf(stderr, "Unhandled function attribute: %x\n", attr);
184 	   return 0;
185    }
186 }
187 
188 #endif
189 
190 void
ac_add_function_attr(LLVMContextRef ctx,LLVMValueRef function,int attr_idx,enum ac_func_attr attr)191 ac_add_function_attr(LLVMContextRef ctx, LLVMValueRef function,
192                      int attr_idx, enum ac_func_attr attr)
193 {
194 #if HAVE_LLVM < 0x0400
195    LLVMAttribute llvm_attr = ac_attr_to_llvm_attr(attr);
196    if (attr_idx == -1) {
197       LLVMAddFunctionAttr(function, llvm_attr);
198    } else {
199       LLVMAddAttribute(LLVMGetParam(function, attr_idx - 1), llvm_attr);
200    }
201 #else
202    const char *attr_name = attr_to_str(attr);
203    unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name,
204                                                       strlen(attr_name));
205    LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(ctx, kind_id, 0);
206 
207    if (LLVMIsAFunction(function))
208       LLVMAddAttributeAtIndex(function, attr_idx, llvm_attr);
209    else
210       LLVMAddCallSiteAttribute(function, attr_idx, llvm_attr);
211 #endif
212 }
213 
ac_add_func_attributes(LLVMContextRef ctx,LLVMValueRef function,unsigned attrib_mask)214 void ac_add_func_attributes(LLVMContextRef ctx, LLVMValueRef function,
215 			    unsigned attrib_mask)
216 {
217 	attrib_mask |= AC_FUNC_ATTR_NOUNWIND;
218 	attrib_mask &= ~AC_FUNC_ATTR_LEGACY;
219 
220 	while (attrib_mask) {
221 		enum ac_func_attr attr = 1u << u_bit_scan(&attrib_mask);
222 		ac_add_function_attr(ctx, function, -1, attr);
223 	}
224 }
225 
226 void
ac_dump_module(LLVMModuleRef module)227 ac_dump_module(LLVMModuleRef module)
228 {
229 	char *str = LLVMPrintModuleToString(module);
230 	fprintf(stderr, "%s", str);
231 	LLVMDisposeMessage(str);
232 }
233 
234 void
ac_llvm_add_target_dep_function_attr(LLVMValueRef F,const char * name,int value)235 ac_llvm_add_target_dep_function_attr(LLVMValueRef F,
236 				     const char *name, int value)
237 {
238 	char str[16];
239 
240 	snprintf(str, sizeof(str), "%i", value);
241 	LLVMAddTargetDependentFunctionAttr(F, name, str);
242 }
243