Skip to content

Commit 2f3c937

Browse files
mmhaandykaylor
andauthored
[CIR] Add binary operators (#132420)
This patch adds upstreams support for BinOp including lvalue assignments. Note that this does not include ternary ops, BinOpOverflowOp, pointer arithmetic, ShiftOp and SelectOp which are required for logical binary operators. --------- Co-authored-by: Morris Hafner <[email protected]> Co-authored-by: Andy Kaylor <[email protected]>
1 parent 577631f commit 2f3c937

File tree

19 files changed

+1490
-38
lines changed

19 files changed

+1490
-38
lines changed

clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,59 @@
1010
#define LLVM_CLANG_CIR_DIALECT_BUILDER_CIRBASEBUILDER_H
1111

1212
#include "clang/AST/CharUnits.h"
13-
#include "clang/AST/Type.h"
1413
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
1514
#include "clang/CIR/Dialect/IR/CIRDialect.h"
1615
#include "clang/CIR/Dialect/IR/CIRTypes.h"
16+
#include "llvm/ADT/STLForwardCompat.h"
1717
#include "llvm/Support/ErrorHandling.h"
1818

1919
#include "mlir/IR/Builders.h"
2020
#include "mlir/IR/BuiltinTypes.h"
21+
#include "mlir/IR/Location.h"
2122
#include "mlir/IR/Types.h"
2223

2324
namespace cir {
2425

26+
enum class OverflowBehavior {
27+
None = 0,
28+
NoSignedWrap = 1 << 0,
29+
NoUnsignedWrap = 1 << 1,
30+
Saturated = 1 << 2,
31+
};
32+
33+
constexpr OverflowBehavior operator|(OverflowBehavior a, OverflowBehavior b) {
34+
return static_cast<OverflowBehavior>(llvm::to_underlying(a) |
35+
llvm::to_underlying(b));
36+
}
37+
38+
constexpr OverflowBehavior operator&(OverflowBehavior a, OverflowBehavior b) {
39+
return static_cast<OverflowBehavior>(llvm::to_underlying(a) &
40+
llvm::to_underlying(b));
41+
}
42+
43+
constexpr OverflowBehavior &operator|=(OverflowBehavior &a,
44+
OverflowBehavior b) {
45+
a = a | b;
46+
return a;
47+
}
48+
49+
constexpr OverflowBehavior &operator&=(OverflowBehavior &a,
50+
OverflowBehavior b) {
51+
a = a & b;
52+
return a;
53+
}
54+
2555
class CIRBaseBuilderTy : public mlir::OpBuilder {
2656

2757
public:
2858
CIRBaseBuilderTy(mlir::MLIRContext &mlirContext)
2959
: mlir::OpBuilder(&mlirContext) {}
3060

61+
mlir::Value getConstAPInt(mlir::Location loc, mlir::Type typ,
62+
const llvm::APInt &val) {
63+
return create<cir::ConstantOp>(loc, typ, getAttr<cir::IntAttr>(typ, val));
64+
}
65+
3166
cir::ConstantOp getConstant(mlir::Location loc, mlir::TypedAttr attr) {
3267
return create<cir::ConstantOp>(loc, attr.getType(), attr);
3368
}
@@ -143,6 +178,93 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
143178
return createCast(loc, cir::CastKind::bitcast, src, newTy);
144179
}
145180

181+
//===--------------------------------------------------------------------===//
182+
// Binary Operators
183+
//===--------------------------------------------------------------------===//
184+
185+
mlir::Value createBinop(mlir::Location loc, mlir::Value lhs,
186+
cir::BinOpKind kind, mlir::Value rhs) {
187+
return create<cir::BinOp>(loc, lhs.getType(), kind, lhs, rhs);
188+
}
189+
190+
mlir::Value createLowBitsSet(mlir::Location loc, unsigned size,
191+
unsigned bits) {
192+
llvm::APInt val = llvm::APInt::getLowBitsSet(size, bits);
193+
auto type = cir::IntType::get(getContext(), size, /*isSigned=*/false);
194+
return getConstAPInt(loc, type, val);
195+
}
196+
197+
mlir::Value createAnd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
198+
return createBinop(loc, lhs, cir::BinOpKind::And, rhs);
199+
}
200+
201+
mlir::Value createOr(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
202+
return createBinop(loc, lhs, cir::BinOpKind::Or, rhs);
203+
}
204+
205+
mlir::Value createMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
206+
OverflowBehavior ob = OverflowBehavior::None) {
207+
auto op =
208+
create<cir::BinOp>(loc, lhs.getType(), cir::BinOpKind::Mul, lhs, rhs);
209+
op.setNoUnsignedWrap(
210+
llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap));
211+
op.setNoSignedWrap(
212+
llvm::to_underlying(ob & OverflowBehavior::NoSignedWrap));
213+
return op;
214+
}
215+
mlir::Value createNSWMul(mlir::Location loc, mlir::Value lhs,
216+
mlir::Value rhs) {
217+
return createMul(loc, lhs, rhs, OverflowBehavior::NoSignedWrap);
218+
}
219+
mlir::Value createNUWAMul(mlir::Location loc, mlir::Value lhs,
220+
mlir::Value rhs) {
221+
return createMul(loc, lhs, rhs, OverflowBehavior::NoUnsignedWrap);
222+
}
223+
224+
mlir::Value createSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
225+
OverflowBehavior ob = OverflowBehavior::Saturated) {
226+
auto op =
227+
create<cir::BinOp>(loc, lhs.getType(), cir::BinOpKind::Sub, lhs, rhs);
228+
op.setNoUnsignedWrap(
229+
llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap));
230+
op.setNoSignedWrap(
231+
llvm::to_underlying(ob & OverflowBehavior::NoSignedWrap));
232+
op.setSaturated(llvm::to_underlying(ob & OverflowBehavior::Saturated));
233+
return op;
234+
}
235+
236+
mlir::Value createNSWSub(mlir::Location loc, mlir::Value lhs,
237+
mlir::Value rhs) {
238+
return createSub(loc, lhs, rhs, OverflowBehavior::NoSignedWrap);
239+
}
240+
241+
mlir::Value createNUWSub(mlir::Location loc, mlir::Value lhs,
242+
mlir::Value rhs) {
243+
return createSub(loc, lhs, rhs, OverflowBehavior::NoUnsignedWrap);
244+
}
245+
246+
mlir::Value createAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
247+
OverflowBehavior ob = OverflowBehavior::None) {
248+
auto op =
249+
create<cir::BinOp>(loc, lhs.getType(), cir::BinOpKind::Add, lhs, rhs);
250+
op.setNoUnsignedWrap(
251+
llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap));
252+
op.setNoSignedWrap(
253+
llvm::to_underlying(ob & OverflowBehavior::NoSignedWrap));
254+
op.setSaturated(llvm::to_underlying(ob & OverflowBehavior::Saturated));
255+
return op;
256+
}
257+
258+
mlir::Value createNSWAdd(mlir::Location loc, mlir::Value lhs,
259+
mlir::Value rhs) {
260+
return createAdd(loc, lhs, rhs, OverflowBehavior::NoSignedWrap);
261+
}
262+
263+
mlir::Value createNUWAdd(mlir::Location loc, mlir::Value lhs,
264+
mlir::Value rhs) {
265+
return createAdd(loc, lhs, rhs, OverflowBehavior::NoUnsignedWrap);
266+
}
267+
146268
//
147269
// Block handling helpers
148270
// ----------------------

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

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,69 @@ def ForOp : CIR_Op<"for", [LoopOpInterface, NoRegionArguments]> {
826826
}];
827827
}
828828

