// // This file is distributed under the MIT License. See LICENSE.md for details. // #include "revng/Clift/ModuleVisitor.h" #include "revng/CliftEmitC/CSemantics.h" namespace clift = mlir::clift; using namespace clift; namespace { static clift::PointerType getPointerOperationType(mlir::Operation *Op) { auto GetPointerTypeChecked = [&](mlir::Type Type) { auto PointerType = getPointerType(Type); revng_assert(PointerType); return PointerType; }; if (mlir::isa(Op)) return GetPointerTypeChecked(Op->getResult(0).getType()); if (mlir::isa(Op)) return GetPointerTypeChecked(Op->getOperand(0).getType()); if (auto A = mlir::dyn_cast(Op); A and A.isIndirect()) return GetPointerTypeChecked(A.getValue().getType()); if (auto C = mlir::dyn_cast(Op); C and C.getKind() == CastKind::Decay) return GetPointerTypeChecked(C.getResult().getType()); if (auto C = mlir::dyn_cast(Op)) { if (auto T = getPointerType(C.getFunction().getType())) return T; } return {}; } class CVerifier : public ModuleVisitor { public: explicit CVerifier(const TargetCImplementation &Target) : Target(Target) {} mlir::LogicalResult visitNestedOp(mlir::Operation *Op) { if (auto T = getPointerOperationType(Op)) { if (T.getPointerSize() != Target.PointerSize) return getCurrentOp()->emitOpError() << "Pointer operation is not " "representable in the target " "implementation."; } if (mlir::isa(Op)) { auto T = mlir::cast(Op->getResult(0).getType()); if (isPotentiallyPromotingType(T)) return Op->emitOpError() << " is not representable in the target" << " implementation."; } if (isPromotingOp(Op)) { auto T = mlir::cast(Op->getResult(0).getType()); if (isPotentiallyPromotingType(T)) return Op->emitOpError() << " causes integer promotion in the target" " implementation."; } if (isBooleanOp(Op)) { auto T = mlir::cast(Op->getResult(0).getType()); if (not isCanonicalBooleanType(T)) return Op->emitOpError() << " - not yielding the canonical boolean type" << " - is not representable in the target" << " implementation."; } return mlir::success(); } private: static bool isPromotingOp(mlir::Operation *Op) { return mlir::isa(Op); } static bool isBooleanOp(mlir::Operation *Op) { return mlir::isa(Op); } bool isPotentiallyPromotingType(ValueType Type) { if (auto P = mlir::dyn_cast(dealias(Type, true))) { if (isIntegerKind(P.getKind())) { auto Integer = Target.getIntegerKind(P.getSize()); return not Integer or *Integer < CIntegerKind::Int; } } return false; } bool isCanonicalBooleanType(ValueType Type) { if (auto P = mlir::dyn_cast(dealias(Type, true))) { if (isIntegerKind(P.getKind())) return Target.getIntegerKind(P.getSize()) == CIntegerKind::Int; } return false; } const TargetCImplementation &Target; }; } // namespace mlir::LogicalResult clift::verifyCSemantics(mlir::ModuleOp Module, const TargetCImplementation &Target) { return CVerifier::visit(Module, Target); }