Skip to content

Commit 86e0d41

Browse files
authored
Merge pull request #170 from Xilinx/matthias.backport_emitc
Backported all emitc-related commits from upstream
2 parents 5f808cd + e91dcde commit 86e0d41

File tree

20 files changed

+417
-90
lines changed

20 files changed

+417
-90
lines changed

llvm/include/llvm/Support/Casting.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,52 @@ template <class X, class Y>
801801
return unique_dyn_cast_or_null<X, Y>(Val);
802802
}
803803

804+
//===----------------------------------------------------------------------===//
805+
// Isa Predicates
806+
//===----------------------------------------------------------------------===//
807+
808+
/// These are wrappers over isa* function that allow them to be used in generic
809+
/// algorithms such as `llvm:all_of`, `llvm::none_of`, etc. This is accomplished
810+
/// by exposing the isa* functions through function objects with a generic
811+
/// function call operator.
812+
813+
namespace detail {
814+
template <typename... Types> struct IsaCheckPredicate {
815+
template <typename T> [[nodiscard]] bool operator()(const T &Val) const {
816+
return isa<Types...>(Val);
817+
}
818+
};
819+
820+
template <typename... Types> struct IsaAndPresentCheckPredicate {
821+
template <typename T> [[nodiscard]] bool operator()(const T &Val) const {
822+
return isa_and_present<Types...>(Val);
823+
}
824+
};
825+
} // namespace detail
826+
827+
/// Function object wrapper for the `llvm::isa` type check. The function call
828+
/// operator returns true when the value can be cast to any type in `Types`.
829+
/// Example:
830+
/// ```
831+
/// SmallVector<Type> myTypes = ...;
832+
/// if (llvm::all_of(myTypes, llvm::IsaPred<VectorType>))
833+
/// ...
834+
/// ```
835+
template <typename... Types>
836+
inline constexpr detail::IsaCheckPredicate<Types...> IsaPred{};
837+
838+
/// Function object wrapper for the `llvm::isa_and_present` type check. The
839+
/// function call operator returns true when the value can be cast to any type
840+
/// in `Types`, or if the value is not present (e.g., nullptr). Example:
841+
/// ```
842+
/// SmallVector<Type> myTypes = ...;
843+
/// if (llvm::all_of(myTypes, llvm::IsaAndPresentPred<VectorType>))
844+
/// ...
845+
/// ```
846+
template <typename... Types>
847+
inline constexpr detail::IsaAndPresentCheckPredicate<Types...>
848+
IsaAndPresentPred{};
849+
804850
} // end namespace llvm
805851

806852
#endif // LLVM_SUPPORT_CASTING_H

llvm/unittests/Support/Casting.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,21 @@ TEST(CastingTest, dyn_cast_if_present) {
282282
EXPECT_FALSE(t4.hasValue);
283283
}
284284

285+
TEST(CastingTest, isa_check_predicates) {
286+
auto IsaFoo = IsaPred<foo>;
287+
EXPECT_TRUE(IsaFoo(B1));
288+
EXPECT_TRUE(IsaFoo(B2));
289+
EXPECT_TRUE(IsaFoo(B3));
290+
EXPECT_TRUE(IsaPred<foo>(B4));
291+
EXPECT_TRUE((IsaPred<foo, bar>(B4)));
292+
293+
auto IsaAndPresentFoo = IsaAndPresentPred<foo>;
294+
EXPECT_TRUE(IsaAndPresentFoo(B2));
295+
EXPECT_TRUE(IsaAndPresentFoo(B4));
296+
EXPECT_FALSE(IsaAndPresentPred<foo>(fub()));
297+
EXPECT_FALSE((IsaAndPresentPred<foo, bar>(fub())));
298+
}
299+
285300
std::unique_ptr<derived> newd() { return std::make_unique<derived>(); }
286301
std::unique_ptr<base> newb() { return std::make_unique<derived>(); }
287302

