1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright 2014 Advanced Micro Devices, Inc. 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the 6bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 7bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 8bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 9bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 10bf215546Sopenharmony_ci * the following conditions: 11bf215546Sopenharmony_ci * 12bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 15bf215546Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 16bf215546Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 17bf215546Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 18bf215546Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 19bf215546Sopenharmony_ci * 20bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 21bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 22bf215546Sopenharmony_ci * of the Software. 23bf215546Sopenharmony_ci * 24bf215546Sopenharmony_ci */ 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include <llvm-c/Core.h> 27bf215546Sopenharmony_ci#include <llvm/Analysis/TargetLibraryInfo.h> 28bf215546Sopenharmony_ci#include <llvm/IR/IRBuilder.h> 29bf215546Sopenharmony_ci#include <llvm/IR/LegacyPassManager.h> 30bf215546Sopenharmony_ci#include <llvm/Target/TargetMachine.h> 31bf215546Sopenharmony_ci#include <llvm/MC/MCSubtargetInfo.h> 32bf215546Sopenharmony_ci#include <llvm/Support/CommandLine.h> 33bf215546Sopenharmony_ci#include <llvm/Transforms/IPO.h> 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_ci#include <cstring> 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ci/* DO NOT REORDER THE HEADERS 38bf215546Sopenharmony_ci * The LLVM headers need to all be included before any Mesa header, 39bf215546Sopenharmony_ci * as they use the `restrict` keyword in ways that are incompatible 40bf215546Sopenharmony_ci * with our #define in include/c99_compat.h 41bf215546Sopenharmony_ci */ 42bf215546Sopenharmony_ci 43bf215546Sopenharmony_ci#include "ac_binary.h" 44bf215546Sopenharmony_ci#include "ac_llvm_util.h" 45bf215546Sopenharmony_ci#include "ac_llvm_build.h" 46bf215546Sopenharmony_ci#include "util/macros.h" 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_cibool ac_is_llvm_processor_supported(LLVMTargetMachineRef tm, const char *processor) 49bf215546Sopenharmony_ci{ 50bf215546Sopenharmony_ci llvm::TargetMachine *TM = reinterpret_cast<llvm::TargetMachine *>(tm); 51bf215546Sopenharmony_ci return TM->getMCSubtargetInfo()->isCPUStringValid(processor); 52bf215546Sopenharmony_ci} 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_civoid ac_reset_llvm_all_options_occurences() 55bf215546Sopenharmony_ci{ 56bf215546Sopenharmony_ci llvm::cl::ResetAllOptionOccurrences(); 57bf215546Sopenharmony_ci} 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_civoid ac_add_attr_dereferenceable(LLVMValueRef val, uint64_t bytes) 60bf215546Sopenharmony_ci{ 61bf215546Sopenharmony_ci llvm::Argument *A = llvm::unwrap<llvm::Argument>(val); 62bf215546Sopenharmony_ci A->addAttr(llvm::Attribute::getWithDereferenceableBytes(A->getContext(), bytes)); 63bf215546Sopenharmony_ci} 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_civoid ac_add_attr_alignment(LLVMValueRef val, uint64_t bytes) 66bf215546Sopenharmony_ci{ 67bf215546Sopenharmony_ci llvm::Argument *A = llvm::unwrap<llvm::Argument>(val); 68bf215546Sopenharmony_ci A->addAttr(llvm::Attribute::getWithAlignment(A->getContext(), llvm::Align(bytes))); 69bf215546Sopenharmony_ci} 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_cibool ac_is_sgpr_param(LLVMValueRef arg) 72bf215546Sopenharmony_ci{ 73bf215546Sopenharmony_ci llvm::Argument *A = llvm::unwrap<llvm::Argument>(arg); 74bf215546Sopenharmony_ci llvm::AttributeList AS = A->getParent()->getAttributes(); 75bf215546Sopenharmony_ci unsigned ArgNo = A->getArgNo(); 76bf215546Sopenharmony_ci return AS.hasParamAttr(ArgNo, llvm::Attribute::InReg); 77bf215546Sopenharmony_ci} 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ciLLVMModuleRef ac_create_module(LLVMTargetMachineRef tm, LLVMContextRef ctx) 80bf215546Sopenharmony_ci{ 81bf215546Sopenharmony_ci llvm::TargetMachine *TM = reinterpret_cast<llvm::TargetMachine *>(tm); 82bf215546Sopenharmony_ci LLVMModuleRef module = LLVMModuleCreateWithNameInContext("mesa-shader", ctx); 83bf215546Sopenharmony_ci 84bf215546Sopenharmony_ci llvm::unwrap(module)->setTargetTriple(TM->getTargetTriple().getTriple()); 85bf215546Sopenharmony_ci llvm::unwrap(module)->setDataLayout(TM->createDataLayout()); 86bf215546Sopenharmony_ci return module; 87bf215546Sopenharmony_ci} 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_ciLLVMBuilderRef ac_create_builder(LLVMContextRef ctx, enum ac_float_mode float_mode) 90bf215546Sopenharmony_ci{ 91bf215546Sopenharmony_ci LLVMBuilderRef builder = LLVMCreateBuilderInContext(ctx); 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci llvm::FastMathFlags flags; 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_ci switch (float_mode) { 96bf215546Sopenharmony_ci case AC_FLOAT_MODE_DEFAULT: 97bf215546Sopenharmony_ci case AC_FLOAT_MODE_DENORM_FLUSH_TO_ZERO: 98bf215546Sopenharmony_ci break; 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_ci case AC_FLOAT_MODE_DEFAULT_OPENGL: 101bf215546Sopenharmony_ci /* Allow optimizations to treat the sign of a zero argument or 102bf215546Sopenharmony_ci * result as insignificant. 103bf215546Sopenharmony_ci */ 104bf215546Sopenharmony_ci flags.setNoSignedZeros(); /* nsz */ 105bf215546Sopenharmony_ci 106bf215546Sopenharmony_ci /* Allow optimizations to use the reciprocal of an argument 107bf215546Sopenharmony_ci * rather than perform division. 108bf215546Sopenharmony_ci */ 109bf215546Sopenharmony_ci flags.setAllowReciprocal(); /* arcp */ 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_ci llvm::unwrap(builder)->setFastMathFlags(flags); 112bf215546Sopenharmony_ci break; 113bf215546Sopenharmony_ci } 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_ci return builder; 116bf215546Sopenharmony_ci} 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_civoid ac_enable_signed_zeros(struct ac_llvm_context *ctx) 119bf215546Sopenharmony_ci{ 120bf215546Sopenharmony_ci if (ctx->float_mode == AC_FLOAT_MODE_DEFAULT_OPENGL) { 121bf215546Sopenharmony_ci auto *b = llvm::unwrap(ctx->builder); 122bf215546Sopenharmony_ci llvm::FastMathFlags flags = b->getFastMathFlags(); 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_ci /* This disables the optimization of (x + 0), which is used 125bf215546Sopenharmony_ci * to convert negative zero to positive zero. 126bf215546Sopenharmony_ci */ 127bf215546Sopenharmony_ci flags.setNoSignedZeros(false); 128bf215546Sopenharmony_ci b->setFastMathFlags(flags); 129bf215546Sopenharmony_ci } 130bf215546Sopenharmony_ci} 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_civoid ac_disable_signed_zeros(struct ac_llvm_context *ctx) 133bf215546Sopenharmony_ci{ 134bf215546Sopenharmony_ci if (ctx->float_mode == AC_FLOAT_MODE_DEFAULT_OPENGL) { 135bf215546Sopenharmony_ci auto *b = llvm::unwrap(ctx->builder); 136bf215546Sopenharmony_ci llvm::FastMathFlags flags = b->getFastMathFlags(); 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci flags.setNoSignedZeros(); 139bf215546Sopenharmony_ci b->setFastMathFlags(flags); 140bf215546Sopenharmony_ci } 141bf215546Sopenharmony_ci} 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_ciLLVMTargetLibraryInfoRef ac_create_target_library_info(const char *triple) 144bf215546Sopenharmony_ci{ 145bf215546Sopenharmony_ci return reinterpret_cast<LLVMTargetLibraryInfoRef>( 146bf215546Sopenharmony_ci new llvm::TargetLibraryInfoImpl(llvm::Triple(triple))); 147bf215546Sopenharmony_ci} 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_civoid ac_dispose_target_library_info(LLVMTargetLibraryInfoRef library_info) 150bf215546Sopenharmony_ci{ 151bf215546Sopenharmony_ci delete reinterpret_cast<llvm::TargetLibraryInfoImpl *>(library_info); 152bf215546Sopenharmony_ci} 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci/* Implementation of raw_pwrite_stream that works on malloc()ed memory for 155bf215546Sopenharmony_ci * better compatibility with C code. */ 156bf215546Sopenharmony_cistruct raw_memory_ostream : public llvm::raw_pwrite_stream { 157bf215546Sopenharmony_ci char *buffer; 158bf215546Sopenharmony_ci size_t written; 159bf215546Sopenharmony_ci size_t bufsize; 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci raw_memory_ostream() 162bf215546Sopenharmony_ci { 163bf215546Sopenharmony_ci buffer = NULL; 164bf215546Sopenharmony_ci written = 0; 165bf215546Sopenharmony_ci bufsize = 0; 166bf215546Sopenharmony_ci SetUnbuffered(); 167bf215546Sopenharmony_ci } 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci ~raw_memory_ostream() 170bf215546Sopenharmony_ci { 171bf215546Sopenharmony_ci free(buffer); 172bf215546Sopenharmony_ci } 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci void clear() 175bf215546Sopenharmony_ci { 176bf215546Sopenharmony_ci written = 0; 177bf215546Sopenharmony_ci } 178bf215546Sopenharmony_ci 179bf215546Sopenharmony_ci void take(char *&out_buffer, size_t &out_size) 180bf215546Sopenharmony_ci { 181bf215546Sopenharmony_ci out_buffer = buffer; 182bf215546Sopenharmony_ci out_size = written; 183bf215546Sopenharmony_ci buffer = NULL; 184bf215546Sopenharmony_ci written = 0; 185bf215546Sopenharmony_ci bufsize = 0; 186bf215546Sopenharmony_ci } 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ci void flush() = delete; 189bf215546Sopenharmony_ci 190bf215546Sopenharmony_ci void write_impl(const char *ptr, size_t size) override 191bf215546Sopenharmony_ci { 192bf215546Sopenharmony_ci if (unlikely(written + size < written)) 193bf215546Sopenharmony_ci abort(); 194bf215546Sopenharmony_ci if (written + size > bufsize) { 195bf215546Sopenharmony_ci bufsize = MAX3(1024, written + size, bufsize / 3 * 4); 196bf215546Sopenharmony_ci buffer = (char *)realloc(buffer, bufsize); 197bf215546Sopenharmony_ci if (!buffer) { 198bf215546Sopenharmony_ci fprintf(stderr, "amd: out of memory allocating ELF buffer\n"); 199bf215546Sopenharmony_ci abort(); 200bf215546Sopenharmony_ci } 201bf215546Sopenharmony_ci } 202bf215546Sopenharmony_ci memcpy(buffer + written, ptr, size); 203bf215546Sopenharmony_ci written += size; 204bf215546Sopenharmony_ci } 205bf215546Sopenharmony_ci 206bf215546Sopenharmony_ci void pwrite_impl(const char *ptr, size_t size, uint64_t offset) override 207bf215546Sopenharmony_ci { 208bf215546Sopenharmony_ci assert(offset == (size_t)offset && offset + size >= offset && offset + size <= written); 209bf215546Sopenharmony_ci memcpy(buffer + offset, ptr, size); 210bf215546Sopenharmony_ci } 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci uint64_t current_pos() const override 213bf215546Sopenharmony_ci { 214bf215546Sopenharmony_ci return written; 215bf215546Sopenharmony_ci } 216bf215546Sopenharmony_ci}; 217bf215546Sopenharmony_ci 218bf215546Sopenharmony_ci/* The LLVM compiler is represented as a pass manager containing passes for 219bf215546Sopenharmony_ci * optimizations, instruction selection, and code generation. 220bf215546Sopenharmony_ci */ 221bf215546Sopenharmony_cistruct ac_compiler_passes { 222bf215546Sopenharmony_ci raw_memory_ostream ostream; /* ELF shader binary stream */ 223bf215546Sopenharmony_ci llvm::legacy::PassManager passmgr; /* list of passes */ 224bf215546Sopenharmony_ci}; 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_cistruct ac_compiler_passes *ac_create_llvm_passes(LLVMTargetMachineRef tm) 227bf215546Sopenharmony_ci{ 228bf215546Sopenharmony_ci struct ac_compiler_passes *p = new ac_compiler_passes(); 229bf215546Sopenharmony_ci if (!p) 230bf215546Sopenharmony_ci return NULL; 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_ci llvm::TargetMachine *TM = reinterpret_cast<llvm::TargetMachine *>(tm); 233bf215546Sopenharmony_ci 234bf215546Sopenharmony_ci if (TM->addPassesToEmitFile(p->passmgr, p->ostream, nullptr, 235bf215546Sopenharmony_ci llvm::CGFT_ObjectFile)) { 236bf215546Sopenharmony_ci fprintf(stderr, "amd: TargetMachine can't emit a file of this type!\n"); 237bf215546Sopenharmony_ci delete p; 238bf215546Sopenharmony_ci return NULL; 239bf215546Sopenharmony_ci } 240bf215546Sopenharmony_ci return p; 241bf215546Sopenharmony_ci} 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_civoid ac_destroy_llvm_passes(struct ac_compiler_passes *p) 244bf215546Sopenharmony_ci{ 245bf215546Sopenharmony_ci delete p; 246bf215546Sopenharmony_ci} 247bf215546Sopenharmony_ci 248bf215546Sopenharmony_ci/* This returns false on failure. */ 249bf215546Sopenharmony_cibool ac_compile_module_to_elf(struct ac_compiler_passes *p, LLVMModuleRef module, 250bf215546Sopenharmony_ci char **pelf_buffer, size_t *pelf_size) 251bf215546Sopenharmony_ci{ 252bf215546Sopenharmony_ci p->passmgr.run(*llvm::unwrap(module)); 253bf215546Sopenharmony_ci p->ostream.take(*pelf_buffer, *pelf_size); 254bf215546Sopenharmony_ci return true; 255bf215546Sopenharmony_ci} 256bf215546Sopenharmony_ci 257bf215546Sopenharmony_civoid ac_llvm_add_barrier_noop_pass(LLVMPassManagerRef passmgr) 258bf215546Sopenharmony_ci{ 259bf215546Sopenharmony_ci llvm::unwrap(passmgr)->add(llvm::createBarrierNoopPass()); 260bf215546Sopenharmony_ci} 261bf215546Sopenharmony_ci 262bf215546Sopenharmony_ciLLVMValueRef ac_build_atomic_rmw(struct ac_llvm_context *ctx, LLVMAtomicRMWBinOp op, 263bf215546Sopenharmony_ci LLVMValueRef ptr, LLVMValueRef val, const char *sync_scope) 264bf215546Sopenharmony_ci{ 265bf215546Sopenharmony_ci llvm::AtomicRMWInst::BinOp binop; 266bf215546Sopenharmony_ci switch (op) { 267bf215546Sopenharmony_ci case LLVMAtomicRMWBinOpXchg: 268bf215546Sopenharmony_ci binop = llvm::AtomicRMWInst::Xchg; 269bf215546Sopenharmony_ci break; 270bf215546Sopenharmony_ci case LLVMAtomicRMWBinOpAdd: 271bf215546Sopenharmony_ci binop = llvm::AtomicRMWInst::Add; 272bf215546Sopenharmony_ci break; 273bf215546Sopenharmony_ci case LLVMAtomicRMWBinOpSub: 274bf215546Sopenharmony_ci binop = llvm::AtomicRMWInst::Sub; 275bf215546Sopenharmony_ci break; 276bf215546Sopenharmony_ci case LLVMAtomicRMWBinOpAnd: 277bf215546Sopenharmony_ci binop = llvm::AtomicRMWInst::And; 278bf215546Sopenharmony_ci break; 279bf215546Sopenharmony_ci case LLVMAtomicRMWBinOpNand: 280bf215546Sopenharmony_ci binop = llvm::AtomicRMWInst::Nand; 281bf215546Sopenharmony_ci break; 282bf215546Sopenharmony_ci case LLVMAtomicRMWBinOpOr: 283bf215546Sopenharmony_ci binop = llvm::AtomicRMWInst::Or; 284bf215546Sopenharmony_ci break; 285bf215546Sopenharmony_ci case LLVMAtomicRMWBinOpXor: 286bf215546Sopenharmony_ci binop = llvm::AtomicRMWInst::Xor; 287bf215546Sopenharmony_ci break; 288bf215546Sopenharmony_ci case LLVMAtomicRMWBinOpMax: 289bf215546Sopenharmony_ci binop = llvm::AtomicRMWInst::Max; 290bf215546Sopenharmony_ci break; 291bf215546Sopenharmony_ci case LLVMAtomicRMWBinOpMin: 292bf215546Sopenharmony_ci binop = llvm::AtomicRMWInst::Min; 293bf215546Sopenharmony_ci break; 294bf215546Sopenharmony_ci case LLVMAtomicRMWBinOpUMax: 295bf215546Sopenharmony_ci binop = llvm::AtomicRMWInst::UMax; 296bf215546Sopenharmony_ci break; 297bf215546Sopenharmony_ci case LLVMAtomicRMWBinOpUMin: 298bf215546Sopenharmony_ci binop = llvm::AtomicRMWInst::UMin; 299bf215546Sopenharmony_ci break; 300bf215546Sopenharmony_ci case LLVMAtomicRMWBinOpFAdd: 301bf215546Sopenharmony_ci binop = llvm::AtomicRMWInst::FAdd; 302bf215546Sopenharmony_ci break; 303bf215546Sopenharmony_ci default: 304bf215546Sopenharmony_ci unreachable("invalid LLVMAtomicRMWBinOp"); 305bf215546Sopenharmony_ci break; 306bf215546Sopenharmony_ci } 307bf215546Sopenharmony_ci unsigned SSID = llvm::unwrap(ctx->context)->getOrInsertSyncScopeID(sync_scope); 308bf215546Sopenharmony_ci return llvm::wrap(llvm::unwrap(ctx->builder) 309bf215546Sopenharmony_ci ->CreateAtomicRMW(binop, llvm::unwrap(ptr), llvm::unwrap(val), 310bf215546Sopenharmony_ci#if LLVM_VERSION_MAJOR >= 13 311bf215546Sopenharmony_ci llvm::MaybeAlign(0), 312bf215546Sopenharmony_ci#endif 313bf215546Sopenharmony_ci llvm::AtomicOrdering::SequentiallyConsistent, SSID)); 314bf215546Sopenharmony_ci} 315bf215546Sopenharmony_ci 316bf215546Sopenharmony_ciLLVMValueRef ac_build_atomic_cmp_xchg(struct ac_llvm_context *ctx, LLVMValueRef ptr, 317bf215546Sopenharmony_ci LLVMValueRef cmp, LLVMValueRef val, const char *sync_scope) 318bf215546Sopenharmony_ci{ 319bf215546Sopenharmony_ci unsigned SSID = llvm::unwrap(ctx->context)->getOrInsertSyncScopeID(sync_scope); 320bf215546Sopenharmony_ci return llvm::wrap(llvm::unwrap(ctx->builder) 321bf215546Sopenharmony_ci ->CreateAtomicCmpXchg(llvm::unwrap(ptr), llvm::unwrap(cmp), 322bf215546Sopenharmony_ci llvm::unwrap(val), 323bf215546Sopenharmony_ci#if LLVM_VERSION_MAJOR >= 13 324bf215546Sopenharmony_ci llvm::MaybeAlign(0), 325bf215546Sopenharmony_ci#endif 326bf215546Sopenharmony_ci llvm::AtomicOrdering::SequentiallyConsistent, 327bf215546Sopenharmony_ci llvm::AtomicOrdering::SequentiallyConsistent, SSID)); 328bf215546Sopenharmony_ci} 329