diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp index 5a95ef36d05024..a94b22e051d0e1 100644 --- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp +++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp @@ -231,11 +231,11 @@ ExprMutationAnalyzer::Analyzer::findPointeeMutation(const Decl *Dec) { const Stmt *ExprMutationAnalyzer::Analyzer::findMutationMemoized( const Expr *Exp, llvm::ArrayRef Finders, Memoized::ResultMap &MemoizedResults) { + // Assume Exp is not mutated before analyzing Exp. auto [Memoized, Inserted] = MemoizedResults.try_emplace(Exp); if (!Inserted) return Memoized->second; - // Assume Exp is not mutated before analyzing Exp. if (isUnevaluated(Exp)) return nullptr; diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index f6d787a0c88319..cd4504630f8719 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -799,7 +799,7 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs, } // If we've not parsed a statement yet, parse one now. - if (!SubStmt.isInvalid() && !SubStmt.isUsable()) + if (SubStmt.isUnset()) SubStmt = ParseStatement(nullptr, StmtCtx); // Broken substmt shouldn't prevent the label from being added to the AST. diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h b/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h index 0749f633b4bcf5..1664b92b213692 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h @@ -120,7 +120,7 @@ class DeadlockDetectorTLS { u32 lock; u32 stk; }; - LockWithContext all_locks_with_contexts_[64]; + LockWithContext all_locks_with_contexts_[128]; uptr n_all_locks_; }; diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp index 5a2d39cd30607f..c83efec8eaca2c 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp @@ -673,7 +673,8 @@ void CheckUnwind() { thr->ignore_reads_and_writes++; atomic_store_relaxed(&thr->in_signal_handler, 0); #endif - PrintCurrentStackSlow(StackTrace::GetCurrentPc()); + PrintCurrentStack(StackTrace::GetCurrentPc(), + common_flags()->fast_unwind_on_fatal); } bool is_initialized; diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h index f48be8e0a4fe08..49bee9c67d3030 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h @@ -514,7 +514,7 @@ bool IsExpectedReport(uptr addr, uptr size); StackID CurrentStackId(ThreadState *thr, uptr pc); ReportStack *SymbolizeStackId(StackID stack_id); void PrintCurrentStack(ThreadState *thr, uptr pc); -void PrintCurrentStackSlow(uptr pc); // uses libunwind +void PrintCurrentStack(uptr pc, bool fast); // may uses libunwind MBlock *JavaHeapBlock(uptr addr, uptr *start); void Initialize(ThreadState *thr); diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp index 0311df553fdd0a..51a98e2f2d5e75 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp @@ -828,18 +828,18 @@ void PrintCurrentStack(ThreadState *thr, uptr pc) { PrintStack(SymbolizeStack(trace)); } -// Always inlining PrintCurrentStackSlow, because LocatePcInTrace assumes +// Always inlining PrintCurrentStack, because LocatePcInTrace assumes // __sanitizer_print_stack_trace exists in the actual unwinded stack, but -// tail-call to PrintCurrentStackSlow breaks this assumption because +// tail-call to PrintCurrentStack breaks this assumption because // __sanitizer_print_stack_trace disappears after tail-call. // However, this solution is not reliable enough, please see dvyukov's comment // http://reviews.llvm.org/D19148#406208 // Also see PR27280 comment 2 and 3 for breaking examples and analysis. -ALWAYS_INLINE USED void PrintCurrentStackSlow(uptr pc) { +ALWAYS_INLINE USED void PrintCurrentStack(uptr pc, bool fast) { #if !SANITIZER_GO uptr bp = GET_CURRENT_FRAME(); auto *ptrace = New(); - ptrace->Unwind(pc, bp, nullptr, false); + ptrace->Unwind(pc, bp, nullptr, fast); for (uptr i = 0; i < ptrace->size / 2; i++) { uptr tmp = ptrace->trace_buffer[i]; @@ -857,6 +857,6 @@ using namespace __tsan; extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_print_stack_trace() { - PrintCurrentStackSlow(StackTrace::GetCurrentPc()); + PrintCurrentStack(StackTrace::GetCurrentPc(), false); } } // extern "C" diff --git a/compiler-rt/test/tsan/many_held_mutex.cpp b/compiler-rt/test/tsan/many_held_mutex.cpp new file mode 100644 index 00000000000000..76e072b35a2336 --- /dev/null +++ b/compiler-rt/test/tsan/many_held_mutex.cpp @@ -0,0 +1,21 @@ +// RUN: %clangxx_tsan -O1 %s %link_libcxx_tsan -fsanitize=thread -o %t +// RUN: %run %t 128 + +#include +#include +#include + +int main(int argc, char *argv[]) { + int num_of_mtx = std::atoi(argv[1]); + + std::vector mutexes(num_of_mtx); + + for (auto &mu : mutexes) { + mu.lock(); + } + for (auto &mu : mutexes) { + mu.unlock(); + } + + return 0; +} diff --git a/lld/Common/ErrorHandler.cpp b/lld/Common/ErrorHandler.cpp index ad6867744c145f..0ec79bb5423e5d 100644 --- a/lld/Common/ErrorHandler.cpp +++ b/lld/Common/ErrorHandler.cpp @@ -339,6 +339,8 @@ void ErrorHandler::fatal(const Twine &msg) { SyncStream::~SyncStream() { os.flush(); switch (level) { + case DiagLevel::None: + break; case DiagLevel::Log: e.log(buf); break; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 682bfd20f1cc2a..97ed9289baf569 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -2715,21 +2715,6 @@ static void redirectSymbols(Ctx &ctx, ArrayRef wrapped) { ctx.symtab->wrap(w.sym, w.real, w.wrap); } -static void reportMissingFeature(Ctx &ctx, StringRef config, - const Twine &report) { - if (config == "error") - ErrAlways(ctx) << report; - else if (config == "warning") - Warn(ctx) << report; -} - -static void checkAndReportMissingFeature(Ctx &ctx, StringRef config, - uint32_t features, uint32_t mask, - const Twine &report) { - if (!(features & mask)) - reportMissingFeature(ctx, config, report); -} - // To enable CET (x86's hardware-assisted control flow enforcement), each // source file must be compiled with -fcf-protection. Object files compiled // with the flag contain feature flags indicating that they are compatible @@ -2762,28 +2747,43 @@ static void readSecurityNotes(Ctx &ctx) { bool hasValidPauthAbiCoreInfo = llvm::any_of( ctx.aarch64PauthAbiCoreInfo, [](uint8_t c) { return c != 0; }); + auto report = [&](StringRef config) -> ELFSyncStream { + if (config == "error") + return {ctx, DiagLevel::Err}; + else if (config == "warning") + return {ctx, DiagLevel::Warn}; + return {ctx, DiagLevel::None}; + }; + auto reportUnless = [&](StringRef config, bool cond) -> ELFSyncStream { + if (cond) + return {ctx, DiagLevel::None}; + return report(config); + }; for (ELFFileBase *f : ctx.objectFiles) { uint32_t features = f->andFeatures; - checkAndReportMissingFeature( - ctx, ctx.arg.zBtiReport, features, GNU_PROPERTY_AARCH64_FEATURE_1_BTI, - toStr(ctx, f) + ": -z bti-report: file does not have " - "GNU_PROPERTY_AARCH64_FEATURE_1_BTI property"); - - checkAndReportMissingFeature( - ctx, ctx.arg.zGcsReport, features, GNU_PROPERTY_AARCH64_FEATURE_1_GCS, - toStr(ctx, f) + ": -z gcs-report: file does not have " - "GNU_PROPERTY_AARCH64_FEATURE_1_GCS property"); - - checkAndReportMissingFeature( - ctx, ctx.arg.zCetReport, features, GNU_PROPERTY_X86_FEATURE_1_IBT, - toStr(ctx, f) + ": -z cet-report: file does not have " - "GNU_PROPERTY_X86_FEATURE_1_IBT property"); - - checkAndReportMissingFeature( - ctx, ctx.arg.zCetReport, features, GNU_PROPERTY_X86_FEATURE_1_SHSTK, - toStr(ctx, f) + ": -z cet-report: file does not have " - "GNU_PROPERTY_X86_FEATURE_1_SHSTK property"); + reportUnless(ctx.arg.zBtiReport, + features & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) + << f + << ": -z bti-report: file does not have " + "GNU_PROPERTY_AARCH64_FEATURE_1_BTI property"; + + reportUnless(ctx.arg.zGcsReport, + features & GNU_PROPERTY_AARCH64_FEATURE_1_GCS) + << f + << ": -z gcs-report: file does not have " + "GNU_PROPERTY_AARCH64_FEATURE_1_GCS property"; + + reportUnless(ctx.arg.zCetReport, features & GNU_PROPERTY_X86_FEATURE_1_IBT) + << f + << ": -z cet-report: file does not have " + "GNU_PROPERTY_X86_FEATURE_1_IBT property"; + + reportUnless(ctx.arg.zCetReport, + features & GNU_PROPERTY_X86_FEATURE_1_SHSTK) + << f + << ": -z cet-report: file does not have " + "GNU_PROPERTY_X86_FEATURE_1_SHSTK property"; if (ctx.arg.zForceBti && !(features & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) { features |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI; @@ -2813,11 +2813,11 @@ static void readSecurityNotes(Ctx &ctx) { continue; if (f->aarch64PauthAbiCoreInfo.empty()) { - reportMissingFeature(ctx, ctx.arg.zPauthReport, - toStr(ctx, f) + - ": -z pauth-report: file does not have AArch64 " - "PAuth core info while '" + - referenceFileName + "' has one"); + report(ctx.arg.zPauthReport) + << f + << ": -z pauth-report: file does not have AArch64 " + "PAuth core info while '" + << referenceFileName << "' has one"; continue; } diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h index e3b4b387320588..268caa547ffed9 100644 --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -475,7 +475,9 @@ class PotentialSpillSection : public InputSection { } }; +#ifndef _WIN32 static_assert(sizeof(InputSection) <= 152, "InputSection is too big"); +#endif class SyntheticSection : public InputSection { public: diff --git a/lld/include/lld/Common/ErrorHandler.h b/lld/include/lld/Common/ErrorHandler.h index ee11f178939710..e70afbd87d1556 100644 --- a/lld/include/lld/Common/ErrorHandler.h +++ b/lld/include/lld/Common/ErrorHandler.h @@ -151,7 +151,7 @@ void message(const Twine &msg, llvm::raw_ostream &s = outs()); void warn(const Twine &msg); uint64_t errorCount(); -enum class DiagLevel { Log, Msg, Warn, Err, Fatal }; +enum class DiagLevel { None, Log, Msg, Warn, Err, Fatal }; // A class that synchronizes thread writing to the same stream similar // std::osyncstream. diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td index e4485d997c34cc..7bb6c3156c43e0 100644 --- a/llvm/include/llvm/Target/TargetSelectionDAG.td +++ b/llvm/include/llvm/Target/TargetSelectionDAG.td @@ -118,6 +118,10 @@ def SDTIntBinOp : SDTypeProfile<1, 2, [ // add, and, or, xor, udiv, etc. def SDTIntShiftOp : SDTypeProfile<1, 2, [ // shl, sra, srl SDTCisSameAs<0, 1>, SDTCisInt<0>, SDTCisInt<2> ]>; +def SDTIntShiftPairOp : SDTypeProfile<2, 3, [ // shl_parts, sra_parts, srl_parts + SDTCisInt<0>, SDTCisSameAs<1, 0>, + SDTCisSameAs<2, 0>, SDTCisSameAs<3, 0>, SDTCisInt<4> +]>; def SDTIntShiftDOp: SDTypeProfile<1, 3, [ // fshl, fshr SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisInt<0>, SDTCisInt<3> ]>; @@ -422,6 +426,9 @@ def sra : SDNode<"ISD::SRA" , SDTIntShiftOp>; def shl : SDNode<"ISD::SHL" , SDTIntShiftOp>; def rotl : SDNode<"ISD::ROTL" , SDTIntShiftOp>; def rotr : SDNode<"ISD::ROTR" , SDTIntShiftOp>; +def shl_parts : SDNode<"ISD::SHL_PARTS" , SDTIntShiftPairOp>; +def sra_parts : SDNode<"ISD::SRA_PARTS" , SDTIntShiftPairOp>; +def srl_parts : SDNode<"ISD::SRL_PARTS" , SDTIntShiftPairOp>; def fshl : SDNode<"ISD::FSHL" , SDTIntShiftDOp>; def fshr : SDNode<"ISD::FSHR" , SDTIntShiftDOp>; def and : SDNode<"ISD::AND" , SDTIntBinOp, diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td b/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td index 702f6e67c55271..bec294a945d2fe 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td +++ b/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td @@ -100,8 +100,8 @@ def AMDGPUtc_return_chain: SDNode<"AMDGPUISD::TC_RETURN_CHAIN", >; def AMDGPUtrap : SDNode<"AMDGPUISD::TRAP", - SDTypeProfile<0, -1, [SDTCisVT<0, i16>]>, - [SDNPHasChain, SDNPVariadic, SDNPSideEffect, SDNPInGlue] + SDTypeProfile<0, 1, [SDTCisVT<0, i16>]>, + [SDNPHasChain, SDNPVariadic, SDNPSideEffect, SDNPOptInGlue] >; def AMDGPUconstdata_ptr : SDNode< diff --git a/llvm/lib/Target/AVR/AVRInstrInfo.td b/llvm/lib/Target/AVR/AVRInstrInfo.td index e912878e9b23cc..3973cd30de1ecb 100644 --- a/llvm/lib/Target/AVR/AVRInstrInfo.td +++ b/llvm/lib/Target/AVR/AVRInstrInfo.td @@ -69,9 +69,9 @@ def AVRasrbn : SDNode<"AVRISD::ASRBN", SDTIntBinOp>; def AVRlslwn : SDNode<"AVRISD::LSLWN", SDTIntBinOp>; def AVRlsrwn : SDNode<"AVRISD::LSRWN", SDTIntBinOp>; def AVRasrwn : SDNode<"AVRISD::ASRWN", SDTIntBinOp>; -def AVRlslw : SDNode<"AVRISD::LSLW", SDTIntShiftDOp>; -def AVRlsrw : SDNode<"AVRISD::LSRW", SDTIntShiftDOp>; -def AVRasrw : SDNode<"AVRISD::ASRW", SDTIntShiftDOp>; +def AVRlslw : SDNode<"AVRISD::LSLW", SDTIntShiftPairOp>; +def AVRlsrw : SDNode<"AVRISD::LSRW", SDTIntShiftPairOp>; +def AVRasrw : SDNode<"AVRISD::ASRW", SDTIntShiftPairOp>; // Pseudo shift nodes for non-constant shift amounts. def AVRlslLoop : SDNode<"AVRISD::LSLLOOP", SDTIntShiftOp>; diff --git a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp index 139e75dd3ddb34..555267327a0a9e 100644 --- a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -244,7 +244,7 @@ class ModuleSanitizerCoverage { void InjectTraceForSwitch(Function &F, ArrayRef SwitchTraceTargets); bool InjectCoverage(Function &F, ArrayRef AllBlocks, - bool IsLeafFunc = true); + bool IsLeafFunc); GlobalVariable *CreateFunctionLocalArrayInSection(size_t NumElements, Function &F, Type *Ty, const char *Section); @@ -254,7 +254,7 @@ class ModuleSanitizerCoverage { Instruction *I); Value *CreateFunctionLocalGateCmp(IRBuilder<> &IRB); void InjectCoverageAtBlock(Function &F, BasicBlock &BB, size_t Idx, - Value *&FunctionGateCmp, bool IsLeafFunc = true); + Value *&FunctionGateCmp, bool IsLeafFunc); Function *CreateInitCallsForSections(Module &M, const char *CtorName, const char *InitFunctionName, Type *Ty, const char *Section); diff --git a/llvm/test/CodeGen/Hexagon/widen-not-load.ll b/llvm/test/CodeGen/Hexagon/widen-not-load.ll index 6206a0a5367e49..d8d658342616c3 100644 --- a/llvm/test/CodeGen/Hexagon/widen-not-load.ll +++ b/llvm/test/CodeGen/Hexagon/widen-not-load.ll @@ -1,4 +1,5 @@ ; Test that double word post increment load is not generated. +; REQUIRES: asserts ; RUN: llc -march=hexagon -O2 -debug-only=hexagon-load-store-widening %s -o 2>&1 - | FileCheck %s diff --git a/mlir/lib/Conversion/LLVMCommon/TypeConverter.cpp b/mlir/lib/Conversion/LLVMCommon/TypeConverter.cpp index ce91424e7a577e..59b0f5c9b09bcd 100644 --- a/mlir/lib/Conversion/LLVMCommon/TypeConverter.cpp +++ b/mlir/lib/Conversion/LLVMCommon/TypeConverter.cpp @@ -153,6 +153,12 @@ LLVMTypeConverter::LLVMTypeConverter(MLIRContext *ctx, type.isVarArg()); }); + // Helper function that checks if the given value range is a bare pointer. + auto isBarePointer = [](ValueRange values) { + return values.size() == 1 && + isa(values.front().getType()); + }; + // Argument materializations convert from the new block argument types // (multiple SSA values that make up a memref descriptor) back to the // original block argument type. The dialect conversion framework will then @@ -161,11 +167,10 @@ LLVMTypeConverter::LLVMTypeConverter(MLIRContext *ctx, addArgumentMaterialization([&](OpBuilder &builder, UnrankedMemRefType resultType, ValueRange inputs, Location loc) { - if (inputs.size() == 1) { - // Bare pointers are not supported for unranked memrefs because a - // memref descriptor cannot be built just from a bare pointer. + // Note: Bare pointers are not supported for unranked memrefs because a + // memref descriptor cannot be built just from a bare pointer. + if (TypeRange(inputs) != getUnrankedMemRefDescriptorFields()) return Value(); - } Value desc = UnrankedMemRefDescriptor::pack(builder, loc, *this, resultType, inputs); // An argument materialization must return a value of type @@ -177,20 +182,17 @@ LLVMTypeConverter::LLVMTypeConverter(MLIRContext *ctx, addArgumentMaterialization([&](OpBuilder &builder, MemRefType resultType, ValueRange inputs, Location loc) { Value desc; - if (inputs.size() == 1) { - // This is a bare pointer. We allow bare pointers only for function entry - // blocks. - BlockArgument barePtr = dyn_cast(inputs.front()); - if (!barePtr) - return Value(); - Block *block = barePtr.getOwner(); - if (!block->isEntryBlock() || - !isa(block->getParentOp())) - return Value(); + if (isBarePointer(inputs)) { desc = MemRefDescriptor::fromStaticShape(builder, loc, *this, resultType, inputs[0]); - } else { + } else if (TypeRange(inputs) == + getMemRefDescriptorFields(resultType, + /*unpackAggregates=*/true)) { desc = MemRefDescriptor::pack(builder, loc, *this, resultType, inputs); + } else { + // The inputs are neither a bare pointer nor an unpacked memref + // descriptor. This materialization function cannot be used. + return Value(); } // An argument materialization must return a value of type `resultType`, // so insert a cast from the memref descriptor type (!llvm.struct) to the diff --git a/mlir/test/Conversion/MemRefToLLVM/type-conversion.mlir b/mlir/test/Conversion/MemRefToLLVM/type-conversion.mlir new file mode 100644 index 00000000000000..0288aa11313c72 --- /dev/null +++ b/mlir/test/Conversion/MemRefToLLVM/type-conversion.mlir @@ -0,0 +1,57 @@ +// RUN: mlir-opt %s -test-llvm-legalize-patterns -split-input-file + +// Test the argument materializer for ranked MemRef types. + +// CHECK-LABEL: func @construct_ranked_memref_descriptor( +// CHECK: llvm.mlir.undef : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)> +// CHECK-COUNT-7: llvm.insertvalue +// CHECK: builtin.unrealized_conversion_cast %{{.*}} : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)> to memref<5x4xf32> +func.func @construct_ranked_memref_descriptor(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: i64, %arg3: i64, %arg4: i64, %arg5: i64, %arg6: i64) { + %0 = "test.direct_replacement"(%arg0, %arg1, %arg2, %arg3, %arg4, %arg5, %arg6) : (!llvm.ptr, !llvm.ptr, i64, i64, i64, i64, i64) -> (memref<5x4xf32>) + "test.legal_op"(%0) : (memref<5x4xf32>) -> () + return +} + +// ----- + +// The argument materializer for ranked MemRef types is called with incorrect +// input types. Make sure that the materializer is skipped and we do not +// generate invalid IR. + +// CHECK-LABEL: func @invalid_ranked_memref_descriptor( +// CHECK: %[[cast:.*]] = builtin.unrealized_conversion_cast %{{.*}} : i1 to memref<5x4xf32> +// CHECK: "test.legal_op"(%[[cast]]) +func.func @invalid_ranked_memref_descriptor(%arg0: i1) { + %0 = "test.direct_replacement"(%arg0) : (i1) -> (memref<5x4xf32>) + "test.legal_op"(%0) : (memref<5x4xf32>) -> () + return +} + +// ----- + +// Test the argument materializer for unranked MemRef types. + +// CHECK-LABEL: func @construct_unranked_memref_descriptor( +// CHECK: llvm.mlir.undef : !llvm.struct<(i64, ptr)> +// CHECK-COUNT-2: llvm.insertvalue +// CHECK: builtin.unrealized_conversion_cast %{{.*}} : !llvm.struct<(i64, ptr)> to memref<*xf32> +func.func @construct_unranked_memref_descriptor(%arg0: i64, %arg1: !llvm.ptr) { + %0 = "test.direct_replacement"(%arg0, %arg1) : (i64, !llvm.ptr) -> (memref<*xf32>) + "test.legal_op"(%0) : (memref<*xf32>) -> () + return +} + +// ----- + +// The argument materializer for unranked MemRef types is called with incorrect +// input types. Make sure that the materializer is skipped and we do not +// generate invalid IR. + +// CHECK-LABEL: func @invalid_unranked_memref_descriptor( +// CHECK: %[[cast:.*]] = builtin.unrealized_conversion_cast %{{.*}} : i1 to memref<*xf32> +// CHECK: "test.legal_op"(%[[cast]]) +func.func @invalid_unranked_memref_descriptor(%arg0: i1) { + %0 = "test.direct_replacement"(%arg0) : (i1) -> (memref<*xf32>) + "test.legal_op"(%0) : (memref<*xf32>) -> () + return +} diff --git a/mlir/test/IR/properties.mlir b/mlir/test/IR/properties.mlir index 9a1c49cb7dabf3..b339a03812badb 100644 --- a/mlir/test/IR/properties.mlir +++ b/mlir/test/IR/properties.mlir @@ -1,4 +1,4 @@ -// # RUN: mlir-opt %s -split-input-file | mlir-opt |FileCheck %s +// # RUN: mlir-opt %s -split-input-file | mlir-opt | FileCheck %s // # RUN: mlir-opt %s -mlir-print-op-generic -split-input-file | mlir-opt -mlir-print-op-generic | FileCheck %s --check-prefix=GENERIC // CHECK: test.with_properties @@ -38,6 +38,14 @@ test.using_property_in_custom [1, 4, 20] // GENERIC-SAME: }> test.using_property_ref_in_custom 1 + 4 = 5 +// Tests that the variadic segment size properties are elided. +// CHECK: %[[CI64:.*]] = arith.constant +// CHECK-NEXT: test.variadic_segment_prop %[[CI64]], %[[CI64]] : %[[CI64]] : i64, i64 : i64 end +// GENERIC: %[[CI64:.*]] = "arith.constant"() +// GENERIC-NEXT: "test.variadic_segment_prop"(%[[CI64]], %[[CI64]], %[[CI64]]) <{operandSegmentSizes = array, resultSegmentSizes = array}> : (i64, i64, i64) -> (i64, i64, i64) +%ci64 = arith.constant 0 : i64 +test.variadic_segment_prop %ci64, %ci64 : %ci64 : i64, i64 : i64 end + // CHECK: test.with_default_valued_properties na{{$}} // GENERIC: "test.with_default_valued_properties"() // GENERIC-SAME: <{a = 0 : i32, b = "", c = -1 : i32, unit = false}> : () -> () diff --git a/mlir/test/lib/Dialect/LLVM/CMakeLists.txt b/mlir/test/lib/Dialect/LLVM/CMakeLists.txt index 734757ce79da37..6a2f0ba2756d43 100644 --- a/mlir/test/lib/Dialect/LLVM/CMakeLists.txt +++ b/mlir/test/lib/Dialect/LLVM/CMakeLists.txt @@ -1,6 +1,7 @@ # Exclude tests from libMLIR.so add_mlir_library(MLIRLLVMTestPasses TestLowerToLLVM.cpp + TestPatterns.cpp EXCLUDE_FROM_LIBMLIR diff --git a/mlir/test/lib/Dialect/LLVM/TestPatterns.cpp b/mlir/test/lib/Dialect/LLVM/TestPatterns.cpp new file mode 100644 index 00000000000000..ab02866970b1d5 --- /dev/null +++ b/mlir/test/lib/Dialect/LLVM/TestPatterns.cpp @@ -0,0 +1,77 @@ +//===- TestPatterns.cpp - LLVM dialect test patterns ----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "mlir/Conversion/LLVMCommon/TypeConverter.h" +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/Dialect/LLVMIR/LLVMTypes.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Transforms/DialectConversion.h" + +using namespace mlir; + +namespace { + +/// Replace this op (which is expected to have 1 result) with the operands. +struct TestDirectReplacementOp : public ConversionPattern { + TestDirectReplacementOp(MLIRContext *ctx, const TypeConverter &converter) + : ConversionPattern(converter, "test.direct_replacement", 1, ctx) {} + LogicalResult + matchAndRewrite(Operation *op, ArrayRef operands, + ConversionPatternRewriter &rewriter) const final { + if (op->getNumResults() != 1) + return failure(); + rewriter.replaceOpWithMultiple(op, {operands}); + return success(); + } +}; + +struct TestLLVMLegalizePatternsPass + : public PassWrapper> { + MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestLLVMLegalizePatternsPass) + + StringRef getArgument() const final { return "test-llvm-legalize-patterns"; } + StringRef getDescription() const final { + return "Run LLVM dialect legalization patterns"; + } + + void getDependentDialects(DialectRegistry ®istry) const override { + registry.insert(); + } + + void runOnOperation() override { + MLIRContext *ctx = &getContext(); + LLVMTypeConverter converter(ctx); + mlir::RewritePatternSet patterns(ctx); + patterns.add(ctx, converter); + + // Define the conversion target used for the test. + ConversionTarget target(*ctx); + target.addLegalOp(OperationName("test.legal_op", ctx)); + + // Handle a partial conversion. + DenseSet unlegalizedOps; + ConversionConfig config; + config.unlegalizedOps = &unlegalizedOps; + if (failed(applyPartialConversion(getOperation(), target, + std::move(patterns), config))) + getOperation()->emitError() << "applyPartialConversion failed"; + } +}; +} // namespace + +//===----------------------------------------------------------------------===// +// PassRegistration +//===----------------------------------------------------------------------===// + +namespace mlir { +namespace test { +void registerTestLLVMLegalizePatternsPass() { + PassRegistration(); +} +} // namespace test +} // namespace mlir diff --git a/mlir/test/lib/Dialect/Test/TestOps.td b/mlir/test/lib/Dialect/Test/TestOps.td index cfe19a2fd5c08b..6752113cab8d41 100644 --- a/mlir/test/lib/Dialect/Test/TestOps.td +++ b/mlir/test/lib/Dialect/Test/TestOps.td @@ -3047,6 +3047,15 @@ def TestOpUsingPropertyInCustomAndOther ); } +def TestOpWithVariadicSegmentProperties : TEST_Op<"variadic_segment_prop", + [AttrSizedOperandSegments, AttrSizedResultSegments]> { + let arguments = (ins Variadic:$a1, Variadic:$a2); + let results = (outs Variadic:$b1, Variadic:$b2); + let assemblyFormat = [{ + $a1 `:` $a2 `:` type($b1) `:` type($b2) prop-dict attr-dict `end` + }]; +} + def TestOpUsingPropertyRefInCustom : TEST_Op<"using_property_ref_in_custom"> { let assemblyFormat = "custom($first) `+` custom($second, ref($first)) attr-dict"; let arguments = (ins IntProperty<"int64_t">:$first, IntProperty<"int64_t">:$second); diff --git a/mlir/tools/mlir-opt/mlir-opt.cpp b/mlir/tools/mlir-opt/mlir-opt.cpp index 002c3900056dee..94bc67a1e96093 100644 --- a/mlir/tools/mlir-opt/mlir-opt.cpp +++ b/mlir/tools/mlir-opt/mlir-opt.cpp @@ -113,6 +113,7 @@ void registerTestLinalgRankReduceContractionOps(); void registerTestLinalgTransforms(); void registerTestLivenessAnalysisPass(); void registerTestLivenessPass(); +void registerTestLLVMLegalizePatternsPass(); void registerTestLoopFusion(); void registerTestLoopMappingPass(); void registerTestLoopUnrollingPass(); @@ -250,6 +251,7 @@ void registerTestPasses() { mlir::test::registerTestLinalgTransforms(); mlir::test::registerTestLivenessAnalysisPass(); mlir::test::registerTestLivenessPass(); + mlir::test::registerTestLLVMLegalizePatternsPass(); mlir::test::registerTestLoopFusion(); mlir::test::registerTestLoopMappingPass(); mlir::test::registerTestLoopUnrollingPass(); diff --git a/mlir/tools/mlir-tblgen/OpFormatGen.cpp b/mlir/tools/mlir-tblgen/OpFormatGen.cpp index 7e2b0694a860a3..8d2e15a941370c 100644 --- a/mlir/tools/mlir-tblgen/OpFormatGen.cpp +++ b/mlir/tools/mlir-tblgen/OpFormatGen.cpp @@ -2008,10 +2008,26 @@ static void genNonDefaultValueCheck(MethodBody &body, const Operator &op, << "() != " << propElement.getVar()->prop.getDefaultValue(); } +/// Elide the variadic segment size attributes if necessary. +/// This pushes elided attribute names in `elidedStorage`. +static void genVariadicSegmentElision(OperationFormat &fmt, Operator &op, + MethodBody &body, + const char *elidedStorage) { + if (!fmt.allOperands && + op.getTrait("::mlir::OpTrait::AttrSizedOperandSegments")) + body << " " << elidedStorage << ".push_back(\"operandSegmentSizes\");\n"; + if (!fmt.allResultTypes && + op.getTrait("::mlir::OpTrait::AttrSizedResultSegments")) + body << " " << elidedStorage << ".push_back(\"resultSegmentSizes\");\n"; +} + /// Generate the printer for the 'prop-dict' directive. static void genPropDictPrinter(OperationFormat &fmt, Operator &op, MethodBody &body) { body << " ::llvm::SmallVector<::llvm::StringRef, 2> elidedProps;\n"; + + genVariadicSegmentElision(fmt, op, body, "elidedProps"); + for (const NamedProperty *namedProperty : fmt.usedProperties) body << " elidedProps.push_back(\"" << namedProperty->name << "\");\n"; for (const NamedAttribute *namedAttr : fmt.usedAttributes) @@ -2057,13 +2073,9 @@ static void genPropDictPrinter(OperationFormat &fmt, Operator &op, static void genAttrDictPrinter(OperationFormat &fmt, Operator &op, MethodBody &body, bool withKeyword) { body << " ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;\n"; - // Elide the variadic segment size attributes if necessary. - if (!fmt.allOperands && - op.getTrait("::mlir::OpTrait::AttrSizedOperandSegments")) - body << " elidedAttrs.push_back(\"operandSegmentSizes\");\n"; - if (!fmt.allResultTypes && - op.getTrait("::mlir::OpTrait::AttrSizedResultSegments")) - body << " elidedAttrs.push_back(\"resultSegmentSizes\");\n"; + + genVariadicSegmentElision(fmt, op, body, "elidedAttrs"); + for (const StringRef key : fmt.inferredAttributes.keys()) body << " elidedAttrs.push_back(\"" << key << "\");\n"; for (const NamedAttribute *attr : fmt.usedAttributes) diff --git a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel index 0628947540ca73..b3c7108d840d38 100644 --- a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel @@ -1220,6 +1220,7 @@ cc_library( ":Core", ":MC", ":Object", + ":ProfileData", ":Support", ":TargetParser", ":config", diff --git a/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel b/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel index c69f793943beec..688edacbc93bf9 100644 --- a/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel @@ -807,6 +807,7 @@ cc_library( "//mlir:FuncToLLVM", "//mlir:IR", "//mlir:IndexToLLVM", + "//mlir:LLVMCommonConversion", "//mlir:LLVMDialect", "//mlir:LinalgTransforms", "//mlir:MathToLLVM", @@ -815,6 +816,7 @@ cc_library( "//mlir:Pass", "//mlir:ReconcileUnrealizedCasts", "//mlir:SCFToControlFlow", + "//mlir:TransformUtils", "//mlir:Transforms", "//mlir:VectorToLLVM", "//mlir:VectorToSCF",