// // 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(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(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(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 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(F, B); } std::string getReturnTypeLocationReference(const llvm::Function *F, const PTMLCBuilder &B) { return getReturnTypeLocation(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(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 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(F, Index, B); } std::string getReturnStructFieldLocationReference(const llvm::Function *F, size_t Index, const PTMLCBuilder &B) { return getReturnStructFieldLocation(F, Index, B); } static std::string serializeHelperFunctionLocation(const llvm::Function *F) { return pipeline::serializedLocation(revng::ranks::HelperFunction, F->getName().str()); } template 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(F, B); } std::string getHelperFunctionLocationReference(const llvm::Function *F, const PTMLCBuilder &B) { return getHelperFunctionLocation(F, B); }