From 360e4abfc8c7298283041e8f5a07f1829a888d18 Mon Sep 17 00:00:00 2001 From: Timm Baeder Date: Sat, 31 Aug 2024 06:24:36 +0200 Subject: [PATCH 01/14] [clang][bytecode] Diagnose comparisons with literals (#106734) This requires adding a new opcode for PointerToBoolean casts, since we otherwise emit too many diagnostics. But that fixes an older problem when casting weak pointers to bool. --- clang/lib/AST/ByteCode/Compiler.cpp | 11 +--- clang/lib/AST/ByteCode/Interp.h | 62 +++++++++++++------ clang/lib/AST/ByteCode/MemberPointer.h | 5 ++ clang/lib/AST/ByteCode/Opcodes.td | 5 ++ clang/lib/AST/ByteCode/Pointer.cpp | 11 ++++ clang/lib/AST/ByteCode/Pointer.h | 4 ++ clang/test/AST/ByteCode/builtin-functions.cpp | 6 ++ clang/test/AST/ByteCode/weak.cpp | 6 -- 8 files changed, 76 insertions(+), 34 deletions(-) diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 9bd77edb0a550f..dced9ea3493732 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -505,14 +505,9 @@ bool Compiler::VisitCastExpr(const CastExpr *CE) { case CK_MemberPointerToBoolean: { PrimType PtrT = classifyPrim(SubExpr->getType()); - // Just emit p != nullptr for this. if (!this->visit(SubExpr)) return false; - - if (!this->emitNull(PtrT, nullptr, CE)) - return false; - - return this->emitNE(PtrT, CE); + return this->emitIsNonNull(PtrT, CE); } case CK_IntegralComplexToBoolean: @@ -2323,8 +2318,8 @@ bool Compiler::VisitMaterializeTemporaryExpr( // For everyhing else, use local variables. if (SubExprT) { - unsigned LocalIndex = allocateLocalPrimitive( - SubExpr, *SubExprT, /*IsConst=*/true, /*IsExtended=*/true); + unsigned LocalIndex = allocateLocalPrimitive(E, *SubExprT, /*IsConst=*/true, + /*IsExtended=*/true); if (!this->visit(SubExpr)) return false; if (!this->emitSetLocal(*SubExprT, LocalIndex, E)) diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index f8af51b71101d2..aa790a71a6b476 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -986,24 +986,7 @@ inline bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) { } } - if (!Pointer::hasSameBase(LHS, RHS)) { - if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() && - RHS.getOffset() == 0) { - const SourceInfo &Loc = S.Current->getSource(OpPC); - S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end) - << LHS.toDiagnosticString(S.getASTContext()); - return false; - } else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() && - LHS.getOffset() == 0) { - const SourceInfo &Loc = S.Current->getSource(OpPC); - S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end) - << RHS.toDiagnosticString(S.getASTContext()); - return false; - } - - S.Stk.push(BoolT::from(Fn(ComparisonCategoryResult::Unordered))); - return true; - } else { + if (Pointer::hasSameBase(LHS, RHS)) { unsigned VL = LHS.getByteOffset(); unsigned VR = RHS.getByteOffset(); @@ -1019,6 +1002,35 @@ inline bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) { S.Stk.push(BoolT::from(Fn(Compare(VL, VR)))); return true; } + // Otherwise we need to do a bunch of extra checks before returning Unordered. + if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() && + RHS.getOffset() == 0) { + const SourceInfo &Loc = S.Current->getSource(OpPC); + S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end) + << LHS.toDiagnosticString(S.getASTContext()); + return false; + } else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() && + LHS.getOffset() == 0) { + const SourceInfo &Loc = S.Current->getSource(OpPC); + S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end) + << RHS.toDiagnosticString(S.getASTContext()); + return false; + } + + bool BothNonNull = !LHS.isZero() && !RHS.isZero(); + // Reject comparisons to literals. + for (const auto &P : {LHS, RHS}) { + if (P.isZero()) + continue; + if (BothNonNull && P.pointsToLiteral()) { + const SourceInfo &Loc = S.Current->getSource(OpPC); + S.FFDiag(Loc, diag::note_constexpr_literal_comparison); + return false; + } + } + + S.Stk.push(BoolT::from(Fn(ComparisonCategoryResult::Unordered))); + return true; } template <> @@ -1030,9 +1042,10 @@ inline bool CmpHelperEQ(InterpState &S, CodePtr OpPC, // If either operand is a pointer to a weak function, the comparison is not // constant. for (const auto &MP : {LHS, RHS}) { - if (const CXXMethodDecl *MD = MP.getMemberFunction(); MD && MD->isWeak()) { + if (MP.isWeak()) { const SourceInfo &Loc = S.Current->getSource(OpPC); - S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison) << MD; + S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison) + << MP.getMemberFunction(); return false; } } @@ -2291,6 +2304,15 @@ inline bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { return true; } +template ::T> +inline bool IsNonNull(InterpState &S, CodePtr OpPC) { + const auto &P = S.Stk.pop(); + if (P.isWeak()) + return false; + S.Stk.push(Boolean::from(!P.isZero())); + return true; +} + //===----------------------------------------------------------------------===// // This, ImplicitThis //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/ByteCode/MemberPointer.h b/clang/lib/AST/ByteCode/MemberPointer.h index 2b3be124db4267..de135a40a3c77b 100644 --- a/clang/lib/AST/ByteCode/MemberPointer.h +++ b/clang/lib/AST/ByteCode/MemberPointer.h @@ -84,6 +84,11 @@ class MemberPointer final { bool isZero() const { return Base.isZero() && !Dcl; } bool hasBase() const { return !Base.isZero(); } + bool isWeak() const { + if (const auto *MF = getMemberFunction()) + return MF->isWeak(); + return false; + } void print(llvm::raw_ostream &OS) const { OS << "MemberPtr(" << Base << " " << (const void *)Dcl << " + " << PtrOffset diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index 7374a441c8bb19..f286c71a129d1d 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -597,6 +597,11 @@ def Comp: Opcode { let HasGroup = 1; } +def IsNonNull : Opcode { + let Types = [PtrTypeClass]; + let HasGroup = 1; +} + //===----------------------------------------------------------------------===// // Cast, CastFP. //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index 5b9e83764cfa50..9eaf0db45c7451 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -463,6 +463,17 @@ bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) { A.getFieldDesc()->IsArray; } +bool Pointer::pointsToLiteral() const { + if (isZero() || !isBlockPointer()) + return false; + + const Expr *E = block()->getDescriptor()->asExpr(); + if (block()->isDynamic()) + return false; + + return E && !isa(E); +} + std::optional Pointer::toRValue(const Context &Ctx, QualType ResultType) const { const ASTContext &ASTCtx = Ctx.getASTContext(); diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index ef90e6e0dd7bd1..d05d8e9bc1f388 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -692,6 +692,10 @@ class Pointer { /// Checks if both given pointers point to the same block. static bool pointToSameBlock(const Pointer &A, const Pointer &B); + /// Whether this points to a block that's been created for a "literal lvalue", + /// i.e. a non-MaterializeTemporaryExpr Expr. + bool pointsToLiteral() const; + /// Prints the pointer. void print(llvm::raw_ostream &OS) const; diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp index 1cff2228cd7a97..e215597579224c 100644 --- a/clang/test/AST/ByteCode/builtin-functions.cpp +++ b/clang/test/AST/ByteCode/builtin-functions.cpp @@ -951,3 +951,9 @@ namespace shufflevector { } #endif + +namespace FunctionStart { + void a(void) {} + static_assert(__builtin_function_start(a) == a, ""); // both-error {{not an integral constant expression}} \ + // both-note {{comparison of addresses of literals has unspecified value}} +} diff --git a/clang/test/AST/ByteCode/weak.cpp b/clang/test/AST/ByteCode/weak.cpp index d4aac3ff764dde..0322241beef83b 100644 --- a/clang/test/AST/ByteCode/weak.cpp +++ b/clang/test/AST/ByteCode/weak.cpp @@ -1,14 +1,8 @@ // RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s // RUN: %clang_cc1 -std=c++20 -verify=ref,both %s - - - -/// FIXME: The new interpreter also emits the "address of weak declaration" note in the pointer-to-bool case. - [[gnu::weak]] extern int a; int ha[(bool)&a]; // both-warning {{variable length arrays in C++ are a Clang extension}} \ - // expected-note {{comparison against address of weak declaration}} \ // both-error {{variable length array declaration not allowed at file scope}} int ha2[&a == nullptr]; // both-warning {{variable length arrays in C++ are a Clang extension}} \ // both-note {{comparison against address of weak declaration '&a' can only be performed at runtime}} \ From 8e972efb58ec35e35365d2f2ee6e8794c9336e59 Mon Sep 17 00:00:00 2001 From: Luke Lau Date: Sat, 31 Aug 2024 13:20:19 +0800 Subject: [PATCH 02/14] [RISCV] Add scalable vector patterns for vfwmaccbf16.v{v,f} (#106771) We can reuse the patterns for vfwmacc.v{v,f} as long as we swap out fpext_oneuse for riscv_fpextend_bf16 in the scalar case. --- .../Target/RISCV/RISCVInstrInfoVSDPatterns.td | 20 +- .../lib/Target/RISCV/RISCVInstrInfoZfbfmin.td | 4 + .../CodeGen/RISCV/rvv/vfwmaccbf16-sdnode.ll | 235 ++++++++++++++++++ 3 files changed, 254 insertions(+), 5 deletions(-) create mode 100644 llvm/test/CodeGen/RISCV/rvv/vfwmaccbf16-sdnode.ll diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoVSDPatterns.td b/llvm/lib/Target/RISCV/RISCVInstrInfoVSDPatterns.td index 8d64788b3cb7db..0f435c4ff3d315 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoVSDPatterns.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoVSDPatterns.td @@ -676,13 +676,18 @@ multiclass VPatWidenBinaryFPSDNode_VV_VF_WV_WF_RM, VPatWidenBinaryFPSDNode_WV_WF_RM; -multiclass VPatWidenFPMulAccSDNode_VV_VF_RM { - foreach vtiToWti = AllWidenableFloatVectors in { +multiclass VPatWidenFPMulAccSDNode_VV_VF_RM vtiToWtis, + PatFrags extop> { + foreach vtiToWti = vtiToWtis in { defvar vti = vtiToWti.Vti; defvar wti = vtiToWti.Wti; defvar suffix = vti.LMul.MX # "_E" # vti.SEW; let Predicates = !listconcat(GetVTypePredicates.Predicates, - GetVTypePredicates.Predicates) in { + GetVTypePredicates.Predicates, + !if(!eq(vti.Scalar, bf16), + [HasStdExtZvfbfwma], + [])) in { def : Pat<(fma (wti.Vector (riscv_fpextend_vl_oneuse (vti.Vector vti.RegClass:$rs1), (vti.Mask true_mask), (XLenVT srcvalue))), @@ -697,7 +702,7 @@ multiclass VPatWidenFPMulAccSDNode_VV_VF_RM { FRM_DYN, vti.AVL, vti.Log2SEW, TAIL_AGNOSTIC)>; def : Pat<(fma (wti.Vector (SplatFPOp - (fpext_oneuse (vti.Scalar vti.ScalarRegClass:$rs1)))), + (extop (vti.Scalar vti.ScalarRegClass:$rs1)))), (wti.Vector (riscv_fpextend_vl_oneuse (vti.Vector vti.RegClass:$rs2), (vti.Mask true_mask), (XLenVT srcvalue))), @@ -1284,7 +1289,12 @@ foreach fvti = AllFloatVectors in { } // 13.7. Vector Widening Floating-Point Fused Multiply-Add Instructions -defm : VPatWidenFPMulAccSDNode_VV_VF_RM<"PseudoVFWMACC">; +defm : VPatWidenFPMulAccSDNode_VV_VF_RM<"PseudoVFWMACC", + AllWidenableFloatVectors, + fpext_oneuse>; +defm : VPatWidenFPMulAccSDNode_VV_VF_RM<"PseudoVFWMACCBF16", + AllWidenableBFloatToFloatVectors, + riscv_fpextend_bf16_oneuse>; defm : VPatWidenFPNegMulAccSDNode_VV_VF_RM<"PseudoVFWNMACC">; defm : VPatWidenFPMulSacSDNode_VV_VF_RM<"PseudoVFWMSAC">; defm : VPatWidenFPNegMulSacSDNode_VV_VF_RM<"PseudoVFWNMSAC">; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZfbfmin.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZfbfmin.td index d819033eea68c7..88b66e7fc49aad 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoZfbfmin.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZfbfmin.td @@ -26,6 +26,10 @@ def riscv_fpround_bf16 : SDNode<"RISCVISD::FP_ROUND_BF16", SDT_RISCVFP_ROUND_BF16>; def riscv_fpextend_bf16 : SDNode<"RISCVISD::FP_EXTEND_BF16", SDT_RISCVFP_EXTEND_BF16>; +def riscv_fpextend_bf16_oneuse : PatFrag<(ops node:$A), + (riscv_fpextend_bf16 node:$A), [{ + return N->hasOneUse(); +}]>; //===----------------------------------------------------------------------===// // Instructions diff --git a/llvm/test/CodeGen/RISCV/rvv/vfwmaccbf16-sdnode.ll b/llvm/test/CodeGen/RISCV/rvv/vfwmaccbf16-sdnode.ll new file mode 100644 index 00000000000000..6682aa1e17a30f --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rvv/vfwmaccbf16-sdnode.ll @@ -0,0 +1,235 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc < %s -mtriple=riscv32 -mattr=+v,+zvfbfwma -verify-machineinstrs | FileCheck %s --check-prefix=ZVFBFWMA +; RUN: llc < %s -mtriple=riscv64 -mattr=+v,+zvfbfwma -verify-machineinstrs | FileCheck %s --check-prefix=ZVFBFWMA +; RUN: llc < %s -mtriple=riscv32 -mattr=+v,+zvfbfmin -verify-machineinstrs | FileCheck %s --check-prefix=ZVFBFMIN +; RUN: llc < %s -mtriple=riscv64 -mattr=+v,+zvfbfmin -verify-machineinstrs | FileCheck %s --check-prefix=ZVFBFMIN + +define @vfwmaccbf16_vv_nxv1f32( %a, %b, %c) { +; ZVFBFWMA-LABEL: vfwmaccbf16_vv_nxv1f32: +; ZVFBFWMA: # %bb.0: +; ZVFBFWMA-NEXT: vsetvli a0, zero, e16, mf4, ta, ma +; ZVFBFWMA-NEXT: vfwmaccbf16.vv v8, v9, v10 +; ZVFBFWMA-NEXT: ret +; +; ZVFBFMIN-LABEL: vfwmaccbf16_vv_nxv1f32: +; ZVFBFMIN: # %bb.0: +; ZVFBFMIN-NEXT: vsetvli a0, zero, e16, mf4, ta, ma +; ZVFBFMIN-NEXT: vfwcvtbf16.f.f.v v11, v9 +; ZVFBFMIN-NEXT: vfwcvtbf16.f.f.v v9, v10 +; ZVFBFMIN-NEXT: vsetvli zero, zero, e32, mf2, ta, ma +; ZVFBFMIN-NEXT: vfmacc.vv v8, v11, v9 +; ZVFBFMIN-NEXT: ret + %b.ext = fpext %b to + %c.ext = fpext %c to + %res = call @llvm.fma.nxv1f32( %b.ext, %c.ext, %a) + ret %res +} + +define @vfwmaccbf16_vf_nxv1f32( %a, bfloat %b, %c) { +; ZVFBFWMA-LABEL: vfwmaccbf16_vf_nxv1f32: +; ZVFBFWMA: # %bb.0: +; ZVFBFWMA-NEXT: vsetvli a0, zero, e16, mf4, ta, ma +; ZVFBFWMA-NEXT: vfwmaccbf16.vf v8, fa0, v9 +; ZVFBFWMA-NEXT: ret +; +; ZVFBFMIN-LABEL: vfwmaccbf16_vf_nxv1f32: +; ZVFBFMIN: # %bb.0: +; ZVFBFMIN-NEXT: fmv.x.w a0, fa0 +; ZVFBFMIN-NEXT: slli a0, a0, 16 +; ZVFBFMIN-NEXT: fmv.w.x fa5, a0 +; ZVFBFMIN-NEXT: vsetvli a0, zero, e16, mf4, ta, ma +; ZVFBFMIN-NEXT: vfwcvtbf16.f.f.v v10, v9 +; ZVFBFMIN-NEXT: vsetvli zero, zero, e32, mf2, ta, ma +; ZVFBFMIN-NEXT: vfmacc.vf v8, fa5, v10 +; ZVFBFMIN-NEXT: ret + %b.head = insertelement poison, bfloat %b, i32 0 + %b.splat = shufflevector %b.head, poison, zeroinitializer + %b.ext = fpext %b.splat to + %c.ext = fpext %c to + %res = call @llvm.fma.nxv1f32( %b.ext, %c.ext, %a) + ret %res +} + +define @vfwmaccbf16_vv_nxv2f32( %a, %b, %c) { +; ZVFBFWMA-LABEL: vfwmaccbf16_vv_nxv2f32: +; ZVFBFWMA: # %bb.0: +; ZVFBFWMA-NEXT: vsetvli a0, zero, e16, mf2, ta, ma +; ZVFBFWMA-NEXT: vfwmaccbf16.vv v8, v9, v10 +; ZVFBFWMA-NEXT: ret +; +; ZVFBFMIN-LABEL: vfwmaccbf16_vv_nxv2f32: +; ZVFBFMIN: # %bb.0: +; ZVFBFMIN-NEXT: vsetvli a0, zero, e16, mf2, ta, ma +; ZVFBFMIN-NEXT: vfwcvtbf16.f.f.v v11, v9 +; ZVFBFMIN-NEXT: vfwcvtbf16.f.f.v v9, v10 +; ZVFBFMIN-NEXT: vsetvli zero, zero, e32, m1, ta, ma +; ZVFBFMIN-NEXT: vfmacc.vv v8, v11, v9 +; ZVFBFMIN-NEXT: ret + %b.ext = fpext %b to + %c.ext = fpext %c to + %res = call @llvm.fma.nxv2f32( %b.ext, %c.ext, %a) + ret %res +} + +define @vfwmaccbf16_vf_nxv2f32( %a, bfloat %b, %c) { +; ZVFBFWMA-LABEL: vfwmaccbf16_vf_nxv2f32: +; ZVFBFWMA: # %bb.0: +; ZVFBFWMA-NEXT: vsetvli a0, zero, e16, mf2, ta, ma +; ZVFBFWMA-NEXT: vfwmaccbf16.vf v8, fa0, v9 +; ZVFBFWMA-NEXT: ret +; +; ZVFBFMIN-LABEL: vfwmaccbf16_vf_nxv2f32: +; ZVFBFMIN: # %bb.0: +; ZVFBFMIN-NEXT: fmv.x.w a0, fa0 +; ZVFBFMIN-NEXT: slli a0, a0, 16 +; ZVFBFMIN-NEXT: fmv.w.x fa5, a0 +; ZVFBFMIN-NEXT: vsetvli a0, zero, e16, mf2, ta, ma +; ZVFBFMIN-NEXT: vfwcvtbf16.f.f.v v10, v9 +; ZVFBFMIN-NEXT: vsetvli zero, zero, e32, m1, ta, ma +; ZVFBFMIN-NEXT: vfmacc.vf v8, fa5, v10 +; ZVFBFMIN-NEXT: ret + %b.head = insertelement poison, bfloat %b, i32 0 + %b.splat = shufflevector %b.head, poison, zeroinitializer + %b.ext = fpext %b.splat to + %c.ext = fpext %c to + %res = call @llvm.fma.nxv2f32( %b.ext, %c.ext, %a) + ret %res +} + +define @vfwmaccbf16_vv_nxv4f32( %a, %b, %c) { +; ZVFBFWMA-LABEL: vfwmaccbf16_vv_nxv4f32: +; ZVFBFWMA: # %bb.0: +; ZVFBFWMA-NEXT: vsetvli a0, zero, e16, m1, ta, ma +; ZVFBFWMA-NEXT: vfwmaccbf16.vv v8, v10, v11 +; ZVFBFWMA-NEXT: ret +; +; ZVFBFMIN-LABEL: vfwmaccbf16_vv_nxv4f32: +; ZVFBFMIN: # %bb.0: +; ZVFBFMIN-NEXT: vsetvli a0, zero, e16, m1, ta, ma +; ZVFBFMIN-NEXT: vfwcvtbf16.f.f.v v12, v10 +; ZVFBFMIN-NEXT: vfwcvtbf16.f.f.v v14, v11 +; ZVFBFMIN-NEXT: vsetvli zero, zero, e32, m2, ta, ma +; ZVFBFMIN-NEXT: vfmacc.vv v8, v12, v14 +; ZVFBFMIN-NEXT: ret + %b.ext = fpext %b to + %c.ext = fpext %c to + %res = call @llvm.fma.nxv4f32( %b.ext, %c.ext, %a) + ret %res +} + +define @vfwmaccbf16_vf_nxv4f32( %a, bfloat %b, %c) { +; ZVFBFWMA-LABEL: vfwmaccbf16_vf_nxv4f32: +; ZVFBFWMA: # %bb.0: +; ZVFBFWMA-NEXT: vsetvli a0, zero, e16, m1, ta, ma +; ZVFBFWMA-NEXT: vfwmaccbf16.vf v8, fa0, v10 +; ZVFBFWMA-NEXT: ret +; +; ZVFBFMIN-LABEL: vfwmaccbf16_vf_nxv4f32: +; ZVFBFMIN: # %bb.0: +; ZVFBFMIN-NEXT: fmv.x.w a0, fa0 +; ZVFBFMIN-NEXT: slli a0, a0, 16 +; ZVFBFMIN-NEXT: fmv.w.x fa5, a0 +; ZVFBFMIN-NEXT: vsetvli a0, zero, e16, m1, ta, ma +; ZVFBFMIN-NEXT: vfwcvtbf16.f.f.v v12, v10 +; ZVFBFMIN-NEXT: vsetvli zero, zero, e32, m2, ta, ma +; ZVFBFMIN-NEXT: vfmacc.vf v8, fa5, v12 +; ZVFBFMIN-NEXT: ret + %b.head = insertelement poison, bfloat %b, i32 0 + %b.splat = shufflevector %b.head, poison, zeroinitializer + %b.ext = fpext %b.splat to + %c.ext = fpext %c to + %res = call @llvm.fma.nxv4f32( %b.ext, %c.ext, %a) + ret %res +} + +define @vfwmaccbf16_vv_nxv8f32( %a, %b, %c) { +; ZVFBFWMA-LABEL: vfwmaccbf16_vv_nxv8f32: +; ZVFBFWMA: # %bb.0: +; ZVFBFWMA-NEXT: vsetvli a0, zero, e16, m2, ta, ma +; ZVFBFWMA-NEXT: vfwmaccbf16.vv v8, v12, v14 +; ZVFBFWMA-NEXT: ret +; +; ZVFBFMIN-LABEL: vfwmaccbf16_vv_nxv8f32: +; ZVFBFMIN: # %bb.0: +; ZVFBFMIN-NEXT: vsetvli a0, zero, e16, m2, ta, ma +; ZVFBFMIN-NEXT: vfwcvtbf16.f.f.v v16, v12 +; ZVFBFMIN-NEXT: vfwcvtbf16.f.f.v v20, v14 +; ZVFBFMIN-NEXT: vsetvli zero, zero, e32, m4, ta, ma +; ZVFBFMIN-NEXT: vfmacc.vv v8, v16, v20 +; ZVFBFMIN-NEXT: ret + %b.ext = fpext %b to + %c.ext = fpext %c to + %res = call @llvm.fma.nxv8f32( %b.ext, %c.ext, %a) + ret %res +} + +define @vfwmaccbf16_vf_nxv8f32( %a, bfloat %b, %c) { +; ZVFBFWMA-LABEL: vfwmaccbf16_vf_nxv8f32: +; ZVFBFWMA: # %bb.0: +; ZVFBFWMA-NEXT: vsetvli a0, zero, e16, m2, ta, ma +; ZVFBFWMA-NEXT: vfwmaccbf16.vf v8, fa0, v12 +; ZVFBFWMA-NEXT: ret +; +; ZVFBFMIN-LABEL: vfwmaccbf16_vf_nxv8f32: +; ZVFBFMIN: # %bb.0: +; ZVFBFMIN-NEXT: fmv.x.w a0, fa0 +; ZVFBFMIN-NEXT: slli a0, a0, 16 +; ZVFBFMIN-NEXT: fmv.w.x fa5, a0 +; ZVFBFMIN-NEXT: vsetvli a0, zero, e16, m2, ta, ma +; ZVFBFMIN-NEXT: vfwcvtbf16.f.f.v v16, v12 +; ZVFBFMIN-NEXT: vsetvli zero, zero, e32, m4, ta, ma +; ZVFBFMIN-NEXT: vfmacc.vf v8, fa5, v16 +; ZVFBFMIN-NEXT: ret + %b.head = insertelement poison, bfloat %b, i32 0 + %b.splat = shufflevector %b.head, poison, zeroinitializer + %b.ext = fpext %b.splat to + %c.ext = fpext %c to + %res = call @llvm.fma.nxv8f32( %b.ext, %c.ext, %a) + ret %res +} + +define @vfwmaccbf16_vv_nxv16f32( %a, %b, %c) { +; ZVFBFWMA-LABEL: vfwmaccbf16_vv_nxv16f32: +; ZVFBFWMA: # %bb.0: +; ZVFBFWMA-NEXT: vsetvli a0, zero, e16, m4, ta, ma +; ZVFBFWMA-NEXT: vfwmaccbf16.vv v8, v16, v20 +; ZVFBFWMA-NEXT: ret +; +; ZVFBFMIN-LABEL: vfwmaccbf16_vv_nxv16f32: +; ZVFBFMIN: # %bb.0: +; ZVFBFMIN-NEXT: vsetvli a0, zero, e16, m4, ta, ma +; ZVFBFMIN-NEXT: vfwcvtbf16.f.f.v v24, v16 +; ZVFBFMIN-NEXT: vfwcvtbf16.f.f.v v0, v20 +; ZVFBFMIN-NEXT: vsetvli zero, zero, e32, m8, ta, ma +; ZVFBFMIN-NEXT: vfmacc.vv v8, v24, v0 +; ZVFBFMIN-NEXT: ret + %b.ext = fpext %b to + %c.ext = fpext %c to + %res = call @llvm.fma.nxv16f32( %b.ext, %c.ext, %a) + ret %res +} + +define @vfwmaccbf16_vf_nxv16f32( %a, bfloat %b, %c) { +; ZVFBFWMA-LABEL: vfwmaccbf16_vf_nxv16f32: +; ZVFBFWMA: # %bb.0: +; ZVFBFWMA-NEXT: vsetvli a0, zero, e16, m4, ta, ma +; ZVFBFWMA-NEXT: vfwmaccbf16.vf v8, fa0, v16 +; ZVFBFWMA-NEXT: ret +; +; ZVFBFMIN-LABEL: vfwmaccbf16_vf_nxv16f32: +; ZVFBFMIN: # %bb.0: +; ZVFBFMIN-NEXT: fmv.x.w a0, fa0 +; ZVFBFMIN-NEXT: slli a0, a0, 16 +; ZVFBFMIN-NEXT: fmv.w.x fa5, a0 +; ZVFBFMIN-NEXT: vsetvli a0, zero, e16, m4, ta, ma +; ZVFBFMIN-NEXT: vfwcvtbf16.f.f.v v24, v16 +; ZVFBFMIN-NEXT: vsetvli zero, zero, e32, m8, ta, ma +; ZVFBFMIN-NEXT: vfmacc.vf v8, fa5, v24 +; ZVFBFMIN-NEXT: ret + %b.head = insertelement poison, bfloat %b, i32 0 + %b.splat = shufflevector %b.head, poison, zeroinitializer + %b.ext = fpext %b.splat to + %c.ext = fpext %c to + %res = call @llvm.fma.nxv16f32( %b.ext, %c.ext, %a) + ret %res +} From 58e1c0e416f4a071482d1d9c2d620c7a0df4cf33 Mon Sep 17 00:00:00 2001 From: Luke Lau Date: Sat, 31 Aug 2024 13:20:53 +0800 Subject: [PATCH 03/14] [RISCV] Discard the false operand in vmerge.vvm -> vmv.v.v peephole (#106688) vmerge.vvm needs to have an all ones mask, so nothing is taken from the false operand. So instead of checking that the passthru is the same as false, just use the passthru directly for the tail elements. This supersedes the convertVMergeToVMv part of #105788, as noted in https://github.com/llvm/llvm-project/pull/105788/files#r1731683971 --- llvm/lib/Target/RISCV/RISCVVectorPeephole.cpp | 18 +++++------------- .../RISCV/rvv/rvv-peephole-vmerge-to-vmv.mir | 10 +++++----- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/llvm/lib/Target/RISCV/RISCVVectorPeephole.cpp b/llvm/lib/Target/RISCV/RISCVVectorPeephole.cpp index 6df3b951f5a06f..412fd790061a37 100644 --- a/llvm/lib/Target/RISCV/RISCVVectorPeephole.cpp +++ b/llvm/lib/Target/RISCV/RISCVVectorPeephole.cpp @@ -333,8 +333,8 @@ bool RISCVVectorPeephole::convertToWholeRegister(MachineInstr &MI) const { return true; } -// Transform (VMERGE_VVM_ false, false, true, allones, vl, sew) to -// (VMV_V_V_ false, true, vl, sew). It may decrease uses of VMSET. +// Transform (VMERGE_VVM_ pt, false, true, allones, vl, sew) to +// (VMV_V_V_ pt, true, vl, sew). It may decrease uses of VMSET. bool RISCVVectorPeephole::convertVMergeToVMv(MachineInstr &MI) const { #define CASE_VMERGE_TO_VMV(lmul) \ case RISCV::PseudoVMERGE_VVM_##lmul: \ @@ -353,21 +353,12 @@ bool RISCVVectorPeephole::convertVMergeToVMv(MachineInstr &MI) const { CASE_VMERGE_TO_VMV(M8) } - Register PassthruReg = MI.getOperand(1).getReg(); - Register FalseReg = MI.getOperand(2).getReg(); - // Check passthru == false (or passthru == undef) - if (PassthruReg != RISCV::NoRegister && - TRI->lookThruCopyLike(PassthruReg, MRI) != - TRI->lookThruCopyLike(FalseReg, MRI)) - return false; - assert(MI.getOperand(4).isReg() && MI.getOperand(4).getReg() == RISCV::V0); if (!isAllOnesMask(V0Defs.lookup(&MI))) return false; MI.setDesc(TII->get(NewOpc)); - MI.removeOperand(1); // Passthru operand - MI.tieOperands(0, 1); // Tie false to dest + MI.removeOperand(2); // False operand MI.removeOperand(3); // Mask operand MI.addOperand( MachineOperand::CreateImm(RISCVII::TAIL_UNDISTURBED_MASK_UNDISTURBED)); @@ -375,7 +366,8 @@ bool RISCVVectorPeephole::convertVMergeToVMv(MachineInstr &MI) const { // vmv.v.v doesn't have a mask operand, so we may be able to inflate the // register class for the destination and passthru operands e.g. VRNoV0 -> VR MRI->recomputeRegClass(MI.getOperand(0).getReg()); - MRI->recomputeRegClass(MI.getOperand(1).getReg()); + if (MI.getOperand(1).getReg() != RISCV::NoRegister) + MRI->recomputeRegClass(MI.getOperand(1).getReg()); return true; } diff --git a/llvm/test/CodeGen/RISCV/rvv/rvv-peephole-vmerge-to-vmv.mir b/llvm/test/CodeGen/RISCV/rvv/rvv-peephole-vmerge-to-vmv.mir index 01fff3de0aa8bd..1419eede6ca9d1 100644 --- a/llvm/test/CodeGen/RISCV/rvv/rvv-peephole-vmerge-to-vmv.mir +++ b/llvm/test/CodeGen/RISCV/rvv/rvv-peephole-vmerge-to-vmv.mir @@ -15,7 +15,7 @@ body: | ; CHECK-NEXT: %avl:gprnox0 = COPY $x1 ; CHECK-NEXT: %mask:vmv0 = PseudoVMSET_M_B8 %avl, 5 /* e32 */ ; CHECK-NEXT: $v0 = COPY %mask - ; CHECK-NEXT: %x:vr = PseudoVMV_V_V_M1 %false, %true, %avl, 5 /* e32 */, 0 /* tu, mu */ + ; CHECK-NEXT: %x:vr = PseudoVMV_V_V_M1 $noreg, %true, %avl, 5 /* e32 */, 0 /* tu, mu */ %false:vr = COPY $v8 %true:vr = COPY $v9 %avl:gprnox0 = COPY $x1 @@ -31,13 +31,13 @@ body: | ; CHECK-LABEL: name: undef_false ; CHECK: liveins: $x1, $v8, $v9 ; CHECK-NEXT: {{ $}} - ; CHECK-NEXT: %pt:vrnov0 = COPY $v8 + ; CHECK-NEXT: %pt:vr = COPY $v8 ; CHECK-NEXT: %false:vr = COPY $noreg ; CHECK-NEXT: %true:vr = COPY $v9 ; CHECK-NEXT: %avl:gprnox0 = COPY $x1 ; CHECK-NEXT: %mask:vmv0 = PseudoVMSET_M_B8 %avl, 5 /* e32 */ ; CHECK-NEXT: $v0 = COPY %mask - ; CHECK-NEXT: %x:vrnov0 = PseudoVMERGE_VVM_M1 %pt, %false, %true, $v0, %avl, 5 /* e32 */ + ; CHECK-NEXT: %x:vr = PseudoVMV_V_V_M1 %pt, %true, %avl, 5 /* e32 */, 0 /* tu, mu */ %pt:vrnov0 = COPY $v8 %false:vr = COPY $noreg %true:vr = COPY $v9 @@ -55,12 +55,12 @@ body: | ; CHECK: liveins: $x1, $v8, $v9 ; CHECK-NEXT: {{ $}} ; CHECK-NEXT: %false:vr = COPY $v8 - ; CHECK-NEXT: %pt:vrnov0 = COPY $v8 + ; CHECK-NEXT: %pt:vr = COPY $v8 ; CHECK-NEXT: %true:vr = COPY $v9 ; CHECK-NEXT: %avl:gprnox0 = COPY $x1 ; CHECK-NEXT: %mask:vmv0 = PseudoVMSET_M_B8 %avl, 5 /* e32 */ ; CHECK-NEXT: $v0 = COPY %mask - ; CHECK-NEXT: %x:vr = PseudoVMV_V_V_M1 %false, %true, %avl, 5 /* e32 */, 0 /* tu, mu */ + ; CHECK-NEXT: %x:vr = PseudoVMV_V_V_M1 %pt, %true, %avl, 5 /* e32 */, 0 /* tu, mu */ %false:vr = COPY $v8 %pt:vrnov0 = COPY $v8 %true:vr = COPY $v9 From d884b77c662374bd779ccbf20ba3b31cb9949a18 Mon Sep 17 00:00:00 2001 From: Tobias Gysi Date: Sat, 31 Aug 2024 07:23:24 +0200 Subject: [PATCH 04/14] [MLIR][LLVM] Make DISubprogramAttr cyclic (#106571) This commit implements LLVM_DIRecursiveTypeAttrInterface for the DISubprogramAttr to ensure cyclic subprograms can be imported properly. In the process multiple shortcuts around the recently introduced DIImportedEntityAttr can be removed. --- .../Transforms/DebugTypeGenerator.cpp | 10 +- mlir/include/mlir-c/Dialect/LLVM.h | 26 +++-- .../mlir/Dialect/LLVMIR/LLVMAttrDefs.td | 68 +++++++++---- .../mlir/Dialect/LLVMIR/LLVMInterfaces.td | 2 +- mlir/lib/CAPI/Dialect/LLVM.cpp | 39 +++++--- mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp | 29 ++++-- mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp | 6 +- .../Transforms/DIScopeForLLVMFuncOp.cpp | 8 +- mlir/lib/Target/LLVMIR/DebugImporter.cpp | 18 ++-- mlir/lib/Target/LLVMIR/DebugTranslation.cpp | 98 ++++++++++--------- mlir/lib/Target/LLVMIR/DebugTranslation.h | 18 ++-- mlir/test/CAPI/llvm.c | 23 +++-- mlir/test/Target/LLVMIR/Import/debug-info.ll | 53 +++++----- mlir/test/Target/LLVMIR/llvmir-debug.mlir | 41 ++++---- 14 files changed, 263 insertions(+), 176 deletions(-) diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp index 54f2a12d800085..029d3776bcc0b8 100644 --- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp +++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp @@ -146,8 +146,8 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertBoxedSequenceType( elements.push_back(subrangeTy); } return mlir::LLVM::DICompositeTypeAttr::get( - context, llvm::dwarf::DW_TAG_array_type, /*recursive_id=*/{}, - /*name=*/nullptr, /*file=*/nullptr, /*line=*/0, /*scope=*/nullptr, elemTy, + context, llvm::dwarf::DW_TAG_array_type, /*name=*/nullptr, + /*file=*/nullptr, /*line=*/0, /*scope=*/nullptr, elemTy, mlir::LLVM::DIFlags::Zero, /*sizeInBits=*/0, /*alignInBits=*/0, elements, dataLocation, /*rank=*/nullptr, allocated, associated); } @@ -188,7 +188,7 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertRecordType( } return mlir::LLVM::DICompositeTypeAttr::get( - context, llvm::dwarf::DW_TAG_structure_type, /*recursive_id=*/{}, + context, llvm::dwarf::DW_TAG_structure_type, mlir::StringAttr::get(context, result.second.name), fileAttr, line, scope, /*baseType=*/nullptr, mlir::LLVM::DIFlags::Zero, offset * 8, /*alignInBits=*/0, elements, /*dataLocation=*/nullptr, /*rank=*/nullptr, @@ -236,8 +236,8 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertSequenceType( // have been set to some valid default values. return mlir::LLVM::DICompositeTypeAttr::get( - context, llvm::dwarf::DW_TAG_array_type, /*recursive_id=*/{}, - /*name=*/nullptr, /*file=*/nullptr, /*line=*/0, /*scope=*/nullptr, elemTy, + context, llvm::dwarf::DW_TAG_array_type, /*name=*/nullptr, + /*file=*/nullptr, /*line=*/0, /*scope=*/nullptr, elemTy, mlir::LLVM::DIFlags::Zero, /*sizeInBits=*/0, /*alignInBits=*/0, elements, /*dataLocation=*/nullptr, /*rank=*/nullptr, /*allocated=*/nullptr, /*associated=*/nullptr); diff --git a/mlir/include/mlir-c/Dialect/LLVM.h b/mlir/include/mlir-c/Dialect/LLVM.h index 5eb96a86e472d6..38bd4d2f3587be 100644 --- a/mlir/include/mlir-c/Dialect/LLVM.h +++ b/mlir/include/mlir-c/Dialect/LLVM.h @@ -234,10 +234,13 @@ MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDIBasicTypeAttrGet( MlirContext ctx, unsigned int tag, MlirAttribute name, uint64_t sizeInBits, MlirLLVMTypeEncoding encoding); +/// Creates a self-referencing LLVM DICompositeType attribute. +MlirAttribute mlirLLVMDICompositeTypeAttrGetRecSelf(MlirAttribute recId); + /// Creates a LLVM DICompositeType attribute. MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDICompositeTypeAttrGet( - MlirContext ctx, unsigned int tag, MlirAttribute recId, MlirAttribute name, - MlirAttribute file, uint32_t line, MlirAttribute scope, + MlirContext ctx, MlirAttribute recId, bool isRecSelf, unsigned int tag, + MlirAttribute name, MlirAttribute file, uint32_t line, MlirAttribute scope, MlirAttribute baseType, int64_t flags, uint64_t sizeInBits, uint64_t alignInBits, intptr_t nElements, MlirAttribute const *elements, MlirAttribute dataLocation, MlirAttribute rank, MlirAttribute allocated, @@ -311,13 +314,16 @@ MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDILocalVariableAttrGet( MlirAttribute diFile, unsigned int line, unsigned int arg, unsigned int alignInBits, MlirAttribute diType, int64_t flags); +/// Creates a self-referencing LLVM DISubprogramAttr attribute. +MlirAttribute mlirLLVMDISubprogramAttrGetRecSelf(MlirAttribute recId); + /// Creates a LLVM DISubprogramAttr attribute. MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDISubprogramAttrGet( - MlirContext ctx, MlirAttribute id, MlirAttribute compileUnit, - MlirAttribute scope, MlirAttribute name, MlirAttribute linkageName, - MlirAttribute file, unsigned int line, unsigned int scopeLine, - uint64_t subprogramFlags, MlirAttribute type, intptr_t nRetainedNodes, - MlirAttribute const *retainedNodes); + MlirContext ctx, MlirAttribute recId, bool isRecSelf, MlirAttribute id, + MlirAttribute compileUnit, MlirAttribute scope, MlirAttribute name, + MlirAttribute linkageName, MlirAttribute file, unsigned int line, + unsigned int scopeLine, uint64_t subprogramFlags, MlirAttribute type, + intptr_t nRetainedNodes, MlirAttribute const *retainedNodes); /// Gets the scope from this DISubprogramAttr. MLIR_CAPI_EXPORTED MlirAttribute @@ -356,9 +362,9 @@ MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDIModuleAttrGet( /// Creates a LLVM DIImportedEntityAttr attribute. MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDIImportedEntityAttrGet( - MlirContext ctx, unsigned int tag, MlirAttribute entity, MlirAttribute file, - unsigned int line, MlirAttribute name, intptr_t nElements, - MlirAttribute const *elements); + MlirContext ctx, unsigned int tag, MlirAttribute scope, + MlirAttribute entity, MlirAttribute file, unsigned int line, + MlirAttribute name, intptr_t nElements, MlirAttribute const *elements); /// Gets the scope of this DIModuleAttr. MLIR_CAPI_EXPORTED MlirAttribute diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td index e57be7f760d380..49e54df3436ff3 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td @@ -271,7 +271,7 @@ def LLVM_DILanguageParameter : LLVM_DIParameter< >; def LLVM_DITagParameter : LLVM_DIParameter< - "tag", /*default=*/"", "Tag", /*errorCase=*/"llvm::dwarf::DW_TAG_invalid" + "tag", /*default=*/"0", "Tag", /*errorCase=*/"llvm::dwarf::DW_TAG_invalid" >; def LLVM_DIOperationEncodingParameter : LLVM_DIParameter< @@ -375,14 +375,17 @@ def LLVM_DICompositeTypeAttr : LLVM_Attr<"DICompositeType", "di_composite_type", [LLVM_DIRecursiveTypeAttrInterface], "DITypeAttr"> { let parameters = (ins - LLVM_DITagParameter:$tag, + // DIRecursiveTypeAttrInterface specific parameters. OptionalParameter<"DistinctAttr">:$recId, + OptionalParameter<"bool">:$isRecSelf, + // DICompositeType specific parameters. + LLVM_DITagParameter:$tag, OptionalParameter<"StringAttr">:$name, OptionalParameter<"DIFileAttr">:$file, OptionalParameter<"uint32_t">:$line, OptionalParameter<"DIScopeAttr">:$scope, OptionalParameter<"DITypeAttr">:$baseType, - OptionalParameter<"DIFlags", "DIFlags::Zero">:$flags, + OptionalParameter<"DIFlags">:$flags, OptionalParameter<"uint64_t">:$sizeInBits, OptionalParameter<"uint64_t">:$alignInBits, OptionalArrayRefParameter<"DINodeAttr">:$elements, @@ -391,14 +394,26 @@ def LLVM_DICompositeTypeAttr : LLVM_Attr<"DICompositeType", "di_composite_type", OptionalParameter<"DIExpressionAttr">:$allocated, OptionalParameter<"DIExpressionAttr">:$associated ); + let builders = [ + AttrBuilder<(ins + "unsigned":$tag, "StringAttr":$name, "DIFileAttr":$file, + "uint32_t":$line, "DIScopeAttr":$scope, "DITypeAttr":$baseType, + "DIFlags":$flags, "uint64_t":$sizeInBits, "uint64_t":$alignInBits, + "ArrayRef":$elements, "DIExpressionAttr":$dataLocation, + "DIExpressionAttr":$rank, "DIExpressionAttr":$allocated, + "DIExpressionAttr":$associated + ), [{ + return $_get($_ctxt, /*recId=*/nullptr, /*isRecSelf=*/nullptr, + tag, name, file, line, scope, baseType, flags, sizeInBits, + alignInBits, elements, dataLocation, rank, allocated, + associated); + }]> + ]; let assemblyFormat = "`<` struct(params) `>`"; let extraClassDeclaration = [{ /// Requirements of DIRecursiveTypeAttrInterface. /// @{ - /// Get whether this attr describes a recursive self reference. - bool isRecSelf() { return getTag() == 0; } - /// Get a copy of this type attr but with the recursive ID set to `recId`. DIRecursiveTypeAttrInterface withRecId(DistinctAttr recId); @@ -554,14 +569,19 @@ def LLVM_DILocalVariableAttr : LLVM_Attr<"DILocalVariable", "di_local_variable", //===----------------------------------------------------------------------===// def LLVM_DISubprogramAttr : LLVM_Attr<"DISubprogram", "di_subprogram", - /*traits=*/[], "DIScopeAttr"> { + [LLVM_DIRecursiveTypeAttrInterface], + "DIScopeAttr"> { let parameters = (ins + // DIRecursiveTypeAttrInterface specific parameters. + OptionalParameter<"DistinctAttr">:$recId, + OptionalParameter<"bool">:$isRecSelf, + // DISubprogramAttr specific parameters. OptionalParameter<"DistinctAttr">:$id, OptionalParameter<"DICompileUnitAttr">:$compileUnit, - "DIScopeAttr":$scope, + OptionalParameter<"DIScopeAttr">:$scope, OptionalParameter<"StringAttr">:$name, OptionalParameter<"StringAttr">:$linkageName, - "DIFileAttr":$file, + OptionalParameter<"DIFileAttr">:$file, OptionalParameter<"unsigned">:$line, OptionalParameter<"unsigned">:$scopeLine, OptionalParameter<"DISubprogramFlags">:$subprogramFlags, @@ -569,21 +589,31 @@ def LLVM_DISubprogramAttr : LLVM_Attr<"DISubprogram", "di_subprogram", OptionalArrayRefParameter<"DINodeAttr">:$retainedNodes ); let builders = [ - AttrBuilderWithInferredContext<(ins + AttrBuilder<(ins "DistinctAttr":$id, "DICompileUnitAttr":$compileUnit, - "DIScopeAttr":$scope, "StringRef":$name, "StringRef":$linkageName, + "DIScopeAttr":$scope, "StringAttr":$name, "StringAttr":$linkageName, "DIFileAttr":$file, "unsigned":$line, "unsigned":$scopeLine, "DISubprogramFlags":$subprogramFlags, "DISubroutineTypeAttr":$type, "ArrayRef":$retainedNodes ), [{ - MLIRContext *ctx = file.getContext(); - return $_get(ctx, id, compileUnit, scope, StringAttr::get(ctx, name), - StringAttr::get(ctx, linkageName), file, line, - scopeLine, subprogramFlags, type, retainedNodes); + return $_get($_ctxt, /*recId=*/nullptr, /*isRecSelf=*/false, id, compileUnit, + scope, name, linkageName, file, line, scopeLine, + subprogramFlags, type, retainedNodes); }]> ]; - let assemblyFormat = "`<` struct(params) `>`"; + let extraClassDeclaration = [{ + /// Requirements of DIRecursiveTypeAttrInterface. + /// @{ + + /// Get a copy of this type attr but with the recursive ID set to `recId`. + DIRecursiveTypeAttrInterface withRecId(DistinctAttr recId); + + /// Build a rec-self instance using the provided `recId`. + static DIRecursiveTypeAttrInterface getRecSelf(DistinctAttr recId); + + /// @} + }]; } //===----------------------------------------------------------------------===// @@ -627,13 +657,9 @@ def LLVM_DINamespaceAttr : LLVM_Attr<"DINamespace", "di_namespace", def LLVM_DIImportedEntityAttr : LLVM_Attr<"DIImportedEntity", "di_imported_entity", /*traits=*/[], "DINodeAttr"> { - /// TODO: DIImportedEntity has a 'scope' field which represents the scope where - /// this entity is imported. Currently, we are not adding a 'scope' field in - /// DIImportedEntityAttr to avoid cyclic dependency. As DIImportedEntityAttr - /// entries will be contained inside a scope entity (e.g. DISubprogramAttr), - /// the scope can easily be inferred. let parameters = (ins LLVM_DITagParameter:$tag, + "DIScopeAttr":$scope, "DINodeAttr":$entity, OptionalParameter<"DIFileAttr">:$file, OptionalParameter<"unsigned">:$line, diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td index 7085f81e203a1e..e2180410a8f04e 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td @@ -406,7 +406,7 @@ def LLVM_DIRecursiveTypeAttrInterface let methods = [ InterfaceMethod<[{ Get whether this attr describes a recursive self reference. - }], "bool", "isRecSelf", (ins)>, + }], "bool", "getIsRecSelf", (ins)>, InterfaceMethod<[{ Get the recursive ID used for matching "rec-decl" with "rec-self". If this attr instance is not recursive, return a null attribute. diff --git a/mlir/lib/CAPI/Dialect/LLVM.cpp b/mlir/lib/CAPI/Dialect/LLVM.cpp index 13341f0c4de881..03b536d7aad98f 100644 --- a/mlir/lib/CAPI/Dialect/LLVM.cpp +++ b/mlir/lib/CAPI/Dialect/LLVM.cpp @@ -159,9 +159,14 @@ MlirAttribute mlirLLVMDIBasicTypeAttrGet(MlirContext ctx, unsigned int tag, unwrap(ctx), tag, cast(unwrap(name)), sizeInBits, encoding)); } +MlirAttribute mlirLLVMDICompositeTypeAttrGetRecSelf(MlirAttribute recId) { + return wrap( + DICompositeTypeAttr::getRecSelf(cast(unwrap(recId)))); +} + MlirAttribute mlirLLVMDICompositeTypeAttrGet( - MlirContext ctx, unsigned int tag, MlirAttribute recId, MlirAttribute name, - MlirAttribute file, uint32_t line, MlirAttribute scope, + MlirContext ctx, MlirAttribute recId, bool isRecSelf, unsigned int tag, + MlirAttribute name, MlirAttribute file, uint32_t line, MlirAttribute scope, MlirAttribute baseType, int64_t flags, uint64_t sizeInBits, uint64_t alignInBits, intptr_t nElements, MlirAttribute const *elements, MlirAttribute dataLocation, MlirAttribute rank, MlirAttribute allocated, @@ -170,7 +175,7 @@ MlirAttribute mlirLLVMDICompositeTypeAttrGet( elementsStorage.reserve(nElements); return wrap(DICompositeTypeAttr::get( - unwrap(ctx), tag, cast(unwrap(recId)), + unwrap(ctx), cast(unwrap(recId)), isRecSelf, tag, cast(unwrap(name)), cast(unwrap(file)), line, cast(unwrap(scope)), cast(unwrap(baseType)), DIFlags(flags), sizeInBits, alignInBits, @@ -289,16 +294,21 @@ MlirAttribute mlirLLVMDISubroutineTypeAttrGet(MlirContext ctx, [](Attribute a) { return cast(a); }))); } +MlirAttribute mlirLLVMDISubprogramAttrGetRecSelf(MlirAttribute recId) { + return wrap(DISubprogramAttr::getRecSelf(cast(unwrap(recId)))); +} + MlirAttribute mlirLLVMDISubprogramAttrGet( - MlirContext ctx, MlirAttribute id, MlirAttribute compileUnit, - MlirAttribute scope, MlirAttribute name, MlirAttribute linkageName, - MlirAttribute file, unsigned int line, unsigned int scopeLine, - uint64_t subprogramFlags, MlirAttribute type, intptr_t nRetainedNodes, - MlirAttribute const *retainedNodes) { + MlirContext ctx, MlirAttribute recId, bool isRecSelf, MlirAttribute id, + MlirAttribute compileUnit, MlirAttribute scope, MlirAttribute name, + MlirAttribute linkageName, MlirAttribute file, unsigned int line, + unsigned int scopeLine, uint64_t subprogramFlags, MlirAttribute type, + intptr_t nRetainedNodes, MlirAttribute const *retainedNodes) { SmallVector nodesStorage; nodesStorage.reserve(nRetainedNodes); return wrap(DISubprogramAttr::get( - unwrap(ctx), cast(unwrap(id)), + unwrap(ctx), cast(unwrap(recId)), isRecSelf, + cast(unwrap(id)), cast(unwrap(compileUnit)), cast(unwrap(scope)), cast(unwrap(name)), cast(unwrap(linkageName)), cast(unwrap(file)), @@ -353,14 +363,15 @@ MlirAttribute mlirLLVMDIModuleAttrGetScope(MlirAttribute diModule) { } MlirAttribute mlirLLVMDIImportedEntityAttrGet( - MlirContext ctx, unsigned int tag, MlirAttribute entity, MlirAttribute file, - unsigned int line, MlirAttribute name, intptr_t nElements, - MlirAttribute const *elements) { + MlirContext ctx, unsigned int tag, MlirAttribute scope, + MlirAttribute entity, MlirAttribute file, unsigned int line, + MlirAttribute name, intptr_t nElements, MlirAttribute const *elements) { SmallVector elementsStorage; elementsStorage.reserve(nElements); return wrap(DIImportedEntityAttr::get( - unwrap(ctx), tag, cast(unwrap(entity)), - cast(unwrap(file)), line, cast(unwrap(name)), + unwrap(ctx), tag, cast(unwrap(scope)), + cast(unwrap(entity)), cast(unwrap(file)), line, + cast(unwrap(name)), llvm::map_to_vector(unwrapList(nElements, elements, elementsStorage), [](Attribute a) { return cast(a); }))); } diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp index 98a9659735e7e6..491dcc7f01e73d 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp @@ -203,16 +203,33 @@ void printExpressionArg(AsmPrinter &printer, uint64_t opcode, DIRecursiveTypeAttrInterface DICompositeTypeAttr::withRecId(DistinctAttr recId) { return DICompositeTypeAttr::get( - getContext(), getTag(), recId, getName(), getFile(), getLine(), - getScope(), getBaseType(), getFlags(), getSizeInBits(), getAlignInBits(), - getElements(), getDataLocation(), getRank(), getAllocated(), - getAssociated()); + getContext(), recId, getIsRecSelf(), getTag(), getName(), getFile(), + getLine(), getScope(), getBaseType(), getFlags(), getSizeInBits(), + getAlignInBits(), getElements(), getDataLocation(), getRank(), + getAllocated(), getAssociated()); } DIRecursiveTypeAttrInterface DICompositeTypeAttr::getRecSelf(DistinctAttr recId) { - return DICompositeTypeAttr::get(recId.getContext(), 0, recId, {}, {}, 0, {}, - {}, DIFlags(), 0, 0, {}, {}, {}, {}, {}); + return DICompositeTypeAttr::get(recId.getContext(), recId, /*isRecSelf=*/true, + 0, {}, {}, 0, {}, {}, DIFlags(), 0, 0, {}, {}, + {}, {}, {}); +} + +//===----------------------------------------------------------------------===// +// DISubprogramAttr +//===----------------------------------------------------------------------===// + +DIRecursiveTypeAttrInterface DISubprogramAttr::withRecId(DistinctAttr recId) { + return DISubprogramAttr::get( + getContext(), recId, getIsRecSelf(), getId(), getCompileUnit(), + getScope(), getName(), getLinkageName(), getFile(), getLine(), + getScopeLine(), getSubprogramFlags(), getType(), getRetainedNodes()); +} + +DIRecursiveTypeAttrInterface DISubprogramAttr::getRecSelf(DistinctAttr recId) { + return DISubprogramAttr::get(recId.getContext(), recId, /*isRecSelf=*/true, + {}, {}, {}, {}, {}, 0, 0, {}, {}, {}, {}); } //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp index 3870aab52f199d..6e4a964f1fc93c 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -3155,9 +3155,9 @@ struct LLVMOpAsmDialectInterface : public OpAsmDialectInterface { .CasesetLoc(FusedLoc::get(context, {loc}, subprogramAttr)); } diff --git a/mlir/lib/Target/LLVMIR/DebugImporter.cpp b/mlir/lib/Target/LLVMIR/DebugImporter.cpp index ce3643f513d34a..8c6f32f6bb0cd0 100644 --- a/mlir/lib/Target/LLVMIR/DebugImporter.cpp +++ b/mlir/lib/Target/LLVMIR/DebugImporter.cpp @@ -89,10 +89,9 @@ DICompositeTypeAttr DebugImporter::translateImpl(llvm::DICompositeType *node) { if (node->getTag() == llvm::dwarf::DW_TAG_array_type && !baseType) return nullptr; return DICompositeTypeAttr::get( - context, node->getTag(), /*recId=*/{}, - getStringAttrOrNull(node->getRawName()), translate(node->getFile()), - node->getLine(), translate(node->getScope()), baseType, - flags.value_or(DIFlags::Zero), node->getSizeInBits(), + context, node->getTag(), getStringAttrOrNull(node->getRawName()), + translate(node->getFile()), node->getLine(), translate(node->getScope()), + baseType, flags.value_or(DIFlags::Zero), node->getSizeInBits(), node->getAlignInBits(), elements, translateExpression(node->getDataLocationExp()), translateExpression(node->getRankExp()), @@ -217,8 +216,8 @@ DebugImporter::translateImpl(llvm::DIImportedEntity *node) { } return DIImportedEntityAttr::get( - context, node->getTag(), translate(node->getEntity()), - translate(node->getFile()), node->getLine(), + context, node->getTag(), translate(node->getScope()), + translate(node->getEntity()), translate(node->getFile()), node->getLine(), getStringAttrOrNull(node->getRawName()), elements); } @@ -227,6 +226,7 @@ DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) { mlir::DistinctAttr id; if (node->isDistinct()) id = getOrCreateDistinctID(node); + // Return nullptr if the scope or type is invalid. DIScopeAttr scope = translate(node->getScope()); if (node->getScope() && !scope) @@ -238,9 +238,12 @@ DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) { if (node->getType() && !type) return nullptr; + // Convert the retained nodes but drop all of them if one of them is invalid. SmallVector retainedNodes; for (llvm::DINode *retainedNode : node->getRetainedNodes()) retainedNodes.push_back(translate(retainedNode)); + if (llvm::is_contained(retainedNodes, nullptr)) + retainedNodes.clear(); return DISubprogramAttr::get(context, id, translate(node->getUnit()), scope, getStringAttrOrNull(node->getRawName()), @@ -374,6 +377,9 @@ getRecSelfConstructor(llvm::DINode *node) { .Case([&](llvm::DICompositeType *) { return CtorType(DICompositeTypeAttr::getRecSelf); }) + .Case([&](llvm::DISubprogram *) { + return CtorType(DISubprogramAttr::getRecSelf); + }) .Default(CtorType()); } diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp index 042e015f107fea..8ca3beca6b66f7 100644 --- a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp @@ -96,6 +96,17 @@ llvm::MDString *DebugTranslation::getMDStringOrNull(StringAttr stringAttr) { return llvm::MDString::get(llvmCtx, stringAttr); } +llvm::MDTuple * +DebugTranslation::getMDTupleOrNull(ArrayRef elements) { + if (elements.empty()) + return nullptr; + SmallVector llvmElements = llvm::to_vector( + llvm::map_range(elements, [&](DINodeAttr attr) -> llvm::Metadata * { + return translate(attr); + })); + return llvm::MDNode::get(llvmCtx, llvmElements); +} + llvm::DIBasicType *DebugTranslation::translateImpl(DIBasicTypeAttr attr) { return llvm::DIBasicType::get( llvmCtx, attr.getTag(), getMDStringOrNull(attr.getName()), @@ -138,6 +149,17 @@ DebugTranslation::translateTemporaryImpl(DICompositeTypeAttr attr) { /*VTableHolder=*/nullptr); } +llvm::TempDISubprogram +DebugTranslation::translateTemporaryImpl(DISubprogramAttr attr) { + return llvm::DISubprogram::getTemporary( + llvmCtx, /*Scope=*/nullptr, /*Name=*/{}, /*LinkageName=*/{}, + /*File=*/nullptr, attr.getLine(), /*Type=*/nullptr, + /*ScopeLine=*/0, /*ContainingType=*/nullptr, /*VirtualIndex=*/0, + /*ThisAdjustment=*/0, llvm::DINode::FlagZero, + static_cast(attr.getSubprogramFlags()), + /*Unit=*/nullptr); +} + llvm::DICompositeType * DebugTranslation::translateImpl(DICompositeTypeAttr attr) { // TODO: Use distinct attributes to model this, once they have landed. @@ -151,10 +173,6 @@ DebugTranslation::translateImpl(DICompositeTypeAttr attr) { isDistinct = true; } - SmallVector elements; - for (DINodeAttr member : attr.getElements()) - elements.push_back(translate(member)); - return getDistinctOrUnique( isDistinct, llvmCtx, attr.getTag(), getMDStringOrNull(attr.getName()), translate(attr.getFile()), attr.getLine(), translate(attr.getScope()), @@ -162,7 +180,7 @@ DebugTranslation::translateImpl(DICompositeTypeAttr attr) { attr.getAlignInBits(), /*OffsetInBits=*/0, /*Flags=*/static_cast(attr.getFlags()), - llvm::MDNode::get(llvmCtx, elements), + getMDTupleOrNull(attr.getElements()), /*RuntimeLang=*/0, /*VTableHolder=*/nullptr, /*TemplateParams=*/nullptr, /*Identifier=*/nullptr, /*Discriminator=*/nullptr, @@ -242,22 +260,21 @@ DebugTranslation::translateImpl(DIGlobalVariableAttr attr) { attr.getIsDefined(), nullptr, nullptr, attr.getAlignInBits(), nullptr); } -llvm::DIType * +llvm::DINode * DebugTranslation::translateRecursive(DIRecursiveTypeAttrInterface attr) { DistinctAttr recursiveId = attr.getRecId(); - if (auto *iter = recursiveTypeMap.find(recursiveId); - iter != recursiveTypeMap.end()) { + if (auto *iter = recursiveNodeMap.find(recursiveId); + iter != recursiveNodeMap.end()) { return iter->second; - } else { - assert(!attr.isRecSelf() && "unbound DI recursive self type"); } + assert(!attr.getIsRecSelf() && "unbound DI recursive self reference"); - auto setRecursivePlaceholder = [&](llvm::DIType *placeholder) { - recursiveTypeMap.try_emplace(recursiveId, placeholder); + auto setRecursivePlaceholder = [&](llvm::DINode *placeholder) { + recursiveNodeMap.try_emplace(recursiveId, placeholder); }; - llvm::DIType *result = - TypeSwitch(attr) + llvm::DINode *result = + TypeSwitch(attr) .Case([&](auto attr) { auto temporary = translateTemporaryImpl(attr); setRecursivePlaceholder(temporary.get()); @@ -266,11 +283,20 @@ DebugTranslation::translateRecursive(DIRecursiveTypeAttrInterface attr) { auto *concrete = translateImpl(attr); temporary->replaceAllUsesWith(concrete); return concrete; + }) + .Case([&](auto attr) { + auto temporary = translateTemporaryImpl(attr); + setRecursivePlaceholder(temporary.get()); + // Must call `translateImpl` directly instead of `translate` to + // avoid handling the recursive interface again. + auto *concrete = translateImpl(attr); + temporary->replaceAllUsesWith(concrete); + return concrete; }); - assert(recursiveTypeMap.back().first == recursiveId && + assert(recursiveNodeMap.back().first == recursiveId && "internal inconsistency: unexpected recursive translation stack"); - recursiveTypeMap.pop_back(); + recursiveNodeMap.pop_back(); return result; } @@ -297,6 +323,7 @@ llvm::DISubprogram *DebugTranslation::translateImpl(DISubprogramAttr attr) { bool isDefinition = static_cast(attr.getSubprogramFlags() & LLVM::DISubprogramFlags::Definition); + llvm::DISubprogram *node = getDistinctOrUnique( isDefinition, llvmCtx, scope, getMDStringOrNull(attr.getName()), getMDStringOrNull(attr.getLinkageName()), file, attr.getLine(), type, @@ -304,21 +331,8 @@ llvm::DISubprogram *DebugTranslation::translateImpl(DISubprogramAttr attr) { /*ContainingType=*/nullptr, /*VirtualIndex=*/0, /*ThisAdjustment=*/0, llvm::DINode::FlagZero, static_cast(attr.getSubprogramFlags()), - compileUnit); - - // DIImportedEntity requires scope information which DIImportedEntityAttr does - // not have. This is why we translate DIImportedEntityAttr after we have - // created DISubprogram as we can use it as the scope. - SmallVector retainedNodes; - for (DINodeAttr nodeAttr : attr.getRetainedNodes()) { - if (auto importedAttr = dyn_cast(nodeAttr)) { - llvm::DINode *dn = translate(importedAttr, node); - retainedNodes.push_back(dn); - } - } - if (!retainedNodes.empty()) - node->replaceRetainedNodes(llvm::MDTuple::get(llvmCtx, retainedNodes)); - + compileUnit, /*TemplateParams=*/nullptr, /*Declaration=*/nullptr, + getMDTupleOrNull(attr.getRetainedNodes())); if (attr.getId()) distinctAttrToNode.try_emplace(attr.getId(), node); return node; @@ -339,16 +353,12 @@ llvm::DINamespace *DebugTranslation::translateImpl(DINamespaceAttr attr) { attr.getExportSymbols()); } -llvm::DIImportedEntity *DebugTranslation::translate(DIImportedEntityAttr attr, - llvm::DIScope *scope) { - SmallVector elements; - for (DINodeAttr member : attr.getElements()) - elements.push_back(translate(member)); - +llvm::DIImportedEntity * +DebugTranslation::translateImpl(DIImportedEntityAttr attr) { return llvm::DIImportedEntity::get( - llvmCtx, attr.getTag(), scope, translate(attr.getEntity()), - translate(attr.getFile()), attr.getLine(), - getMDStringOrNull(attr.getName()), llvm::MDNode::get(llvmCtx, elements)); + llvmCtx, attr.getTag(), translate(attr.getScope()), + translate(attr.getEntity()), translate(attr.getFile()), attr.getLine(), + getMDStringOrNull(attr.getName()), getMDTupleOrNull(attr.getElements())); } llvm::DISubrange *DebugTranslation::translateImpl(DISubrangeAttr attr) { @@ -413,10 +423,10 @@ llvm::DINode *DebugTranslation::translate(DINodeAttr attr) { node = TypeSwitch(attr) .Case( + DIImportedEntityAttr, DILabelAttr, DILexicalBlockAttr, + DILexicalBlockFileAttr, DILocalVariableAttr, DIModuleAttr, + DINamespaceAttr, DINullTypeAttr, DIStringTypeAttr, + DISubprogramAttr, DISubrangeAttr, DISubroutineTypeAttr>( [&](auto attr) { return translateImpl(attr); }); if (node && !node->isTemporary()) diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.h b/mlir/lib/Target/LLVMIR/DebugTranslation.h index 37b985acf8541e..422aa34e28f3c9 100644 --- a/mlir/lib/Target/LLVMIR/DebugTranslation.h +++ b/mlir/lib/Target/LLVMIR/DebugTranslation.h @@ -75,6 +75,7 @@ class DebugTranslation { llvm::DIDerivedType *translateImpl(DIDerivedTypeAttr attr); llvm::DIStringType *translateImpl(DIStringTypeAttr attr); llvm::DIFile *translateImpl(DIFileAttr attr); + llvm::DIImportedEntity *translateImpl(DIImportedEntityAttr attr); llvm::DILabel *translateImpl(DILabelAttr attr); llvm::DILexicalBlock *translateImpl(DILexicalBlockAttr attr); llvm::DILexicalBlockFile *translateImpl(DILexicalBlockFileAttr attr); @@ -90,27 +91,26 @@ class DebugTranslation { llvm::DISubroutineType *translateImpl(DISubroutineTypeAttr attr); llvm::DIType *translateImpl(DITypeAttr attr); - /// Currently, DIImportedEntityAttr does not have a scope field to avoid a - /// cyclic dependency. The scope information is obtained from the entity - /// which holds the list of DIImportedEntityAttr. This requires that scope - /// information be passed to translate function. - llvm::DIImportedEntity *translate(DIImportedEntityAttr attr, llvm::DIScope *); - /// Attributes that support self recursion need to implement an additional /// method to hook into `translateRecursive`. /// - ` translateTemporaryImpl()`: /// Create a temporary translation of the DI attr without recursively /// translating any nested DI attrs. - llvm::DIType *translateRecursive(DIRecursiveTypeAttrInterface attr); + llvm::DINode *translateRecursive(DIRecursiveTypeAttrInterface attr); /// Translate the given attribute to a temporary llvm debug metadata of the /// corresponding type. llvm::TempDICompositeType translateTemporaryImpl(DICompositeTypeAttr attr); + llvm::TempDISubprogram translateTemporaryImpl(DISubprogramAttr attr); /// Constructs a string metadata node from the string attribute. Returns /// nullptr if `stringAttr` is null or contains and empty string. llvm::MDString *getMDStringOrNull(StringAttr stringAttr); + /// Constructs a tuple metadata node from the `elements`. Returns nullptr if + /// `elements` is empty. + llvm::MDTuple *getMDTupleOrNull(ArrayRef elements); + /// Constructs a DIExpression metadata node from the DIExpressionAttr. Returns /// nullptr if `DIExpressionAttr` is null. llvm::DIExpression *getExpressionAttrOrNull(DIExpressionAttr attr); @@ -125,8 +125,8 @@ class DebugTranslation { /// metadata. DenseMap attrToNode; - /// A mapping between recursive ID and the translated DIType. - llvm::MapVector recursiveTypeMap; + /// A mapping between recursive ID and the translated DINode. + llvm::MapVector recursiveNodeMap; /// A mapping between a distinct ID and the translated LLVM metadata node. /// This helps identify attrs that should translate into the same LLVM debug diff --git a/mlir/test/CAPI/llvm.c b/mlir/test/CAPI/llvm.c index da28a96f89691d..36277122801de4 100644 --- a/mlir/test/CAPI/llvm.c +++ b/mlir/test/CAPI/llvm.c @@ -248,12 +248,16 @@ static void testDebugInfoAttributes(MlirContext ctx) { mlirStringAttrGet(ctx, mlirStringRefCreateFromCString("foo")); MlirAttribute bar = mlirStringAttrGet(ctx, mlirStringRefCreateFromCString("bar")); - MlirAttribute id = mlirDisctinctAttrCreate(foo); + + MlirAttribute none = mlirUnitAttrGet(ctx); + MlirAttribute id = mlirDisctinctAttrCreate(none); + MlirAttribute recId0 = mlirDisctinctAttrCreate(none); + MlirAttribute recId1 = mlirDisctinctAttrCreate(none); // CHECK: #llvm.di_null_type mlirAttributeDump(mlirLLVMDINullTypeAttrGet(ctx)); - // CHECK: #llvm.di_basic_type MlirAttribute di_type = mlirLLVMDIBasicTypeAttrGet(ctx, 0, foo, 64, MlirLLVMTypeEncodingSigned); @@ -312,15 +316,17 @@ static void testDebugInfoAttributes(MlirContext ctx) { // CHECK: #llvm.di_subroutine_type<{{.*}}> mlirAttributeDump(subroutine_type); + MlirAttribute di_subprogram_self_rec = + mlirLLVMDISubprogramAttrGetRecSelf(recId0); MlirAttribute di_imported_entity = mlirLLVMDIImportedEntityAttrGet( - ctx, 0, di_module, file, 1, foo, 1, &local_var); + ctx, 0, di_subprogram_self_rec, di_module, file, 1, foo, 1, &local_var); mlirAttributeDump(di_imported_entity); // CHECK: #llvm.di_imported_entity<{{.*}}> MlirAttribute di_subprogram = mlirLLVMDISubprogramAttrGet( - ctx, id, compile_unit, compile_unit, foo, bar, file, 1, 2, 0, - subroutine_type, 1, &di_imported_entity); + ctx, recId0, false, id, compile_unit, compile_unit, foo, bar, file, 1, 2, + 0, subroutine_type, 1, &di_imported_entity); // CHECK: #llvm.di_subprogram<{{.*}}> mlirAttributeDump(di_subprogram); @@ -350,10 +356,13 @@ static void testDebugInfoAttributes(MlirContext ctx) { // CHECK: #llvm.di_string_type<{{.*}}> mlirAttributeDump(string_type); + // CHECK: #llvm.di_composite_type + mlirAttributeDump(mlirLLVMDICompositeTypeAttrGetRecSelf(recId1)); + // CHECK: #llvm.di_composite_type<{{.*}}> mlirAttributeDump(mlirLLVMDICompositeTypeAttrGet( - ctx, 0, id, foo, file, 1, compile_unit, di_type, 0, 64, 8, 1, &di_type, - expression, expression, expression, expression)); + ctx, recId1, false, 0, foo, file, 1, compile_unit, di_type, 0, 64, 8, 1, + &di_type, expression, expression, expression, expression)); } int main(void) { diff --git a/mlir/test/Target/LLVMIR/Import/debug-info.ll b/mlir/test/Target/LLVMIR/Import/debug-info.ll index bb03da37c0d097..02e35ae7f0ee9d 100644 --- a/mlir/test/Target/LLVMIR/Import/debug-info.ll +++ b/mlir/test/Target/LLVMIR/Import/debug-info.ll @@ -307,17 +307,13 @@ define void @class_method() { ret void, !dbg !9 } -; Verify the cyclic composite type is identified, even though conversion begins from the subprogram type. -; CHECK-DAG: #[[COMP_SELF:.+]] = #llvm.di_composite_type -; CHECK-DAG: #[[COMP_PTR:.+]] = #llvm.di_derived_type +; Verify the cyclic subprogram is handled correctly. +; CHECK-DAG: #[[SP_SELF:.+]] = #llvm.di_subprogram +; CHECK-DAG: #[[COMP:.+]] = #llvm.di_composite_type +; CHECK-DAG: #[[COMP_PTR:.+]] = #llvm.di_derived_type ; CHECK-DAG: #[[SP_TYPE:.+]] = #llvm.di_subroutine_type -; CHECK-DAG: #[[SP_INNER:.+]] = #llvm.di_subprogram -; CHECK-DAG: #[[COMP:.+]] = #llvm.di_composite_type - -; CHECK-DAG: #[[COMP_PTR_OUTER:.+]] = #llvm.di_derived_type -; CHECK-DAG: #[[SP_TYPE_OUTER:.+]] = #llvm.di_subroutine_type -; CHECK-DAG: #[[SP_OUTER:.+]] = #llvm.di_subprogram -; CHECK-DAG: #[[LOC]] = loc(fused<#[[SP_OUTER]]> +; CHECK-DAG: #[[SP:.+]] = #llvm.di_subprogram +; CHECK-DAG: #[[LOC]] = loc(fused<#[[SP]]> !llvm.dbg.cu = !{!1} !llvm.module.flags = !{!0} @@ -335,10 +331,10 @@ define void @class_method() { ; // ----- ; Verify the cyclic composite type is handled correctly. -; CHECK-DAG: #[[COMP_SELF:.+]] = #llvm.di_composite_type +; CHECK-DAG: #[[COMP_SELF:.+]] = #llvm.di_composite_type ; CHECK-DAG: #[[COMP_PTR_INNER:.+]] = #llvm.di_derived_type ; CHECK-DAG: #[[FIELD:.+]] = #llvm.di_derived_type -; CHECK-DAG: #[[COMP:.+]] = #llvm.di_composite_type +; CHECK-DAG: #[[COMP:.+]] = #llvm.di_composite_type ; CHECK-DAG: #[[COMP_PTR_OUTER:.+]] = #llvm.di_derived_type ; CHECK-DAG: #[[VAR0:.+]] = #llvm.di_local_variable @@ -610,9 +606,10 @@ define void @distinct_cu_func1() !dbg !5 { ; CHECK-LABEL: @declaration declare !dbg !1 void @declaration() -; CHECK: #di_subprogram = #llvm.di_subprogram< +; CHECK: #[[SP:.+]] = #llvm.di_subprogram< ; CHECK-NOT: id = distinct ; CHECK-NOT: subprogramFlags = +; CHECK: loc(fused<#[[SP]]> !llvm.module.flags = !{!0} !0 = !{i32 2, !"Debug Info Version", i32 3} @@ -633,14 +630,14 @@ declare !dbg !1 void @declaration() ; CHECK-DAG: #[[B1_INNER:.+]] = #llvm.di_derived_type<{{.*}}name = "B:B1", baseType = #[[B_SELF:.+]]> ; CHECK-DAG: #[[B2_INNER:.+]] = #llvm.di_derived_type<{{.*}}name = "B:B2", baseType = #[[B_SELF]]> -; CHECK-DAG: #[[B_INNER:.+]] = #llvm.di_composite_type<{{.*}}recId = [[B_RECID:.+]], {{.*}}name = "B", {{.*}}elements = #[[B1_INNER]], #[[B2_INNER]] +; CHECK-DAG: #[[B_INNER:.+]] = #llvm.di_composite_type ; CHECK-DAG: #[[B2_OUTER:.+]] = #llvm.di_derived_type<{{.*}}name = "B:B2", baseType = #[[B_INNER]]> -; CHECK-DAG: #[[A_OUTER:.+]] = #llvm.di_composite_type<{{.*}}recId = [[A_RECID:.+]], {{.*}}name = "A", {{.*}}elements = #[[B1_OUTER]], #[[B2_OUTER]] +; CHECK-DAG: #[[A_OUTER:.+]] = #llvm.di_composite_typeB", {{.*}}baseType = #[[B_OUTER:.+]]> -; CHECK-DAG: #[[B_OUTER]] = #llvm.di_composite_type<{{.*}}recId = [[B_RECID:.+]], {{.*}}name = "B", {{.*}}elements = #[[TO_C_INNER:.+]]> +; CHECK-DAG: #[[B_OUTER]] = #llvm.di_composite_type ; CHECK-DAG: #[[TO_C_INNER]] = #llvm.di_derived_type<{{.*}}name = "->C", {{.*}}baseType = #[[C_INNER:.+]]> ; CHECK-DAG: #[[C_INNER]] = #llvm.di_composite_type<{{.*}}name = "C", {{.*}}elements = #[[TO_B_SELF:.+]]> ; CHECK-DAG: #[[TO_B_SELF]] = #llvm.di_derived_type<{{.*}}name = "->B", {{.*}}baseType = #[[B_SELF:.+]]> -; CHECK-DAG: #[[B_SELF]] = #llvm.di_composite_type<{{.*}}recId = [[B_RECID]]> +; CHECK-DAG: #[[B_SELF]] = #llvm.di_composite_type ; CHECK-DAG: #[[TO_C_OUTER]] = #llvm.di_derived_type<{{.*}}name = "->C", {{.*}}baseType = #[[C_OUTER:.+]]> ; CHECK-DAG: #[[C_OUTER]] = #llvm.di_composite_type<{{.*}}name = "C", {{.*}}elements = #[[TO_B_OUTER]]> @@ -718,23 +715,23 @@ define void @class_field(ptr %arg1) !dbg !18 { ; ^ ^ ; +-------------+ -; CHECK-DAG: #[[A:.+]] = #llvm.di_composite_type<{{.*}}recId = [[A_RECID:.+]], {{.*}}name = "A", {{.*}}elements = #[[A_TO_B:.+]], #[[A_TO_C:.+]]> +; CHECK-DAG: #[[A:.+]] = #llvm.di_composite_type ; CHECK-DAG: #llvm.di_subprogram<{{.*}}scope = #[[A]], ; CHECK-DAG: #[[A_TO_B]] = #llvm.di_derived_type<{{.*}}name = "->B", {{.*}}baseType = #[[B_FROM_A:.+]]> ; CHECK-DAG: #[[A_TO_C]] = #llvm.di_derived_type<{{.*}}name = "->C", {{.*}}baseType = #[[C_FROM_A:.+]]> -; CHECK-DAG: #[[B_FROM_A]] = #llvm.di_composite_type<{{.*}}recId = [[B_RECID:.+]], {{.*}}name = "B", {{.*}}elements = #[[B_TO_C:.+]]> +; CHECK-DAG: #[[B_FROM_A]] = #llvm.di_composite_type ; CHECK-DAG: #[[B_TO_C]] = #llvm.di_derived_type<{{.*}}name = "->C", {{.*}}baseType = #[[C_FROM_B:.+]]> -; CHECK-DAG: #[[C_FROM_B]] = #llvm.di_composite_type<{{.*}}recId = [[C_RECID:.+]], {{.*}}name = "C", {{.*}}elements = #[[TO_A_SELF:.+]], #[[TO_B_SELF:.+]], #[[TO_C_SELF:.+]]> +; CHECK-DAG: #[[C_FROM_B]] = #llvm.di_composite_type -; CHECK-DAG: #[[C_FROM_A]] = #llvm.di_composite_type<{{.*}}recId = [[C_RECID]], {{.*}}name = "C", {{.*}}elements = #[[TO_A_SELF]], #[[A_TO_B:.+]], #[[TO_C_SELF]] +; CHECK-DAG: #[[C_FROM_A]] = #llvm.di_composite_typeA", {{.*}}baseType = #[[A_SELF:.+]]> ; CHECK-DAG: #[[TO_B_SELF]] = #llvm.di_derived_type<{{.*}}name = "->B", {{.*}}baseType = #[[B_SELF:.+]]> ; CHECK-DAG: #[[TO_C_SELF]] = #llvm.di_derived_type<{{.*}}name = "->C", {{.*}}baseType = #[[C_SELF:.+]]> -; CHECK-DAG: #[[A_SELF]] = #llvm.di_composite_type<{{.*}}recId = [[A_RECID]]> -; CHECK-DAG: #[[B_SELF]] = #llvm.di_composite_type<{{.*}}recId = [[B_RECID]]> -; CHECK-DAG: #[[C_SELF]] = #llvm.di_composite_type<{{.*}}recId = [[C_RECID]]> +; CHECK-DAG: #[[A_SELF]] = #llvm.di_composite_type +; CHECK-DAG: #[[B_SELF]] = #llvm.di_composite_type +; CHECK-DAG: #[[C_SELF]] = #llvm.di_composite_type define void @class_field(ptr %arg1) !dbg !18 { ret void @@ -816,4 +813,6 @@ define void @imp_fn() !dbg !12 { !17 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !12, entity: !8, file: !3, line: 1, elements: !15) ; CHECK-DAG: #[[M:.+]] = #llvm.di_module<{{.*}}name = "mod1"{{.*}}> -; CHECK-DAG: #[[SP:.+]] = #llvm.di_subprogram<{{.*}}name = "imp_fn"{{.*}}retainedNodes = #llvm.di_imported_entity> +; CHECK-DAG: #[[SP_REC:.+]] = #llvm.di_subprogram, isRecSelf = true> +; CHECK-DAG: #[[IE:.+]] = #llvm.di_imported_entity +; CHECK-DAG: #[[SP:.+]] = #llvm.di_subprogram<{{.*}}name = "imp_fn"{{.*}}retainedNodes = #[[IE]]> diff --git a/mlir/test/Target/LLVMIR/llvmir-debug.mlir b/mlir/test/Target/LLVMIR/llvmir-debug.mlir index 30b2ba5e9bad1f..01194df5047742 100644 --- a/mlir/test/Target/LLVMIR/llvmir-debug.mlir +++ b/mlir/test/Target/LLVMIR/llvmir-debug.mlir @@ -372,23 +372,28 @@ llvm.func @fn_with_gl() { llvm.func @imp_fn() { llvm.return } loc(#loc2) -#file = #llvm.di_file<"test.f90" in ""> -#SP_TY = #llvm.di_subroutine_type -#CU = #llvm.di_compile_unit, - sourceLanguage = DW_LANG_Fortran95, file = #file, isOptimized = false, + +#di_file = #llvm.di_file<"test.f90" in ""> +#di_subroutine_type = #llvm.di_subroutine_type +#di_compile_unit = #llvm.di_compile_unit, + sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full> -#MOD = #llvm.di_module -#MOD1 = #llvm.di_module -#SP = #llvm.di_subprogram, compileUnit = #CU, scope = #file, - name = "imp_fn", file = #file, subprogramFlags = Definition, type = #SP_TY, - retainedNodes = #llvm.di_imported_entity, #llvm.di_imported_entity> +#di_module_1 = #llvm.di_module +#di_module_2 = #llvm.di_module +#di_subprogram_self_rec = #llvm.di_subprogram> +#di_imported_entity_1 = #llvm.di_imported_entity +#di_imported_entity_2 = #llvm.di_imported_entity +#di_subprogram = #llvm.di_subprogram, recId = distinct[1]<>, + compileUnit = #di_compile_unit, scope = #di_file, name = "imp_fn", + file = #di_file, subprogramFlags = Definition, type = #di_subroutine_type, + retainedNodes = #di_imported_entity_1, #di_imported_entity_2> #loc1 = loc("test.f90":12:14) -#loc2 = loc(fused<#SP>[#loc1]) +#loc2 = loc(fused<#di_subprogram>[#loc1]) // CHECK-DAG: ![[SP:[0-9]+]] = {{.*}}!DISubprogram(name: "imp_fn"{{.*}}retainedNodes: ![[NODES:[0-9]+]]) -// CHECK-DAG: ![[NODES]] = !{![[NODE2:[0-9]+]], ![[NODE1:[0-9]+]]} +// CHECK-DAG: ![[NODES]] = !{![[NODE1:[0-9]+]], ![[NODE2:[0-9]+]]} // CHECK-DAG: ![[NODE1]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: ![[SP]], entity: ![[MOD1:[0-9]+]]{{.*}}) // CHECK-DAG: ![[NODE2]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: ![[SP]], entity: ![[MOD2:[0-9]+]]{{.*}}) // CHECK-DAG: ![[MOD1]] = !DIModule({{.*}}name: "mod1"{{.*}}) @@ -443,7 +448,7 @@ llvm.func @func_debug_directives() { #di_compile_unit = #llvm.di_compile_unit, sourceLanguage = DW_LANG_C, file = #di_file, isOptimized = false, emissionKind = None> // Recursive type itself. -#di_struct_self = #llvm.di_composite_type> +#di_struct_self = #llvm.di_composite_type, isRecSelf = true> #di_ptr_inner = #llvm.di_derived_type #di_subroutine_inner = #llvm.di_subroutine_type #di_subprogram_inner = #llvm.di_subprogram< @@ -497,7 +502,7 @@ llvm.func @class_method() { // Ensures composite types with a recursive scope work. -#di_composite_type_self = #llvm.di_composite_type> +#di_composite_type_self = #llvm.di_composite_type, isRecSelf = true> #di_file = #llvm.di_file<"test.mlir" in "/"> #di_subroutine_type = #llvm.di_subroutine_type #di_subprogram = #llvm.di_subprogram @@ -508,7 +513,7 @@ llvm.func @class_method() { llvm.mlir.global @global_variable() {dbg_expr = #di_global_variable_expression} : !llvm.struct<()> // CHECK: distinct !DIGlobalVariable({{.*}}type: ![[COMP:[0-9]+]], -// CHECK: ![[COMP]] = distinct !DICompositeType({{.*}}scope: ![[SCOPE:[0-9]+]], +// CHECK: ![[COMP]] = distinct !DICompositeType({{.*}}scope: ![[SCOPE:[0-9]+]] // CHECK: ![[SCOPE]] = !DISubprogram({{.*}}type: ![[SUBROUTINE:[0-9]+]], // CHECK: ![[SUBROUTINE]] = !DISubroutineType(types: ![[SR_TYPES:[0-9]+]]) // CHECK: ![[SR_TYPES]] = !{![[COMP]]} @@ -520,7 +525,7 @@ llvm.mlir.global @global_variable() {dbg_expr = #di_global_variable_expression} // replaced with the recursive self reference. #di_file = #llvm.di_file<"test.mlir" in "/"> -#di_composite_type_self = #llvm.di_composite_type> +#di_composite_type_self = #llvm.di_composite_type, isRecSelf = true> #di_subroutine_type_inner = #llvm.di_subroutine_type #di_subprogram_inner = #llvm.di_subprogram @@ -540,7 +545,7 @@ llvm.mlir.global @global_variable() {dbg_expr = #di_global_variable_expression} // CHECK: distinct !DIGlobalVariable({{.*}}type: ![[VAR:[0-9]+]], // CHECK: ![[VAR]] = !DISubroutineType(types: ![[COMPS:[0-9]+]]) // CHECK: ![[COMPS]] = !{![[COMP:[0-9]+]], -// CHECK: ![[COMP]] = distinct !DICompositeType({{.*}}scope: ![[SCOPE:[0-9]+]], +// CHECK: ![[COMP]] = distinct !DICompositeType({{.*}}scope: ![[SCOPE:[0-9]+]] // CHECK: ![[SCOPE]] = !DISubprogram({{.*}}type: ![[SUBROUTINE:[0-9]+]], // CHECK: ![[SUBROUTINE]] = !DISubroutineType(types: ![[SR_TYPES:[0-9]+]]) // CHECK: ![[SR_TYPES]] = !{![[COMP]]} From 6f81c878ecd40acf1a0364e0ea5c9e6ea87407a2 Mon Sep 17 00:00:00 2001 From: Timm Baeder Date: Sat, 31 Aug 2024 07:26:02 +0200 Subject: [PATCH 05/14] [clang][bytecode][NFC] Implement MemberPointer::toDiagnosticString() (#106825) --- clang/lib/AST/ByteCode/Interp.h | 2 +- clang/lib/AST/ByteCode/MemberPointer.h | 12 ++++++------ clang/lib/AST/ByteCode/Opcodes.td | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index aa790a71a6b476..c1423a060bcb97 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -2828,7 +2828,7 @@ inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { return true; } -inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const Decl *D) { +inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D) { S.Stk.push(D); return true; } diff --git a/clang/lib/AST/ByteCode/MemberPointer.h b/clang/lib/AST/ByteCode/MemberPointer.h index de135a40a3c77b..b17ce256e75e29 100644 --- a/clang/lib/AST/ByteCode/MemberPointer.h +++ b/clang/lib/AST/ByteCode/MemberPointer.h @@ -22,21 +22,21 @@ class FunctionPointer; class MemberPointer final { private: Pointer Base; - const Decl *Dcl = nullptr; + const ValueDecl *Dcl = nullptr; int32_t PtrOffset = 0; - MemberPointer(Pointer Base, const Decl *Dcl, int32_t PtrOffset) + MemberPointer(Pointer Base, const ValueDecl *Dcl, int32_t PtrOffset) : Base(Base), Dcl(Dcl), PtrOffset(PtrOffset) {} public: MemberPointer() = default; - MemberPointer(Pointer Base, const Decl *Dcl) : Base(Base), Dcl(Dcl) {} + MemberPointer(Pointer Base, const ValueDecl *Dcl) : Base(Base), Dcl(Dcl) {} MemberPointer(uint32_t Address, const Descriptor *D) { // We only reach this for Address == 0, when creating a null member pointer. assert(Address == 0); } - MemberPointer(const Decl *D) : Dcl(D) { + MemberPointer(const ValueDecl *D) : Dcl(D) { assert((isa(D))); } @@ -67,7 +67,7 @@ class MemberPointer final { } bool hasDecl() const { return Dcl; } - const Decl *getDecl() const { return Dcl; } + const ValueDecl *getDecl() const { return Dcl; } MemberPointer atInstanceBase(unsigned Offset) const { if (Base.isZero()) @@ -96,7 +96,7 @@ class MemberPointer final { } std::string toDiagnosticString(const ASTContext &Ctx) const { - return "FIXME"; + return toAPValue(Ctx).getAsString(Ctx, Dcl->getType()); } ComparisonCategoryResult compare(const MemberPointer &RHS) const { diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index f286c71a129d1d..46247688d4ef85 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -62,7 +62,7 @@ def ArgExpr : ArgType { let Name = "const Expr *"; } def ArgOffsetOfExpr : ArgType { let Name = "const OffsetOfExpr *"; } def ArgDeclRef : ArgType { let Name = "const DeclRefExpr *"; } def ArgCCI : ArgType { let Name = "const ComparisonCategoryInfo *"; } -def ArgDecl : ArgType { let Name = "const Decl*"; } +def ArgValueDecl : ArgType { let Name = "const ValueDecl*"; } def ArgVarDecl : ArgType { let Name = "const VarDecl*"; } def ArgDesc : ArgType { let Name = "const Descriptor *"; } def ArgPrimType : ArgType { let Name = "PrimType"; } @@ -756,7 +756,7 @@ def Memcpy : Opcode; def ToMemberPtr : Opcode; def CastMemberPtrPtr : Opcode; def GetMemberPtr : Opcode { - let Args = [ArgDecl]; + let Args = [ArgValueDecl]; } def GetMemberPtrBase : Opcode; def GetMemberPtrDecl : Opcode; From 5257fa19c985f6fbb7ca422c60e9631c7d16527c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Clement=20=28=E3=83=90=E3=83=AC=E3=83=B3?= =?UTF-8?q?=E3=82=BF=E3=82=A4=E3=83=B3=20=E3=82=AF=E3=83=AC=E3=83=A1?= =?UTF-8?q?=E3=83=B3=29?= Date: Fri, 30 Aug 2024 22:45:56 -0700 Subject: [PATCH 06/14] [flang][openacc] Attach post allocate action on the correct operation (#106805) In some cases (when using stat), the action was attached to the invisible fir.result op. Apply same fix as in #89662. --- flang/lib/Lower/OpenACC.cpp | 35 ++++++++++++++---------- flang/test/Lower/OpenACC/acc-declare.f90 | 17 ++++++++++++ 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp index 431fab52872d33..c97398fc43f923 100644 --- a/flang/lib/Lower/OpenACC.cpp +++ b/flang/lib/Lower/OpenACC.cpp @@ -4293,23 +4293,30 @@ void Fortran::lower::attachDeclarePostAllocAction( const Fortran::semantics::Symbol &sym) { std::stringstream fctName; fctName << converter.mangleName(sym) << declarePostAllocSuffix.str(); - mlir::Operation &op = builder.getInsertionBlock()->back(); + mlir::Operation *op = &builder.getInsertionBlock()->back(); + + if (auto resOp = mlir::dyn_cast(*op)) { + assert(resOp.getOperands().size() == 0 && + "expect only fir.result op with no operand"); + op = op->getPrevNode(); + } + assert(op && "expect operation to attach the post allocation action"); - if (op.hasAttr(mlir::acc::getDeclareActionAttrName())) { - auto attr = op.getAttrOfType( + if (op->hasAttr(mlir::acc::getDeclareActionAttrName())) { + auto attr = op->getAttrOfType( mlir::acc::getDeclareActionAttrName()); - op.setAttr(mlir::acc::getDeclareActionAttrName(), - mlir::acc::DeclareActionAttr::get( - builder.getContext(), attr.getPreAlloc(), - /*postAlloc=*/builder.getSymbolRefAttr(fctName.str()), - attr.getPreDealloc(), attr.getPostDealloc())); + op->setAttr(mlir::acc::getDeclareActionAttrName(), + mlir::acc::DeclareActionAttr::get( + builder.getContext(), attr.getPreAlloc(), + /*postAlloc=*/builder.getSymbolRefAttr(fctName.str()), + attr.getPreDealloc(), attr.getPostDealloc())); } else { - op.setAttr(mlir::acc::getDeclareActionAttrName(), - mlir::acc::DeclareActionAttr::get( - builder.getContext(), - /*preAlloc=*/{}, - /*postAlloc=*/builder.getSymbolRefAttr(fctName.str()), - /*preDealloc=*/{}, /*postDealloc=*/{})); + op->setAttr(mlir::acc::getDeclareActionAttrName(), + mlir::acc::DeclareActionAttr::get( + builder.getContext(), + /*preAlloc=*/{}, + /*postAlloc=*/builder.getSymbolRefAttr(fctName.str()), + /*preDealloc=*/{}, /*postDealloc=*/{})); } } diff --git a/flang/test/Lower/OpenACC/acc-declare.f90 b/flang/test/Lower/OpenACC/acc-declare.f90 index ff1e756c20e125..0066e712fbdcce 100644 --- a/flang/test/Lower/OpenACC/acc-declare.f90 +++ b/flang/test/Lower/OpenACC/acc-declare.f90 @@ -455,3 +455,20 @@ module acc_declare_allocatable_test3 ! CHECK-LABEL: acc.global_ctor @_QMacc_declare_allocatable_test3Edata1_acc_ctor ! CHECK-LABEL: acc.global_ctor @_QMacc_declare_allocatable_test3Edata2_acc_ctor + +module acc_declare_post_action_stat + real, dimension(:), allocatable :: x, y + !$acc declare create(x,y) + +contains + + subroutine init() + integer :: stat + allocate(x(10), y(10), stat=stat) + end subroutine +end module + +! CHECK-LABEL: func.func @_QMacc_declare_post_action_statPinit() +! CHECK: fir.call @_FortranAAllocatableAllocate({{.*}}) fastmath {acc.declare_action = #acc.declare_action} : (!fir.ref>, i1, !fir.box, !fir.ref, i32) -> i32 +! CHECK: fir.if +! CHECK: fir.call @_FortranAAllocatableAllocate({{.*}}) fastmath {acc.declare_action = #acc.declare_action} : (!fir.ref>, i1, !fir.box, !fir.ref, i32) -> i32 From fa93be4b1c249f5899ac8721724f7ee511c8b992 Mon Sep 17 00:00:00 2001 From: Tobias Gysi Date: Sat, 31 Aug 2024 07:51:53 +0200 Subject: [PATCH 07/14] Revert "[MLIR][LLVM] Make DISubprogramAttr cyclic" (#106827) Reverts llvm/llvm-project#106571 This commit breaks the following build bot: https://lab.llvm.org/buildbot/#/builders/138/builds/2992 It looks like there is a missing dependency in this particular setup. --- .../Transforms/DebugTypeGenerator.cpp | 10 +- mlir/include/mlir-c/Dialect/LLVM.h | 26 ++--- .../mlir/Dialect/LLVMIR/LLVMAttrDefs.td | 68 ++++--------- .../mlir/Dialect/LLVMIR/LLVMInterfaces.td | 2 +- mlir/lib/CAPI/Dialect/LLVM.cpp | 39 +++----- mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp | 29 ++---- mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp | 6 +- .../Transforms/DIScopeForLLVMFuncOp.cpp | 8 +- mlir/lib/Target/LLVMIR/DebugImporter.cpp | 18 ++-- mlir/lib/Target/LLVMIR/DebugTranslation.cpp | 98 +++++++++---------- mlir/lib/Target/LLVMIR/DebugTranslation.h | 18 ++-- mlir/test/CAPI/llvm.c | 23 ++--- mlir/test/Target/LLVMIR/Import/debug-info.ll | 53 +++++----- mlir/test/Target/LLVMIR/llvmir-debug.mlir | 41 ++++---- 14 files changed, 176 insertions(+), 263 deletions(-) diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp index 029d3776bcc0b8..54f2a12d800085 100644 --- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp +++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp @@ -146,8 +146,8 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertBoxedSequenceType( elements.push_back(subrangeTy); } return mlir::LLVM::DICompositeTypeAttr::get( - context, llvm::dwarf::DW_TAG_array_type, /*name=*/nullptr, - /*file=*/nullptr, /*line=*/0, /*scope=*/nullptr, elemTy, + context, llvm::dwarf::DW_TAG_array_type, /*recursive_id=*/{}, + /*name=*/nullptr, /*file=*/nullptr, /*line=*/0, /*scope=*/nullptr, elemTy, mlir::LLVM::DIFlags::Zero, /*sizeInBits=*/0, /*alignInBits=*/0, elements, dataLocation, /*rank=*/nullptr, allocated, associated); } @@ -188,7 +188,7 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertRecordType( } return mlir::LLVM::DICompositeTypeAttr::get( - context, llvm::dwarf::DW_TAG_structure_type, + context, llvm::dwarf::DW_TAG_structure_type, /*recursive_id=*/{}, mlir::StringAttr::get(context, result.second.name), fileAttr, line, scope, /*baseType=*/nullptr, mlir::LLVM::DIFlags::Zero, offset * 8, /*alignInBits=*/0, elements, /*dataLocation=*/nullptr, /*rank=*/nullptr, @@ -236,8 +236,8 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertSequenceType( // have been set to some valid default values. return mlir::LLVM::DICompositeTypeAttr::get( - context, llvm::dwarf::DW_TAG_array_type, /*name=*/nullptr, - /*file=*/nullptr, /*line=*/0, /*scope=*/nullptr, elemTy, + context, llvm::dwarf::DW_TAG_array_type, /*recursive_id=*/{}, + /*name=*/nullptr, /*file=*/nullptr, /*line=*/0, /*scope=*/nullptr, elemTy, mlir::LLVM::DIFlags::Zero, /*sizeInBits=*/0, /*alignInBits=*/0, elements, /*dataLocation=*/nullptr, /*rank=*/nullptr, /*allocated=*/nullptr, /*associated=*/nullptr); diff --git a/mlir/include/mlir-c/Dialect/LLVM.h b/mlir/include/mlir-c/Dialect/LLVM.h index 38bd4d2f3587be..5eb96a86e472d6 100644 --- a/mlir/include/mlir-c/Dialect/LLVM.h +++ b/mlir/include/mlir-c/Dialect/LLVM.h @@ -234,13 +234,10 @@ MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDIBasicTypeAttrGet( MlirContext ctx, unsigned int tag, MlirAttribute name, uint64_t sizeInBits, MlirLLVMTypeEncoding encoding); -/// Creates a self-referencing LLVM DICompositeType attribute. -MlirAttribute mlirLLVMDICompositeTypeAttrGetRecSelf(MlirAttribute recId); - /// Creates a LLVM DICompositeType attribute. MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDICompositeTypeAttrGet( - MlirContext ctx, MlirAttribute recId, bool isRecSelf, unsigned int tag, - MlirAttribute name, MlirAttribute file, uint32_t line, MlirAttribute scope, + MlirContext ctx, unsigned int tag, MlirAttribute recId, MlirAttribute name, + MlirAttribute file, uint32_t line, MlirAttribute scope, MlirAttribute baseType, int64_t flags, uint64_t sizeInBits, uint64_t alignInBits, intptr_t nElements, MlirAttribute const *elements, MlirAttribute dataLocation, MlirAttribute rank, MlirAttribute allocated, @@ -314,16 +311,13 @@ MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDILocalVariableAttrGet( MlirAttribute diFile, unsigned int line, unsigned int arg, unsigned int alignInBits, MlirAttribute diType, int64_t flags); -/// Creates a self-referencing LLVM DISubprogramAttr attribute. -MlirAttribute mlirLLVMDISubprogramAttrGetRecSelf(MlirAttribute recId); - /// Creates a LLVM DISubprogramAttr attribute. MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDISubprogramAttrGet( - MlirContext ctx, MlirAttribute recId, bool isRecSelf, MlirAttribute id, - MlirAttribute compileUnit, MlirAttribute scope, MlirAttribute name, - MlirAttribute linkageName, MlirAttribute file, unsigned int line, - unsigned int scopeLine, uint64_t subprogramFlags, MlirAttribute type, - intptr_t nRetainedNodes, MlirAttribute const *retainedNodes); + MlirContext ctx, MlirAttribute id, MlirAttribute compileUnit, + MlirAttribute scope, MlirAttribute name, MlirAttribute linkageName, + MlirAttribute file, unsigned int line, unsigned int scopeLine, + uint64_t subprogramFlags, MlirAttribute type, intptr_t nRetainedNodes, + MlirAttribute const *retainedNodes); /// Gets the scope from this DISubprogramAttr. MLIR_CAPI_EXPORTED MlirAttribute @@ -362,9 +356,9 @@ MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDIModuleAttrGet( /// Creates a LLVM DIImportedEntityAttr attribute. MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDIImportedEntityAttrGet( - MlirContext ctx, unsigned int tag, MlirAttribute scope, - MlirAttribute entity, MlirAttribute file, unsigned int line, - MlirAttribute name, intptr_t nElements, MlirAttribute const *elements); + MlirContext ctx, unsigned int tag, MlirAttribute entity, MlirAttribute file, + unsigned int line, MlirAttribute name, intptr_t nElements, + MlirAttribute const *elements); /// Gets the scope of this DIModuleAttr. MLIR_CAPI_EXPORTED MlirAttribute diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td index 49e54df3436ff3..e57be7f760d380 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td @@ -271,7 +271,7 @@ def LLVM_DILanguageParameter : LLVM_DIParameter< >; def LLVM_DITagParameter : LLVM_DIParameter< - "tag", /*default=*/"0", "Tag", /*errorCase=*/"llvm::dwarf::DW_TAG_invalid" + "tag", /*default=*/"", "Tag", /*errorCase=*/"llvm::dwarf::DW_TAG_invalid" >; def LLVM_DIOperationEncodingParameter : LLVM_DIParameter< @@ -375,17 +375,14 @@ def LLVM_DICompositeTypeAttr : LLVM_Attr<"DICompositeType", "di_composite_type", [LLVM_DIRecursiveTypeAttrInterface], "DITypeAttr"> { let parameters = (ins - // DIRecursiveTypeAttrInterface specific parameters. - OptionalParameter<"DistinctAttr">:$recId, - OptionalParameter<"bool">:$isRecSelf, - // DICompositeType specific parameters. LLVM_DITagParameter:$tag, + OptionalParameter<"DistinctAttr">:$recId, OptionalParameter<"StringAttr">:$name, OptionalParameter<"DIFileAttr">:$file, OptionalParameter<"uint32_t">:$line, OptionalParameter<"DIScopeAttr">:$scope, OptionalParameter<"DITypeAttr">:$baseType, - OptionalParameter<"DIFlags">:$flags, + OptionalParameter<"DIFlags", "DIFlags::Zero">:$flags, OptionalParameter<"uint64_t">:$sizeInBits, OptionalParameter<"uint64_t">:$alignInBits, OptionalArrayRefParameter<"DINodeAttr">:$elements, @@ -394,26 +391,14 @@ def LLVM_DICompositeTypeAttr : LLVM_Attr<"DICompositeType", "di_composite_type", OptionalParameter<"DIExpressionAttr">:$allocated, OptionalParameter<"DIExpressionAttr">:$associated ); - let builders = [ - AttrBuilder<(ins - "unsigned":$tag, "StringAttr":$name, "DIFileAttr":$file, - "uint32_t":$line, "DIScopeAttr":$scope, "DITypeAttr":$baseType, - "DIFlags":$flags, "uint64_t":$sizeInBits, "uint64_t":$alignInBits, - "ArrayRef":$elements, "DIExpressionAttr":$dataLocation, - "DIExpressionAttr":$rank, "DIExpressionAttr":$allocated, - "DIExpressionAttr":$associated - ), [{ - return $_get($_ctxt, /*recId=*/nullptr, /*isRecSelf=*/nullptr, - tag, name, file, line, scope, baseType, flags, sizeInBits, - alignInBits, elements, dataLocation, rank, allocated, - associated); - }]> - ]; let assemblyFormat = "`<` struct(params) `>`"; let extraClassDeclaration = [{ /// Requirements of DIRecursiveTypeAttrInterface. /// @{ + /// Get whether this attr describes a recursive self reference. + bool isRecSelf() { return getTag() == 0; } + /// Get a copy of this type attr but with the recursive ID set to `recId`. DIRecursiveTypeAttrInterface withRecId(DistinctAttr recId); @@ -569,19 +554,14 @@ def LLVM_DILocalVariableAttr : LLVM_Attr<"DILocalVariable", "di_local_variable", //===----------------------------------------------------------------------===// def LLVM_DISubprogramAttr : LLVM_Attr<"DISubprogram", "di_subprogram", - [LLVM_DIRecursiveTypeAttrInterface], - "DIScopeAttr"> { + /*traits=*/[], "DIScopeAttr"> { let parameters = (ins - // DIRecursiveTypeAttrInterface specific parameters. - OptionalParameter<"DistinctAttr">:$recId, - OptionalParameter<"bool">:$isRecSelf, - // DISubprogramAttr specific parameters. OptionalParameter<"DistinctAttr">:$id, OptionalParameter<"DICompileUnitAttr">:$compileUnit, - OptionalParameter<"DIScopeAttr">:$scope, + "DIScopeAttr":$scope, OptionalParameter<"StringAttr">:$name, OptionalParameter<"StringAttr">:$linkageName, - OptionalParameter<"DIFileAttr">:$file, + "DIFileAttr":$file, OptionalParameter<"unsigned">:$line, OptionalParameter<"unsigned">:$scopeLine, OptionalParameter<"DISubprogramFlags">:$subprogramFlags, @@ -589,31 +569,21 @@ def LLVM_DISubprogramAttr : LLVM_Attr<"DISubprogram", "di_subprogram", OptionalArrayRefParameter<"DINodeAttr">:$retainedNodes ); let builders = [ - AttrBuilder<(ins + AttrBuilderWithInferredContext<(ins "DistinctAttr":$id, "DICompileUnitAttr":$compileUnit, - "DIScopeAttr":$scope, "StringAttr":$name, "StringAttr":$linkageName, + "DIScopeAttr":$scope, "StringRef":$name, "StringRef":$linkageName, "DIFileAttr":$file, "unsigned":$line, "unsigned":$scopeLine, "DISubprogramFlags":$subprogramFlags, "DISubroutineTypeAttr":$type, "ArrayRef":$retainedNodes ), [{ - return $_get($_ctxt, /*recId=*/nullptr, /*isRecSelf=*/false, id, compileUnit, - scope, name, linkageName, file, line, scopeLine, - subprogramFlags, type, retainedNodes); + MLIRContext *ctx = file.getContext(); + return $_get(ctx, id, compileUnit, scope, StringAttr::get(ctx, name), + StringAttr::get(ctx, linkageName), file, line, + scopeLine, subprogramFlags, type, retainedNodes); }]> ]; - let assemblyFormat = "`<` struct(params) `>`"; - let extraClassDeclaration = [{ - /// Requirements of DIRecursiveTypeAttrInterface. - /// @{ - - /// Get a copy of this type attr but with the recursive ID set to `recId`. - DIRecursiveTypeAttrInterface withRecId(DistinctAttr recId); - /// Build a rec-self instance using the provided `recId`. - static DIRecursiveTypeAttrInterface getRecSelf(DistinctAttr recId); - - /// @} - }]; + let assemblyFormat = "`<` struct(params) `>`"; } //===----------------------------------------------------------------------===// @@ -657,9 +627,13 @@ def LLVM_DINamespaceAttr : LLVM_Attr<"DINamespace", "di_namespace", def LLVM_DIImportedEntityAttr : LLVM_Attr<"DIImportedEntity", "di_imported_entity", /*traits=*/[], "DINodeAttr"> { + /// TODO: DIImportedEntity has a 'scope' field which represents the scope where + /// this entity is imported. Currently, we are not adding a 'scope' field in + /// DIImportedEntityAttr to avoid cyclic dependency. As DIImportedEntityAttr + /// entries will be contained inside a scope entity (e.g. DISubprogramAttr), + /// the scope can easily be inferred. let parameters = (ins LLVM_DITagParameter:$tag, - "DIScopeAttr":$scope, "DINodeAttr":$entity, OptionalParameter<"DIFileAttr">:$file, OptionalParameter<"unsigned">:$line, diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td index e2180410a8f04e..7085f81e203a1e 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td @@ -406,7 +406,7 @@ def LLVM_DIRecursiveTypeAttrInterface let methods = [ InterfaceMethod<[{ Get whether this attr describes a recursive self reference. - }], "bool", "getIsRecSelf", (ins)>, + }], "bool", "isRecSelf", (ins)>, InterfaceMethod<[{ Get the recursive ID used for matching "rec-decl" with "rec-self". If this attr instance is not recursive, return a null attribute. diff --git a/mlir/lib/CAPI/Dialect/LLVM.cpp b/mlir/lib/CAPI/Dialect/LLVM.cpp index 03b536d7aad98f..13341f0c4de881 100644 --- a/mlir/lib/CAPI/Dialect/LLVM.cpp +++ b/mlir/lib/CAPI/Dialect/LLVM.cpp @@ -159,14 +159,9 @@ MlirAttribute mlirLLVMDIBasicTypeAttrGet(MlirContext ctx, unsigned int tag, unwrap(ctx), tag, cast(unwrap(name)), sizeInBits, encoding)); } -MlirAttribute mlirLLVMDICompositeTypeAttrGetRecSelf(MlirAttribute recId) { - return wrap( - DICompositeTypeAttr::getRecSelf(cast(unwrap(recId)))); -} - MlirAttribute mlirLLVMDICompositeTypeAttrGet( - MlirContext ctx, MlirAttribute recId, bool isRecSelf, unsigned int tag, - MlirAttribute name, MlirAttribute file, uint32_t line, MlirAttribute scope, + MlirContext ctx, unsigned int tag, MlirAttribute recId, MlirAttribute name, + MlirAttribute file, uint32_t line, MlirAttribute scope, MlirAttribute baseType, int64_t flags, uint64_t sizeInBits, uint64_t alignInBits, intptr_t nElements, MlirAttribute const *elements, MlirAttribute dataLocation, MlirAttribute rank, MlirAttribute allocated, @@ -175,7 +170,7 @@ MlirAttribute mlirLLVMDICompositeTypeAttrGet( elementsStorage.reserve(nElements); return wrap(DICompositeTypeAttr::get( - unwrap(ctx), cast(unwrap(recId)), isRecSelf, tag, + unwrap(ctx), tag, cast(unwrap(recId)), cast(unwrap(name)), cast(unwrap(file)), line, cast(unwrap(scope)), cast(unwrap(baseType)), DIFlags(flags), sizeInBits, alignInBits, @@ -294,21 +289,16 @@ MlirAttribute mlirLLVMDISubroutineTypeAttrGet(MlirContext ctx, [](Attribute a) { return cast(a); }))); } -MlirAttribute mlirLLVMDISubprogramAttrGetRecSelf(MlirAttribute recId) { - return wrap(DISubprogramAttr::getRecSelf(cast(unwrap(recId)))); -} - MlirAttribute mlirLLVMDISubprogramAttrGet( - MlirContext ctx, MlirAttribute recId, bool isRecSelf, MlirAttribute id, - MlirAttribute compileUnit, MlirAttribute scope, MlirAttribute name, - MlirAttribute linkageName, MlirAttribute file, unsigned int line, - unsigned int scopeLine, uint64_t subprogramFlags, MlirAttribute type, - intptr_t nRetainedNodes, MlirAttribute const *retainedNodes) { + MlirContext ctx, MlirAttribute id, MlirAttribute compileUnit, + MlirAttribute scope, MlirAttribute name, MlirAttribute linkageName, + MlirAttribute file, unsigned int line, unsigned int scopeLine, + uint64_t subprogramFlags, MlirAttribute type, intptr_t nRetainedNodes, + MlirAttribute const *retainedNodes) { SmallVector nodesStorage; nodesStorage.reserve(nRetainedNodes); return wrap(DISubprogramAttr::get( - unwrap(ctx), cast(unwrap(recId)), isRecSelf, - cast(unwrap(id)), + unwrap(ctx), cast(unwrap(id)), cast(unwrap(compileUnit)), cast(unwrap(scope)), cast(unwrap(name)), cast(unwrap(linkageName)), cast(unwrap(file)), @@ -363,15 +353,14 @@ MlirAttribute mlirLLVMDIModuleAttrGetScope(MlirAttribute diModule) { } MlirAttribute mlirLLVMDIImportedEntityAttrGet( - MlirContext ctx, unsigned int tag, MlirAttribute scope, - MlirAttribute entity, MlirAttribute file, unsigned int line, - MlirAttribute name, intptr_t nElements, MlirAttribute const *elements) { + MlirContext ctx, unsigned int tag, MlirAttribute entity, MlirAttribute file, + unsigned int line, MlirAttribute name, intptr_t nElements, + MlirAttribute const *elements) { SmallVector elementsStorage; elementsStorage.reserve(nElements); return wrap(DIImportedEntityAttr::get( - unwrap(ctx), tag, cast(unwrap(scope)), - cast(unwrap(entity)), cast(unwrap(file)), line, - cast(unwrap(name)), + unwrap(ctx), tag, cast(unwrap(entity)), + cast(unwrap(file)), line, cast(unwrap(name)), llvm::map_to_vector(unwrapList(nElements, elements, elementsStorage), [](Attribute a) { return cast(a); }))); } diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp index 491dcc7f01e73d..98a9659735e7e6 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp @@ -203,33 +203,16 @@ void printExpressionArg(AsmPrinter &printer, uint64_t opcode, DIRecursiveTypeAttrInterface DICompositeTypeAttr::withRecId(DistinctAttr recId) { return DICompositeTypeAttr::get( - getContext(), recId, getIsRecSelf(), getTag(), getName(), getFile(), - getLine(), getScope(), getBaseType(), getFlags(), getSizeInBits(), - getAlignInBits(), getElements(), getDataLocation(), getRank(), - getAllocated(), getAssociated()); + getContext(), getTag(), recId, getName(), getFile(), getLine(), + getScope(), getBaseType(), getFlags(), getSizeInBits(), getAlignInBits(), + getElements(), getDataLocation(), getRank(), getAllocated(), + getAssociated()); } DIRecursiveTypeAttrInterface DICompositeTypeAttr::getRecSelf(DistinctAttr recId) { - return DICompositeTypeAttr::get(recId.getContext(), recId, /*isRecSelf=*/true, - 0, {}, {}, 0, {}, {}, DIFlags(), 0, 0, {}, {}, - {}, {}, {}); -} - -//===----------------------------------------------------------------------===// -// DISubprogramAttr -//===----------------------------------------------------------------------===// - -DIRecursiveTypeAttrInterface DISubprogramAttr::withRecId(DistinctAttr recId) { - return DISubprogramAttr::get( - getContext(), recId, getIsRecSelf(), getId(), getCompileUnit(), - getScope(), getName(), getLinkageName(), getFile(), getLine(), - getScopeLine(), getSubprogramFlags(), getType(), getRetainedNodes()); -} - -DIRecursiveTypeAttrInterface DISubprogramAttr::getRecSelf(DistinctAttr recId) { - return DISubprogramAttr::get(recId.getContext(), recId, /*isRecSelf=*/true, - {}, {}, {}, {}, {}, 0, 0, {}, {}, {}, {}); + return DICompositeTypeAttr::get(recId.getContext(), 0, recId, {}, {}, 0, {}, + {}, DIFlags(), 0, 0, {}, {}, {}, {}, {}); } //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp index 6e4a964f1fc93c..3870aab52f199d 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -3155,9 +3155,9 @@ struct LLVMOpAsmDialectInterface : public OpAsmDialectInterface { .CasesetLoc(FusedLoc::get(context, {loc}, subprogramAttr)); } diff --git a/mlir/lib/Target/LLVMIR/DebugImporter.cpp b/mlir/lib/Target/LLVMIR/DebugImporter.cpp index 8c6f32f6bb0cd0..ce3643f513d34a 100644 --- a/mlir/lib/Target/LLVMIR/DebugImporter.cpp +++ b/mlir/lib/Target/LLVMIR/DebugImporter.cpp @@ -89,9 +89,10 @@ DICompositeTypeAttr DebugImporter::translateImpl(llvm::DICompositeType *node) { if (node->getTag() == llvm::dwarf::DW_TAG_array_type && !baseType) return nullptr; return DICompositeTypeAttr::get( - context, node->getTag(), getStringAttrOrNull(node->getRawName()), - translate(node->getFile()), node->getLine(), translate(node->getScope()), - baseType, flags.value_or(DIFlags::Zero), node->getSizeInBits(), + context, node->getTag(), /*recId=*/{}, + getStringAttrOrNull(node->getRawName()), translate(node->getFile()), + node->getLine(), translate(node->getScope()), baseType, + flags.value_or(DIFlags::Zero), node->getSizeInBits(), node->getAlignInBits(), elements, translateExpression(node->getDataLocationExp()), translateExpression(node->getRankExp()), @@ -216,8 +217,8 @@ DebugImporter::translateImpl(llvm::DIImportedEntity *node) { } return DIImportedEntityAttr::get( - context, node->getTag(), translate(node->getScope()), - translate(node->getEntity()), translate(node->getFile()), node->getLine(), + context, node->getTag(), translate(node->getEntity()), + translate(node->getFile()), node->getLine(), getStringAttrOrNull(node->getRawName()), elements); } @@ -226,7 +227,6 @@ DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) { mlir::DistinctAttr id; if (node->isDistinct()) id = getOrCreateDistinctID(node); - // Return nullptr if the scope or type is invalid. DIScopeAttr scope = translate(node->getScope()); if (node->getScope() && !scope) @@ -238,12 +238,9 @@ DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) { if (node->getType() && !type) return nullptr; - // Convert the retained nodes but drop all of them if one of them is invalid. SmallVector retainedNodes; for (llvm::DINode *retainedNode : node->getRetainedNodes()) retainedNodes.push_back(translate(retainedNode)); - if (llvm::is_contained(retainedNodes, nullptr)) - retainedNodes.clear(); return DISubprogramAttr::get(context, id, translate(node->getUnit()), scope, getStringAttrOrNull(node->getRawName()), @@ -377,9 +374,6 @@ getRecSelfConstructor(llvm::DINode *node) { .Case([&](llvm::DICompositeType *) { return CtorType(DICompositeTypeAttr::getRecSelf); }) - .Case([&](llvm::DISubprogram *) { - return CtorType(DISubprogramAttr::getRecSelf); - }) .Default(CtorType()); } diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp index 8ca3beca6b66f7..042e015f107fea 100644 --- a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp @@ -96,17 +96,6 @@ llvm::MDString *DebugTranslation::getMDStringOrNull(StringAttr stringAttr) { return llvm::MDString::get(llvmCtx, stringAttr); } -llvm::MDTuple * -DebugTranslation::getMDTupleOrNull(ArrayRef elements) { - if (elements.empty()) - return nullptr; - SmallVector llvmElements = llvm::to_vector( - llvm::map_range(elements, [&](DINodeAttr attr) -> llvm::Metadata * { - return translate(attr); - })); - return llvm::MDNode::get(llvmCtx, llvmElements); -} - llvm::DIBasicType *DebugTranslation::translateImpl(DIBasicTypeAttr attr) { return llvm::DIBasicType::get( llvmCtx, attr.getTag(), getMDStringOrNull(attr.getName()), @@ -149,17 +138,6 @@ DebugTranslation::translateTemporaryImpl(DICompositeTypeAttr attr) { /*VTableHolder=*/nullptr); } -llvm::TempDISubprogram -DebugTranslation::translateTemporaryImpl(DISubprogramAttr attr) { - return llvm::DISubprogram::getTemporary( - llvmCtx, /*Scope=*/nullptr, /*Name=*/{}, /*LinkageName=*/{}, - /*File=*/nullptr, attr.getLine(), /*Type=*/nullptr, - /*ScopeLine=*/0, /*ContainingType=*/nullptr, /*VirtualIndex=*/0, - /*ThisAdjustment=*/0, llvm::DINode::FlagZero, - static_cast(attr.getSubprogramFlags()), - /*Unit=*/nullptr); -} - llvm::DICompositeType * DebugTranslation::translateImpl(DICompositeTypeAttr attr) { // TODO: Use distinct attributes to model this, once they have landed. @@ -173,6 +151,10 @@ DebugTranslation::translateImpl(DICompositeTypeAttr attr) { isDistinct = true; } + SmallVector elements; + for (DINodeAttr member : attr.getElements()) + elements.push_back(translate(member)); + return getDistinctOrUnique( isDistinct, llvmCtx, attr.getTag(), getMDStringOrNull(attr.getName()), translate(attr.getFile()), attr.getLine(), translate(attr.getScope()), @@ -180,7 +162,7 @@ DebugTranslation::translateImpl(DICompositeTypeAttr attr) { attr.getAlignInBits(), /*OffsetInBits=*/0, /*Flags=*/static_cast(attr.getFlags()), - getMDTupleOrNull(attr.getElements()), + llvm::MDNode::get(llvmCtx, elements), /*RuntimeLang=*/0, /*VTableHolder=*/nullptr, /*TemplateParams=*/nullptr, /*Identifier=*/nullptr, /*Discriminator=*/nullptr, @@ -260,21 +242,22 @@ DebugTranslation::translateImpl(DIGlobalVariableAttr attr) { attr.getIsDefined(), nullptr, nullptr, attr.getAlignInBits(), nullptr); } -llvm::DINode * +llvm::DIType * DebugTranslation::translateRecursive(DIRecursiveTypeAttrInterface attr) { DistinctAttr recursiveId = attr.getRecId(); - if (auto *iter = recursiveNodeMap.find(recursiveId); - iter != recursiveNodeMap.end()) { + if (auto *iter = recursiveTypeMap.find(recursiveId); + iter != recursiveTypeMap.end()) { return iter->second; + } else { + assert(!attr.isRecSelf() && "unbound DI recursive self type"); } - assert(!attr.getIsRecSelf() && "unbound DI recursive self reference"); - auto setRecursivePlaceholder = [&](llvm::DINode *placeholder) { - recursiveNodeMap.try_emplace(recursiveId, placeholder); + auto setRecursivePlaceholder = [&](llvm::DIType *placeholder) { + recursiveTypeMap.try_emplace(recursiveId, placeholder); }; - llvm::DINode *result = - TypeSwitch(attr) + llvm::DIType *result = + TypeSwitch(attr) .Case([&](auto attr) { auto temporary = translateTemporaryImpl(attr); setRecursivePlaceholder(temporary.get()); @@ -283,20 +266,11 @@ DebugTranslation::translateRecursive(DIRecursiveTypeAttrInterface attr) { auto *concrete = translateImpl(attr); temporary->replaceAllUsesWith(concrete); return concrete; - }) - .Case([&](auto attr) { - auto temporary = translateTemporaryImpl(attr); - setRecursivePlaceholder(temporary.get()); - // Must call `translateImpl` directly instead of `translate` to - // avoid handling the recursive interface again. - auto *concrete = translateImpl(attr); - temporary->replaceAllUsesWith(concrete); - return concrete; }); - assert(recursiveNodeMap.back().first == recursiveId && + assert(recursiveTypeMap.back().first == recursiveId && "internal inconsistency: unexpected recursive translation stack"); - recursiveNodeMap.pop_back(); + recursiveTypeMap.pop_back(); return result; } @@ -323,7 +297,6 @@ llvm::DISubprogram *DebugTranslation::translateImpl(DISubprogramAttr attr) { bool isDefinition = static_cast(attr.getSubprogramFlags() & LLVM::DISubprogramFlags::Definition); - llvm::DISubprogram *node = getDistinctOrUnique( isDefinition, llvmCtx, scope, getMDStringOrNull(attr.getName()), getMDStringOrNull(attr.getLinkageName()), file, attr.getLine(), type, @@ -331,8 +304,21 @@ llvm::DISubprogram *DebugTranslation::translateImpl(DISubprogramAttr attr) { /*ContainingType=*/nullptr, /*VirtualIndex=*/0, /*ThisAdjustment=*/0, llvm::DINode::FlagZero, static_cast(attr.getSubprogramFlags()), - compileUnit, /*TemplateParams=*/nullptr, /*Declaration=*/nullptr, - getMDTupleOrNull(attr.getRetainedNodes())); + compileUnit); + + // DIImportedEntity requires scope information which DIImportedEntityAttr does + // not have. This is why we translate DIImportedEntityAttr after we have + // created DISubprogram as we can use it as the scope. + SmallVector retainedNodes; + for (DINodeAttr nodeAttr : attr.getRetainedNodes()) { + if (auto importedAttr = dyn_cast(nodeAttr)) { + llvm::DINode *dn = translate(importedAttr, node); + retainedNodes.push_back(dn); + } + } + if (!retainedNodes.empty()) + node->replaceRetainedNodes(llvm::MDTuple::get(llvmCtx, retainedNodes)); + if (attr.getId()) distinctAttrToNode.try_emplace(attr.getId(), node); return node; @@ -353,12 +339,16 @@ llvm::DINamespace *DebugTranslation::translateImpl(DINamespaceAttr attr) { attr.getExportSymbols()); } -llvm::DIImportedEntity * -DebugTranslation::translateImpl(DIImportedEntityAttr attr) { +llvm::DIImportedEntity *DebugTranslation::translate(DIImportedEntityAttr attr, + llvm::DIScope *scope) { + SmallVector elements; + for (DINodeAttr member : attr.getElements()) + elements.push_back(translate(member)); + return llvm::DIImportedEntity::get( - llvmCtx, attr.getTag(), translate(attr.getScope()), - translate(attr.getEntity()), translate(attr.getFile()), attr.getLine(), - getMDStringOrNull(attr.getName()), getMDTupleOrNull(attr.getElements())); + llvmCtx, attr.getTag(), scope, translate(attr.getEntity()), + translate(attr.getFile()), attr.getLine(), + getMDStringOrNull(attr.getName()), llvm::MDNode::get(llvmCtx, elements)); } llvm::DISubrange *DebugTranslation::translateImpl(DISubrangeAttr attr) { @@ -423,10 +413,10 @@ llvm::DINode *DebugTranslation::translate(DINodeAttr attr) { node = TypeSwitch(attr) .Case( + DILabelAttr, DILexicalBlockAttr, DILexicalBlockFileAttr, + DILocalVariableAttr, DIModuleAttr, DINamespaceAttr, + DINullTypeAttr, DIStringTypeAttr, DISubprogramAttr, + DISubrangeAttr, DISubroutineTypeAttr>( [&](auto attr) { return translateImpl(attr); }); if (node && !node->isTemporary()) diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.h b/mlir/lib/Target/LLVMIR/DebugTranslation.h index 422aa34e28f3c9..37b985acf8541e 100644 --- a/mlir/lib/Target/LLVMIR/DebugTranslation.h +++ b/mlir/lib/Target/LLVMIR/DebugTranslation.h @@ -75,7 +75,6 @@ class DebugTranslation { llvm::DIDerivedType *translateImpl(DIDerivedTypeAttr attr); llvm::DIStringType *translateImpl(DIStringTypeAttr attr); llvm::DIFile *translateImpl(DIFileAttr attr); - llvm::DIImportedEntity *translateImpl(DIImportedEntityAttr attr); llvm::DILabel *translateImpl(DILabelAttr attr); llvm::DILexicalBlock *translateImpl(DILexicalBlockAttr attr); llvm::DILexicalBlockFile *translateImpl(DILexicalBlockFileAttr attr); @@ -91,26 +90,27 @@ class DebugTranslation { llvm::DISubroutineType *translateImpl(DISubroutineTypeAttr attr); llvm::DIType *translateImpl(DITypeAttr attr); + /// Currently, DIImportedEntityAttr does not have a scope field to avoid a + /// cyclic dependency. The scope information is obtained from the entity + /// which holds the list of DIImportedEntityAttr. This requires that scope + /// information be passed to translate function. + llvm::DIImportedEntity *translate(DIImportedEntityAttr attr, llvm::DIScope *); + /// Attributes that support self recursion need to implement an additional /// method to hook into `translateRecursive`. /// - ` translateTemporaryImpl()`: /// Create a temporary translation of the DI attr without recursively /// translating any nested DI attrs. - llvm::DINode *translateRecursive(DIRecursiveTypeAttrInterface attr); + llvm::DIType *translateRecursive(DIRecursiveTypeAttrInterface attr); /// Translate the given attribute to a temporary llvm debug metadata of the /// corresponding type. llvm::TempDICompositeType translateTemporaryImpl(DICompositeTypeAttr attr); - llvm::TempDISubprogram translateTemporaryImpl(DISubprogramAttr attr); /// Constructs a string metadata node from the string attribute. Returns /// nullptr if `stringAttr` is null or contains and empty string. llvm::MDString *getMDStringOrNull(StringAttr stringAttr); - /// Constructs a tuple metadata node from the `elements`. Returns nullptr if - /// `elements` is empty. - llvm::MDTuple *getMDTupleOrNull(ArrayRef elements); - /// Constructs a DIExpression metadata node from the DIExpressionAttr. Returns /// nullptr if `DIExpressionAttr` is null. llvm::DIExpression *getExpressionAttrOrNull(DIExpressionAttr attr); @@ -125,8 +125,8 @@ class DebugTranslation { /// metadata. DenseMap attrToNode; - /// A mapping between recursive ID and the translated DINode. - llvm::MapVector recursiveNodeMap; + /// A mapping between recursive ID and the translated DIType. + llvm::MapVector recursiveTypeMap; /// A mapping between a distinct ID and the translated LLVM metadata node. /// This helps identify attrs that should translate into the same LLVM debug diff --git a/mlir/test/CAPI/llvm.c b/mlir/test/CAPI/llvm.c index 36277122801de4..da28a96f89691d 100644 --- a/mlir/test/CAPI/llvm.c +++ b/mlir/test/CAPI/llvm.c @@ -248,16 +248,12 @@ static void testDebugInfoAttributes(MlirContext ctx) { mlirStringAttrGet(ctx, mlirStringRefCreateFromCString("foo")); MlirAttribute bar = mlirStringAttrGet(ctx, mlirStringRefCreateFromCString("bar")); - - MlirAttribute none = mlirUnitAttrGet(ctx); - MlirAttribute id = mlirDisctinctAttrCreate(none); - MlirAttribute recId0 = mlirDisctinctAttrCreate(none); - MlirAttribute recId1 = mlirDisctinctAttrCreate(none); + MlirAttribute id = mlirDisctinctAttrCreate(foo); // CHECK: #llvm.di_null_type mlirAttributeDump(mlirLLVMDINullTypeAttrGet(ctx)); - // CHECK: #llvm.di_basic_type MlirAttribute di_type = mlirLLVMDIBasicTypeAttrGet(ctx, 0, foo, 64, MlirLLVMTypeEncodingSigned); @@ -316,17 +312,15 @@ static void testDebugInfoAttributes(MlirContext ctx) { // CHECK: #llvm.di_subroutine_type<{{.*}}> mlirAttributeDump(subroutine_type); - MlirAttribute di_subprogram_self_rec = - mlirLLVMDISubprogramAttrGetRecSelf(recId0); MlirAttribute di_imported_entity = mlirLLVMDIImportedEntityAttrGet( - ctx, 0, di_subprogram_self_rec, di_module, file, 1, foo, 1, &local_var); + ctx, 0, di_module, file, 1, foo, 1, &local_var); mlirAttributeDump(di_imported_entity); // CHECK: #llvm.di_imported_entity<{{.*}}> MlirAttribute di_subprogram = mlirLLVMDISubprogramAttrGet( - ctx, recId0, false, id, compile_unit, compile_unit, foo, bar, file, 1, 2, - 0, subroutine_type, 1, &di_imported_entity); + ctx, id, compile_unit, compile_unit, foo, bar, file, 1, 2, 0, + subroutine_type, 1, &di_imported_entity); // CHECK: #llvm.di_subprogram<{{.*}}> mlirAttributeDump(di_subprogram); @@ -356,13 +350,10 @@ static void testDebugInfoAttributes(MlirContext ctx) { // CHECK: #llvm.di_string_type<{{.*}}> mlirAttributeDump(string_type); - // CHECK: #llvm.di_composite_type - mlirAttributeDump(mlirLLVMDICompositeTypeAttrGetRecSelf(recId1)); - // CHECK: #llvm.di_composite_type<{{.*}}> mlirAttributeDump(mlirLLVMDICompositeTypeAttrGet( - ctx, recId1, false, 0, foo, file, 1, compile_unit, di_type, 0, 64, 8, 1, - &di_type, expression, expression, expression, expression)); + ctx, 0, id, foo, file, 1, compile_unit, di_type, 0, 64, 8, 1, &di_type, + expression, expression, expression, expression)); } int main(void) { diff --git a/mlir/test/Target/LLVMIR/Import/debug-info.ll b/mlir/test/Target/LLVMIR/Import/debug-info.ll index 02e35ae7f0ee9d..bb03da37c0d097 100644 --- a/mlir/test/Target/LLVMIR/Import/debug-info.ll +++ b/mlir/test/Target/LLVMIR/Import/debug-info.ll @@ -307,13 +307,17 @@ define void @class_method() { ret void, !dbg !9 } -; Verify the cyclic subprogram is handled correctly. -; CHECK-DAG: #[[SP_SELF:.+]] = #llvm.di_subprogram -; CHECK-DAG: #[[COMP:.+]] = #llvm.di_composite_type -; CHECK-DAG: #[[COMP_PTR:.+]] = #llvm.di_derived_type +; Verify the cyclic composite type is identified, even though conversion begins from the subprogram type. +; CHECK-DAG: #[[COMP_SELF:.+]] = #llvm.di_composite_type +; CHECK-DAG: #[[COMP_PTR:.+]] = #llvm.di_derived_type ; CHECK-DAG: #[[SP_TYPE:.+]] = #llvm.di_subroutine_type -; CHECK-DAG: #[[SP:.+]] = #llvm.di_subprogram -; CHECK-DAG: #[[LOC]] = loc(fused<#[[SP]]> +; CHECK-DAG: #[[SP_INNER:.+]] = #llvm.di_subprogram +; CHECK-DAG: #[[COMP:.+]] = #llvm.di_composite_type + +; CHECK-DAG: #[[COMP_PTR_OUTER:.+]] = #llvm.di_derived_type +; CHECK-DAG: #[[SP_TYPE_OUTER:.+]] = #llvm.di_subroutine_type +; CHECK-DAG: #[[SP_OUTER:.+]] = #llvm.di_subprogram +; CHECK-DAG: #[[LOC]] = loc(fused<#[[SP_OUTER]]> !llvm.dbg.cu = !{!1} !llvm.module.flags = !{!0} @@ -331,10 +335,10 @@ define void @class_method() { ; // ----- ; Verify the cyclic composite type is handled correctly. -; CHECK-DAG: #[[COMP_SELF:.+]] = #llvm.di_composite_type +; CHECK-DAG: #[[COMP_SELF:.+]] = #llvm.di_composite_type ; CHECK-DAG: #[[COMP_PTR_INNER:.+]] = #llvm.di_derived_type ; CHECK-DAG: #[[FIELD:.+]] = #llvm.di_derived_type -; CHECK-DAG: #[[COMP:.+]] = #llvm.di_composite_type +; CHECK-DAG: #[[COMP:.+]] = #llvm.di_composite_type ; CHECK-DAG: #[[COMP_PTR_OUTER:.+]] = #llvm.di_derived_type ; CHECK-DAG: #[[VAR0:.+]] = #llvm.di_local_variable @@ -606,10 +610,9 @@ define void @distinct_cu_func1() !dbg !5 { ; CHECK-LABEL: @declaration declare !dbg !1 void @declaration() -; CHECK: #[[SP:.+]] = #llvm.di_subprogram< +; CHECK: #di_subprogram = #llvm.di_subprogram< ; CHECK-NOT: id = distinct ; CHECK-NOT: subprogramFlags = -; CHECK: loc(fused<#[[SP]]> !llvm.module.flags = !{!0} !0 = !{i32 2, !"Debug Info Version", i32 3} @@ -630,14 +633,14 @@ declare !dbg !1 void @declaration() ; CHECK-DAG: #[[B1_INNER:.+]] = #llvm.di_derived_type<{{.*}}name = "B:B1", baseType = #[[B_SELF:.+]]> ; CHECK-DAG: #[[B2_INNER:.+]] = #llvm.di_derived_type<{{.*}}name = "B:B2", baseType = #[[B_SELF]]> -; CHECK-DAG: #[[B_INNER:.+]] = #llvm.di_composite_type ; CHECK-DAG: #[[B2_OUTER:.+]] = #llvm.di_derived_type<{{.*}}name = "B:B2", baseType = #[[B_INNER]]> -; CHECK-DAG: #[[A_OUTER:.+]] = #llvm.di_composite_typeB", {{.*}}baseType = #[[B_OUTER:.+]]> -; CHECK-DAG: #[[B_OUTER]] = #llvm.di_composite_type +; CHECK-DAG: #[[B_OUTER]] = #llvm.di_composite_type<{{.*}}recId = [[B_RECID:.+]], {{.*}}name = "B", {{.*}}elements = #[[TO_C_INNER:.+]]> ; CHECK-DAG: #[[TO_C_INNER]] = #llvm.di_derived_type<{{.*}}name = "->C", {{.*}}baseType = #[[C_INNER:.+]]> ; CHECK-DAG: #[[C_INNER]] = #llvm.di_composite_type<{{.*}}name = "C", {{.*}}elements = #[[TO_B_SELF:.+]]> ; CHECK-DAG: #[[TO_B_SELF]] = #llvm.di_derived_type<{{.*}}name = "->B", {{.*}}baseType = #[[B_SELF:.+]]> -; CHECK-DAG: #[[B_SELF]] = #llvm.di_composite_type +; CHECK-DAG: #[[B_SELF]] = #llvm.di_composite_type<{{.*}}recId = [[B_RECID]]> ; CHECK-DAG: #[[TO_C_OUTER]] = #llvm.di_derived_type<{{.*}}name = "->C", {{.*}}baseType = #[[C_OUTER:.+]]> ; CHECK-DAG: #[[C_OUTER]] = #llvm.di_composite_type<{{.*}}name = "C", {{.*}}elements = #[[TO_B_OUTER]]> @@ -715,23 +718,23 @@ define void @class_field(ptr %arg1) !dbg !18 { ; ^ ^ ; +-------------+ -; CHECK-DAG: #[[A:.+]] = #llvm.di_composite_type +; CHECK-DAG: #[[A:.+]] = #llvm.di_composite_type<{{.*}}recId = [[A_RECID:.+]], {{.*}}name = "A", {{.*}}elements = #[[A_TO_B:.+]], #[[A_TO_C:.+]]> ; CHECK-DAG: #llvm.di_subprogram<{{.*}}scope = #[[A]], ; CHECK-DAG: #[[A_TO_B]] = #llvm.di_derived_type<{{.*}}name = "->B", {{.*}}baseType = #[[B_FROM_A:.+]]> ; CHECK-DAG: #[[A_TO_C]] = #llvm.di_derived_type<{{.*}}name = "->C", {{.*}}baseType = #[[C_FROM_A:.+]]> -; CHECK-DAG: #[[B_FROM_A]] = #llvm.di_composite_type +; CHECK-DAG: #[[B_FROM_A]] = #llvm.di_composite_type<{{.*}}recId = [[B_RECID:.+]], {{.*}}name = "B", {{.*}}elements = #[[B_TO_C:.+]]> ; CHECK-DAG: #[[B_TO_C]] = #llvm.di_derived_type<{{.*}}name = "->C", {{.*}}baseType = #[[C_FROM_B:.+]]> -; CHECK-DAG: #[[C_FROM_B]] = #llvm.di_composite_type +; CHECK-DAG: #[[C_FROM_B]] = #llvm.di_composite_type<{{.*}}recId = [[C_RECID:.+]], {{.*}}name = "C", {{.*}}elements = #[[TO_A_SELF:.+]], #[[TO_B_SELF:.+]], #[[TO_C_SELF:.+]]> -; CHECK-DAG: #[[C_FROM_A]] = #llvm.di_composite_typeA", {{.*}}baseType = #[[A_SELF:.+]]> ; CHECK-DAG: #[[TO_B_SELF]] = #llvm.di_derived_type<{{.*}}name = "->B", {{.*}}baseType = #[[B_SELF:.+]]> ; CHECK-DAG: #[[TO_C_SELF]] = #llvm.di_derived_type<{{.*}}name = "->C", {{.*}}baseType = #[[C_SELF:.+]]> -; CHECK-DAG: #[[A_SELF]] = #llvm.di_composite_type -; CHECK-DAG: #[[B_SELF]] = #llvm.di_composite_type -; CHECK-DAG: #[[C_SELF]] = #llvm.di_composite_type +; CHECK-DAG: #[[A_SELF]] = #llvm.di_composite_type<{{.*}}recId = [[A_RECID]]> +; CHECK-DAG: #[[B_SELF]] = #llvm.di_composite_type<{{.*}}recId = [[B_RECID]]> +; CHECK-DAG: #[[C_SELF]] = #llvm.di_composite_type<{{.*}}recId = [[C_RECID]]> define void @class_field(ptr %arg1) !dbg !18 { ret void @@ -813,6 +816,4 @@ define void @imp_fn() !dbg !12 { !17 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !12, entity: !8, file: !3, line: 1, elements: !15) ; CHECK-DAG: #[[M:.+]] = #llvm.di_module<{{.*}}name = "mod1"{{.*}}> -; CHECK-DAG: #[[SP_REC:.+]] = #llvm.di_subprogram, isRecSelf = true> -; CHECK-DAG: #[[IE:.+]] = #llvm.di_imported_entity -; CHECK-DAG: #[[SP:.+]] = #llvm.di_subprogram<{{.*}}name = "imp_fn"{{.*}}retainedNodes = #[[IE]]> +; CHECK-DAG: #[[SP:.+]] = #llvm.di_subprogram<{{.*}}name = "imp_fn"{{.*}}retainedNodes = #llvm.di_imported_entity> diff --git a/mlir/test/Target/LLVMIR/llvmir-debug.mlir b/mlir/test/Target/LLVMIR/llvmir-debug.mlir index 01194df5047742..30b2ba5e9bad1f 100644 --- a/mlir/test/Target/LLVMIR/llvmir-debug.mlir +++ b/mlir/test/Target/LLVMIR/llvmir-debug.mlir @@ -372,28 +372,23 @@ llvm.func @fn_with_gl() { llvm.func @imp_fn() { llvm.return } loc(#loc2) - -#di_file = #llvm.di_file<"test.f90" in ""> -#di_subroutine_type = #llvm.di_subroutine_type -#di_compile_unit = #llvm.di_compile_unit, - sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, +#file = #llvm.di_file<"test.f90" in ""> +#SP_TY = #llvm.di_subroutine_type +#CU = #llvm.di_compile_unit, + sourceLanguage = DW_LANG_Fortran95, file = #file, isOptimized = false, emissionKind = Full> -#di_module_1 = #llvm.di_module -#di_module_2 = #llvm.di_module -#di_subprogram_self_rec = #llvm.di_subprogram> -#di_imported_entity_1 = #llvm.di_imported_entity -#di_imported_entity_2 = #llvm.di_imported_entity -#di_subprogram = #llvm.di_subprogram, recId = distinct[1]<>, - compileUnit = #di_compile_unit, scope = #di_file, name = "imp_fn", - file = #di_file, subprogramFlags = Definition, type = #di_subroutine_type, - retainedNodes = #di_imported_entity_1, #di_imported_entity_2> +#MOD = #llvm.di_module +#MOD1 = #llvm.di_module +#SP = #llvm.di_subprogram, compileUnit = #CU, scope = #file, + name = "imp_fn", file = #file, subprogramFlags = Definition, type = #SP_TY, + retainedNodes = #llvm.di_imported_entity, #llvm.di_imported_entity> #loc1 = loc("test.f90":12:14) -#loc2 = loc(fused<#di_subprogram>[#loc1]) +#loc2 = loc(fused<#SP>[#loc1]) // CHECK-DAG: ![[SP:[0-9]+]] = {{.*}}!DISubprogram(name: "imp_fn"{{.*}}retainedNodes: ![[NODES:[0-9]+]]) -// CHECK-DAG: ![[NODES]] = !{![[NODE1:[0-9]+]], ![[NODE2:[0-9]+]]} +// CHECK-DAG: ![[NODES]] = !{![[NODE2:[0-9]+]], ![[NODE1:[0-9]+]]} // CHECK-DAG: ![[NODE1]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: ![[SP]], entity: ![[MOD1:[0-9]+]]{{.*}}) // CHECK-DAG: ![[NODE2]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: ![[SP]], entity: ![[MOD2:[0-9]+]]{{.*}}) // CHECK-DAG: ![[MOD1]] = !DIModule({{.*}}name: "mod1"{{.*}}) @@ -448,7 +443,7 @@ llvm.func @func_debug_directives() { #di_compile_unit = #llvm.di_compile_unit, sourceLanguage = DW_LANG_C, file = #di_file, isOptimized = false, emissionKind = None> // Recursive type itself. -#di_struct_self = #llvm.di_composite_type, isRecSelf = true> +#di_struct_self = #llvm.di_composite_type> #di_ptr_inner = #llvm.di_derived_type #di_subroutine_inner = #llvm.di_subroutine_type #di_subprogram_inner = #llvm.di_subprogram< @@ -502,7 +497,7 @@ llvm.func @class_method() { // Ensures composite types with a recursive scope work. -#di_composite_type_self = #llvm.di_composite_type, isRecSelf = true> +#di_composite_type_self = #llvm.di_composite_type> #di_file = #llvm.di_file<"test.mlir" in "/"> #di_subroutine_type = #llvm.di_subroutine_type #di_subprogram = #llvm.di_subprogram @@ -513,7 +508,7 @@ llvm.func @class_method() { llvm.mlir.global @global_variable() {dbg_expr = #di_global_variable_expression} : !llvm.struct<()> // CHECK: distinct !DIGlobalVariable({{.*}}type: ![[COMP:[0-9]+]], -// CHECK: ![[COMP]] = distinct !DICompositeType({{.*}}scope: ![[SCOPE:[0-9]+]] +// CHECK: ![[COMP]] = distinct !DICompositeType({{.*}}scope: ![[SCOPE:[0-9]+]], // CHECK: ![[SCOPE]] = !DISubprogram({{.*}}type: ![[SUBROUTINE:[0-9]+]], // CHECK: ![[SUBROUTINE]] = !DISubroutineType(types: ![[SR_TYPES:[0-9]+]]) // CHECK: ![[SR_TYPES]] = !{![[COMP]]} @@ -525,7 +520,7 @@ llvm.mlir.global @global_variable() {dbg_expr = #di_global_variable_expression} // replaced with the recursive self reference. #di_file = #llvm.di_file<"test.mlir" in "/"> -#di_composite_type_self = #llvm.di_composite_type, isRecSelf = true> +#di_composite_type_self = #llvm.di_composite_type> #di_subroutine_type_inner = #llvm.di_subroutine_type #di_subprogram_inner = #llvm.di_subprogram @@ -545,7 +540,7 @@ llvm.mlir.global @global_variable() {dbg_expr = #di_global_variable_expression} // CHECK: distinct !DIGlobalVariable({{.*}}type: ![[VAR:[0-9]+]], // CHECK: ![[VAR]] = !DISubroutineType(types: ![[COMPS:[0-9]+]]) // CHECK: ![[COMPS]] = !{![[COMP:[0-9]+]], -// CHECK: ![[COMP]] = distinct !DICompositeType({{.*}}scope: ![[SCOPE:[0-9]+]] +// CHECK: ![[COMP]] = distinct !DICompositeType({{.*}}scope: ![[SCOPE:[0-9]+]], // CHECK: ![[SCOPE]] = !DISubprogram({{.*}}type: ![[SUBROUTINE:[0-9]+]], // CHECK: ![[SUBROUTINE]] = !DISubroutineType(types: ![[SR_TYPES:[0-9]+]]) // CHECK: ![[SR_TYPES]] = !{![[COMP]]} From e4cf0a047d30fcd6cf606af0764883ca896a5153 Mon Sep 17 00:00:00 2001 From: Timm Baeder Date: Sat, 31 Aug 2024 08:06:06 +0200 Subject: [PATCH 08/14] [clang][bytecode][NFC] Check for custom typechecking in call cleanup (#106826) The comment already explains that this is only true for _some_ builtin functions. This also brings the time it takes me to run the builtin-functions.cpp test locally from 50s down to 47s. --- clang/lib/AST/ByteCode/Interp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 42012767c22332..c4f76a3cc03aae 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -226,7 +226,8 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) { // Some builtin functions require us to only look at the call site, since // the classified parameter types do not match. - if (CurFunc->isBuiltin()) { + if (unsigned BID = CurFunc->getBuiltinID(); + BID && S.getASTContext().BuiltinInfo.hasCustomTypechecking(BID)) { const auto *CE = cast(S.Current->Caller->getExpr(S.Current->getRetPC())); for (int32_t I = CE->getNumArgs() - 1; I >= 0; --I) { From c6008cef7a710b3d97e6b9b6fcf8e9661333c5e6 Mon Sep 17 00:00:00 2001 From: Antonio Frighetto Date: Fri, 30 Aug 2024 10:34:02 +0200 Subject: [PATCH 09/14] [DL] Invert `getTypeStoreSize` bytes/bits relationship to avoid ceil div (NFC) Change how `getTypeStoreSize` and `getTypeStoreSizeInBits` interact by first aligning the bit size to the nearest power of 2 boundary and then applying plain division to derive the byte size. This simplifies the calculation by avoiding possible overflow concerns in the first place. --- llvm/include/llvm/IR/DataLayout.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/llvm/include/llvm/IR/DataLayout.h b/llvm/include/llvm/IR/DataLayout.h index 145f1a29c7dfb7..8f7ab2f9df389e 100644 --- a/llvm/include/llvm/IR/DataLayout.h +++ b/llvm/include/llvm/IR/DataLayout.h @@ -421,8 +421,9 @@ class DataLayout { /// /// For example, returns 5 for i36 and 10 for x86_fp80. TypeSize getTypeStoreSize(Type *Ty) const { - TypeSize BaseSize = getTypeSizeInBits(Ty); - return {divideCeil(BaseSize.getKnownMinValue(), 8), BaseSize.isScalable()}; + TypeSize StoreSizeInBits = getTypeStoreSizeInBits(Ty); + return {StoreSizeInBits.getKnownMinValue() / 8, + StoreSizeInBits.isScalable()}; } /// Returns the maximum number of bits that may be overwritten by @@ -433,7 +434,10 @@ class DataLayout { /// /// For example, returns 40 for i36 and 80 for x86_fp80. TypeSize getTypeStoreSizeInBits(Type *Ty) const { - return 8 * getTypeStoreSize(Ty); + TypeSize BaseSize = getTypeSizeInBits(Ty); + uint64_t AlignedSizeInBits = + alignToPowerOf2(BaseSize.getKnownMinValue(), 8); + return {AlignedSizeInBits, BaseSize.isScalable()}; } /// Returns true if no extra padding bits are needed when storing the From 3766ba44a8945681f4c52acb0331efcff66ef7b1 Mon Sep 17 00:00:00 2001 From: Kasper Nielsen Date: Sat, 31 Aug 2024 09:17:33 +0200 Subject: [PATCH 10/14] [mlir][python] Fix how the mlir variadic Python accessor `_ods_equally_sized_accessor` is used (#101132) (#106003) As reported in https://github.com/llvm/llvm-project/issues/101132, this fixes two bugs: 1. When accessing variadic operands inside an operation, it must be accessed as `self.operation.operands` instead of `operation.operands` 2. The implementation of the `equally_sized_accessor` function is doing wrong arithmetics when calculating the resulting index and group sizes. I have added a test for the `equally_sized_accessor` function, which did not have a test previously. --- mlir/python/mlir/dialects/_ods_common.py | 5 +- mlir/test/mlir-tblgen/op-python-bindings.td | 20 +-- mlir/test/python/dialects/ods_helpers.py | 68 ++++++++++ mlir/test/python/dialects/python_test.py | 120 ++++++++++++++++++ mlir/test/python/python_test_ops.td | 38 ++++++ mlir/tools/mlir-tblgen/OpPythonBindingGen.cpp | 59 ++++----- 6 files changed, 269 insertions(+), 41 deletions(-) diff --git a/mlir/python/mlir/dialects/_ods_common.py b/mlir/python/mlir/dialects/_ods_common.py index 1e7e8244ed4420..d40d936cdc83d6 100644 --- a/mlir/python/mlir/dialects/_ods_common.py +++ b/mlir/python/mlir/dialects/_ods_common.py @@ -51,13 +51,14 @@ def segmented_accessor(elements, raw_segments, idx): def equally_sized_accessor( - elements, n_variadic, n_preceding_simple, n_preceding_variadic + elements, n_simple, n_variadic, n_preceding_simple, n_preceding_variadic ): """ Returns a starting position and a number of elements per variadic group assuming equally-sized groups and the given numbers of preceding groups. elements: a sequential container. + n_simple: the number of non-variadic groups in the container. n_variadic: the number of variadic groups in the container. n_preceding_simple: the number of non-variadic groups preceding the current group. @@ -65,7 +66,7 @@ def equally_sized_accessor( group. """ - total_variadic_length = len(elements) - n_variadic + 1 + total_variadic_length = len(elements) - n_simple # This should be enforced by the C++-side trait verifier. assert total_variadic_length % n_variadic == 0 diff --git a/mlir/test/mlir-tblgen/op-python-bindings.td b/mlir/test/mlir-tblgen/op-python-bindings.td index 9f202ba08608c6..ba85cb8406b31a 100644 --- a/mlir/test/mlir-tblgen/op-python-bindings.td +++ b/mlir/test/mlir-tblgen/op-python-bindings.td @@ -480,18 +480,18 @@ def SameVariadicOperandSizeOp : TestOp<"same_variadic_operand", [SameVariadicOperandSize]> { // CHECK: @builtins.property // CHECK: def variadic1(self): - // CHECK: start, pg = _ods_equally_sized_accessor(operation.operands, 2, 0, 0) - // CHECK: return self.operation.operands[start:start + pg] + // CHECK: start, elements_per_group = _ods_equally_sized_accessor(self.operation.operands, 1, 2, 0, 0) + // CHECK: return self.operation.operands[start:start + elements_per_group] // // CHECK: @builtins.property // CHECK: def non_variadic(self): - // CHECK: start, pg = _ods_equally_sized_accessor(operation.operands, 2, 0, 1) + // CHECK: start, elements_per_group = _ods_equally_sized_accessor(self.operation.operands, 1, 2, 0, 1) // CHECK: return self.operation.operands[start] // // CHECK: @builtins.property // CHECK: def variadic2(self): - // CHECK: start, pg = _ods_equally_sized_accessor(operation.operands, 2, 1, 1) - // CHECK: return self.operation.operands[start:start + pg] + // CHECK: start, elements_per_group = _ods_equally_sized_accessor(self.operation.operands, 1, 2, 1, 1) + // CHECK: return self.operation.operands[start:start + elements_per_group] let arguments = (ins Variadic:$variadic1, AnyType:$non_variadic, Variadic:$variadic2); } @@ -506,18 +506,18 @@ def SameVariadicResultSizeOp : TestOp<"same_variadic_result", [SameVariadicResultSize]> { // CHECK: @builtins.property // CHECK: def variadic1(self): - // CHECK: start, pg = _ods_equally_sized_accessor(operation.results, 2, 0, 0) - // CHECK: return self.operation.results[start:start + pg] + // CHECK: start, elements_per_group = _ods_equally_sized_accessor(self.operation.results, 1, 2, 0, 0) + // CHECK: return self.operation.results[start:start + elements_per_group] // // CHECK: @builtins.property // CHECK: def non_variadic(self): - // CHECK: start, pg = _ods_equally_sized_accessor(operation.results, 2, 0, 1) + // CHECK: start, elements_per_group = _ods_equally_sized_accessor(self.operation.results, 1, 2, 0, 1) // CHECK: return self.operation.results[start] // // CHECK: @builtins.property // CHECK: def variadic2(self): - // CHECK: start, pg = _ods_equally_sized_accessor(operation.results, 2, 1, 1) - // CHECK: return self.operation.results[start:start + pg] + // CHECK: start, elements_per_group = _ods_equally_sized_accessor(self.operation.results, 1, 2, 1, 1) + // CHECK: return self.operation.results[start:start + elements_per_group] let results = (outs Variadic:$variadic1, AnyType:$non_variadic, Variadic:$variadic2); } diff --git a/mlir/test/python/dialects/ods_helpers.py b/mlir/test/python/dialects/ods_helpers.py index 0d2a18e0eb0af2..6f02153e08db5e 100644 --- a/mlir/test/python/dialects/ods_helpers.py +++ b/mlir/test/python/dialects/ods_helpers.py @@ -3,6 +3,7 @@ import gc from mlir.ir import * +from mlir.dialects._ods_common import equally_sized_accessor def run(f): @@ -208,3 +209,70 @@ class TestOp(OpView): run(testOdsBuildDefaultCastError) + + +def testOdsEquallySizedAccessor(): + class TestOpMultiResultSegments(OpView): + OPERATION_NAME = "custom.test_op" + _ODS_REGIONS = (1, True) + + with Context() as ctx, Location.unknown(): + ctx.allow_unregistered_dialects = True + m = Module.create() + with InsertionPoint(m.body): + v = add_dummy_value() + ts = [IntegerType.get_signless(i * 8) for i in range(4)] + + op = TestOpMultiResultSegments.build_generic( + results=[ts[0], ts[1], ts[2], ts[3]], operands=[v] + ) + start, elements_per_group = equally_sized_accessor(op.results, 1, 3, 1, 0) + # CHECK: start: 1, elements_per_group: 1 + print(f"start: {start}, elements_per_group: {elements_per_group}") + # CHECK: i8 + print(op.results[start].type) + + start, elements_per_group = equally_sized_accessor(op.results, 1, 3, 1, 1) + # CHECK: start: 2, elements_per_group: 1 + print(f"start: {start}, elements_per_group: {elements_per_group}") + # CHECK: i16 + print(op.results[start].type) + + +run(testOdsEquallySizedAccessor) + + +def testOdsEquallySizedAccessorMultipleSegments(): + class TestOpMultiResultSegments(OpView): + OPERATION_NAME = "custom.test_op" + _ODS_REGIONS = (1, True) + _ODS_RESULT_SEGMENTS = [0, -1, -1] + + def types(lst): + return [e.type for e in lst] + + with Context() as ctx, Location.unknown(): + ctx.allow_unregistered_dialects = True + m = Module.create() + with InsertionPoint(m.body): + v = add_dummy_value() + ts = [IntegerType.get_signless(i * 8) for i in range(7)] + + op = TestOpMultiResultSegments.build_generic( + results=[ts[0], [ts[1], ts[2], ts[3]], [ts[4], ts[5], ts[6]]], + operands=[v], + ) + start, elements_per_group = equally_sized_accessor(op.results, 1, 2, 1, 0) + # CHECK: start: 1, elements_per_group: 3 + print(f"start: {start}, elements_per_group: {elements_per_group}") + # CHECK: [IntegerType(i8), IntegerType(i16), IntegerType(i24)] + print(types(op.results[start : start + elements_per_group])) + + start, elements_per_group = equally_sized_accessor(op.results, 1, 2, 1, 1) + # CHECK: start: 4, elements_per_group: 3 + print(f"start: {start}, elements_per_group: {elements_per_group}") + # CHECK: [IntegerType(i32), IntegerType(i40), IntegerType(i48)] + print(types(op.results[start : start + elements_per_group])) + + +run(testOdsEquallySizedAccessorMultipleSegments) diff --git a/mlir/test/python/dialects/python_test.py b/mlir/test/python/dialects/python_test.py index a76f3f2b5e4583..948d1225ea489c 100644 --- a/mlir/test/python/dialects/python_test.py +++ b/mlir/test/python/dialects/python_test.py @@ -555,3 +555,123 @@ def testInferTypeOpInterface(): two_operands = test.InferResultsVariadicInputsOp(single=zero, doubled=zero) # CHECK: f32 print(two_operands.result.type) + + +# CHECK-LABEL: TEST: testVariadicOperandAccess +@run +def testVariadicOperandAccess(): + def values(lst): + return [str(e) for e in lst] + + with Context() as ctx, Location.unknown(ctx): + module = Module.create() + with InsertionPoint(module.body): + i32 = IntegerType.get_signless(32) + zero = arith.ConstantOp(i32, 0) + one = arith.ConstantOp(i32, 1) + two = arith.ConstantOp(i32, 2) + three = arith.ConstantOp(i32, 3) + four = arith.ConstantOp(i32, 4) + + variadic_operands = test.SameVariadicOperandSizeOp( + [zero, one], two, [three, four] + ) + # CHECK: Value(%{{.*}} = arith.constant 2 : i32) + print(variadic_operands.non_variadic) + # CHECK: ['Value(%{{.*}} = arith.constant 0 : i32)', 'Value(%{{.*}} = arith.constant 1 : i32)'] + print(values(variadic_operands.variadic1)) + # CHECK: ['Value(%{{.*}} = arith.constant 3 : i32)', 'Value(%{{.*}} = arith.constant 4 : i32)'] + print(values(variadic_operands.variadic2)) + + +# CHECK-LABEL: TEST: testVariadicResultAccess +@run +def testVariadicResultAccess(): + def types(lst): + return [e.type for e in lst] + + with Context() as ctx, Location.unknown(ctx): + module = Module.create() + with InsertionPoint(module.body): + i = [IntegerType.get_signless(k) for k in range(7)] + + # Test Variadic-Fixed-Variadic + op = test.SameVariadicResultSizeOpVFV([i[0], i[1]], i[2], [i[3], i[4]]) + # CHECK: i2 + print(op.non_variadic.type) + # CHECK: [IntegerType(i0), IntegerType(i1)] + print(types(op.variadic1)) + # CHECK: [IntegerType(i3), IntegerType(i4)] + print(types(op.variadic2)) + + # Test Variadic-Variadic-Variadic + op = test.SameVariadicResultSizeOpVVV( + [i[0], i[1]], [i[2], i[3]], [i[4], i[5]] + ) + # CHECK: [IntegerType(i0), IntegerType(i1)] + print(types(op.variadic1)) + # CHECK: [IntegerType(i2), IntegerType(i3)] + print(types(op.variadic2)) + # CHECK: [IntegerType(i4), IntegerType(i5)] + print(types(op.variadic3)) + + # Test Fixed-Fixed-Variadic + op = test.SameVariadicResultSizeOpFFV(i[0], i[1], [i[2], i[3], i[4]]) + # CHECK: i0 + print(op.non_variadic1.type) + # CHECK: i1 + print(op.non_variadic2.type) + # CHECK: [IntegerType(i2), IntegerType(i3), IntegerType(i4)] + print(types(op.variadic)) + + # Test Variadic-Variadic-Fixed + op = test.SameVariadicResultSizeOpVVF( + [i[0], i[1], i[2]], [i[3], i[4], i[5]], i[6] + ) + # CHECK: [IntegerType(i0), IntegerType(i1), IntegerType(i2)] + print(types(op.variadic1)) + # CHECK: [IntegerType(i3), IntegerType(i4), IntegerType(i5)] + print(types(op.variadic2)) + # CHECK: i6 + print(op.non_variadic.type) + + # Test Fixed-Variadic-Fixed-Variadic-Fixed + op = test.SameVariadicResultSizeOpFVFVF( + i[0], [i[1], i[2]], i[3], [i[4], i[5]], i[6] + ) + # CHECK: i0 + print(op.non_variadic1.type) + # CHECK: [IntegerType(i1), IntegerType(i2)] + print(types(op.variadic1)) + # CHECK: i3 + print(op.non_variadic2.type) + # CHECK: [IntegerType(i4), IntegerType(i5)] + print(types(op.variadic2)) + # CHECK: i6 + print(op.non_variadic3.type) + + # Test Fixed-Variadic-Fixed-Variadic-Fixed - Variadic group size 0 + op = test.SameVariadicResultSizeOpFVFVF(i[0], [], i[1], [], i[2]) + # CHECK: i0 + print(op.non_variadic1.type) + # CHECK: [] + print(types(op.variadic1)) + # CHECK: i1 + print(op.non_variadic2.type) + # CHECK: [] + print(types(op.variadic2)) + # CHECK: i2 + print(op.non_variadic3.type) + + # Test Fixed-Variadic-Fixed-Variadic-Fixed - Variadic group size 1 + op = test.SameVariadicResultSizeOpFVFVF(i[0], [i[1]], i[2], [i[3]], i[4]) + # CHECK: i0 + print(op.non_variadic1.type) + # CHECK: [IntegerType(i1)] + print(types(op.variadic1)) + # CHECK: i2 + print(op.non_variadic2.type) + # CHECK: [IntegerType(i3)] + print(types(op.variadic2)) + # CHECK: i4 + print(op.non_variadic3.type) diff --git a/mlir/test/python/python_test_ops.td b/mlir/test/python/python_test_ops.td index 6211fb9987c76a..026e64a3cfc19b 100644 --- a/mlir/test/python/python_test_ops.td +++ b/mlir/test/python/python_test_ops.td @@ -227,4 +227,42 @@ def OptionalOperandOp : TestOp<"optional_operand_op"> { let results = (outs I32:$result); } +def SameVariadicOperandSizeOp : TestOp<"same_variadic_operand", + [SameVariadicOperandSize]> { + let arguments = (ins Variadic:$variadic1, AnyType:$non_variadic, + Variadic:$variadic2); +} + +// Check different arrangements of variadic groups +def SameVariadicResultSizeOpVFV : TestOp<"same_variadic_result_vfv", + [SameVariadicResultSize]> { + let results = (outs Variadic:$variadic1, AnyType:$non_variadic, + Variadic:$variadic2); +} + +def SameVariadicResultSizeOpVVV : TestOp<"same_variadic_result_vvv", + [SameVariadicResultSize]> { + let results = (outs Variadic:$variadic1, Variadic:$variadic2, + Variadic:$variadic3); +} + +def SameVariadicResultSizeOpFFV : TestOp<"same_variadic_result_ffv", + [SameVariadicResultSize]> { + let results = (outs AnyType:$non_variadic1, AnyType:$non_variadic2, + Variadic:$variadic); +} + +def SameVariadicResultSizeOpVVF : TestOp<"same_variadic_result_vvf", + [SameVariadicResultSize]> { + let results = (outs Variadic:$variadic1, Variadic:$variadic2, + AnyType:$non_variadic); +} + +def SameVariadicResultSizeOpFVFVF : TestOp<"same_variadic_result_fvfvf", + [SameVariadicResultSize]> { + let results = (outs AnyType:$non_variadic1, Variadic:$variadic1, + AnyType:$non_variadic2, Variadic:$variadic2, + AnyType:$non_variadic3); +} + #endif // PYTHON_TEST_OPS diff --git a/mlir/tools/mlir-tblgen/OpPythonBindingGen.cpp b/mlir/tools/mlir-tblgen/OpPythonBindingGen.cpp index 052020acdcb764..553ab6adc65b06 100644 --- a/mlir/tools/mlir-tblgen/OpPythonBindingGen.cpp +++ b/mlir/tools/mlir-tblgen/OpPythonBindingGen.cpp @@ -139,13 +139,14 @@ constexpr const char *opOneVariadicTemplate = R"Py( /// First part of the template for equally-sized variadic group accessor: /// {0} is the name of the accessor; /// {1} is either 'operand' or 'result'; -/// {2} is the total number of variadic groups; -/// {3} is the number of non-variadic groups preceding the current group; -/// {3} is the number of variadic groups preceding the current group. +/// {2} is the total number of non-variadic groups; +/// {3} is the total number of variadic groups; +/// {4} is the number of non-variadic groups preceding the current group; +/// {5} is the number of variadic groups preceding the current group. constexpr const char *opVariadicEqualPrefixTemplate = R"Py( @builtins.property def {0}(self): - start, pg = _ods_equally_sized_accessor(operation.{1}s, {2}, {3}, {4}))Py"; + start, elements_per_group = _ods_equally_sized_accessor(self.operation.{1}s, {2}, {3}, {4}, {5}))Py"; /// Second part of the template for equally-sized case, accessing a single /// element: @@ -158,7 +159,7 @@ constexpr const char *opVariadicEqualSimpleTemplate = R"Py( /// group: /// {0} is either 'operand' or 'result'. constexpr const char *opVariadicEqualVariadicTemplate = R"Py( - return self.operation.{0}s[start:start + pg] + return self.operation.{0}s[start:start + elements_per_group] )Py"; /// Template for an attribute-sized group accessor: @@ -324,8 +325,7 @@ static std::string attrSizedTraitForKind(const char *kind) { /// `operand` or `result` and is used verbatim in the emitted code. static void emitElementAccessors( const Operator &op, raw_ostream &os, const char *kind, - llvm::function_ref getNumVariableLength, - llvm::function_ref getNumElements, + unsigned numVariadicGroups, unsigned numElements, llvm::function_ref getElement) { assert(llvm::is_contained( @@ -339,14 +339,12 @@ static void emitElementAccessors( llvm::StringRef(kind).drop_front()); std::string attrSizedTrait = attrSizedTraitForKind(kind); - unsigned numVariableLength = getNumVariableLength(op); - // If there is only one variable-length element group, its size can be // inferred from the total number of elements. If there are none, the // generation is straightforward. - if (numVariableLength <= 1) { + if (numVariadicGroups <= 1) { bool seenVariableLength = false; - for (int i = 0, e = getNumElements(op); i < e; ++i) { + for (unsigned i = 0; i < numElements; ++i) { const NamedTypeConstraint &element = getElement(op, i); if (element.isVariableLength()) seenVariableLength = true; @@ -355,12 +353,10 @@ static void emitElementAccessors( if (element.isVariableLength()) { os << llvm::formatv(element.isOptional() ? opOneOptionalTemplate : opOneVariadicTemplate, - sanitizeName(element.name), kind, - getNumElements(op), i); + sanitizeName(element.name), kind, numElements, i); } else if (seenVariableLength) { os << llvm::formatv(opSingleAfterVariableTemplate, - sanitizeName(element.name), kind, - getNumElements(op), i); + sanitizeName(element.name), kind, numElements, i); } else { os << llvm::formatv(opSingleTemplate, sanitizeName(element.name), kind, i); @@ -371,14 +367,25 @@ static void emitElementAccessors( // Handle the operations where variadic groups have the same size. if (op.getTrait(sameSizeTrait)) { + // Count the number of simple elements + unsigned numSimpleLength = 0; + for (unsigned i = 0; i < numElements; ++i) { + const NamedTypeConstraint &element = getElement(op, i); + if (!element.isVariableLength()) { + ++numSimpleLength; + } + } + + // Generate the accessors int numPrecedingSimple = 0; int numPrecedingVariadic = 0; - for (int i = 0, e = getNumElements(op); i < e; ++i) { + for (unsigned i = 0; i < numElements; ++i) { const NamedTypeConstraint &element = getElement(op, i); if (!element.name.empty()) { os << llvm::formatv(opVariadicEqualPrefixTemplate, - sanitizeName(element.name), kind, numVariableLength, - numPrecedingSimple, numPrecedingVariadic); + sanitizeName(element.name), kind, numSimpleLength, + numVariadicGroups, numPrecedingSimple, + numPrecedingVariadic); os << llvm::formatv(element.isVariableLength() ? opVariadicEqualVariadicTemplate : opVariadicEqualSimpleTemplate, @@ -396,7 +403,7 @@ static void emitElementAccessors( // provided as an attribute. For non-variadic elements, make sure to return // an element rather than a singleton container. if (op.getTrait(attrSizedTrait)) { - for (int i = 0, e = getNumElements(op); i < e; ++i) { + for (unsigned i = 0; i < numElements; ++i) { const NamedTypeConstraint &element = getElement(op, i); if (element.name.empty()) continue; @@ -427,20 +434,14 @@ static const NamedTypeConstraint &getResult(const Operator &op, int i) { /// Emits accessors to Op operands. static void emitOperandAccessors(const Operator &op, raw_ostream &os) { - auto getNumVariableLengthOperands = [](const Operator &oper) { - return oper.getNumVariableLengthOperands(); - }; - emitElementAccessors(op, os, "operand", getNumVariableLengthOperands, - getNumOperands, getOperand); + emitElementAccessors(op, os, "operand", op.getNumVariableLengthOperands(), + getNumOperands(op), getOperand); } /// Emits accessors Op results. static void emitResultAccessors(const Operator &op, raw_ostream &os) { - auto getNumVariableLengthResults = [](const Operator &oper) { - return oper.getNumVariableLengthResults(); - }; - emitElementAccessors(op, os, "result", getNumVariableLengthResults, - getNumResults, getResult); + emitElementAccessors(op, os, "result", op.getNumVariableLengthResults(), + getNumResults(op), getResult); } /// Emits accessors to Op attributes. From 49aa255009f6096b055dab4b4dd31ffa5403b750 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Sat, 31 Aug 2024 00:59:21 -0700 Subject: [PATCH 11/14] [X86] Add missing pass initialization function for X86DynAllocaExpander. (#106820) This allows it to show up in -print-before/after-all --- llvm/lib/Target/X86/X86.h | 1 + llvm/lib/Target/X86/X86DynAllocaExpander.cpp | 5 +++++ llvm/lib/Target/X86/X86TargetMachine.cpp | 1 + 3 files changed, 7 insertions(+) diff --git a/llvm/lib/Target/X86/X86.h b/llvm/lib/Target/X86/X86.h index 3d7a322d392f7f..054ff64f7796bc 100644 --- a/llvm/lib/Target/X86/X86.h +++ b/llvm/lib/Target/X86/X86.h @@ -184,6 +184,7 @@ void initializeX86CallFrameOptimizationPass(PassRegistry &); void initializeX86CmovConverterPassPass(PassRegistry &); void initializeX86DAGToDAGISelLegacyPass(PassRegistry &); void initializeX86DomainReassignmentPass(PassRegistry &); +void initializeX86DynAllocaExpanderPass(PassRegistry &); void initializeX86ExecutionDomainFixPass(PassRegistry &); void initializeX86ExpandPseudoPass(PassRegistry &); void initializeX86FastPreTileConfigPass(PassRegistry &); diff --git a/llvm/lib/Target/X86/X86DynAllocaExpander.cpp b/llvm/lib/Target/X86/X86DynAllocaExpander.cpp index 5ed94f329c4b4c..fc48055b2fac73 100644 --- a/llvm/lib/Target/X86/X86DynAllocaExpander.cpp +++ b/llvm/lib/Target/X86/X86DynAllocaExpander.cpp @@ -65,6 +65,8 @@ class X86DynAllocaExpander : public MachineFunctionPass { bool NoStackArgProbe = false; StringRef getPassName() const override { return "X86 DynAlloca Expander"; } + +public: static char ID; }; @@ -72,6 +74,9 @@ char X86DynAllocaExpander::ID = 0; } // end anonymous namespace +INITIALIZE_PASS(X86DynAllocaExpander, "x86-dyn-alloca-expander", + "X86 DynAlloca Expander", false, false) + FunctionPass *llvm::createX86DynAllocaExpander() { return new X86DynAllocaExpander(); } diff --git a/llvm/lib/Target/X86/X86TargetMachine.cpp b/llvm/lib/Target/X86/X86TargetMachine.cpp index d2d59ff3b93cf2..fc2a1e34b711ef 100644 --- a/llvm/lib/Target/X86/X86TargetMachine.cpp +++ b/llvm/lib/Target/X86/X86TargetMachine.cpp @@ -106,6 +106,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeX86Target() { initializeX86ArgumentStackSlotPassPass(PR); initializeX86FixupInstTuningPassPass(PR); initializeX86FixupVectorConstantsPassPass(PR); + initializeX86DynAllocaExpanderPass(PR); } static std::unique_ptr createTLOF(const Triple &TT) { From 8c5d53f8deb26456432cc0459551cdd69754fea7 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Sat, 31 Aug 2024 00:56:45 -0700 Subject: [PATCH 12/14] [RISCV] Use MCRegister instead of unsigned in RISCVAsmParser.cpp. NFC Rename RegNo to Reg. --- .../Target/RISCV/AsmParser/RISCVAsmParser.cpp | 97 +++++++++---------- 1 file changed, 48 insertions(+), 49 deletions(-) diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index f299e823aa3f50..6d33a1f64195d5 100644 --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -1110,9 +1110,9 @@ struct RISCVOperand final : public MCParsedAsmOperand { } static std::unique_ptr - createReg(unsigned RegNo, SMLoc S, SMLoc E, bool IsGPRAsFPR = false) { + createReg(MCRegister Reg, SMLoc S, SMLoc E, bool IsGPRAsFPR = false) { auto Op = std::make_unique(KindTy::Register); - Op->Reg.RegNum = RegNo; + Op->Reg.RegNum = Reg.id(); Op->Reg.IsGPRAsFPR = IsGPRAsFPR; Op->StartLoc = S; Op->EndLoc = E; @@ -1181,11 +1181,11 @@ struct RISCVOperand final : public MCParsedAsmOperand { return Op; } - static std::unique_ptr createRegReg(unsigned Reg1No, - unsigned Reg2No, SMLoc S) { + static std::unique_ptr createRegReg(MCRegister Reg1, + MCRegister Reg2, SMLoc S) { auto Op = std::make_unique(KindTy::RegReg); - Op->RegReg.Reg1 = Reg1No; - Op->RegReg.Reg2 = Reg2No; + Op->RegReg.Reg1 = Reg1.id(); + Op->RegReg.Reg2 = Reg2.id(); Op->StartLoc = S; Op->EndLoc = S; return Op; @@ -1310,7 +1310,7 @@ static MCRegister convertVRToVRMx(const MCRegisterInfo &RI, MCRegister Reg, else if (Kind == MCK_VRM8) RegClassID = RISCV::VRM8RegClassID; else - return 0; + return MCRegister(); return RI.getMatchingSuperReg(Reg, RISCV::sub_vrm1_0, &RISCVMCRegisterClasses[RegClassID]); } @@ -1661,9 +1661,9 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, } // Attempts to match Name as a register (either using the default name or -// alternative ABI names), setting RegNo to the matching register. Upon -// failure, returns a non-valid MCRegister. If IsRVE, then registers x16-x31 -// will be rejected. +// alternative ABI names), returning the matching register. Upon failure, +// returns a non-valid MCRegister. If IsRVE, then registers x16-x31 will be +// rejected. MCRegister RISCVAsmParser::matchRegisterNameHelper(StringRef Name) const { MCRegister Reg = MatchRegisterName(Name); // The 16-/32- and 64-bit FPRs have the same asm name. Check that the initial @@ -1676,7 +1676,7 @@ MCRegister RISCVAsmParser::matchRegisterNameHelper(StringRef Name) const { if (!Reg) Reg = MatchRegisterAltName(Name); if (isRVE() && Reg >= RISCV::X16 && Reg <= RISCV::X31) - Reg = RISCV::NoRegister; + Reg = MCRegister(); return Reg; } @@ -1727,9 +1727,9 @@ ParseStatus RISCVAsmParser::parseRegister(OperandVector &Operands, return ParseStatus::NoMatch; case AsmToken::Identifier: StringRef Name = getLexer().getTok().getIdentifier(); - MCRegister RegNo = matchRegisterNameHelper(Name); + MCRegister Reg = matchRegisterNameHelper(Name); - if (!RegNo) { + if (!Reg) { if (HadParens) getLexer().UnLex(LParen); return ParseStatus::NoMatch; @@ -1739,7 +1739,7 @@ ParseStatus RISCVAsmParser::parseRegister(OperandVector &Operands, SMLoc S = getLoc(); SMLoc E = SMLoc::getFromPointer(S.getPointer() + Name.size()); getLexer().Lex(); - Operands.push_back(RISCVOperand::createReg(RegNo, S, E)); + Operands.push_back(RISCVOperand::createReg(Reg, S, E)); } if (HadParens) { @@ -2305,16 +2305,16 @@ ParseStatus RISCVAsmParser::parseMaskReg(OperandVector &Operands) { StringRef Name = getLexer().getTok().getIdentifier(); if (!Name.consume_back(".t")) return Error(getLoc(), "expected '.t' suffix"); - MCRegister RegNo = matchRegisterNameHelper(Name); + MCRegister Reg = matchRegisterNameHelper(Name); - if (!RegNo) + if (!Reg) return ParseStatus::NoMatch; - if (RegNo != RISCV::V0) + if (Reg != RISCV::V0) return ParseStatus::NoMatch; SMLoc S = getLoc(); SMLoc E = SMLoc::getFromPointer(S.getPointer() + Name.size()); getLexer().Lex(); - Operands.push_back(RISCVOperand::createReg(RegNo, S, E)); + Operands.push_back(RISCVOperand::createReg(Reg, S, E)); return ParseStatus::Success; } @@ -2323,15 +2323,15 @@ ParseStatus RISCVAsmParser::parseGPRAsFPR(OperandVector &Operands) { return ParseStatus::NoMatch; StringRef Name = getLexer().getTok().getIdentifier(); - MCRegister RegNo = matchRegisterNameHelper(Name); + MCRegister Reg = matchRegisterNameHelper(Name); - if (!RegNo) + if (!Reg) return ParseStatus::NoMatch; SMLoc S = getLoc(); SMLoc E = SMLoc::getFromPointer(S.getPointer() + Name.size()); getLexer().Lex(); Operands.push_back(RISCVOperand::createReg( - RegNo, S, E, !getSTI().hasFeature(RISCV::FeatureStdExtF))); + Reg, S, E, !getSTI().hasFeature(RISCV::FeatureStdExtF))); return ParseStatus::Success; } @@ -2354,15 +2354,15 @@ ParseStatus RISCVAsmParser::parseGPRPair(OperandVector &Operands, return ParseStatus::NoMatch; StringRef Name = getLexer().getTok().getIdentifier(); - MCRegister RegNo = matchRegisterNameHelper(Name); + MCRegister Reg = matchRegisterNameHelper(Name); - if (!RegNo) + if (!Reg) return ParseStatus::NoMatch; - if (!RISCVMCRegisterClasses[RISCV::GPRRegClassID].contains(RegNo)) + if (!RISCVMCRegisterClasses[RISCV::GPRRegClassID].contains(Reg)) return ParseStatus::NoMatch; - if ((RegNo - RISCV::X0) & 1) + if ((Reg - RISCV::X0) & 1) return TokError("register must be even"); SMLoc S = getLoc(); @@ -2370,8 +2370,8 @@ ParseStatus RISCVAsmParser::parseGPRPair(OperandVector &Operands, getLexer().Lex(); const MCRegisterInfo *RI = getContext().getRegisterInfo(); - unsigned Pair = RI->getMatchingSuperReg( - RegNo, RISCV::sub_gpr_even, + MCRegister Pair = RI->getMatchingSuperReg( + Reg, RISCV::sub_gpr_even, &RISCVMCRegisterClasses[RISCV::GPRPairRegClassID]); Operands.push_back(RISCVOperand::createReg(Pair, S, E)); return ParseStatus::Success; @@ -2629,7 +2629,7 @@ ParseStatus RISCVAsmParser::parseReglist(OperandVector &Operands) { if (getLexer().isNot(AsmToken::Identifier)) return Error(getLoc(), "invalid register"); EndName = getLexer().getTok().getIdentifier(); - if (MatchRegisterName(EndName) == RISCV::NoRegister) + if (!MatchRegisterName(EndName)) return Error(getLoc(), "invalid register"); getLexer().Lex(); } @@ -2644,7 +2644,7 @@ ParseStatus RISCVAsmParser::parseReglist(OperandVector &Operands) { if (parseToken(AsmToken::RCurly, "register list must end with '}'")) return ParseStatus::Failure; - if (RegEnd == RISCV::NoRegister) + if (!RegEnd) RegEnd = RegStart; auto Encode = RISCVZC::encodeRlist(RegEnd, IsEABI); @@ -3356,7 +3356,7 @@ void RISCVAsmParser::emitVMSGE(MCInst &Inst, unsigned Opcode, SMLoc IDLoc, .addOperand(Inst.getOperand(0)) .addOperand(Inst.getOperand(1)) .addOperand(Inst.getOperand(2)) - .addReg(RISCV::NoRegister) + .addReg(MCRegister()) .setLoc(IDLoc)); emitToStreamer(Out, MCInstBuilder(RISCV::VMNAND_MM) .addOperand(Inst.getOperand(0)) @@ -3395,7 +3395,7 @@ void RISCVAsmParser::emitVMSGE(MCInst &Inst, unsigned Opcode, SMLoc IDLoc, .addOperand(Inst.getOperand(1)) .addOperand(Inst.getOperand(2)) .addOperand(Inst.getOperand(3)) - .addReg(RISCV::NoRegister) + .addReg(MCRegister()) .setLoc(IDLoc)); emitToStreamer(Out, MCInstBuilder(RISCV::VMANDN_MM) .addOperand(Inst.getOperand(0)) @@ -3414,7 +3414,7 @@ void RISCVAsmParser::emitVMSGE(MCInst &Inst, unsigned Opcode, SMLoc IDLoc, .addOperand(Inst.getOperand(1)) .addOperand(Inst.getOperand(2)) .addOperand(Inst.getOperand(3)) - .addReg(RISCV::NoRegister) + .addReg(MCRegister()) .setLoc(IDLoc)); emitToStreamer(Out, MCInstBuilder(RISCV::VMANDN_MM) .addOperand(Inst.getOperand(1)) @@ -3461,8 +3461,7 @@ bool RISCVAsmParser::checkPseudoTLSDESCCall(MCInst &Inst, } std::unique_ptr RISCVAsmParser::defaultMaskRegOp() const { - return RISCVOperand::createReg(RISCV::NoRegister, llvm::SMLoc(), - llvm::SMLoc()); + return RISCVOperand::createReg(MCRegister(), llvm::SMLoc(), llvm::SMLoc()); } std::unique_ptr RISCVAsmParser::defaultFRMArgOp() const { @@ -3481,8 +3480,8 @@ bool RISCVAsmParser::validateInstruction(MCInst &Inst, if (Opcode == RISCV::PseudoVMSGEU_VX_M_T || Opcode == RISCV::PseudoVMSGE_VX_M_T) { - unsigned DestReg = Inst.getOperand(0).getReg(); - unsigned TempReg = Inst.getOperand(1).getReg(); + MCRegister DestReg = Inst.getOperand(0).getReg(); + MCRegister TempReg = Inst.getOperand(1).getReg(); if (DestReg == TempReg) { SMLoc Loc = Operands.back()->getStartLoc(); return Error(Loc, "the temporary vector register cannot be the same as " @@ -3492,9 +3491,9 @@ bool RISCVAsmParser::validateInstruction(MCInst &Inst, if (Opcode == RISCV::TH_LDD || Opcode == RISCV::TH_LWUD || Opcode == RISCV::TH_LWD) { - unsigned Rd1 = Inst.getOperand(0).getReg(); - unsigned Rd2 = Inst.getOperand(1).getReg(); - unsigned Rs1 = Inst.getOperand(2).getReg(); + MCRegister Rd1 = Inst.getOperand(0).getReg(); + MCRegister Rd2 = Inst.getOperand(1).getReg(); + MCRegister Rs1 = Inst.getOperand(2).getReg(); // The encoding with rd1 == rd2 == rs1 is reserved for XTHead load pair. if (Rs1 == Rd1 && Rs1 == Rd2) { SMLoc Loc = Operands[1]->getStartLoc(); @@ -3503,8 +3502,8 @@ bool RISCVAsmParser::validateInstruction(MCInst &Inst, } if (Opcode == RISCV::CM_MVSA01) { - unsigned Rd1 = Inst.getOperand(0).getReg(); - unsigned Rd2 = Inst.getOperand(1).getReg(); + MCRegister Rd1 = Inst.getOperand(0).getReg(); + MCRegister Rd2 = Inst.getOperand(1).getReg(); if (Rd1 == Rd2) { SMLoc Loc = Operands[1]->getStartLoc(); return Error(Loc, "rs1 and rs2 must be different"); @@ -3531,16 +3530,16 @@ bool RISCVAsmParser::validateInstruction(MCInst &Inst, if (Opcode == RISCV::VC_V_XVW || Opcode == RISCV::VC_V_IVW || Opcode == RISCV::VC_V_FVW || Opcode == RISCV::VC_V_VVW) { // Operands Opcode, Dst, uimm, Dst, Rs2, Rs1 for VC_V_XVW. - unsigned VCIXDst = Inst.getOperand(0).getReg(); + MCRegister VCIXDst = Inst.getOperand(0).getReg(); SMLoc VCIXDstLoc = Operands[2]->getStartLoc(); if (MCID.TSFlags & RISCVII::VS1Constraint) { - unsigned VCIXRs1 = Inst.getOperand(Inst.getNumOperands() - 1).getReg(); + MCRegister VCIXRs1 = Inst.getOperand(Inst.getNumOperands() - 1).getReg(); if (VCIXDst == VCIXRs1) return Error(VCIXDstLoc, "the destination vector register group cannot" " overlap the source vector register group"); } if (MCID.TSFlags & RISCVII::VS2Constraint) { - unsigned VCIXRs2 = Inst.getOperand(Inst.getNumOperands() - 2).getReg(); + MCRegister VCIXRs2 = Inst.getOperand(Inst.getNumOperands() - 2).getReg(); if (VCIXDst == VCIXRs2) return Error(VCIXDstLoc, "the destination vector register group cannot" " overlap the source vector register group"); @@ -3548,7 +3547,7 @@ bool RISCVAsmParser::validateInstruction(MCInst &Inst, return false; } - unsigned DestReg = Inst.getOperand(0).getReg(); + MCRegister DestReg = Inst.getOperand(0).getReg(); unsigned Offset = 0; int TiedOp = MCID.getOperandConstraint(1, MCOI::TIED_TO); if (TiedOp == 0) @@ -3557,13 +3556,13 @@ bool RISCVAsmParser::validateInstruction(MCInst &Inst, // Operands[1] will be the first operand, DestReg. SMLoc Loc = Operands[1]->getStartLoc(); if (MCID.TSFlags & RISCVII::VS2Constraint) { - unsigned CheckReg = Inst.getOperand(Offset + 1).getReg(); + MCRegister CheckReg = Inst.getOperand(Offset + 1).getReg(); if (DestReg == CheckReg) return Error(Loc, "the destination vector register group cannot overlap" " the source vector register group"); } if ((MCID.TSFlags & RISCVII::VS1Constraint) && Inst.getOperand(Offset + 2).isReg()) { - unsigned CheckReg = Inst.getOperand(Offset + 2).getReg(); + MCRegister CheckReg = Inst.getOperand(Offset + 2).getReg(); if (DestReg == CheckReg) return Error(Loc, "the destination vector register group cannot overlap" " the source vector register group"); @@ -3582,8 +3581,8 @@ bool RISCVAsmParser::validateInstruction(MCInst &Inst, // same. For example, "viota.m v0, v2" is "viota.m v0, v2, NoRegister" // actually. We need to check the last operand to ensure whether it is // masked or not. - unsigned CheckReg = Inst.getOperand(Inst.getNumOperands() - 1).getReg(); - assert((CheckReg == RISCV::V0 || CheckReg == RISCV::NoRegister) && + MCRegister CheckReg = Inst.getOperand(Inst.getNumOperands() - 1).getReg(); + assert((CheckReg == RISCV::V0 || !CheckReg) && "Unexpected register for mask operand"); if (DestReg == CheckReg) From 5b0bcec93dbc2e5bec049c452b157548334c5e28 Mon Sep 17 00:00:00 2001 From: Younan Zhang Date: Sat, 31 Aug 2024 17:35:51 +0800 Subject: [PATCH 13/14] [Clang][Parser] Fix name lookup of template parameters for out-of-line specializations (#101020) Since the implementation of DR458 (d1446017), we have had an algorithm that template parameters would take precedence over its parent scopes at the name lookup. However, we failed to handle the following case where the member function declaration is not yet deferral parsed (This is where the patch of DR458 applies): ```cpp namespace NS { int CC; template struct C; } template struct NS::C { void foo(CC); }; ``` When parsing the parameter of the function declaration `void foo(CC)`, we used to perform a name lookup following such a Scope chain: ``` FunctionScope foo (failed) RecordScope C (failed) NamespaceScope NS (found `int CC`) (If failed) TemplateParameterScope of C ``` This doesn't seem right because according to `[temp.local]`, a template parameter scope should be searched before its parent scope to which the parameter appertains. This patch corrects the search scopes by setting a lookup Entity for template parameter Scopes so that we can bail out in CppNameLookup() when reaching the RecordScope. Afterward, the search chain would be like: ``` FunctionScope foo (failed) RecordScope C (failed) TemplateParameterScope of C (found CC) (If failed) NamespaceScope NS ``` Fixes https://github.com/llvm/llvm-project/issues/64082 --- clang/docs/ReleaseNotes.rst | 2 ++ clang/lib/Sema/SemaTemplate.cpp | 24 +++++++++++++ .../test/CXX/temp/temp.res/temp.local/p8.cpp | 35 +++++++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index d0ac3b65820b05..98fb0174d4a37e 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -336,6 +336,8 @@ Bug Fixes to C++ Support - Mangle placeholders for deduced types as a template-prefix, such that mangling of template template parameters uses the correct production. (#GH106182) - Fixed an assertion failure when converting vectors to int/float with invalid expressions. (#GH105486) +- Template parameter names are considered in the name lookup of out-of-line class template + specialization right before its declaration context. (#GH64082) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index f8f41d0bafffc3..bf6b53700d90eb 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1873,6 +1873,27 @@ DeclResult Sema::CheckClassTemplate( if (Previous.isAmbiguous()) return true; + // Let the template parameter scope enter the lookup chain of the current + // class template. For example, given + // + // namespace ns { + // template bool Param = false; + // template struct N; + // } + // + // template struct ns::N { void foo(Param); }; + // + // When we reference Param inside the function parameter list, our name lookup + // chain for it should be like: + // FunctionScope foo + // -> RecordScope N + // -> TemplateParamScope (where we will find Param) + // -> NamespaceScope ns + // + // See also CppLookupName(). + if (S->isTemplateParamScope()) + EnterTemplatedContext(S, SemanticContext); + NamedDecl *PrevDecl = nullptr; if (Previous.begin() != Previous.end()) PrevDecl = (*Previous.begin())->getUnderlyingDecl(); @@ -8089,6 +8110,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization( return true; } + if (S->isTemplateParamScope()) + EnterTemplatedContext(S, ClassTemplate->getTemplatedDecl()); + DeclContext *DC = ClassTemplate->getDeclContext(); bool isMemberSpecialization = false; diff --git a/clang/test/CXX/temp/temp.res/temp.local/p8.cpp b/clang/test/CXX/temp/temp.res/temp.local/p8.cpp index 6b2071eb12ce0f..56599985da06e9 100644 --- a/clang/test/CXX/temp/temp.res/temp.local/p8.cpp +++ b/clang/test/CXX/temp/temp.res/temp.local/p8.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s namespace N { enum { C }; @@ -151,4 +152,38 @@ namespace SearchClassBetweenTemplateParameterLists { void A::B::k(V) { // expected-error {{does not match}} BB bb; // expected-error {{incomplete type}} } + + int CC; + template struct C; + template typename> struct D; +#if __cplusplus >= 202002L + template requires (CC) struct E; + template struct F; + template concept True = true; +#endif } + +template +struct SearchClassBetweenTemplateParameterLists::C { + void foo(CC); // This should find the template type parameter. +}; + +template typename CC> +struct SearchClassBetweenTemplateParameterLists::D { + template + CC foo(CC); +}; + +#if __cplusplus >= 202002L + +template requires (CC) +struct SearchClassBetweenTemplateParameterLists::E { + void foo() requires (CC); +}; + +template +struct SearchClassBetweenTemplateParameterLists::F { + void foo(CC); +}; + +#endif From 0f7400c4c97f813808e72b87a9ef73ab16d6bb4a Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Sat, 31 Aug 2024 12:30:32 +0200 Subject: [PATCH 14/14] [libc++] Add missing include to std/utilities/charconv/charconv.to.chars/integral.pass.cpp --- .../std/utilities/charconv/charconv.to.chars/integral.pass.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcxx/test/std/utilities/charconv/charconv.to.chars/integral.pass.cpp b/libcxx/test/std/utilities/charconv/charconv.to.chars/integral.pass.cpp index 77ae5ea1493b10..420b0e168539d8 100644 --- a/libcxx/test/std/utilities/charconv/charconv.to.chars/integral.pass.cpp +++ b/libcxx/test/std/utilities/charconv/charconv.to.chars/integral.pass.cpp @@ -18,6 +18,8 @@ // int base = 10) #include +#include + #include "test_macros.h" #include "charconv_test_helpers.h"