summaryrefslogtreecommitdiff
path: root/src/gallium/drivers/radeon/radeon_llvm_emit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/drivers/radeon/radeon_llvm_emit.cpp')
-rw-r--r--src/gallium/drivers/radeon/radeon_llvm_emit.cpp145
1 files changed, 145 insertions, 0 deletions
diff --git a/src/gallium/drivers/radeon/radeon_llvm_emit.cpp b/src/gallium/drivers/radeon/radeon_llvm_emit.cpp
new file mode 100644
index 00000000000..1bc6a15610a
--- /dev/null
+++ b/src/gallium/drivers/radeon/radeon_llvm_emit.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors: Tom Stellard <thomas.stellard@amd.com>
+ *
+ */
+#include "radeon_llvm.h"
+
+#include <llvm/LLVMContext.h>
+#include <llvm/Module.h>
+#include <llvm/PassManager.h>
+#include <llvm/ADT/Triple.h>
+#include <llvm/Support/FormattedStream.h>
+#include <llvm/Support/Host.h>
+#include <llvm/Support/IRReader.h>
+#include <llvm/Support/SourceMgr.h>
+#include <llvm/Support/TargetRegistry.h>
+#include <llvm/Support/TargetSelect.h>
+#include <llvm/Target/TargetData.h>
+#include <llvm/Target/TargetMachine.h>
+
+#include <llvm/Transforms/Scalar.h>
+
+#include <llvm-c/Target.h>
+
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+
+using namespace llvm;
+
+#ifndef EXTERNAL_LLVM
+extern "C" {
+
+void LLVMInitializeAMDILTargetMC(void);
+void LLVMInitializeAMDILTarget(void);
+void LLVMInitializeAMDILTargetInfo(void);
+}
+#endif
+
+/**
+ * Compile an LLVM module to machine code.
+ *
+ * @param bytes This function allocates memory for the byte stream, it is the
+ * caller's responsibility to free it.
+ */
+extern "C" unsigned
+radeon_llvm_compile(LLVMModuleRef M, unsigned char ** bytes,
+ unsigned * byte_count, const char * gpu_family,
+ unsigned dump) {
+
+#if HAVE_LLVM > 0x0300
+ Triple AMDGPUTriple(sys::getDefaultTargetTriple());
+#else
+ Triple AMDGPUTriple(sys::getHostTriple());
+#endif
+
+
+#ifdef EXTERNAL_LLVM
+ /* XXX: Can we just initialize the AMDGPU target here? */
+ InitializeAllTargets();
+ InitializeAllTargetMCs();
+#else
+ LLVMInitializeAMDILTargetInfo();
+ LLVMInitializeAMDILTarget();
+ LLVMInitializeAMDILTargetMC();
+#endif
+ std::string err;
+ const Target * AMDGPUTarget = TargetRegistry::lookupTarget("r600", err);
+ fprintf(stderr, "%s\n", err.c_str());
+ if(!AMDGPUTarget) {
+ fprintf(stderr, "Can't find target\n");
+ return 1;
+ }
+
+ Triple::ArchType Arch = Triple::getArchTypeForLLVMName("r600");
+ if (Arch == Triple::UnknownArch) {
+ fprintf(stderr, "Unknown Arch\n");
+ }
+ AMDGPUTriple.setArch(Arch);
+
+ Module * mod = unwrap(M);
+ std::string FS = gpu_family;
+#if HAVE_LLVM > 0x0300
+ TargetOptions TO;
+#endif
+
+ std::auto_ptr<TargetMachine> tm(AMDGPUTarget->createTargetMachine(
+ AMDGPUTriple.getTriple(), gpu_family, "" /* Features */,
+ TO, Reloc::Default, CodeModel::Default,
+ CodeGenOpt::Default
+ ));
+ TargetMachine &AMDGPUTargetMachine = *tm.get();
+ /* XXX: Use TargetMachine.Options in 3.0 */
+ if (dump) {
+ mod->dump();
+ }
+ PassManager PM;
+ PM.add(new TargetData(*AMDGPUTargetMachine.getTargetData()));
+ PM.add(createPromoteMemoryToRegisterPass());
+ AMDGPUTargetMachine.setAsmVerbosityDefault(true);
+
+ std::string CodeString;
+ raw_string_ostream oStream(CodeString);
+ formatted_raw_ostream out(oStream);
+
+ /* Optional extra paramater true / false to disable verify */
+ if (AMDGPUTargetMachine.addPassesToEmitFile(PM, out, TargetMachine::CGFT_AssemblyFile,
+#if HAVE_LLVM <= 0x300
+ CodeGenOpt::Default,
+#endif
+ true)){
+ fprintf(stderr, "AddingPasses failed.\n");
+ return 1;
+ }
+ PM.run(*mod);
+
+ out.flush();
+ std::string &data = oStream.str();
+
+ *bytes = (unsigned char*)malloc(data.length() * sizeof(unsigned char));
+ memcpy(*bytes, data.c_str(), data.length() * sizeof(unsigned char));
+ *byte_count = data.length();
+
+ return 0;
+}