mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
Migrate Clift users to CDataModel
This commit is contained in:
@@ -9,8 +9,6 @@
|
||||
|
||||
#include "revng/Clift/Clift.h"
|
||||
#include "revng/PTML/CTokenEmitter.h"
|
||||
#include "revng/Support/CTarget.h"
|
||||
#include "revng/Support/CDataModel.h"
|
||||
|
||||
void decompile(clift::FunctionOp Function,
|
||||
ptml::CTokenEmitter &Emitter,
|
||||
const TargetCImplementation &Target);
|
||||
void decompile(clift::FunctionOp Function, ptml::CTokenEmitter &Emitter);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "revng/Clift/Clift.h"
|
||||
#include "revng/PTML/CDoxygenEmitter.h"
|
||||
#include "revng/PTML/CTokenEmitter.h"
|
||||
#include "revng/Support/CTarget.h"
|
||||
#include "revng/Support/CDataModel.h"
|
||||
|
||||
template<typename Type>
|
||||
concept EntityWithComment = requires(Type const &Value) {
|
||||
@@ -20,12 +20,11 @@ protected:
|
||||
using CTE = ptml::CTokenEmitter;
|
||||
|
||||
ptml::CTokenEmitter &Tokens;
|
||||
const TargetCImplementation &Target;
|
||||
const CDataModel &DataModel;
|
||||
|
||||
public:
|
||||
explicit CEmitter(ptml::CTokenEmitter &Emitter,
|
||||
const TargetCImplementation &Target) :
|
||||
Tokens(Emitter), Target(Target) {}
|
||||
explicit CEmitter(ptml::CTokenEmitter &Emitter, const CDataModel &DataModel) :
|
||||
Tokens(Emitter), DataModel(DataModel) {}
|
||||
|
||||
//===------------------------------- Types ------------------------------===//
|
||||
|
||||
|
||||
@@ -5,9 +5,8 @@
|
||||
//
|
||||
|
||||
#include "revng/Clift/Clift.h"
|
||||
#include "revng/Support/CTarget.h"
|
||||
#include "revng/Support/CDataModel.h"
|
||||
|
||||
// TODO: does this really belong with the emitters?
|
||||
|
||||
mlir::LogicalResult verifyCSemantics(mlir::ModuleOp Module,
|
||||
const TargetCImplementation &Target);
|
||||
mlir::LogicalResult verifyCSemantics(mlir::ModuleOp Module);
|
||||
|
||||
@@ -10,10 +10,8 @@
|
||||
#include "revng/PTML/CTokenEmitter.h"
|
||||
|
||||
void emitTypeAndGlobalHeader(ptml::CTokenEmitter &Tokens,
|
||||
const TargetCImplementation &Target,
|
||||
mlir::ModuleOp Module,
|
||||
TypeEmitterConfiguration Configuration);
|
||||
|
||||
void emitHelperHeader(ptml::CTokenEmitter &Tokens,
|
||||
const TargetCImplementation &Target,
|
||||
llvm::ArrayRef<mlir::ModuleOp> Modules);
|
||||
|
||||
@@ -18,9 +18,9 @@ private:
|
||||
|
||||
public:
|
||||
explicit TypeDefinitionEmitter(ptml::CTokenEmitter &Tokens,
|
||||
const TargetCImplementation &Target,
|
||||
const CDataModel &DataModel,
|
||||
TypeEmitterConfiguration Configuration) :
|
||||
CEmitter(Tokens, Target), Configuration(Configuration) {}
|
||||
CEmitter(Tokens, DataModel), Configuration(Configuration) {}
|
||||
|
||||
private:
|
||||
void emitTypeKeyword(clift::DefinedType Type);
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
//
|
||||
|
||||
#include "revng/Clift/Clift.h"
|
||||
#include "revng/Support/CTarget.h"
|
||||
|
||||
namespace clift {
|
||||
|
||||
mlir::LogicalResult legalizeForC(clift::FunctionOp Function,
|
||||
const TargetCImplementation &Target);
|
||||
mlir::LogicalResult legalizeForC(clift::FunctionOp Function);
|
||||
|
||||
} // namespace clift
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "mlir/Pass/Pass.h"
|
||||
|
||||
#include "revng/Clift/Clift.h"
|
||||
#include "revng/Support/CTarget.h"
|
||||
|
||||
namespace clift {
|
||||
|
||||
@@ -29,8 +28,7 @@ PassPtr<clift::FunctionOp> createEmitFieldAccessesPass();
|
||||
|
||||
PassPtr<clift::FunctionOp> createTerminalBranchComplementHoistingPass();
|
||||
|
||||
PassPtr<clift::FunctionOp>
|
||||
createCLegalizationPass(const TargetCImplementation &Target);
|
||||
PassPtr<clift::FunctionOp> createCLegalizationPass();
|
||||
|
||||
PassPtr<clift::FunctionOp> createImmediateRadixDeductionPass();
|
||||
|
||||
|
||||
@@ -58,9 +58,7 @@ def CliftTerminalBranchComplementHoisting
|
||||
|
||||
def CliftCLegalization : Clift_Pass<"c-legalization", "clift::FunctionOp"> {
|
||||
let summary = "Legalize the input for emitting C code.";
|
||||
|
||||
// Use the default target C implementation for clift-opt:
|
||||
let constructor = "clift::createCLegalizationPass(TargetCImplementation::Default)";
|
||||
let constructor = "clift::createCLegalizationPass()";
|
||||
}
|
||||
|
||||
def CliftImmediateRadixDeduction : Clift_Pass<"deduce-immediate-radices",
|
||||
|
||||
@@ -13,12 +13,14 @@ inline uint64_t getExplicitPointerSize(const model::Binary &Model) {
|
||||
if (Model.Architecture() == model::Architecture::Invalid)
|
||||
return 0;
|
||||
|
||||
uint64_t PointerSize = getPointerSize(Model.Architecture());
|
||||
uint64_t BinaryPointerSize = getPointerSize(Model.Architecture());
|
||||
uint64_t TargetPointerSize = getPointerSize(getArchitecture(Model
|
||||
.targetABI()));
|
||||
|
||||
// Currently we hardcode the target pointer size as 8 (64-bit), so there is
|
||||
// no reason to emit explicit pointer sizes for binaries with matching size.
|
||||
if (PointerSize == 8)
|
||||
// If the binary and target pointer sizes match, there is no need to emit
|
||||
// explicit pointer sizes.
|
||||
if (BinaryPointerSize == TargetPointerSize)
|
||||
return 0;
|
||||
|
||||
return PointerSize;
|
||||
return TargetPointerSize;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#include "revng/PTML/Constants.h"
|
||||
#include "revng/PTML/PTMLEmitter.h"
|
||||
#include "revng/Support/CTarget.h"
|
||||
#include "revng/Support/CDataModel.h"
|
||||
|
||||
namespace ptml {
|
||||
|
||||
@@ -194,7 +194,7 @@ public:
|
||||
|
||||
struct IntegerSuffix {
|
||||
bool Unsigned;
|
||||
CIntegerKind MinimumType;
|
||||
CStandardType MinimumType;
|
||||
};
|
||||
|
||||
/// \pre \param Radix must be one of 2, 8, 10 or 16.
|
||||
|
||||
+10
-12
@@ -75,7 +75,7 @@ public:
|
||||
|
||||
void emitIntegerLiteral(uint64_t Value,
|
||||
bool IsSigned,
|
||||
CIntegerKind CKind,
|
||||
CStandardType Type,
|
||||
unsigned Radix) {
|
||||
if (IsSigned and static_cast<int64_t>(Value) < 0) {
|
||||
Tokens.emitOperator(ptml::CTokenEmitter::Operator::Minus);
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
|
||||
Tokens.emitIntegerLiteral(llvm::APInt(64, Value, IsSigned),
|
||||
CTE::IntegerSuffix{ .Unsigned = not IsSigned,
|
||||
.MinimumType = CKind },
|
||||
.MinimumType = Type },
|
||||
Radix);
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ public:
|
||||
Radix = mlir::cast<mlir::IntegerAttr>(Attr).getValue().getZExtValue();
|
||||
|
||||
auto IntType = mlir::cast<IntegerType>(Type);
|
||||
auto CKind = CIntegerKind::Int;
|
||||
auto CType = CStandardType::Int;
|
||||
|
||||
// Using any specific integer suffix is only required when the value is not
|
||||
// immediately converted to another integer type. While such casts are
|
||||
@@ -132,12 +132,12 @@ public:
|
||||
auto Cast = getOnlyUser<CastOpInterface>(V);
|
||||
if (not Cast
|
||||
or not unwrapped_isa<IntegralType>(Cast.getResult().getType())) {
|
||||
auto K = Target.getIntegerKind(IntType.getSize());
|
||||
revng_assert(K, "Integer immediate not representable in C.");
|
||||
CKind = *K;
|
||||
auto Range = DataModel.getStandardIntegerRange(IntType.getSize());
|
||||
revng_assert(Range, "Integer immediate not representable in C.");
|
||||
CType = Range->first;
|
||||
}
|
||||
|
||||
emitIntegerLiteral(E.getValue(), IntType.isSigned(), CKind, Radix);
|
||||
emitIntegerLiteral(E.getValue(), IntType.isSigned(), CType, Radix);
|
||||
rc_return;
|
||||
}
|
||||
|
||||
@@ -983,7 +983,7 @@ public:
|
||||
Parent.emitCStyleCast(Type);
|
||||
}
|
||||
|
||||
Parent.emitIntegerLiteral(Value, IsSigned, CIntegerKind::Int, Radix);
|
||||
Parent.emitIntegerLiteral(Value, IsSigned, CStandardType::Int, Radix);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1279,8 +1279,6 @@ public:
|
||||
|
||||
} // namespace
|
||||
|
||||
void decompile(FunctionOp Function,
|
||||
ptml::CTokenEmitter &Emitter,
|
||||
const TargetCImplementation &Target) {
|
||||
CliftToCEmitter(Emitter, Target).emitFunction(Function);
|
||||
void decompile(FunctionOp Function, ptml::CTokenEmitter &Emitter) {
|
||||
CliftToCEmitter(Emitter, getDataModel(Function)).emitFunction(Function);
|
||||
}
|
||||
|
||||
@@ -46,10 +46,12 @@ struct CEmissionPass : BaseT<CEmissionPass<BaseT, Impl>> {
|
||||
if (not File)
|
||||
return Base::signalPassFailure();
|
||||
|
||||
mlir::ModuleOp Module = Base::getOperation();
|
||||
|
||||
auto Tagging = static_cast<ptml::Tagging>(Base::EmitTags.getValue());
|
||||
ptml::CTokenEmitter Emitter(File->os(), Tagging);
|
||||
|
||||
if (not std::invoke(Impl, Base::getOperation(), Emitter))
|
||||
if (not Impl(Module, Emitter))
|
||||
return Base::signalPassFailure();
|
||||
}
|
||||
};
|
||||
@@ -59,11 +61,9 @@ struct CEmissionPass : BaseT<CEmissionPass<BaseT, Impl>> {
|
||||
clift::PassPtr<mlir::ModuleOp> clift::createEmitCPass() {
|
||||
static constexpr auto Impl = [](mlir::ModuleOp Module,
|
||||
ptml::CTokenEmitter &Emitter) {
|
||||
const auto &Target = TargetCImplementation::Default;
|
||||
|
||||
Module->walk([&Emitter](clift::FunctionOp Function) {
|
||||
if (not Function.isExternal())
|
||||
decompile(Function, Emitter, Target);
|
||||
decompile(Function, Emitter);
|
||||
});
|
||||
|
||||
return true;
|
||||
@@ -84,11 +84,7 @@ clift::PassPtr<mlir::ModuleOp> clift::createEmitTypeAndGlobalHeaderPass() {
|
||||
.ExplicitPadding = true,
|
||||
};
|
||||
|
||||
// TODO: select target properly
|
||||
const auto &Target = TargetCImplementation::Default;
|
||||
|
||||
emitTypeAndGlobalHeader(Tokens, Target, Module, Configuration);
|
||||
|
||||
emitTypeAndGlobalHeader(Tokens, Module, Configuration);
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -101,11 +97,7 @@ using HHBase = clift::impl::CliftEmitHelperHeaderBase<T>;
|
||||
clift::PassPtr<mlir::ModuleOp> clift::createEmitHelperHeaderPass() {
|
||||
static constexpr auto Impl = [](mlir::ModuleOp Module,
|
||||
ptml::CTokenEmitter &Tokens) {
|
||||
// TODO: select target properly
|
||||
const auto &Target = TargetCImplementation::Default;
|
||||
|
||||
emitHelperHeader(Tokens, Target, { Module });
|
||||
|
||||
emitHelperHeader(Tokens, { Module });
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ private:
|
||||
Parent.emitPrimitiveType(T);
|
||||
NeedSpace = true;
|
||||
} else if (auto T = mlir::dyn_cast<PointerType>(Type)) {
|
||||
if (T.getPointerSize() == Parent.Target.PointerSize) {
|
||||
if (T.getPointerSize() == Parent.DataModel.PointerSize) {
|
||||
Item.Kind = StackItemKind::Pointer;
|
||||
Type = T.getPointeeType();
|
||||
} else {
|
||||
|
||||
@@ -32,12 +32,12 @@ static clift::PointerType getPointerOperationType(mlir::Operation *Op) {
|
||||
}
|
||||
|
||||
class CVerifier : public ModuleVisitor<CVerifier> {
|
||||
public:
|
||||
explicit CVerifier(const TargetCImplementation &Target) : Target(Target) {}
|
||||
std::optional<CDataModel> DataModel;
|
||||
|
||||
public:
|
||||
mlir::LogicalResult visitNestedOp(mlir::Operation *Op) {
|
||||
if (auto T = getPointerOperationType(Op)) {
|
||||
if (T.getPointerSize() != Target.PointerSize)
|
||||
if (T.getPointerSize() != DataModel->PointerSize)
|
||||
return getCurrentOp()->emitOpError() << "Pointer operation is not "
|
||||
"representable in the target "
|
||||
"implementation.";
|
||||
@@ -65,6 +65,11 @@ public:
|
||||
return mlir::success();
|
||||
}
|
||||
|
||||
mlir::LogicalResult visitModuleOp(mlir::ModuleOp Op) {
|
||||
DataModel = getDataModel(Op);
|
||||
return mlir::success();
|
||||
}
|
||||
|
||||
private:
|
||||
static bool isPromotingOp(mlir::Operation *Op) {
|
||||
return mlir::isa<NegOp,
|
||||
@@ -94,25 +99,20 @@ private:
|
||||
}
|
||||
|
||||
bool isPotentiallyPromotingType(mlir::Type Type) {
|
||||
if (auto IntType = clift::unwrapped_dyn_cast<IntegerType>(Type)) {
|
||||
auto Integer = Target.getIntegerKind(IntType.getSize());
|
||||
return not Integer or *Integer < CIntegerKind::Int;
|
||||
}
|
||||
if (auto IntType = clift::unwrapped_dyn_cast<IntegerType>(Type))
|
||||
return IntType.getSize() < DataModel->getIntSize();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isCanonicalBooleanType(mlir::Type Type) {
|
||||
if (auto IntType = clift::unwrapped_dyn_cast<IntegerType>(Type))
|
||||
return Target.getIntegerKind(IntType.getSize()) == CIntegerKind::Int;
|
||||
return IntType.getSize() == DataModel->getIntSize();
|
||||
return false;
|
||||
}
|
||||
|
||||
const TargetCImplementation &Target;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
mlir::LogicalResult verifyCSemantics(mlir::ModuleOp Module,
|
||||
const TargetCImplementation &Target) {
|
||||
return CVerifier::visit(Module, Target);
|
||||
mlir::LogicalResult verifyCSemantics(mlir::ModuleOp Module) {
|
||||
return CVerifier::visit(Module);
|
||||
}
|
||||
|
||||
@@ -16,9 +16,9 @@ namespace {
|
||||
|
||||
struct VerifyCPass : clift::impl::CliftVerifyCBase<VerifyCPass> {
|
||||
void runOnOperation() override {
|
||||
const auto &Target = TargetCImplementation::Default;
|
||||
mlir::ModuleOp Module = getOperation();
|
||||
|
||||
if (mlir::failed(verifyCSemantics(getOperation(), Target)))
|
||||
if (mlir::failed(verifyCSemantics(Module)))
|
||||
signalPassFailure();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -17,9 +17,9 @@ class CHeaderEmitterImpl : TypeDefinitionEmitter {
|
||||
|
||||
public:
|
||||
explicit CHeaderEmitterImpl(ptml::CTokenEmitter &Tokens,
|
||||
const TargetCImplementation &Target,
|
||||
const CDataModel &DataModel,
|
||||
TypeEmitterConfiguration Configuration) :
|
||||
TypeDefinitionEmitter(Tokens, Target, Configuration) {}
|
||||
TypeDefinitionEmitter(Tokens, DataModel, Configuration) {}
|
||||
|
||||
public:
|
||||
void emitHeaderPrologue() {
|
||||
@@ -135,8 +135,6 @@ public:
|
||||
|
||||
public:
|
||||
void emitHelpers(llvm::ArrayRef<mlir::ModuleOp> Modules) {
|
||||
revng_check(not Modules.empty());
|
||||
|
||||
// TODO: emit `#include`s
|
||||
|
||||
auto Graph = TypeDependencyGraph::makeHelperGraph(Modules);
|
||||
@@ -179,10 +177,11 @@ public:
|
||||
};
|
||||
|
||||
void emitTypeAndGlobalHeader(ptml::CTokenEmitter &Tokens,
|
||||
const TargetCImplementation &Target,
|
||||
mlir::ModuleOp Module,
|
||||
TypeEmitterConfiguration Configuration) {
|
||||
CHeaderEmitterImpl Emitter(Tokens, Target, Configuration);
|
||||
CHeaderEmitterImpl Emitter(Tokens,
|
||||
clift::getDataModel(Module),
|
||||
Configuration);
|
||||
|
||||
Emitter.emitHeaderPrologue();
|
||||
Emitter.emitCommonIncludes();
|
||||
@@ -195,13 +194,20 @@ void emitTypeAndGlobalHeader(ptml::CTokenEmitter &Tokens,
|
||||
}
|
||||
|
||||
void emitHelperHeader(ptml::CTokenEmitter &Tokens,
|
||||
const TargetCImplementation &Target,
|
||||
llvm::ArrayRef<mlir::ModuleOp> Modules) {
|
||||
revng_check(not Modules.empty());
|
||||
|
||||
const CDataModel &DataModel = clift::getDataModel(Modules.front());
|
||||
revng_assert(llvm::all_of(Modules.drop_front(),
|
||||
[&DataModel](mlir::ModuleOp Module) {
|
||||
return clift::getDataModel(Module) == DataModel;
|
||||
}));
|
||||
|
||||
TypeEmitterConfiguration Configuration = {
|
||||
.ExplicitPadding = true,
|
||||
};
|
||||
|
||||
CHeaderEmitterImpl Emitter(Tokens, Target, Configuration);
|
||||
CHeaderEmitterImpl Emitter(Tokens, DataModel, Configuration);
|
||||
|
||||
Emitter.emitHeaderPrologue();
|
||||
Emitter.emitHelpers(Modules);
|
||||
|
||||
@@ -273,7 +273,7 @@ void TypeDefinitionEmitter::emitEnumDefinition(clift::EnumType Enum) {
|
||||
Tokens.emitIntegerLiteral(llvm::APInt{ 64, Value },
|
||||
ptml::CTokenEmitter::IntegerSuffix{
|
||||
.Unsigned = true,
|
||||
.MinimumType = CIntegerKind::Int,
|
||||
.MinimumType = CStandardType::Int,
|
||||
},
|
||||
16);
|
||||
|
||||
|
||||
@@ -36,12 +36,10 @@ public:
|
||||
void run(pipeline::ExecutionContext &EC,
|
||||
const pipes::CliftFunctionContainer &CliftFunctionContainer,
|
||||
pipes::DecompileStringMap &DecompiledFunctionsContainer) {
|
||||
const auto &Target = TargetCImplementation::Default;
|
||||
|
||||
mlir::ModuleOp Module = CliftFunctionContainer.getModule();
|
||||
const auto &Model = *revng::getModelFromContext(EC);
|
||||
|
||||
revng_assert(verifyCSemantics(Module, Target).succeeded());
|
||||
const auto &Model = *revng::getModelFromContext(EC);
|
||||
revng_assert(verifyCSemantics(Module).succeeded());
|
||||
|
||||
std::unordered_map<MetaAddress, clift::FunctionOp> Functions;
|
||||
Module->walk([&](clift::FunctionOp F) {
|
||||
@@ -62,7 +60,7 @@ public:
|
||||
{
|
||||
llvm::raw_string_ostream OS(Code);
|
||||
ptml::CTokenEmitter Emitter(OS, ptml::Tagging::Enabled);
|
||||
decompile(It->second, Emitter, Target);
|
||||
decompile(It->second, Emitter);
|
||||
}
|
||||
|
||||
DecompiledFunctionsContainer.insert_or_assign(Function.Entry(),
|
||||
@@ -88,18 +86,16 @@ EmitC::EmitC(const Model &Model,
|
||||
void EmitC::runOnFunction(const model::Function &Function) {
|
||||
using namespace clift;
|
||||
|
||||
const auto &Target = TargetCImplementation::Default;
|
||||
ObjectID Object(Function.Entry());
|
||||
|
||||
mlir::ModuleOp Module = Input.getModule(Object);
|
||||
revng_assert(verifyCSemantics(Module, Target).succeeded());
|
||||
|
||||
revng_assert(verifyCSemantics(Module).succeeded());
|
||||
FunctionOp MLIRFunction = getUniqueIsolatedFunction(Module, Function.Entry());
|
||||
|
||||
{
|
||||
auto OS = Output.getOStream(Object);
|
||||
ptml::CTokenEmitter Emitter(*OS, ptml::Tagging::Enabled);
|
||||
decompile(MLIRFunction, Emitter, Target);
|
||||
}
|
||||
auto OS = Output.getOStream(Object);
|
||||
ptml::CTokenEmitter Emitter(*OS, ptml::Tagging::Enabled);
|
||||
decompile(MLIRFunction, Emitter);
|
||||
}
|
||||
|
||||
} // namespace revng::pypeline::piperuns
|
||||
|
||||
@@ -100,7 +100,7 @@ struct TargetOptimizationPipe {
|
||||
static constexpr auto Name = "clift-target-optimization";
|
||||
|
||||
static void configurePassManager(mlir::PassManager &PM) {
|
||||
PM.addPass(clift::createCLegalizationPass(TargetCImplementation::Default));
|
||||
PM.addPass(clift::createCLegalizationPass());
|
||||
PM.addPass(clift::createImmediateRadixDeductionPass());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
|
||||
|
||||
#include "revng/Clift/CliftOpHelpers.h"
|
||||
#include "revng/CliftTransforms/Expressions.h"
|
||||
#include "revng/CliftTransforms/Legalization.h"
|
||||
#include "revng/CliftTransforms/Passes.h"
|
||||
|
||||
@@ -19,19 +20,10 @@ using namespace clift;
|
||||
namespace {
|
||||
|
||||
static IntegerType getIntType(mlir::MLIRContext *Context,
|
||||
const TargetCImplementation &Target) {
|
||||
return IntegerType::get(Context, IntegerKind::Signed, Target.getIntSize());
|
||||
const CDataModel &DataModel) {
|
||||
return IntegerType::get(Context, IntegerKind::Signed, DataModel.getIntSize());
|
||||
}
|
||||
|
||||
struct TargetInfo {
|
||||
const TargetCImplementation &Target;
|
||||
IntegerType IntType;
|
||||
|
||||
explicit TargetInfo(mlir::MLIRContext *Context,
|
||||
const TargetCImplementation &Target) :
|
||||
Target(Target), IntType(getIntType(Context, Target)) {}
|
||||
};
|
||||
|
||||
static mlir::OpOperand &getOnlyUse(mlir::Value Value) {
|
||||
revng_assert(Value.hasOneUse());
|
||||
return *Value.use_begin();
|
||||
@@ -104,9 +96,9 @@ struct PointerResizePattern : mlir::OpRewritePattern<OpT> {
|
||||
uint64_t TargetPointerSize;
|
||||
|
||||
explicit PointerResizePattern(mlir::MLIRContext *Context,
|
||||
const TargetInfo &Target) :
|
||||
const CDataModel &DataModel) :
|
||||
mlir::OpRewritePattern<OpT>(Context),
|
||||
TargetPointerSize(Target.Target.PointerSize) {}
|
||||
TargetPointerSize(DataModel.PointerSize) {}
|
||||
|
||||
clift::PointerType
|
||||
makeTargetPointerType(clift::PointerType OldPointerType) const {
|
||||
@@ -256,9 +248,9 @@ struct BooleanCanonicalizationPattern
|
||||
IntegerType IntType;
|
||||
|
||||
explicit BooleanCanonicalizationPattern(mlir::MLIRContext *Context,
|
||||
const TargetInfo &Target) :
|
||||
const CDataModel &DataModel) :
|
||||
mlir::OpTraitRewritePattern<clift::ReturnsBoolean>(Context),
|
||||
IntType(Target.IntType) {}
|
||||
IntType(getIntType(Context, DataModel)) {}
|
||||
|
||||
mlir::LogicalResult
|
||||
matchAndRewrite(mlir::Operation *Op,
|
||||
@@ -281,8 +273,9 @@ struct ArithmeticPromotionPattern : mlir::OpRewritePattern<OpT> {
|
||||
IntegerType IntType;
|
||||
|
||||
explicit ArithmeticPromotionPattern(mlir::MLIRContext *Context,
|
||||
const TargetInfo &Target) :
|
||||
mlir::OpRewritePattern<OpT>(Context), IntType(Target.IntType) {}
|
||||
const CDataModel &DataModel) :
|
||||
mlir::OpRewritePattern<OpT>(Context),
|
||||
IntType(getIntType(Context, DataModel)) {}
|
||||
|
||||
mlir::LogicalResult tryPromoteTypes(mlir::PatternRewriter &Rewriter,
|
||||
clift::ExpressionOpInterface Op,
|
||||
@@ -335,14 +328,11 @@ struct ShiftPromotionPattern : ArithmeticPromotionPattern<OpT> {
|
||||
// * 0 -> (my_enum)0, where the original expression has type my_enum and my_enum
|
||||
// does not have an enumerator with a value of 0.
|
||||
struct ImmediateCastPattern : mlir::OpRewritePattern<ImmediateOp> {
|
||||
const TargetCImplementation &Target;
|
||||
uint64_t IntSize;
|
||||
const CDataModel &DataModel;
|
||||
|
||||
explicit ImmediateCastPattern(mlir::MLIRContext *Context,
|
||||
const TargetInfo &Target) :
|
||||
mlir::OpRewritePattern<ImmediateOp>(Context),
|
||||
Target(Target.Target),
|
||||
IntSize(Target.IntType.getSize()) {}
|
||||
const CDataModel &DataModel) :
|
||||
mlir::OpRewritePattern<ImmediateOp>(Context), DataModel(DataModel) {}
|
||||
|
||||
mlir::LogicalResult rewriteWithCast(ImmediateOp Op,
|
||||
mlir::Type NewImmediateType,
|
||||
@@ -370,8 +360,8 @@ struct ImmediateCastPattern : mlir::OpRewritePattern<ImmediateOp> {
|
||||
}
|
||||
|
||||
bool isRepresentableLiteralSize(uint64_t Size) const {
|
||||
auto C = Target.getIntegerKind(Size);
|
||||
return C and CIntegerKind::Int <= *C and *C <= CIntegerKind::LongLong;
|
||||
auto Range = DataModel.getStandardIntegerRange(Size);
|
||||
return Range and Range->second >= CStandardType::Int;
|
||||
}
|
||||
|
||||
mlir::LogicalResult
|
||||
@@ -382,7 +372,9 @@ struct ImmediateCastPattern : mlir::OpRewritePattern<ImmediateOp> {
|
||||
return mlir::failure();
|
||||
|
||||
// Sizes in the range [sizeof(int), 8] must be representable in the target.
|
||||
uint64_t NewSize = std::clamp<uint64_t>(Type.getSize(), IntSize, 8);
|
||||
uint64_t NewSize = std::clamp<uint64_t>(Type.getSize(),
|
||||
DataModel.getIntSize(),
|
||||
8);
|
||||
|
||||
revng_assert(NewSize != Type.getSize());
|
||||
revng_assert(isRepresentableLiteralSize(NewSize));
|
||||
@@ -414,62 +406,55 @@ struct ImmediateCastPattern : mlir::OpRewritePattern<ImmediateOp> {
|
||||
struct CLegalizationPass
|
||||
: clift::impl::CliftCLegalizationBase<CLegalizationPass> {
|
||||
|
||||
const TargetCImplementation &Target;
|
||||
|
||||
explicit CLegalizationPass(const TargetCImplementation &Target) :
|
||||
Target(Target) {}
|
||||
|
||||
void runOnOperation() override {
|
||||
if (legalizeForC(getOperation(), Target).failed())
|
||||
if (legalizeForC(getOperation()).failed())
|
||||
signalPassFailure();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
mlir::LogicalResult clift::legalizeForC(clift::FunctionOp Function,
|
||||
const TargetCImplementation &Target) {
|
||||
mlir::LogicalResult clift::legalizeForC(clift::FunctionOp Function) {
|
||||
mlir::MLIRContext *Context = Function.getContext();
|
||||
mlir::RewritePatternSet Set(Context);
|
||||
|
||||
TargetInfo T(Context, Target);
|
||||
const CDataModel &DataModel = getDataModel(Function);
|
||||
|
||||
// Pointer resizing
|
||||
Set.add<ResizePtrAddPattern>(Context, T);
|
||||
Set.add<ResizePtrSubPattern>(Context, T);
|
||||
Set.add<ResizePtrDiffPattern>(Context, T);
|
||||
Set.add<PointerResizePattern<IndirectionOp>>(Context, T);
|
||||
Set.add<PointerResizePattern<SubscriptOp>>(Context, T);
|
||||
Set.add<PointerResizePattern<AccessOp>>(Context, T);
|
||||
Set.add<PointerResizePattern<CallOp>>(Context, T);
|
||||
Set.add<ResizeAddressofPattern>(Context, T);
|
||||
Set.add<ResizeDecayCastPattern>(Context, T);
|
||||
Set.add<ResizePtrAddPattern>(Context, DataModel);
|
||||
Set.add<ResizePtrSubPattern>(Context, DataModel);
|
||||
Set.add<ResizePtrDiffPattern>(Context, DataModel);
|
||||
Set.add<PointerResizePattern<IndirectionOp>>(Context, DataModel);
|
||||
Set.add<PointerResizePattern<SubscriptOp>>(Context, DataModel);
|
||||
Set.add<PointerResizePattern<AccessOp>>(Context, DataModel);
|
||||
Set.add<PointerResizePattern<CallOp>>(Context, DataModel);
|
||||
Set.add<ResizeAddressofPattern>(Context, DataModel);
|
||||
Set.add<ResizeDecayCastPattern>(Context, DataModel);
|
||||
|
||||
// Boolean canonicalization
|
||||
Set.add<BooleanCanonicalizationPattern>(Context, T);
|
||||
Set.add<BooleanCanonicalizationPattern>(Context, DataModel);
|
||||
|
||||
// Integer promotion
|
||||
Set.add<ArithmeticPromotionPattern<NegOp>>(Context, T);
|
||||
Set.add<ArithmeticPromotionPattern<AddOp>>(Context, T);
|
||||
Set.add<ArithmeticPromotionPattern<SubOp>>(Context, T);
|
||||
Set.add<ArithmeticPromotionPattern<MulOp>>(Context, T);
|
||||
Set.add<ArithmeticPromotionPattern<DivOp>>(Context, T);
|
||||
Set.add<ArithmeticPromotionPattern<RemOp>>(Context, T);
|
||||
Set.add<ArithmeticPromotionPattern<BitwiseNotOp>>(Context, T);
|
||||
Set.add<ArithmeticPromotionPattern<BitwiseAndOp>>(Context, T);
|
||||
Set.add<ArithmeticPromotionPattern<BitwiseOrOp>>(Context, T);
|
||||
Set.add<ArithmeticPromotionPattern<BitwiseXorOp>>(Context, T);
|
||||
Set.add<ShiftPromotionPattern<ShiftLeftOp>>(Context, T);
|
||||
Set.add<ShiftPromotionPattern<ShiftRightOp>>(Context, T);
|
||||
Set.add<ArithmeticPromotionPattern<NegOp>>(Context, DataModel);
|
||||
Set.add<ArithmeticPromotionPattern<AddOp>>(Context, DataModel);
|
||||
Set.add<ArithmeticPromotionPattern<SubOp>>(Context, DataModel);
|
||||
Set.add<ArithmeticPromotionPattern<MulOp>>(Context, DataModel);
|
||||
Set.add<ArithmeticPromotionPattern<DivOp>>(Context, DataModel);
|
||||
Set.add<ArithmeticPromotionPattern<RemOp>>(Context, DataModel);
|
||||
Set.add<ArithmeticPromotionPattern<BitwiseNotOp>>(Context, DataModel);
|
||||
Set.add<ArithmeticPromotionPattern<BitwiseAndOp>>(Context, DataModel);
|
||||
Set.add<ArithmeticPromotionPattern<BitwiseOrOp>>(Context, DataModel);
|
||||
Set.add<ArithmeticPromotionPattern<BitwiseXorOp>>(Context, DataModel);
|
||||
Set.add<ShiftPromotionPattern<ShiftLeftOp>>(Context, DataModel);
|
||||
Set.add<ShiftPromotionPattern<ShiftRightOp>>(Context, DataModel);
|
||||
|
||||
// Literal typing
|
||||
Set.add<ImmediateCastPattern>(Context, T);
|
||||
Set.add<ImmediateCastPattern>(Context, DataModel);
|
||||
|
||||
auto Patterns = mlir::FrozenRewritePatternSet(std::move(Set));
|
||||
return mlir::applyPatternsAndFoldGreedily(Function, Patterns);
|
||||
}
|
||||
|
||||
clift::PassPtr<clift::FunctionOp>
|
||||
clift::createCLegalizationPass(const TargetCImplementation &Target) {
|
||||
return std::make_unique<CLegalizationPass>(Target);
|
||||
clift::PassPtr<clift::FunctionOp> clift::createCLegalizationPass() {
|
||||
return std::make_unique<CLegalizationPass>();
|
||||
}
|
||||
|
||||
@@ -69,11 +69,11 @@ static llvm::StringRef
|
||||
getCIntegerLiteralSuffix(const ptml::CTokenEmitter::IntegerSuffix &Suffix) {
|
||||
switch (Suffix.MinimumType) {
|
||||
default:
|
||||
case CIntegerKind::Int:
|
||||
case CStandardType::Int:
|
||||
return Suffix.Unsigned ? "U" : "";
|
||||
case CIntegerKind::Long:
|
||||
case CStandardType::Long:
|
||||
return Suffix.Unsigned ? "UL" : "L";
|
||||
case CIntegerKind::LongLong:
|
||||
case CStandardType::LongLong:
|
||||
return Suffix.Unsigned ? "ULL" : "LL";
|
||||
}
|
||||
}
|
||||
@@ -593,6 +593,7 @@ static bool isRadixSupported(uint64_t Radix) {
|
||||
void CTokenEmitter::emitIntegerLiteral(llvm::APInt Value,
|
||||
std::optional<IntegerSuffix> Suffix,
|
||||
uint64_t Radix) {
|
||||
revng_assert(not Suffix or isIntegerType(Suffix->MinimumType));
|
||||
revng_assert(not IsEmittingComment,
|
||||
"Cannot emit tokens while an open CommentEmitter exists.");
|
||||
|
||||
|
||||
@@ -43,13 +43,13 @@ module attributes {clift.module} {
|
||||
clift.yield %u : !uint32_t
|
||||
}
|
||||
|
||||
// CHECK: 0LL;
|
||||
// CHECK: 0L;
|
||||
clift.expr {
|
||||
%0 = clift.imm 0 : !int64_t
|
||||
clift.yield %0 : !int64_t
|
||||
}
|
||||
|
||||
// CHECK: 0ULL;
|
||||
// CHECK: 0UL;
|
||||
clift.expr {
|
||||
%0 = clift.imm 0 : !uint64_t
|
||||
clift.yield %0 : !uint64_t
|
||||
|
||||
@@ -18,10 +18,16 @@ using namespace llvm::cl;
|
||||
|
||||
static constexpr char ToolName[] = "Standalone optimizer driver\n";
|
||||
|
||||
static void initializeCliftDialect(mlir::MLIRContext *Context,
|
||||
clift::CliftDialect *Dialect) {
|
||||
Dialect->setDefaultDataModel(CDataModel::getDefaultDataModel(8));
|
||||
}
|
||||
|
||||
int main(int Argc, char *Argv[]) {
|
||||
mlir::DialectRegistry Registry;
|
||||
|
||||
Registry.insert<clift::CliftDialect>();
|
||||
Registry.addExtension(initializeCliftDialect);
|
||||
|
||||
mlir::registerTransformsPasses();
|
||||
clift::registerCliftPasses();
|
||||
|
||||
Reference in New Issue
Block a user