Files
revng-revng/lib/CliftEmitC/CSemantics.cpp
2026-04-22 08:19:47 +00:00

120 lines
3.8 KiB
C++

//
// 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) {
if (mlir::isa<PtrAddOp, PtrSubOp, AddressofOp>(Op))
return clift::unwrapped_cast<PointerType>(Op->getResult(0).getType());
if (mlir::isa<PtrDiffOp, IndirectionOp, SubscriptOp>(Op))
return clift::unwrapped_cast<PointerType>(Op->getOperand(0).getType());
if (auto A = mlir::dyn_cast<AccessOp>(Op); A and A.isIndirect())
return clift::unwrapped_cast<PointerType>(A.getValue().getType());
if (auto C = mlir::dyn_cast<DecayOp>(Op))
return clift::unwrapped_cast<PointerType>(C.getResult().getType());
if (auto C = mlir::dyn_cast<CallOp>(Op)) {
if (auto T = clift::unwrapped_dyn_cast<PointerType>(C.getFunction()
.getType()))
return T;
}
return {};
}
class CVerifier : public ModuleVisitor<CVerifier> {
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<ImmediateOp>(Op)) {
if (isPotentiallyPromotingType(Op->getResult(0).getType()))
return Op->emitOpError() << " is not representable in the target"
<< " implementation.";
}
if (isPromotingOp(Op)) {
if (isPotentiallyPromotingType(Op->getResult(0).getType()))
return Op->emitOpError() << " causes integer promotion in the target"
" implementation.";
}
if (isBooleanOp(Op)) {
if (not isCanonicalBooleanType(Op->getResult(0).getType()))
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<NegOp,
AddOp,
SubOp,
MulOp,
DivOp,
RemOp,
BitwiseNotOp,
BitwiseAndOp,
BitwiseOrOp,
BitwiseXorOp,
ShiftLeftOp,
ShiftRightOp>(Op);
}
static bool isBooleanOp(mlir::Operation *Op) {
return mlir::isa<LogicalNotOp,
LogicalAndOp,
LogicalOrOp,
CmpEqOp,
CmpNeOp,
CmpLtOp,
CmpGtOp,
CmpLeOp,
CmpGeOp>(Op);
}
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;
}
return false;
}
bool isCanonicalBooleanType(mlir::Type Type) {
if (auto IntType = clift::unwrapped_dyn_cast<IntegerType>(Type))
return Target.getIntegerKind(IntType.getSize()) == CIntegerKind::Int;
return false;
}
const TargetCImplementation &Target;
};
} // namespace
mlir::LogicalResult verifyCSemantics(mlir::ModuleOp Module,
const TargetCImplementation &Target) {
return CVerifier::visit(Module, Target);
}