1b8e80941Smrg/* 2b8e80941Smrg * Copyright 2014 Advanced Micro Devices, Inc. 3b8e80941Smrg * 4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5b8e80941Smrg * copy of this software and associated documentation files (the 6b8e80941Smrg * "Software"), to deal in the Software without restriction, including 7b8e80941Smrg * without limitation the rights to use, copy, modify, merge, publish, 8b8e80941Smrg * distribute, sub license, and/or sell copies of the Software, and to 9b8e80941Smrg * permit persons to whom the Software is furnished to do so, subject to 10b8e80941Smrg * the following conditions: 11b8e80941Smrg * 12b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 15b8e80941Smrg * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 16b8e80941Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 17b8e80941Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 18b8e80941Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE. 19b8e80941Smrg * 20b8e80941Smrg * The above copyright notice and this permission notice (including the 21b8e80941Smrg * next paragraph) shall be included in all copies or substantial portions 22b8e80941Smrg * of the Software. 23b8e80941Smrg * 24b8e80941Smrg */ 25b8e80941Smrg 26b8e80941Smrg/* based on Marek's patch to lp_bld_misc.cpp */ 27b8e80941Smrg 28b8e80941Smrg// Workaround http://llvm.org/PR23628 29b8e80941Smrg#pragma push_macro("DEBUG") 30b8e80941Smrg#undef DEBUG 31b8e80941Smrg 32b8e80941Smrg#include "ac_binary.h" 33b8e80941Smrg#include "ac_llvm_util.h" 34b8e80941Smrg#include "ac_llvm_build.h" 35b8e80941Smrg 36b8e80941Smrg#include <llvm-c/Core.h> 37b8e80941Smrg#include <llvm/ADT/SmallString.h> 38b8e80941Smrg#include <llvm/Target/TargetMachine.h> 39b8e80941Smrg#include <llvm/IR/IRBuilder.h> 40b8e80941Smrg#include <llvm/Analysis/TargetLibraryInfo.h> 41b8e80941Smrg#include <llvm/Transforms/IPO.h> 42b8e80941Smrg 43b8e80941Smrg#include <llvm/IR/LegacyPassManager.h> 44b8e80941Smrg 45b8e80941Smrgvoid ac_add_attr_dereferenceable(LLVMValueRef val, uint64_t bytes) 46b8e80941Smrg{ 47b8e80941Smrg llvm::Argument *A = llvm::unwrap<llvm::Argument>(val); 48b8e80941Smrg A->addAttr(llvm::Attribute::getWithDereferenceableBytes(A->getContext(), bytes)); 49b8e80941Smrg} 50b8e80941Smrg 51b8e80941Smrgbool ac_is_sgpr_param(LLVMValueRef arg) 52b8e80941Smrg{ 53b8e80941Smrg llvm::Argument *A = llvm::unwrap<llvm::Argument>(arg); 54b8e80941Smrg llvm::AttributeList AS = A->getParent()->getAttributes(); 55b8e80941Smrg unsigned ArgNo = A->getArgNo(); 56b8e80941Smrg return AS.hasAttribute(ArgNo + 1, llvm::Attribute::InReg); 57b8e80941Smrg} 58b8e80941Smrg 59b8e80941SmrgLLVMValueRef ac_llvm_get_called_value(LLVMValueRef call) 60b8e80941Smrg{ 61b8e80941Smrg return LLVMGetCalledValue(call); 62b8e80941Smrg} 63b8e80941Smrg 64b8e80941Smrgbool ac_llvm_is_function(LLVMValueRef v) 65b8e80941Smrg{ 66b8e80941Smrg return LLVMGetValueKind(v) == LLVMFunctionValueKind; 67b8e80941Smrg} 68b8e80941Smrg 69b8e80941SmrgLLVMModuleRef ac_create_module(LLVMTargetMachineRef tm, LLVMContextRef ctx) 70b8e80941Smrg{ 71b8e80941Smrg llvm::TargetMachine *TM = reinterpret_cast<llvm::TargetMachine*>(tm); 72b8e80941Smrg LLVMModuleRef module = LLVMModuleCreateWithNameInContext("mesa-shader", ctx); 73b8e80941Smrg 74b8e80941Smrg llvm::unwrap(module)->setTargetTriple(TM->getTargetTriple().getTriple()); 75b8e80941Smrg llvm::unwrap(module)->setDataLayout(TM->createDataLayout()); 76b8e80941Smrg return module; 77b8e80941Smrg} 78b8e80941Smrg 79b8e80941SmrgLLVMBuilderRef ac_create_builder(LLVMContextRef ctx, 80b8e80941Smrg enum ac_float_mode float_mode) 81b8e80941Smrg{ 82b8e80941Smrg LLVMBuilderRef builder = LLVMCreateBuilderInContext(ctx); 83b8e80941Smrg 84b8e80941Smrg llvm::FastMathFlags flags; 85b8e80941Smrg 86b8e80941Smrg switch (float_mode) { 87b8e80941Smrg case AC_FLOAT_MODE_DEFAULT: 88b8e80941Smrg break; 89b8e80941Smrg case AC_FLOAT_MODE_NO_SIGNED_ZEROS_FP_MATH: 90b8e80941Smrg flags.setNoSignedZeros(); 91b8e80941Smrg llvm::unwrap(builder)->setFastMathFlags(flags); 92b8e80941Smrg break; 93b8e80941Smrg case AC_FLOAT_MODE_UNSAFE_FP_MATH: 94b8e80941Smrg flags.setFast(); 95b8e80941Smrg llvm::unwrap(builder)->setFastMathFlags(flags); 96b8e80941Smrg break; 97b8e80941Smrg } 98b8e80941Smrg 99b8e80941Smrg return builder; 100b8e80941Smrg} 101b8e80941Smrg 102b8e80941SmrgLLVMTargetLibraryInfoRef 103b8e80941Smrgac_create_target_library_info(const char *triple) 104b8e80941Smrg{ 105b8e80941Smrg return reinterpret_cast<LLVMTargetLibraryInfoRef>(new llvm::TargetLibraryInfoImpl(llvm::Triple(triple))); 106b8e80941Smrg} 107b8e80941Smrg 108b8e80941Smrgvoid 109b8e80941Smrgac_dispose_target_library_info(LLVMTargetLibraryInfoRef library_info) 110b8e80941Smrg{ 111b8e80941Smrg delete reinterpret_cast<llvm::TargetLibraryInfoImpl *>(library_info); 112b8e80941Smrg} 113b8e80941Smrg 114b8e80941Smrg/* The LLVM compiler is represented as a pass manager containing passes for 115b8e80941Smrg * optimizations, instruction selection, and code generation. 116b8e80941Smrg */ 117b8e80941Smrgstruct ac_compiler_passes { 118b8e80941Smrg ac_compiler_passes(): ostream(code_string) {} 119b8e80941Smrg 120b8e80941Smrg llvm::SmallString<0> code_string; /* ELF shader binary */ 121b8e80941Smrg llvm::raw_svector_ostream ostream; /* stream for appending data to the binary */ 122b8e80941Smrg llvm::legacy::PassManager passmgr; /* list of passes */ 123b8e80941Smrg}; 124b8e80941Smrg 125b8e80941Smrgstruct ac_compiler_passes *ac_create_llvm_passes(LLVMTargetMachineRef tm) 126b8e80941Smrg{ 127b8e80941Smrg struct ac_compiler_passes *p = new ac_compiler_passes(); 128b8e80941Smrg if (!p) 129b8e80941Smrg return NULL; 130b8e80941Smrg 131b8e80941Smrg llvm::TargetMachine *TM = reinterpret_cast<llvm::TargetMachine*>(tm); 132b8e80941Smrg 133b8e80941Smrg#if HAVE_LLVM < 0x900 134b8e80941Smrg if (TM->addPassesToEmitFile(p->passmgr, p->ostream, 135b8e80941Smrg nullptr, 136b8e80941Smrg llvm::TargetMachine::CGFT_ObjectFile)) { 137b8e80941Smrg#else 138b8e80941Smrg if (TM->addPassesToEmitFile(p->passmgr, p->ostream, 139b8e80941Smrg nullptr, 140b8e80941Smrg llvm::CGFT_ObjectFile)) { 141b8e80941Smrg#endif 142b8e80941Smrg fprintf(stderr, "amd: TargetMachine can't emit a file of this type!\n"); 143b8e80941Smrg delete p; 144b8e80941Smrg return NULL; 145b8e80941Smrg } 146b8e80941Smrg return p; 147b8e80941Smrg} 148b8e80941Smrg 149b8e80941Smrgvoid ac_destroy_llvm_passes(struct ac_compiler_passes *p) 150b8e80941Smrg{ 151b8e80941Smrg delete p; 152b8e80941Smrg} 153b8e80941Smrg 154b8e80941Smrg/* This returns false on failure. */ 155b8e80941Smrgbool ac_compile_module_to_binary(struct ac_compiler_passes *p, LLVMModuleRef module, 156b8e80941Smrg struct ac_shader_binary *binary) 157b8e80941Smrg{ 158b8e80941Smrg p->passmgr.run(*llvm::unwrap(module)); 159b8e80941Smrg 160b8e80941Smrg llvm::StringRef data = p->ostream.str(); 161b8e80941Smrg bool success = ac_elf_read(data.data(), data.size(), binary); 162b8e80941Smrg p->code_string = ""; /* release the ELF shader binary */ 163b8e80941Smrg 164b8e80941Smrg if (!success) 165b8e80941Smrg fprintf(stderr, "amd: cannot read an ELF shader binary\n"); 166b8e80941Smrg return success; 167b8e80941Smrg} 168b8e80941Smrg 169b8e80941Smrgvoid ac_llvm_add_barrier_noop_pass(LLVMPassManagerRef passmgr) 170b8e80941Smrg{ 171b8e80941Smrg llvm::unwrap(passmgr)->add(llvm::createBarrierNoopPass()); 172b8e80941Smrg} 173b8e80941Smrg 174b8e80941Smrgvoid ac_enable_global_isel(LLVMTargetMachineRef tm) 175b8e80941Smrg{ 176b8e80941Smrg reinterpret_cast<llvm::TargetMachine*>(tm)->setGlobalISel(true); 177b8e80941Smrg} 178b8e80941Smrg 179b8e80941SmrgLLVMValueRef ac_build_atomic_rmw(struct ac_llvm_context *ctx, LLVMAtomicRMWBinOp op, 180b8e80941Smrg LLVMValueRef ptr, LLVMValueRef val, 181b8e80941Smrg const char *sync_scope) { 182b8e80941Smrg llvm::AtomicRMWInst::BinOp binop; 183b8e80941Smrg switch (op) { 184b8e80941Smrg case LLVMAtomicRMWBinOpXchg: 185b8e80941Smrg binop = llvm::AtomicRMWInst::Xchg; 186b8e80941Smrg break; 187b8e80941Smrg case LLVMAtomicRMWBinOpAdd: 188b8e80941Smrg binop = llvm::AtomicRMWInst::Add; 189b8e80941Smrg break; 190b8e80941Smrg case LLVMAtomicRMWBinOpSub: 191b8e80941Smrg binop = llvm::AtomicRMWInst::Sub; 192b8e80941Smrg break; 193b8e80941Smrg case LLVMAtomicRMWBinOpAnd: 194b8e80941Smrg binop = llvm::AtomicRMWInst::And; 195b8e80941Smrg break; 196b8e80941Smrg case LLVMAtomicRMWBinOpNand: 197b8e80941Smrg binop = llvm::AtomicRMWInst::Nand; 198b8e80941Smrg break; 199b8e80941Smrg case LLVMAtomicRMWBinOpOr: 200b8e80941Smrg binop = llvm::AtomicRMWInst::Or; 201b8e80941Smrg break; 202b8e80941Smrg case LLVMAtomicRMWBinOpXor: 203b8e80941Smrg binop = llvm::AtomicRMWInst::Xor; 204b8e80941Smrg break; 205b8e80941Smrg case LLVMAtomicRMWBinOpMax: 206b8e80941Smrg binop = llvm::AtomicRMWInst::Max; 207b8e80941Smrg break; 208b8e80941Smrg case LLVMAtomicRMWBinOpMin: 209b8e80941Smrg binop = llvm::AtomicRMWInst::Min; 210b8e80941Smrg break; 211b8e80941Smrg case LLVMAtomicRMWBinOpUMax: 212b8e80941Smrg binop = llvm::AtomicRMWInst::UMax; 213b8e80941Smrg break; 214b8e80941Smrg case LLVMAtomicRMWBinOpUMin: 215b8e80941Smrg binop = llvm::AtomicRMWInst::UMin; 216b8e80941Smrg break; 217b8e80941Smrg default: 218b8e80941Smrg unreachable(!"invalid LLVMAtomicRMWBinOp"); 219b8e80941Smrg break; 220b8e80941Smrg } 221b8e80941Smrg unsigned SSID = llvm::unwrap(ctx->context)->getOrInsertSyncScopeID(sync_scope); 222b8e80941Smrg return llvm::wrap(llvm::unwrap(ctx->builder)->CreateAtomicRMW( 223b8e80941Smrg binop, llvm::unwrap(ptr), llvm::unwrap(val), 224b8e80941Smrg#if LLVM_VERSION_MAJOR >= 13 225b8e80941Smrg llvm::MaybeAlign(0), 226b8e80941Smrg#endif 227b8e80941Smrg llvm::AtomicOrdering::SequentiallyConsistent, SSID)); 228b8e80941Smrg} 229b8e80941Smrg 230b8e80941SmrgLLVMValueRef ac_build_atomic_cmp_xchg(struct ac_llvm_context *ctx, LLVMValueRef ptr, 231b8e80941Smrg LLVMValueRef cmp, LLVMValueRef val, 232b8e80941Smrg const char *sync_scope) { 233b8e80941Smrg unsigned SSID = llvm::unwrap(ctx->context)->getOrInsertSyncScopeID(sync_scope); 234b8e80941Smrg return llvm::wrap(llvm::unwrap(ctx->builder)->CreateAtomicCmpXchg( 235b8e80941Smrg llvm::unwrap(ptr), llvm::unwrap(cmp), llvm::unwrap(val), 236b8e80941Smrg#if LLVM_VERSION_MAJOR >= 13 237b8e80941Smrg llvm::MaybeAlign(0), 238b8e80941Smrg#endif 239b8e80941Smrg llvm::AtomicOrdering::SequentiallyConsistent, 240b8e80941Smrg llvm::AtomicOrdering::SequentiallyConsistent, SSID)); 241b8e80941Smrg} 242