Skip to content

Commit ecca836

Browse files
committed
Remove BinOpOverflowOp and pointer arithmetic
1 parent 42c170c commit ecca836

File tree

5 files changed

+2
-317
lines changed

5 files changed

+2
-317
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 0 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -889,65 +889,6 @@ def BinOp : CIR_Op<"binop", [Pure,
889889
let hasVerifier = 1;
890890
}
891891

892-
893-
//===----------------------------------------------------------------------===//
894-
// BinOpOverflowOp
895-
//===----------------------------------------------------------------------===//
896-
897-
def BinOpOverflowKind : I32EnumAttr<
898-
"BinOpOverflowKind",
899-
"checked binary arithmetic operation kind",
900-
[BinOpKind_Add, BinOpKind_Sub, BinOpKind_Mul]> {
901-
let cppNamespace = "::cir";
902-
}
903-
904-
def BinOpOverflowOp : CIR_Op<"binop.overflow", [Pure, SameTypeOperands]> {
905-
let summary = "Perform binary integral arithmetic with overflow checking";
906-
let description = [{
907-
`cir.binop.overflow` performs binary arithmetic operations with overflow
908-
checking on integral operands.
909-
910-
The `kind` argument specifies the kind of arithmetic operation to perform.
911-
It can be either `add`, `sub`, or `mul`. The `lhs` and `rhs` arguments
912-
specify the input operands of the arithmetic operation. The types of `lhs`
913-
and `rhs` must be the same.
914-
915-
`cir.binop.overflow` produces two SSA values. `result` is the result of the
916-
arithmetic operation truncated to its specified type. `overflow` is a
917-
boolean value indicating whether overflow happens during the operation.
918-
919-
The exact semantic of this operation is as follows:
920-
921-
- `lhs` and `rhs` are promoted to an imaginary integral type that has
922-
infinite precision.
923-
- The arithmetic operation is performed on the promoted operands.
924-
- The infinite-precision result is truncated to the type of `result`. The
925-
truncated result is assigned to `result`.
926-
- If the truncated result is equal to the un-truncated result, `overflow`
927-
is assigned to false. Otherwise, `overflow` is assigned to true.
928-
}];
929-
930-
let arguments = (ins Arg<BinOpOverflowKind, "arithmetic kind">:$kind,
931-
CIR_IntType:$lhs, CIR_IntType:$rhs);
932-
let results = (outs CIR_IntType:$result, CIR_BoolType:$overflow);
933-
934-
let assemblyFormat = [{
935-
`(` $kind `,` $lhs `,` $rhs `)` `:` type($lhs) `,`
936-
`(` type($result) `,` type($overflow) `)`
937-
attr-dict
938-
}];
939-
940-
let builders = [
941-
OpBuilder<(ins "cir::IntType":$resultTy,
942-
"cir::BinOpOverflowKind":$kind,
943-
"mlir::Value":$lhs,
944-
"mlir::Value":$rhs), [{
945-
auto overflowTy = cir::BoolType::get($_builder.getContext());
946-
build($_builder, $_state, resultTy, overflowTy, kind, lhs, rhs);
947-
}]>
948-
];
949-
}
950-
951892
//===----------------------------------------------------------------------===//
952893
// GlobalOp
953894
//===----------------------------------------------------------------------===//

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 2 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -921,102 +921,8 @@ mlir::Value CIRGenFunction::emitPromotedScalarExpr(const Expr *e,
921921
static mlir::Value emitPointerArithmetic(CIRGenFunction &cgf,
922922
const BinOpInfo &op,
923923
bool isSubtraction) {
924-
// Must have binary (not unary) expr here. Unary pointer
925-
// increment/decrement doesn't use this path.
926-
const BinaryOperator *expr = cast<BinaryOperator>(op.e);
927-
928-
mlir::Value pointer = op.lhs;
929-
Expr *pointerOperand = expr->getLHS();
930-
mlir::Value index = op.rhs;
931-
Expr *indexOperand = expr->getRHS();
932-
933-
// In a subtraction, the LHS is always the pointer.
934-
if (!isSubtraction && !mlir::isa<cir::PointerType>(pointer.getType())) {
935-
std::swap(pointer, index);
936-
std::swap(pointerOperand, indexOperand);
937-
}
938-
939-
bool isSigned = indexOperand->getType()->isSignedIntegerOrEnumerationType();
940-
941-
// Some versions of glibc and gcc use idioms (particularly in their malloc
942-
// routines) that add a pointer-sized integer (known to be a pointer value)
943-
// to a null pointer in order to cast the value back to an integer or as
944-
// part of a pointer alignment algorithm. This is undefined behavior, but
945-
// we'd like to be able to compile programs that use it.
946-
//
947-
// Normally, we'd generate a GEP with a null-pointer base here in response
948-
// to that code, but it's also UB to dereference a pointer created that
949-
// way. Instead (as an acknowledged hack to tolerate the idiom) we will
950-
// generate a direct cast of the integer value to a pointer.
951-
//
952-
// The idiom (p = nullptr + N) is not met if any of the following are true:
953-
//
954-
// The operation is subtraction.
955-
// The index is not pointer-sized.
956-
// The pointer type is not byte-sized.
957-
//
958-
if (BinaryOperator::isNullPointerArithmeticExtension(
959-
cgf.getContext(), op.opcode, expr->getLHS(), expr->getRHS()))
960-
return cgf.getBuilder().createIntToPtr(index, pointer.getType());
961-
962-
// Differently from LLVM codegen, ABI bits for index sizes is handled during
963-
// LLVM lowering.
964-
965-
// If this is subtraction, negate the index.
966-
if (isSubtraction)
967-
index = cgf.getBuilder().createNeg(index);
968-
969-
if (cgf.sanOpts.has(SanitizerKind::ArrayBounds))
970-
cgf.cgm.errorNYI("array bounds sanitizer");
971-
972-
const PointerType *pointerType =
973-
pointerOperand->getType()->getAs<PointerType>();
974-
if (!pointerType)
975-
cgf.cgm.errorNYI("ObjC");
976-
977-
QualType elementType = pointerType->getPointeeType();
978-
if (const VariableArrayType *vla =
979-
cgf.getContext().getAsVariableArrayType(elementType)) {
980-
981-
// The element count here is the total number of non-VLA elements.
982-
mlir::Value numElements = nullptr; // cgf.getVLASize(vla).NumElts;
983-
984-
// GEP indexes are signed, and scaling an index isn't permitted to
985-
// signed-overflow, so we use the same semantics for our explicit
986-
// multiply. We suppress this if overflow is not undefined behavior.
987-
mlir::Type elemTy = cgf.convertTypeForMem(vla->getElementType());
988-
989-
index = cgf.getBuilder().createCast(cir::CastKind::integral, index,
990-
numElements.getType());
991-
index = cgf.getBuilder().createMul(index.getLoc(), index, numElements);
992-
993-
if (cgf.getLangOpts().isSignedOverflowDefined()) {
994-
assert(!cir::MissingFeatures::ptrStrideOp());
995-
cgf.cgm.errorNYI("pointer stride");
996-
} else {
997-
pointer = cgf.emitCheckedInBoundsGEP(elemTy, pointer, index, isSigned,
998-
isSubtraction, op.e->getExprLoc());
999-
}
1000-
1001-
return pointer;
1002-
}
1003-
// Explicitly handle GNU void* and function pointer arithmetic extensions. The
1004-
// GNU void* casts amount to no-ops since our void* type is i8*, but this is
1005-
// future proof.
1006-
mlir::Type elemTy;
1007-
if (elementType->isVoidType() || elementType->isFunctionType())
1008-
elemTy = cgf.UInt8Ty;
1009-
else
1010-
elemTy = cgf.convertTypeForMem(elementType);
1011-
1012-
if (cgf.getLangOpts().isSignedOverflowDefined()) {
1013-
assert(!cir::MissingFeatures::ptrStrideOp());
1014-
cgf.cgm.errorNYI("pointer stride");
1015-
return pointer;
1016-
}
1017-
1018-
return cgf.emitCheckedInBoundsGEP(elemTy, pointer, index, isSigned,
1019-
isSubtraction, op.e->getExprLoc());
924+
cgf.cgm.errorNYI(op.loc, "pointer arithmetic");
925+
return {};
1020926
}
1021927

1022928
mlir::Value ScalarExprEmitter::emitMul(const BinOpInfo &ops) {
@@ -1481,20 +1387,3 @@ mlir::Value CIRGenFunction::emitScalarPrePostIncDec(const UnaryOperator *e,
14811387
return ScalarExprEmitter(*this, builder)
14821388
.emitScalarPrePostIncDec(e, lv, isInc, isPre);
14831389
}
1484-
1485-
mlir::Value CIRGenFunction::emitCheckedInBoundsGEP(
1486-
mlir::Type elemTy, mlir::Value ptr, ArrayRef<mlir::Value> idxList,
1487-
bool signedIndices, bool isSubtraction, SourceLocation loc) {
1488-
assert(!cir::MissingFeatures::ptrStrideOp());
1489-
if (idxList.size() != 1)
1490-
cgm.errorNYI("multi-index ptr arithmetic");
1491-
mlir::Value gepVal = nullptr;
1492-
1493-
// If the pointer overflow sanitizer isn't enabled, do nothing.
1494-
if (!sanOpts.has(SanitizerKind::PointerOverflow))
1495-
return gepVal;
1496-
1497-
assert(!cir::MissingFeatures::pointerOverflowSanitizer());
1498-
cgm.errorNYI("pointer overflow sanitizer");
1499-
return nullptr;
1500-
}

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -217,16 +217,6 @@ class CIRGenFunction : public CIRGenTypeCache {
217217

218218
void emitDecl(const clang::Decl &d);
219219

220-
/// Same as IRBuilder::CreateInBoundsGEP, but additionally emits a check to
221-
/// detect undefined behavior when the pointer overflow sanitizer is enabled.
222-
/// \p SignedIndices indicates whether any of the GEP indices are signed.
223-
/// \p IsSubtraction indicates whether the expression used to form the GEP
224-
/// is a subtraction.
225-
mlir::Value emitCheckedInBoundsGEP(mlir::Type elemTy, mlir::Value ptr,
226-
llvm::ArrayRef<mlir::Value> idxList,
227-
bool signedIndices, bool isSubtraction,
228-
SourceLocation loc);
229-
230220
void emitScalarInit(const clang::Expr *init, mlir::Location loc,
231221
LValue lvalue, bool capturedByInit = false);
232222

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 0 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,118 +1113,6 @@ mlir::LogicalResult CIRToLLVMBinOpLowering::matchAndRewrite(
11131113
return mlir::LogicalResult::success();
11141114
}
11151115

1116-
mlir::LogicalResult CIRToLLVMBinOpOverflowOpLowering::matchAndRewrite(
1117-
cir::BinOpOverflowOp op, OpAdaptor adaptor,
1118-
mlir::ConversionPatternRewriter &rewriter) const {
1119-
auto loc = op.getLoc();
1120-
auto arithKind = op.getKind();
1121-
auto operandTy = op.getLhs().getType();
1122-
auto resultTy = op.getResult().getType();
1123-
1124-
auto encompassedTyInfo = computeEncompassedTypeWidth(operandTy, resultTy);
1125-
auto encompassedLLVMTy = rewriter.getIntegerType(encompassedTyInfo.width);
1126-
1127-
auto lhs = adaptor.getLhs();
1128-
auto rhs = adaptor.getRhs();
1129-
if (operandTy.getWidth() < encompassedTyInfo.width) {
1130-
if (operandTy.isSigned()) {
1131-
lhs = rewriter.create<mlir::LLVM::SExtOp>(loc, encompassedLLVMTy, lhs);
1132-
rhs = rewriter.create<mlir::LLVM::SExtOp>(loc, encompassedLLVMTy, rhs);
1133-
} else {
1134-
lhs = rewriter.create<mlir::LLVM::ZExtOp>(loc, encompassedLLVMTy, lhs);
1135-
rhs = rewriter.create<mlir::LLVM::ZExtOp>(loc, encompassedLLVMTy, rhs);
1136-
}
1137-
}
1138-
1139-
auto intrinName = getLLVMIntrinName(arithKind, encompassedTyInfo.sign,
1140-
encompassedTyInfo.width);
1141-
auto intrinNameAttr = mlir::StringAttr::get(op.getContext(), intrinName);
1142-
1143-
auto overflowLLVMTy = rewriter.getI1Type();
1144-
auto intrinRetTy = mlir::LLVM::LLVMStructType::getLiteral(
1145-
rewriter.getContext(), {encompassedLLVMTy, overflowLLVMTy});
1146-
1147-
auto callLLVMIntrinOp = rewriter.create<mlir::LLVM::CallIntrinsicOp>(
1148-
loc, intrinRetTy, intrinNameAttr, mlir::ValueRange{lhs, rhs});
1149-
auto intrinRet = callLLVMIntrinOp.getResult(0);
1150-
1151-
auto result = rewriter
1152-
.create<mlir::LLVM::ExtractValueOp>(loc, intrinRet,
1153-
ArrayRef<int64_t>{0})
1154-
.getResult();
1155-
auto overflow = rewriter
1156-
.create<mlir::LLVM::ExtractValueOp>(loc, intrinRet,
1157-
ArrayRef<int64_t>{1})
1158-
.getResult();
1159-
1160-
if (resultTy.getWidth() < encompassedTyInfo.width) {
1161-
auto resultLLVMTy = getTypeConverter()->convertType(resultTy);
1162-
auto truncResult =
1163-
rewriter.create<mlir::LLVM::TruncOp>(loc, resultLLVMTy, result);
1164-
1165-
// Extend the truncated result back to the encompassing type to check for
1166-
// any overflows during the truncation.
1167-
mlir::Value truncResultExt;
1168-
if (resultTy.isSigned())
1169-
truncResultExt = rewriter.create<mlir::LLVM::SExtOp>(
1170-
loc, encompassedLLVMTy, truncResult);
1171-
else
1172-
truncResultExt = rewriter.create<mlir::LLVM::ZExtOp>(
1173-
loc, encompassedLLVMTy, truncResult);
1174-
auto truncOverflow = rewriter.create<mlir::LLVM::ICmpOp>(
1175-
loc, mlir::LLVM::ICmpPredicate::ne, truncResultExt, result);
1176-
1177-
result = truncResult;
1178-
overflow = rewriter.create<mlir::LLVM::OrOp>(loc, overflow, truncOverflow);
1179-
}
1180-
1181-
auto boolLLVMTy = getTypeConverter()->convertType(op.getOverflow().getType());
1182-
if (boolLLVMTy != rewriter.getI1Type())
1183-
overflow = rewriter.create<mlir::LLVM::ZExtOp>(loc, boolLLVMTy, overflow);
1184-
1185-
rewriter.replaceOp(op, mlir::ValueRange{result, overflow});
1186-
1187-
return mlir::success();
1188-
}
1189-
1190-
std::string CIRToLLVMBinOpOverflowOpLowering::getLLVMIntrinName(
1191-
cir::BinOpOverflowKind opKind, bool isSigned, unsigned width) {
1192-
// The intrinsic name is `@llvm.{s|u}{opKind}.with.overflow.i{width}`
1193-
1194-
std::string name = "llvm.";
1195-
1196-
if (isSigned)
1197-
name.push_back('s');
1198-
else
1199-
name.push_back('u');
1200-
1201-
switch (opKind) {
1202-
case cir::BinOpOverflowKind::Add:
1203-
name.append("add.");
1204-
break;
1205-
case cir::BinOpOverflowKind::Sub:
1206-
name.append("sub.");
1207-
break;
1208-
case cir::BinOpOverflowKind::Mul:
1209-
name.append("mul.");
1210-
break;
1211-
}
1212-
1213-
name.append("with.overflow.i");
1214-
name.append(std::to_string(width));
1215-
1216-
return name;
1217-
}
1218-
1219-
CIRToLLVMBinOpOverflowOpLowering::EncompassedTypeInfo
1220-
CIRToLLVMBinOpOverflowOpLowering::computeEncompassedTypeWidth(
1221-
cir::IntType operandTy, cir::IntType resultTy) {
1222-
auto sign = operandTy.getIsSigned() || resultTy.getIsSigned();
1223-
auto width = std::max(operandTy.getWidth() + (sign && operandTy.isUnsigned()),
1224-
resultTy.getWidth() + (sign && resultTy.isUnsigned()));
1225-
return {sign, width};
1226-
}
1227-
12281116
static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
12291117
mlir::DataLayout &dataLayout) {
12301118
converter.addConversion([&](cir::PointerType type) -> mlir::Type {
@@ -1365,7 +1253,6 @@ void ConvertCIRToLLVMPass::runOnOperation() {
13651253
// clang-format off
13661254
CIRToLLVMBrCondOpLowering,
13671255
CIRToLLVMBinOpLowering,
1368-
CIRToLLVMBinOpOverflowOpLowering,
13691256
CIRToLLVMBrOpLowering,
13701257
CIRToLLVMFuncOpLowering,
13711258
CIRToLLVMTrapOpLowering,

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -189,28 +189,6 @@ class CIRToLLVMBinOpLowering : public mlir::OpConversionPattern<cir::BinOp> {
189189
mlir::ConversionPatternRewriter &) const override;
190190
};
191191

192-
class CIRToLLVMBinOpOverflowOpLowering
193-
: public mlir::OpConversionPattern<cir::BinOpOverflowOp> {
194-
public:
195-
using mlir::OpConversionPattern<cir::BinOpOverflowOp>::OpConversionPattern;
196-
197-
mlir::LogicalResult
198-
matchAndRewrite(cir::BinOpOverflowOp op, OpAdaptor,
199-
mlir::ConversionPatternRewriter &) const override;
200-
201-
private:
202-
static std::string getLLVMIntrinName(cir::BinOpOverflowKind opKind,
203-
bool isSigned, unsigned width);
204-
205-
struct EncompassedTypeInfo {
206-
bool sign;
207-
unsigned width;
208-
};
209-
210-
static EncompassedTypeInfo computeEncompassedTypeWidth(cir::IntType operandTy,
211-
cir::IntType resultTy);
212-
};
213-
214192
class CIRToLLVMBrOpLowering : public mlir::OpConversionPattern<cir::BrOp> {
215193
public:
216194
using mlir::OpConversionPattern<cir::BrOp>::OpConversionPattern;

0 commit comments

Comments
 (0)