mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
243 lines
8.2 KiB
C++
243 lines
8.2 KiB
C++
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ADT/Twine.h"
|
|
#include "llvm/IR/DerivedTypes.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/Type.h"
|
|
|
|
#include "revng/Model/Binary.h"
|
|
#include "revng/Model/Identifier.h"
|
|
#include "revng/Pipeline/Location.h"
|
|
#include "revng/Support/Assert.h"
|
|
#include "revng/Support/FunctionTags.h"
|
|
|
|
#include "revng-c/Pipes/Ranks.h"
|
|
#include "revng-c/Support/FunctionTags.h"
|
|
#include "revng-c/Support/PTMLC.h"
|
|
#include "revng-c/TypeNames/LLVMTypeNames.h"
|
|
|
|
using llvm::Twine;
|
|
using PTMLCBuilder = ptml::PTMLCBuilder;
|
|
|
|
constexpr const char *const StructWrapperPrefix = "_artificial_struct_returned_"
|
|
"by_";
|
|
constexpr const char *const StructFieldPrefix = "field_";
|
|
|
|
namespace tokens = ptml::c::tokens;
|
|
namespace tags = ptml::tags;
|
|
namespace attributes = ptml::attributes;
|
|
|
|
bool isScalarCType(const llvm::Type *LLVMType) {
|
|
switch (LLVMType->getTypeID()) {
|
|
case llvm::Type::HalfTyID:
|
|
case llvm::Type::BFloatTyID:
|
|
case llvm::Type::FloatTyID:
|
|
case llvm::Type::DoubleTyID:
|
|
case llvm::Type::X86_FP80TyID:
|
|
case llvm::Type::FP128TyID:
|
|
case llvm::Type::PPC_FP128TyID:
|
|
case llvm::Type::VoidTyID:
|
|
case llvm::Type::PointerTyID:
|
|
return true;
|
|
|
|
case llvm::Type::IntegerTyID: {
|
|
auto *IntType = cast<llvm::IntegerType>(LLVMType);
|
|
switch (IntType->getIntegerBitWidth()) {
|
|
case 1:
|
|
case 8:
|
|
case 16:
|
|
case 32:
|
|
case 64:
|
|
case 128:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
} break;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
std::string getScalarCType(const llvm::Type *LLVMType, const PTMLCBuilder &B) {
|
|
revng_assert(isScalarCType(LLVMType));
|
|
using Operator = PTMLCBuilder::Operator;
|
|
switch (LLVMType->getTypeID()) {
|
|
case llvm::Type::HalfTyID:
|
|
case llvm::Type::BFloatTyID:
|
|
return B.tokenTag("float16_t", ptml::c::tokens::Type).serialize();
|
|
break;
|
|
case llvm::Type::FloatTyID:
|
|
return B.tokenTag("float32_t", ptml::c::tokens::Type).serialize();
|
|
break;
|
|
case llvm::Type::DoubleTyID:
|
|
return B.tokenTag("float64_t", ptml::c::tokens::Type).serialize();
|
|
break;
|
|
case llvm::Type::X86_FP80TyID:
|
|
// TODO: 80-bit float have 96 bit storage, how should we call them?
|
|
return B.tokenTag("float96_t", ptml::c::tokens::Type).serialize();
|
|
break;
|
|
case llvm::Type::FP128TyID:
|
|
case llvm::Type::PPC_FP128TyID:
|
|
return B.tokenTag("float128_t", ptml::c::tokens::Type).serialize();
|
|
break;
|
|
|
|
case llvm::Type::VoidTyID: {
|
|
return B.tokenTag("void", ptml::c::tokens::Type).serialize();
|
|
break;
|
|
|
|
case llvm::Type::IntegerTyID: {
|
|
auto *IntType = cast<llvm::IntegerType>(LLVMType);
|
|
switch (IntType->getIntegerBitWidth()) {
|
|
case 1:
|
|
return B.tokenTag("bool", ptml::c::tokens::Type).serialize();
|
|
case 8:
|
|
return B.tokenTag("uint8_t", ptml::c::tokens::Type).serialize();
|
|
case 16:
|
|
return B.tokenTag("uint16_t", ptml::c::tokens::Type).serialize();
|
|
break;
|
|
case 32:
|
|
return B.tokenTag("uint32_t", ptml::c::tokens::Type).serialize();
|
|
break;
|
|
case 64:
|
|
return B.tokenTag("uint64_t", ptml::c::tokens::Type).serialize();
|
|
break;
|
|
case 128:
|
|
return B.tokenTag("uint128_t", ptml::c::tokens::Type).serialize();
|
|
break;
|
|
default:
|
|
revng_abort("Found an LLVM integer with a size that is not a power of "
|
|
"two");
|
|
}
|
|
} break;
|
|
|
|
case llvm::Type::PointerTyID: {
|
|
return B.tokenTag("void", ptml::c::tokens::Type) + " "
|
|
+ B.getOperator(Operator::PointerDereference);
|
|
} break;
|
|
|
|
default:
|
|
revng_abort("Cannot convert this type directly to a C type.");
|
|
}
|
|
}
|
|
}
|
|
|
|
static std::string getHelperFunctionIdentifier(const llvm::Function *F) {
|
|
revng_assert(not FunctionTags::Isolated.isTagOf(F));
|
|
return (Twine("_") + model::Identifier::sanitize(F->getName())).str();
|
|
}
|
|
|
|
static std::string getReturnedStructIdentifier(const llvm::Function *F) {
|
|
revng_assert(not FunctionTags::Isolated.isTagOf(F));
|
|
revng_assert(llvm::isa<llvm::StructType>(F->getReturnType()));
|
|
return (Twine(StructWrapperPrefix) + Twine(getHelperFunctionIdentifier(F)))
|
|
.str();
|
|
}
|
|
|
|
static std::string serializeHelperStructLocation(const std::string &Name) {
|
|
return pipeline::serializedLocation(revng::ranks::HelperStructType, Name);
|
|
}
|
|
|
|
template<bool IsDefinition>
|
|
static std::string
|
|
getReturnTypeLocation(const llvm::Function *F, const PTMLCBuilder &B) {
|
|
auto *RetType = F->getReturnType();
|
|
// Isolated functions' return types must be converted using model types
|
|
revng_assert(not FunctionTags::Isolated.isTagOf(F));
|
|
|
|
if (RetType->isAggregateType()) {
|
|
std::string StructName = getReturnedStructIdentifier(F);
|
|
return B.tokenTag(StructName, ptml::c::tokens::Type)
|
|
.addAttribute(B.getLocationAttribute(IsDefinition),
|
|
serializeHelperStructLocation(StructName))
|
|
.serialize();
|
|
} else {
|
|
return getScalarCType(RetType, B);
|
|
}
|
|
}
|
|
|
|
std::string getReturnTypeLocationDefinition(const llvm::Function *F,
|
|
const PTMLCBuilder &B) {
|
|
return getReturnTypeLocation<false>(F, B);
|
|
}
|
|
|
|
std::string getReturnTypeLocationReference(const llvm::Function *F,
|
|
const PTMLCBuilder &B) {
|
|
return getReturnTypeLocation<true>(F, B);
|
|
}
|
|
|
|
std::string getReturnStructFieldType(const llvm::Function *F,
|
|
size_t Index,
|
|
const PTMLCBuilder &B) {
|
|
revng_assert(not FunctionTags::Isolated.isTagOf(F));
|
|
auto *StructTy = llvm::cast<llvm::StructType>(F->getReturnType());
|
|
return getScalarCType(StructTy->getTypeAtIndex(Index), B);
|
|
}
|
|
|
|
static std::string
|
|
serializeHelperStructFieldLocation(const std::string &StructName,
|
|
const std::string &FieldName) {
|
|
revng_assert(not StructName.empty() and not FieldName.empty());
|
|
return pipeline::serializedLocation(revng::ranks::HelperStructField,
|
|
StructName,
|
|
FieldName);
|
|
}
|
|
|
|
template<bool IsDefinition>
|
|
static std::string getReturnStructFieldLocation(const llvm::Function *F,
|
|
size_t Index,
|
|
const PTMLCBuilder &B) {
|
|
revng_assert(not FunctionTags::Isolated.isTagOf(F));
|
|
revng_assert(F->getReturnType()->isStructTy());
|
|
|
|
std::string StructName = getReturnedStructIdentifier(F);
|
|
std::string FieldName = (Twine(StructFieldPrefix) + Twine(Index)).str();
|
|
return B.getTag(ptml::tags::Span, FieldName)
|
|
.addAttribute(attributes::Token, tokens::Field)
|
|
.addAttribute(B.getLocationAttribute(IsDefinition),
|
|
serializeHelperStructFieldLocation(StructName, FieldName))
|
|
.serialize();
|
|
}
|
|
|
|
std::string getReturnStructFieldLocationDefinition(const llvm::Function *F,
|
|
size_t Index,
|
|
const PTMLCBuilder &B) {
|
|
return getReturnStructFieldLocation<true>(F, Index, B);
|
|
}
|
|
|
|
std::string getReturnStructFieldLocationReference(const llvm::Function *F,
|
|
size_t Index,
|
|
const PTMLCBuilder &B) {
|
|
return getReturnStructFieldLocation<false>(F, Index, B);
|
|
}
|
|
|
|
static std::string serializeHelperFunctionLocation(const llvm::Function *F) {
|
|
return pipeline::serializedLocation(revng::ranks::HelperFunction,
|
|
F->getName().str());
|
|
}
|
|
|
|
template<bool IsDefinition>
|
|
static std::string
|
|
getHelperFunctionLocation(const llvm::Function *F, const PTMLCBuilder &B) {
|
|
return B.tokenTag(getHelperFunctionIdentifier(F), ptml::c::tokens::Function)
|
|
.addAttribute(B.getLocationAttribute(IsDefinition),
|
|
serializeHelperFunctionLocation(F))
|
|
.serialize();
|
|
}
|
|
|
|
std::string getHelperFunctionLocationDefinition(const llvm::Function *F,
|
|
const PTMLCBuilder &B) {
|
|
return getHelperFunctionLocation<true>(F, B);
|
|
}
|
|
|
|
std::string getHelperFunctionLocationReference(const llvm::Function *F,
|
|
const PTMLCBuilder &B) {
|
|
return getHelperFunctionLocation<false>(F, B);
|
|
}
|