1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
|
//===-- valueparser.cpp ---------------------------------------------------===//
//
// LDC – the LLVM D compiler
//
// This file is distributed under the Boost Software License. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
#include "valueparser.h"
#include <cassert>
#include <cstdint>
#include <string>
#include "utils.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/Support/raw_ostream.h"
namespace {
void checkOverrideType(
llvm::Type &type, llvm::Constant &val,
const llvm::function_ref<void(const std::string &)> &errHandler) {
auto retType = val.getType();
if (retType != &type) {
std::string str;
llvm::raw_string_ostream ss(str);
ss << "Override type mismatch, expected \"";
type.print(ss);
ss << "\", got \"";
retType->print(ss);
ss << "\"";
ss.flush();
errHandler(str);
}
}
template <typename T>
llvm::Constant *
callOverride(const ParseInitializerOverride &override, llvm::Type &type,
const T &val,
const llvm::function_ref<void(const std::string &)> &errHandler) {
if (override) {
auto ptr = reinterpret_cast<const char *>(&val);
auto ret = (*override)(type, ptr, sizeof(val));
if (ret != nullptr) {
checkOverrideType(type, *ret, errHandler);
}
return ret;
}
return nullptr;
}
llvm::Constant *
getBool(llvm::LLVMContext &context, const void *data, llvm::Type &type,
const llvm::function_ref<void(const std::string &)> &errHandler,
const ParseInitializerOverride &override) {
assert(nullptr != data);
const bool val = *static_cast<const bool *>(data);
if (auto ret = callOverride(override, type, val, errHandler)) {
return ret;
}
return llvm::ConstantInt::get(context, llvm::APInt(1, (val ? 1 : 0), true));
}
template <typename T>
llvm::Constant *
getInt(llvm::LLVMContext &context, const void *data, llvm::Type &type,
const llvm::function_ref<void(const std::string &)> &errHandler,
const ParseInitializerOverride &override) {
assert(nullptr != data);
const T val = *static_cast<const T *>(data);
if (auto ret = callOverride(override, type, val, errHandler)) {
return ret;
}
return llvm::ConstantInt::get(context, llvm::APInt(sizeof(T) * 8, val, true));
}
template <typename T>
llvm::Constant *
getFloat(llvm::LLVMContext &context, const void *data, llvm::Type &type,
const llvm::function_ref<void(const std::string &)> &errHandler,
const ParseInitializerOverride &override) {
assert(nullptr != data);
const T val = *static_cast<const T *>(data);
if (auto ret = callOverride(override, type, val, errHandler)) {
return ret;
}
return llvm::ConstantFP::get(context, llvm::APFloat(val));
}
llvm::Constant *
getPtr(llvm::LLVMContext &context, const void *data, llvm::Type &type,
const llvm::function_ref<void(const std::string &)> &errHandler,
const ParseInitializerOverride &override) {
assert(nullptr != data);
const auto val = *static_cast<const uintptr_t *>(data);
if (auto ret = callOverride(override, type, val, errHandler)) {
return ret;
}
return llvm::ConstantExpr::getIntToPtr(
llvm::ConstantInt::get(context, llvm::APInt(sizeof(val) * 8, val)),
&type);
}
llvm::Constant *
getStruct(const void *data, const llvm::DataLayout &dataLayout,
llvm::Type &type,
const llvm::function_ref<void(const std::string &)> &errHandler,
const ParseInitializerOverride &override) {
assert(nullptr != data);
if (override) {
auto size = dataLayout.getTypeStoreSize(&type);
auto ptr = static_cast<const char *>(data);
auto ret = (*override)(type, ptr, size);
if (ret != nullptr) {
checkOverrideType(type, *ret, errHandler);
return ret;
}
}
auto stype = llvm::cast<llvm::StructType>(&type);
auto slayout = dataLayout.getStructLayout(stype);
auto numElements = stype->getNumElements();
llvm::SmallVector<llvm::Constant *, 16> elements(numElements);
for (unsigned i = 0; i < numElements; ++i) {
const auto elemType = stype->getElementType(i);
const auto elemOffset = slayout->getElementOffset(i);
const auto elemPtr = static_cast<const char *>(data) + elemOffset;
elements[i] =
parseInitializer(dataLayout, *elemType, elemPtr, errHandler, override);
}
return llvm::ConstantStruct::get(stype, elements);
}
}
llvm::Constant *
parseInitializer(const llvm::DataLayout &dataLayout, llvm::Type &type,
const void *data,
llvm::function_ref<void(const std::string &)> errHandler,
const ParseInitializerOverride &override) {
assert(nullptr != data);
auto &llcontext = type.getContext();
if (type.isIntegerTy()) {
const auto width = type.getIntegerBitWidth();
switch (width) {
case 1:
return getBool(llcontext, data, type, errHandler, override);
case 8:
return getInt<uint8_t>(llcontext, data, type, errHandler, override);
case 16:
return getInt<uint16_t>(llcontext, data, type, errHandler, override);
case 32:
return getInt<uint32_t>(llcontext, data, type, errHandler, override);
case 64:
return getInt<uint64_t>(llcontext, data, type, errHandler, override);
default:
errHandler(std::string("Invalid int bit width: ") +
std::to_string(width));
return nullptr;
}
}
if (type.isFloatingPointTy()) {
const auto width = type.getPrimitiveSizeInBits();
switch (width) {
case 32:
return getFloat<float>(llcontext, data, type, errHandler, override);
case 64:
return getFloat<double>(llcontext, data, type, errHandler, override);
default:
errHandler(std::string("Invalid fp bit width: ") + std::to_string(width));
return nullptr;
}
}
if (type.isPointerTy()) {
return getPtr(llcontext, data, type, errHandler, override);
}
if (type.isStructTy()) {
return getStruct(data, dataLayout, type, errHandler, override);
}
if (type.isArrayTy()) {
auto elemType = type.getArrayElementType();
const auto step = dataLayout.getTypeAllocSize(elemType);
const auto numElements = type.getArrayNumElements();
llvm::SmallVector<llvm::Constant *, 16> elements(numElements);
for (uint64_t i = 0; i < numElements; ++i) {
const auto elemPtr = static_cast<const char *>(data) + step * i;
elements[i] = parseInitializer(dataLayout, *elemType, elemPtr, errHandler,
override);
}
return llvm::ConstantArray::get(llvm::cast<llvm::ArrayType>(&type),
elements);
}
std::string tname;
llvm::raw_string_ostream os(tname);
type.print(os, true);
errHandler(std::string("Unhandled type: ") + os.str());
return nullptr;
}
|