829+
//===----------------------------------------------------------------------===//
830+
// BinOp
831+
//===----------------------------------------------------------------------===//
832+
833+
// FIXME: represent Commutative, Idempotent traits for appropriate binops
834+
def BinOpKind_Mul : I32EnumAttrCase<"Mul", 1, "mul">;
835+
def BinOpKind_Div : I32EnumAttrCase<"Div", 2, "div">;
836+
def BinOpKind_Rem : I32EnumAttrCase<"Rem", 3, "rem">;
837+
def BinOpKind_Add : I32EnumAttrCase<"Add", 4, "add">;
838+
def BinOpKind_Sub : I32EnumAttrCase<"Sub", 5, "sub">;
839+
def BinOpKind_And : I32EnumAttrCase<"And", 8, "and">;
840+
def BinOpKind_Xor : I32EnumAttrCase<"Xor", 9, "xor">;
841+
def BinOpKind_Or : I32EnumAttrCase<"Or", 10, "or">;
842+
// TODO(cir): Do we need a min binop?
843+
def BinOpKind_Max : I32EnumAttrCase<"Max", 11, "max">;
844+
845+
def BinOpKind : I32EnumAttr<
846+
"BinOpKind",
847+
"binary operation (arith and logic) kind",
848+
[BinOpKind_Mul, BinOpKind_Div, BinOpKind_Rem,
849+
BinOpKind_Add, BinOpKind_Sub,
850+
BinOpKind_And, BinOpKind_Xor,
851+
BinOpKind_Or, BinOpKind_Max]> {
852+
let cppNamespace = "::cir";
853+
}
854+
855+
def BinOp : CIR_Op<"binop", [Pure,
856+
SameTypeOperands, SameOperandsAndResultType]> {
857+
858+
let summary = "Binary operations (arith and logic)";
859+
let description = [{
860+
cir.binop performs the binary operation according to
861+
the specified opcode kind: [mul, div, rem, add, sub,
862+
and, xor, or, max].
863+
864+
It requires two input operands and has one result, all types
865+
should be the same.
866+
867+
```mlir
868+
%7 = cir.binop(add, %1, %2) : !s32i
869+
%7 = cir.binop(mul, %1, %2) : !u8i
870+
```
871+
}];
872+
873+
// TODO: get more accurate than CIR_AnyType
874+
let results = (outs CIR_AnyType:$result);
875+
let arguments = (ins Arg<BinOpKind, "binop kind">:$kind,
876+
CIR_AnyType:$lhs, CIR_AnyType:$rhs,
877+
UnitAttr:$no_unsigned_wrap,
878+
UnitAttr:$no_signed_wrap,
879+
UnitAttr:$saturated);
880+
881+
let assemblyFormat = [{
882+
`(` $kind `,` $lhs `,` $rhs `)`
883+
(`nsw` $no_signed_wrap^)?
884+
(`nuw` $no_unsigned_wrap^)?
885+
(`sat` $saturated^)?
886+
`:` type($lhs) attr-dict
887+
}];
888+
889+
let hasVerifier = 1;
890+
}
891+
829892
//===----------------------------------------------------------------------===//
830893
// GlobalOp
831894
//===----------------------------------------------------------------------===//

