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 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 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 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 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 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 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 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 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 227 ac_dump_module(LLVMModuleRef module) 228 { 229 char *str = LLVMPrintModuleToString(module); 230 fprintf(stderr, "%s", str); 231 LLVMDisposeMessage(str); 232 } 233 234 void 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