1//
2// Copyright 2016 Francisco Jerez
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20// OTHER DEALINGS IN THE SOFTWARE.
21//
22
23///
24/// \file
25/// Some thin wrappers around the Clang/LLVM API used to preserve
26/// compatibility with older API versions while keeping the ifdef clutter low
27/// in the rest of the clover::llvm subtree.  In case of an API break please
28/// consider whether it's possible to preserve backwards compatibility by
29/// introducing a new one-liner inline function or typedef here under the
30/// compat namespace in order to keep the running code free from preprocessor
31/// conditionals.
32///
33
34#ifndef CLOVER_LLVM_COMPAT_HPP
35#define CLOVER_LLVM_COMPAT_HPP
36
37#include "util/algorithm.hpp"
38
39#if HAVE_LLVM < 0x0400
40#include <llvm/Bitcode/ReaderWriter.h>
41#else
42#include <llvm/Bitcode/BitcodeReader.h>
43#include <llvm/Bitcode/BitcodeWriter.h>
44#endif
45
46#include <llvm/IR/LLVMContext.h>
47#include <llvm/Linker/Linker.h>
48#include <llvm/Transforms/IPO.h>
49#include <llvm/Transforms/Utils/Cloning.h>
50#include <llvm/Target/TargetMachine.h>
51#if HAVE_LLVM >= 0x0400
52#include <llvm/Support/Error.h>
53#else
54#include <llvm/Support/ErrorOr.h>
55#endif
56
57#include <llvm/IR/LegacyPassManager.h>
58#include <llvm/Analysis/TargetLibraryInfo.h>
59
60#include <clang/Basic/TargetInfo.h>
61#include <clang/Frontend/CompilerInstance.h>
62
63#if HAVE_LLVM >= 0x0800
64#include <clang/Basic/CodeGenOptions.h>
65#else
66#include <clang/Frontend/CodeGenOptions.h>
67#endif
68
69namespace clover {
70   namespace llvm {
71      namespace compat {
72         template<typename T, typename AS>
73         unsigned target_address_space(const T &target, const AS lang_as) {
74            const auto &map = target.getAddressSpaceMap();
75#if HAVE_LLVM >= 0x0500
76            return map[static_cast<unsigned>(lang_as)];
77#else
78            return map[lang_as - clang::LangAS::Offset];
79#endif
80         }
81
82#if HAVE_LLVM >= 0x0500
83         const clang::InputKind ik_opencl = clang::InputKind::OpenCL;
84         const clang::LangStandard::Kind lang_opencl10 = clang::LangStandard::lang_opencl10;
85#else
86         const clang::InputKind ik_opencl = clang::IK_OpenCL;
87         const clang::LangStandard::Kind lang_opencl10 = clang::LangStandard::lang_opencl;
88#endif
89
90         inline void
91         add_link_bitcode_file(clang::CodeGenOptions &opts,
92                               const std::string &path) {
93#if HAVE_LLVM >= 0x0500
94            clang::CodeGenOptions::BitcodeFileToLink F;
95
96            F.Filename = path;
97            F.PropagateAttrs = true;
98            F.LinkFlags = ::llvm::Linker::Flags::None;
99            opts.LinkBitcodeFiles.emplace_back(F);
100#else
101            opts.LinkBitcodeFiles.emplace_back(::llvm::Linker::Flags::None, path);
102#endif
103         }
104
105#if HAVE_LLVM >= 0x0600
106         const auto default_code_model = ::llvm::None;
107#else
108         const auto default_code_model = ::llvm::CodeModel::Default;
109#endif
110
111         template<typename M, typename F> void
112         handle_module_error(M &mod, const F &f) {
113#if HAVE_LLVM >= 0x0400
114            if (::llvm::Error err = mod.takeError())
115               ::llvm::handleAllErrors(std::move(err), [&](::llvm::ErrorInfoBase &eib) {
116                     f(eib.message());
117                  });
118#else
119            if (!mod)
120               f(mod.getError().message());
121#endif
122         }
123
124         template<typename T> void
125         set_diagnostic_handler(::llvm::LLVMContext &ctx,
126                                T *diagnostic_handler, void *data) {
127#if HAVE_LLVM >= 0x0600
128            ctx.setDiagnosticHandlerCallBack(diagnostic_handler, data);
129#else
130            ctx.setDiagnosticHandler(diagnostic_handler, data);
131#endif
132         }
133
134         inline std::unique_ptr< ::llvm::Module>
135         clone_module(const ::llvm::Module &mod)
136         {
137#if HAVE_LLVM >= 0x0700
138            return ::llvm::CloneModule(mod);
139#else
140            return ::llvm::CloneModule(&mod);
141#endif
142         }
143
144         template<typename T> void
145         write_bitcode_to_file(const ::llvm::Module &mod, T &os)
146         {
147#if HAVE_LLVM >= 0x0700
148            ::llvm::WriteBitcodeToFile(mod, os);
149#else
150            ::llvm::WriteBitcodeToFile(&mod, os);
151#endif
152         }
153
154         template<typename TM, typename PM, typename OS, typename FT>
155         bool add_passes_to_emit_file(TM &tm, PM &pm, OS &os, FT &ft)
156         {
157#if HAVE_LLVM >= 0x0700
158            return tm.addPassesToEmitFile(pm, os, nullptr, ft);
159#else
160            return tm.addPassesToEmitFile(pm, os, ft);
161#endif
162         }
163
164         template<typename T, typename M>
165         T get_abi_type(const T &arg_type, const M &mod) {
166#if HAVE_LLVM >= 0x0700
167            return arg_type;
168#else
169            ::llvm::DataLayout dl(&mod);
170            const unsigned arg_store_size = dl.getTypeStoreSize(arg_type);
171            return !arg_type->isIntegerTy() ? arg_type :
172               dl.getSmallestLegalIntType(mod.getContext(), arg_store_size * 8);
173#endif
174         }
175      }
176   }
177}
178
179#endif
180