clang/include/clang/CIR/Dialect/IR/CIRTypes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
namespace cir {
2222

2323
bool isAnyFloatingPointType(mlir::Type t);
24+
bool isFPOrFPVectorTy(mlir::Type);
2425

2526
} // namespace cir
2627

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ struct MissingFeatures {
7979
static bool opUnarySignedOverflow() { return false; }
8080
static bool opUnaryPromotionType() { return false; }
8181

82+
// Clang early optimizations or things defered to LLVM lowering.
83+
static bool mayHaveIntegerOverflow() { return false; }
84+
8285
// Misc
8386
static bool cxxABI() { return false; }
8487
static bool tryEmitAsConstant() { return false; }
@@ -93,16 +96,19 @@ struct MissingFeatures {
9396
static bool stackSaveOp() { return false; }
9497
static bool aggValueSlot() { return false; }
9598
static bool generateDebugInfo() { return false; }
99+
static bool pointerOverflowSanitizer() { return false; }
96100
static bool fpConstraints() { return false; }
97101
static bool sanitizers() { return false; }
98102
static bool addHeapAllocSiteMetadata() { return false; }
99103
static bool targetCodeGenInfoGetNullPointer() { return false; }
100-
static bool CGFPOptionsRAII() { return false; }
101104
static bool loopInfoStack() { return false; }
102105
static bool requiresCleanups() { return false; }
103106
static bool createProfileWeightsForLoop() { return false; }
104107
static bool emitCondLikelihoodViaExpectIntrinsic() { return false; }
105108
static bool pgoUse() { return false; }
109+
static bool cgFPOptionsRAII() { return false; }
110+
static bool metaDataNode() { return false; }
111+
static bool fastMathFlags() { return false; }
106112

107113
// Missing types
108114
static bool dataMemberType() { return false; }
@@ -111,6 +117,8 @@ struct MissingFeatures {
111117
static bool scalableVectors() { return false; }
112118
static bool unsizedTypes() { return false; }
113119
static bool vectorType() { return false; }
120+
static bool complexType() { return false; }
121+
static bool fixedPointType() { return false; }
114122

115123
// Future CIR operations
116124
static bool awaitOp() { return false; }
@@ -127,6 +135,8 @@ struct MissingFeatures {
127135
static bool ternaryOp() { return false; }
128136
static bool tryOp() { return false; }
129137
static bool zextOp() { return false; }
138+
static bool ptrStrideOp() { return false; }
139+
static bool ptrDiffOp() { return false; }
130140
};
131141

132142
} // namespace cir

0 commit comments

Comments
 (0)