mlir/include/mlir/Dialect/EmitC/IR/EmitC.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,17 @@
3030
namespace mlir {
3131
namespace emitc {
3232
void buildTerminatedBody(OpBuilder &builder, Location loc);
33+
3334
/// Determines whether \p type is valid in EmitC.
3435
bool isSupportedEmitCType(mlir::Type type);
36+
3537
/// Determines whether \p type is a valid integer type in EmitC.
3638
bool isSupportedIntegerType(mlir::Type type);
39+
40+
/// Determines whether \p type is integer like, i.e. it's a supported integer,
41+
/// an index or opaque type.
42+
bool isIntegerIndexOrOpaqueType(Type type);
43+
3744
/// Determines whether \p type is a valid floating-point type in EmitC.
3845
bool isSupportedFloatType(mlir::Type type);
3946
} // namespace emitc

mlir/include/mlir/Dialect/EmitC/IR/EmitC.td

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -347,9 +347,8 @@ def EmitC_ConstantOp : EmitC_Op<"constant", [ConstantLike]> {
347347
%0 = "emitc.constant"(){value = 42 : i32} : () -> i32
348348

349349
// Constant emitted as `char = CHAR_MIN;`
350-
%1 = "emitc.constant"()
351-
{value = #emitc.opaque<"CHAR_MIN"> : !emitc.opaque<"char">}
352-
: () -> !emitc.opaque<"char">
350+
%1 = "emitc.constant"() {value = #emitc.opaque<"CHAR_MIN">}
351+
: () -> !emitc.opaque<"char">
353352
```
354353
}];
355354

@@ -992,9 +991,8 @@ def EmitC_VariableOp : EmitC_Op<"variable", []> {
992991
%0 = "emitc.variable"(){value = 42 : i32} : () -> i32
993992

994993
// Variable emitted as `int32_t* = NULL;`
995-
%1 = "emitc.variable"()
996-
{value = #emitc.opaque<"NULL"> : !emitc.opaque<"int32_t*">}
997-
: () -> !emitc.opaque<"int32_t*">
994+
%1 = "emitc.variable"() {value = #emitc.opaque<"NULL">}
995+
: () -> !emitc.ptr<!emitc.opaque<"int32_t">>
998996
```
999997

1000998
Since folding is not supported, it can be used with pointers.
@@ -1022,12 +1020,12 @@ def EmitC_GlobalOp : EmitC_Op<"global", [Symbol]> {
10221020
The `emitc.global` operation declares or defines a named global variable.
10231021
The backing memory for the variable is allocated statically and is
10241022
described by the type of the variable.
1025-
Optionally, and `initial_value` can be provided.
1026-
Internal linkage can be specified using the `staticSpecifier` unit attribute
1027-
and external linkage can be specified using the `externSpecifier` unit attribute.
1023+
Optionally, an `initial_value` can be provided.
1024+
Internal linkage can be specified using the `static_specifier` unit attribute
1025+
and external linkage can be specified using the `extern_specifier` unit attribute.
10281026
Note that the default linkage without those two keywords depends on whether
10291027
the target is C or C++ and whether the global variable is `const`.
1030-
The global variable can also be marked constant using the `constSpecifier`
1028+
The global variable can also be marked constant using the `const_specifier`
10311029
unit attribute. Writing to such constant global variables is
10321030
undefined.
10331031

@@ -1049,14 +1047,14 @@ def EmitC_GlobalOp : EmitC_Op<"global", [Symbol]> {
10491047
let arguments = (ins SymbolNameAttr:$sym_name,
10501048
TypeAttr:$type,
10511049
OptionalAttr<EmitC_OpaqueOrTypedAttr>:$initial_value,
1052-
UnitAttr:$externSpecifier,
1053-
UnitAttr:$staticSpecifier,
1054-
UnitAttr:$constSpecifier);
1050+
UnitAttr:$extern_specifier,
1051+
UnitAttr:$static_specifier,
1052+
UnitAttr:$const_specifier);
10551053

10561054
let assemblyFormat = [{
1057-
(`extern` $externSpecifier^)?
1058-
(`static` $staticSpecifier^)?
1059-
(`const` $constSpecifier^)?
1055+
(`extern` $extern_specifier^)?
1056+
(`static` $static_specifier^)?
1057+
(`const` $const_specifier^)?
10601058
$sym_name
10611059
`:` custom<EmitCGlobalOpTypeAndInitialValue>($type, $initial_value)
10621060
attr-dict
@@ -1224,35 +1222,41 @@ def EmitC_IfOp : EmitC_Op<"if",
12241222
let hasCustomAssemblyFormat = 1;
12251223
}
12261224

1227-
def EmitC_SubscriptOp : EmitC_Op<"subscript",
1228-
[TypesMatchWith<"result type matches element type of 'array'",
1229-
"array", "result",
1230-
"::llvm::cast<ArrayType>($_self).getElementType()">]> {
1231-
let summary = "Array subscript operation";
1225+
def EmitC_SubscriptOp : EmitC_Op<"subscript", []> {
1226+
let summary = "Subscript operation";
12321227
let description = [{
12331228
With the `subscript` operation the subscript operator `[]` can be applied
1234-
to variables or arguments of array type.
1229+
to variables or arguments of array, pointer and opaque type.
12351230

12361231
Example:
12371232

12381233
```mlir
12391234
%i = index.constant 1
12401235
%j = index.constant 7
1241-
%0 = emitc.subscript %arg0[%i, %j] : <4x8xf32>, index, index
1236+
%0 = emitc.subscript %arg0[%i, %j] : !emitc.array<4x8xf32>, index, index
1237+
%1 = emitc.subscript %arg1[%i] : !emitc.ptr<i32>, index
12421238
```
12431239
}];
1244-
let arguments = (ins Arg<EmitC_ArrayType, "the reference to load from">:$array,
1245-
Variadic<IntegerIndexOrOpaqueType>:$indices);
1240+
let arguments = (ins Arg<AnyTypeOf<[
1241+
EmitC_ArrayType,
1242+
EmitC_OpaqueType,
1243+
EmitC_PointerType]>,
1244+
"the value to subscript">:$value,
1245+
Variadic<EmitCType>:$indices);
12461246
let results = (outs EmitCType:$result);
12471247

12481248
let builders = [
1249-
OpBuilder<(ins "Value":$array, "ValueRange":$indices), [{
1250-
build($_builder, $_state, cast<ArrayType>(array.getType()).getElementType(), array, indices);
1249+
OpBuilder<(ins "TypedValue<ArrayType>":$array, "ValueRange":$indices), [{
1250+
build($_builder, $_state, array.getType().getElementType(), array, indices);
1251+
}]>,
1252+
OpBuilder<(ins "TypedValue<PointerType>":$pointer, "Value":$index), [{
1253+
build($_builder, $_state, pointer.getType().getPointee(), pointer,
1254+
ValueRange{index});
12511255
}]>
12521256
];
12531257

12541258
let hasVerifier = 1;
1255-
let assemblyFormat = "$array `[` $indices `]` attr-dict `:` type($array) `,` type($indices)";
1259+
let assemblyFormat = "$value `[` $indices `]` attr-dict `:` functional-type(operands, results)";
12561260
}
12571261

12581262

mlir/include/mlir/Target/Cpp/CppEmitter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#ifndef MLIR_TARGET_CPP_CPPEMITTER_H
1414
#define MLIR_TARGET_CPP_CPPEMITTER_H
1515

16-
#include "llvm/Support/raw_ostream.h"
16+
#include "mlir/Support/LLVM.h"
1717

1818
namespace mlir {
1919
struct LogicalResult;

mlir/lib/Conversion/ArithToEmitC/ArithToEmitC.cpp

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,55 @@ class ArithOpConversion final : public OpConversionPattern<ArithOp> {
290290
}
291291
};
292292

293+
template <typename ArithOp, typename EmitCOp>
294+
class IntegerOpConversion final : public OpConversionPattern<ArithOp> {
295+
public:
296+
using OpConversionPattern<ArithOp>::OpConversionPattern;
297+
298+
LogicalResult
299+
matchAndRewrite(ArithOp op, typename ArithOp::Adaptor adaptor,
300+
ConversionPatternRewriter &rewriter) const override {
301+
302+
Type type = this->getTypeConverter()->convertType(op.getType());
303+
if (!isa_and_nonnull<IntegerType, IndexType>(type)) {
304+
return rewriter.notifyMatchFailure(op, "expected integer type");
305+
}
306+
307+
if (type.isInteger(1)) {
308+
// arith expects wrap-around arithmethic, which doesn't happen on `bool`.
309+
return rewriter.notifyMatchFailure(op, "i1 type is not implemented");
310+
}
311+
312+
Value lhs = adaptor.getLhs();
313+
Value rhs = adaptor.getRhs();
314+
Type arithmeticType = type;
315+
if ((type.isSignlessInteger() || type.isSignedInteger()) &&
316+
!bitEnumContainsAll(op.getOverflowFlags(),
317+
arith::IntegerOverflowFlags::nsw)) {
318+
// If the C type is signed and the op doesn't guarantee "No Signed Wrap",
319+
// we compute in unsigned integers to avoid UB.
320+
arithmeticType = rewriter.getIntegerType(type.getIntOrFloatBitWidth(),
321+
/*isSigned=*/false);
322+
}
323+
if (arithmeticType != type) {
324+
lhs = rewriter.template create<emitc::CastOp>(op.getLoc(), arithmeticType,
325+
lhs);
326+
rhs = rewriter.template create<emitc::CastOp>(op.getLoc(), arithmeticType,
327+
rhs);
328+
}
329+
330+
Value result = rewriter.template create<EmitCOp>(op.getLoc(),
331+
arithmeticType, lhs, rhs);
332+
333+
if (arithmeticType != type) {
334+
result =
335+
rewriter.template create<emitc::CastOp>(op.getLoc(), type, result);
336+
}
337+
rewriter.replaceOp(op, result);
338+
return success();
339+
}
340+
};
341+
293342
class SelectOpConversion : public OpConversionPattern<arith::SelectOp> {
294343
public:
295344
using OpConversionPattern<arith::SelectOp>::OpConversionPattern;
@@ -432,9 +481,9 @@ void mlir::populateArithToEmitCPatterns(TypeConverter &typeConverter,
432481
ArithOpConversion<arith::RemSIOp, emitc::RemOp>,
433482
ArithOpConversion<arith::MulFOp, emitc::MulOp>,
434483
ArithOpConversion<arith::SubFOp, emitc::SubOp>,
435-
ArithOpConversion<arith::AddIOp, emitc::AddOp>,
436-
ArithOpConversion<arith::MulIOp, emitc::MulOp>,
437-
ArithOpConversion<arith::SubIOp, emitc::SubOp>,
484+
IntegerOpConversion<arith::AddIOp, emitc::AddOp>,
485+
IntegerOpConversion<arith::MulIOp, emitc::MulOp>,
486+
IntegerOpConversion<arith::SubIOp, emitc::SubOp>,
438487
CmpFOpConversion,
439488
CmpIOpConversion,
440489
SelectOpConversion,

mlir/lib/Conversion/ArithToEmitC/ArithToEmitCPass.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ namespace {
3030
struct ConvertArithToEmitC
3131
: public impl::ConvertArithToEmitCBase<ConvertArithToEmitC> {
3232
using Base::Base;
33-
3433
void runOnOperation() override;
3534
};
3635
} // namespace

mlir/lib/Conversion/FuncToEmitC/FuncToEmitCPass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===- FuncToEmitC.cpp - Func to EmitC Pass ---------------------*- C++ -*-===//
1+
//===- FuncToEmitCPass.cpp - Func to EmitC Pass -----------------*- C++ -*-===//
22
//
33
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44
// See https://llvm.org/LICENSE.txt for license information.

mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,18 @@ struct ConvertGlobal final : public OpConversionPattern<memref::GlobalOp> {
8181
op.getLoc(),
8282
"only public and private visibility is currently supported");
8383
}
84-
// We are explicit in specifier the linkage because the default linkage
84+
// We are explicit in specifing the linkage because the default linkage
8585
// for constants is different in C and C++.
8686
bool staticSpecifier = visibility == SymbolTable::Visibility::Private;
8787
bool externSpecifier = !staticSpecifier;
8888

89+
Attribute initialValue = operands.getInitialValueAttr();
90+
if (isa_and_present<UnitAttr>(initialValue))
91+
initialValue = {};
92+
8993
rewriter.replaceOpWithNewOp<emitc::GlobalOp>(
90-
op, operands.getSymName(), resultTy, operands.getInitialValueAttr(),
91-
externSpecifier, staticSpecifier, operands.getConstant());
94+
op, operands.getSymName(), resultTy, initialValue, externSpecifier,
95+
staticSpecifier, operands.getConstant());
9296
return success();
9397
}
9498
};
@@ -124,8 +128,14 @@ struct ConvertLoad final : public OpConversionPattern<memref::LoadOp> {
124128
return rewriter.notifyMatchFailure(op.getLoc(), "cannot convert type");
125129
}
126130

131+
auto arrayValue =
132+
dyn_cast<TypedValue<emitc::ArrayType>>(operands.getMemref());
133+
if (!arrayValue) {
134+
return rewriter.notifyMatchFailure(op.getLoc(), "expected array type");
135+
}
136+
127137
auto subscript = rewriter.create<emitc::SubscriptOp>(
128-
op.getLoc(), operands.getMemref(), operands.getIndices());
138+
op.getLoc(), arrayValue, operands.getIndices());
129139

130140
auto noInit = emitc::OpaqueAttr::get(getContext(), "");
131141
auto var =
@@ -143,9 +153,14 @@ struct ConvertStore final : public OpConversionPattern<memref::StoreOp> {
143153
LogicalResult
144154
matchAndRewrite(memref::StoreOp op, OpAdaptor operands,
145155
ConversionPatternRewriter &rewriter) const override {
156+
auto arrayValue =
157+
dyn_cast<TypedValue<emitc::ArrayType>>(operands.getMemref());
158+
if (!arrayValue) {
159+
return rewriter.notifyMatchFailure(op.getLoc(), "expected array type");
160+
}
146161

147162
auto subscript = rewriter.create<emitc::SubscriptOp>(
148-
op.getLoc(), operands.getMemref(), operands.getIndices());
163+
op.getLoc(), arrayValue, operands.getIndices());
149164
rewriter.replaceOpWithNewOp<emitc::AssignOp>(op, subscript,
150165
operands.getValue());
151166
return success();

0 commit comments

Comments
 (0)