llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clangir Author: Priyanshu Kumar (Priyanshu3820) <details> <summary>Changes</summary> ## Summary Implements CIR IR generation for X86 sqrt builtin functions, addressing issue #<!-- -->167765. ## Details This PR adds support for lowering the following X86 `sqrt` builtins to CIR operations: - `__builtin_ia32_sqrtps` (128-bit float vector sqrt) - `__builtin_ia32_sqrtps256` (256-bit float vector sqrt) - `__builtin_ia32_sqrtps512` (512-bit float vector sqrt) - `__builtin_ia32_sqrtpd` (128-bit double vector sqrt) - `__builtin_ia32_sqrtpd256` (256-bit double vector sqrt) - `__builtin_ia32_sqrtpd512` (512-bit double vector sqrt) - `__builtin_ia32_sqrtph`, `__builtin_ia32_sqrtph256`, `__builtin_ia32_sqrtph512` (half precision) - `__builtin_ia32_vsqrtbf16*` variants (bfloat16) - Masked rounding variants with round/mask modifiers ## Changes Made ### New Files - `clang/include/clang/CIR/Dialect/IR/CIROps.h` - Wrapper header declaring CIR operations ### Modified Files - `clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp` - Added builtin cases for sqrt operations - `clang/include/clang/CIR/Dialect/IR/CIROps.td` - Defined `CIR_SqrtOp` operation - `clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td` - Added float type constraints ### Test Coverage - `clang/test/CIR/CodeGen/X86/cir-sqrtps-builtins.c` - LIT test cases covering all sqrt builtin variants with FileCheck validation ## Implementation Details The implementation generates proper `cir.sqrt` operations for: - Vector types: `<4xf32>`, `<8xf32>`, `<16xf32>`, `<2xf64>`, `<4xf64>`, `<8xf64>` etc. - Scalar types: `f32`, `f64`, `f16`, `bf16` - Type safety enforced through MLIR's `TypeConstraint` mechanism - Pure operation (no side effects), type-preserving (same type in/out) ## Testing All test cases pass locally with FileCheck validation. The implementation properly generates `cir.sqrt` operations for all sqrt builtin variants. ## Fixes Fixes #<!-- -->167765 --- Patch is 28.92 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/169310.diff 13 Files Affected: - (modified) clang/include/clang/CIR/Dialect/IR/CIRAttrs.td (+113) - (added) clang/include/clang/CIR/Dialect/IR/CIROps.h (+27) - (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+230-5) - (modified) clang/include/clang/CIR/Dialect/IR/CIRTypes.td (+3) - (modified) clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp (+13-1) - (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+22) - (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+93-1) - (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h (+14) - (added) clang/test/CIR/CodeGen/X86/cir-sqrtps-builtins.c (+46) - (added) clang/test/CIR/LowerToLLVM/sqrt-lowering.mlir (+20) - (added) clang/test/CIR/cir-sqrt-f32.mlir (+15) - (added) clang/test/CIR/cir-sqrt-f64.mlir (+12) - (added) clang/test/CIR/cir-sqrt-v4f32.mlir (+15) ``````````diff diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index 47ff9389e8028..12bc9cf7b5b04 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -822,6 +822,119 @@ def CIR_GlobalDtorAttr : CIR_GlobalCtorDtor<"Dtor", "dtor"> { }]; } +//===----------------------------------------------------------------------===// +// CXX SpecialMemberAttr +//===----------------------------------------------------------------------===// + +def CIR_CtorKind : CIR_I32EnumAttr<"CtorKind", "CXX Constructor Kind", [ + I32EnumAttrCase<"Custom", 0, "custom">, + I32EnumAttrCase<"Default", 1, "default">, + I32EnumAttrCase<"Copy", 2, "copy">, + I32EnumAttrCase<"Move", 3, "move">, +]> { + let genSpecializedAttr = 0; +} + +def CIR_CXXCtorAttr : CIR_Attr<"CXXCtor", "cxx_ctor"> { + let summary = "Marks a function as a C++ constructor"; + let description = [{ + This attribute identifies a C++ constructor and classifies its kind: + + - `custom`: a user-defined constructor + - `default`: a default constructor + - `copy`: a copy constructor + - `move`: a move constructor + + Example: + ```mlir + #cir.cxx_ctor<!rec_a, copy> + #cir.cxx_ctor<!rec_b, default, trivial> + ``` + }]; + + let parameters = (ins + "mlir::Type":$type, + EnumParameter<CIR_CtorKind>:$ctor_kind, + DefaultValuedParameter<"bool", "false">:$is_trivial + ); + + let builders = [ + AttrBuilderWithInferredContext<(ins "mlir::Type":$type, + CArg<"CtorKind", "cir::CtorKind::Custom">:$ctorKind, + CArg<"bool", "false">:$isTrivial), [{ + return $_get(type.getContext(), type, ctorKind, isTrivial); + }]>, + ]; + + let assemblyFormat = [{ + `<` $type `,` $ctor_kind (`,` `trivial` $is_trivial^)? `>` + }]; +} + +def CIR_CXXDtorAttr : CIR_Attr<"CXXDtor", "cxx_dtor"> { + let summary = "Marks a function as a CXX destructor"; + let description = [{ + This attribute identifies a C++ destructor. + }]; + + let parameters = (ins + "mlir::Type":$type, + DefaultValuedParameter<"bool", "false">:$is_trivial + ); + + let builders = [ + AttrBuilderWithInferredContext<(ins "mlir::Type":$type, + CArg<"bool", "false">:$isTrivial), [{ + return $_get(type.getContext(), type, isTrivial); + }]> + ]; + + let assemblyFormat = [{ + `<` $type (`,` `trivial` $is_trivial^)? `>` + }]; +} + +def CIR_AssignKind : CIR_I32EnumAttr<"AssignKind", "CXX Assignment Operator Kind", [ + I32EnumAttrCase<"Copy", 0, "copy">, + I32EnumAttrCase<"Move", 1, "move">, +]> { + let genSpecializedAttr = 0; +} + +def CIR_CXXAssignAttr : CIR_Attr<"CXXAssign", "cxx_assign"> { + let summary = "Marks a function as a CXX assignment operator"; + let description = [{ + This attribute identifies a C++ assignment operator and classifies its kind: + + - `copy`: a copy assignment + - `move`: a move assignment + }]; + + let parameters = (ins + "mlir::Type":$type, + EnumParameter<CIR_AssignKind>:$assign_kind, + DefaultValuedParameter<"bool", "false">:$is_trivial + ); + + let builders = [ + AttrBuilderWithInferredContext<(ins "mlir::Type":$type, + CArg<"AssignKind">:$assignKind, + CArg<"bool", "false">:$isTrivial), [{ + return $_get(type.getContext(), type, assignKind, isTrivial); + }]> + ]; + + let assemblyFormat = [{ + `<` $type `,` $assign_kind (`,` `trivial` $is_trivial^)? `>` + }]; +} + +def CIR_CXXSpecialMemberAttr : AnyAttrOf<[ + CIR_CXXCtorAttr, + CIR_CXXDtorAttr, + CIR_CXXAssignAttr +]>; + //===----------------------------------------------------------------------===// // BitfieldInfoAttr //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.h b/clang/include/clang/CIR/Dialect/IR/CIROps.h new file mode 100644 index 0000000000000..41da044b683a9 --- /dev/null +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.h @@ -0,0 +1,27 @@ +//===- CIROps.h - CIR dialect operations ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the operations in the CIR dialect. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CIR_DIALECT_IR_CIROPS_H +#define CLANG_CIR_DIALECT_IR_CIROPS_H + +#include "mlir/IR/Builders.h" +#include "mlir/IR/BuiltinOps.h" +#include "mlir/IR/BuiltinTypes.h" +#include "mlir/IR/OpDefinition.h" +#include "mlir/Interfaces/InferTypeOpInterface.h" + +#include "clang/CIR/Dialect/IR/CIRAttrs.h" +#include "clang/CIR/Dialect/IR/CIRTypes.h" + +#include "clang/CIR/Dialect/IR/CIROps.h.inc" + +#endif // CLANG_CIR_DIALECT_IR_CIROPS_H diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index e612d6a0ba886..3c59a0b2a3144 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -802,8 +802,8 @@ def CIR_ConditionOp : CIR_Op<"condition", [ //===----------------------------------------------------------------------===// defvar CIR_YieldableScopes = [ - "ArrayCtor", "ArrayDtor", "CaseOp", "DoWhileOp", "ForOp", "GlobalOp", "IfOp", - "ScopeOp", "SwitchOp", "TernaryOp", "WhileOp", "TryOp" + "ArrayCtor", "ArrayDtor", "AwaitOp", "CaseOp", "DoWhileOp", "ForOp", + "GlobalOp", "IfOp", "ScopeOp", "SwitchOp", "TernaryOp", "WhileOp", "TryOp" ]; def CIR_YieldOp : CIR_Op<"yield", [ @@ -2533,7 +2533,9 @@ def CIR_FuncOp : CIR_Op<"func", [ OptionalAttr<DictArrayAttr>:$res_attrs, OptionalAttr<FlatSymbolRefAttr>:$aliasee, CIR_OptionalPriorityAttr:$global_ctor_priority, - CIR_OptionalPriorityAttr:$global_dtor_priority); + CIR_OptionalPriorityAttr:$global_dtor_priority, + OptionalAttr<CIR_CXXSpecialMemberAttr>:$cxx_special_member + ); let regions = (region AnyRegion:$body); @@ -2572,7 +2574,32 @@ def CIR_FuncOp : CIR_Op<"func", [ //===------------------------------------------------------------------===// bool isDeclaration(); - }]; + + //===------------------------------------------------------------------===// + // C++ Special Member Functions + //===------------------------------------------------------------------===// + + /// Returns true if this function is a C++ special member function. + bool isCXXSpecialMemberFunction(); + + bool isCxxConstructor(); + bool isCxxDestructor(); + + /// Returns true if this function is a copy or move assignment operator. + bool isCxxSpecialAssignment(); + + /// Returns the kind of constructor this function represents, if any. + std::optional<CtorKind> getCxxConstructorKind(); + + /// Returns the kind of assignment operator (move, copy) this function + /// represents, if any. + std::optional<AssignKind> getCxxSpecialAssignKind(); + + /// Returns true if the function is a trivial C++ member functions such as + /// trivial default constructor, copy/move constructor, copy/move assignment, + /// or destructor. + bool isCxxTrivialMemberFunction(); +}]; let hasCustomAssemblyFormat = 1; let hasVerifier = 1; @@ -2752,6 +2779,100 @@ def CIR_CallOp : CIR_CallOpBase<"call", [NoRegionArguments]> { ]; } +//===----------------------------------------------------------------------===// +// AwaitOp +//===----------------------------------------------------------------------===// + +def CIR_AwaitKind : CIR_I32EnumAttr<"AwaitKind", "await kind", [ + I32EnumAttrCase<"Init", 0, "init">, + I32EnumAttrCase<"User", 1, "user">, + I32EnumAttrCase<"Yield", 2, "yield">, + I32EnumAttrCase<"Final", 3, "final"> +]>; + +def CIR_AwaitOp : CIR_Op<"await",[ + DeclareOpInterfaceMethods<RegionBranchOpInterface>, + RecursivelySpeculatable, NoRegionArguments +]> { + let summary = "Wraps C++ co_await implicit logic"; + let description = [{ + The under the hood effect of using C++ `co_await expr` roughly + translates to: + + ```c++ + // co_await expr; + + auto &&x = CommonExpr(); + if (!x.await_ready()) { + ... + x.await_suspend(...); + ... + } + x.await_resume(); + ``` + + `cir.await` represents this logic by using 3 regions: + - ready: covers veto power from x.await_ready() + - suspend: wraps actual x.await_suspend() logic + - resume: handles x.await_resume() + + Breaking this up in regions allows individual scrutiny of conditions + which might lead to folding some of them out. Lowerings coming out + of CIR, e.g. LLVM, should use the `suspend` region to track more + lower level codegen (e.g. intrinsic emission for coro.save/coro.suspend). + + There are also 4 flavors of `cir.await` available: + - `init`: compiler generated initial suspend via implicit `co_await`. + - `user`: also known as normal, representing a user written `co_await`. + - `yield`: user written `co_yield` expressions. + - `final`: compiler generated final suspend via implicit `co_await`. + + ```mlir + cir.scope { + ... // auto &&x = CommonExpr(); + cir.await(user, ready : { + ... // x.await_ready() + }, suspend : { + ... // x.await_suspend() + }, resume : { + ... // x.await_resume() + }) + } + ``` + + Note that resulution of the common expression is assumed to happen + as part of the enclosing await scope. + }]; + + let arguments = (ins CIR_AwaitKind:$kind); + let regions = (region SizedRegion<1>:$ready, + SizedRegion<1>:$suspend, + SizedRegion<1>:$resume); + let assemblyFormat = [{ + `(` $kind `,` + `ready` `:` $ready `,` + `suspend` `:` $suspend `,` + `resume` `:` $resume `,` + `)` + attr-dict + }]; + + let skipDefaultBuilders = 1; + let builders = [ + OpBuilder<(ins + "cir::AwaitKind":$kind, + CArg<"BuilderCallbackRef", + "nullptr">:$readyBuilder, + CArg<"BuilderCallbackRef", + "nullptr">:$suspendBuilder, + CArg<"BuilderCallbackRef", + "nullptr">:$resumeBuilder + )> + ]; + + let hasVerifier = 1; +} + //===----------------------------------------------------------------------===// // CopyOp //===----------------------------------------------------------------------===// @@ -4018,6 +4139,72 @@ def CIR_RotateOp : CIR_Op<"rotate", [Pure, SameOperandsAndResultType]> { let hasFolder = 1; } +//===----------------------------------------------------------------------===// +// FPClass Test Flags +//===----------------------------------------------------------------------===// + +def FPClassTestEnum : CIR_I32EnumAttr<"FPClassTest", "floating-point class test flags", [ + // Basic flags + I32EnumAttrCase<"SignalingNaN", 1, "fcSNan">, + I32EnumAttrCase<"QuietNaN", 2, "fcQNan">, + I32EnumAttrCase<"NegativeInfinity", 4, "fcNegInf">, + I32EnumAttrCase<"NegativeNormal", 8, "fcNegNormal">, + I32EnumAttrCase<"NegativeSubnormal", 16, "fcNegSubnormal">, + I32EnumAttrCase<"NegativeZero", 32, "fcNegZero">, + I32EnumAttrCase<"PositiveZero", 64, "fcPosZero">, + I32EnumAttrCase<"PositiveSubnormal", 128, "fcPosSubnormal">, + I32EnumAttrCase<"PositiveNormal", 256, "fcPosNormal">, + I32EnumAttrCase<"PositiveInfinity", 512, "fcPosInf">, + + // Composite flags + I32EnumAttrCase<"Nan", 3, "fcNan">, // fcSNan | fcQNan + I32EnumAttrCase<"Infinity", 516, "fcInf">, // fcPosInf | fcNegInf + I32EnumAttrCase<"Normal", 264, "fcNormal">, // fcPosNormal | fcNegNormal + I32EnumAttrCase<"Subnormal", 144, "fcSubnormal">, // fcPosSubnormal | fcNegSubnormal + I32EnumAttrCase<"Zero", 96, "fcZero">, // fcPosZero | fcNegZero + I32EnumAttrCase<"PositiveFinite", 448, "fcPosFinite">,// fcPosNormal | fcPosSubnormal | fcPosZero + I32EnumAttrCase<"NegativeFinite", 56, "fcNegFinite">, // fcNegNormal | fcNegSubnormal | fcNegZero + I32EnumAttrCase<"Finite", 504, "fcFinite">, // fcPosFinite | fcNegFinite + I32EnumAttrCase<"Positive", 960, "fcPositive">, // fcPosFinite | fcPosInf + I32EnumAttrCase<"Negative", 60, "fcNegative">, // fcNegFinite | fcNegInf + I32EnumAttrCase<"All", 1023, "fcAllFlags">, // fcNan | fcInf | fcFinite +]> { + let cppNamespace = "::cir"; +} + +def CIR_IsFPClassOp : CIR_Op<"is_fp_class"> { + let summary = "Corresponding to the `__builtin_fpclassify` builtin function in clang"; + + let description = [{ + The `cir.is_fp_class` operation takes a floating-point value as its first + argument and a bitfield of flags as its second argument. The operation + returns a boolean value indicating whether the floating-point value + satisfies the given flags. + + The flags must be a compile time constant and the values are: + + | Bit # | floating-point class | + | ----- | -------------------- | + | 0 | Signaling NaN | + | 1 | Quiet NaN | + | 2 | Negative infinity | + | 3 | Negative normal | + | 4 | Negative subnormal | + | 5 | Negative zero | + | 6 | Positive zero | + | 7 | Positive subnormal | + | 8 | Positive normal | + | 9 | Positive infinity | + }]; + + let arguments = (ins CIR_AnyFloatType:$src, + FPClassTestEnum:$flags); + let results = (outs CIR_BoolType:$result); + let assemblyFormat = [{ + $src `,` $flags `:` functional-type($src, $result) attr-dict + }]; +} + //===----------------------------------------------------------------------===// // Assume Operations //===----------------------------------------------------------------------===// @@ -4202,7 +4389,7 @@ def CIR_ObjSizeOp : CIR_Op<"objsize", [Pure]> { When the `min` attribute is present, the operation returns the minimum guaranteed accessible size. When absent (max mode), it returns the maximum possible object size. Corresponds to `llvm.objectsize`'s `min` argument. - + The `dynamic` attribute determines if the value should be evaluated at runtime. Corresponds to `llvm.objectsize`'s `dynamic` argument. @@ -4658,6 +4845,44 @@ def CIR_TryOp : CIR_Op<"try",[ let hasLLVMLowering = false; } +//===----------------------------------------------------------------------===// +// Exception related: EhInflightOp +//===----------------------------------------------------------------------===// + +def CIR_EhInflightOp : CIR_Op<"eh.inflight_exception"> { + let summary = "Materialize the catch clause formal parameter"; + let description = [{ + `cir.eh.inflight_exception` returns two values: + - `exception_ptr`: The exception pointer for the inflight exception + - `type_id`: the type info index for the exception type + This operation is expected to be the first operation in the unwind + destination basic blocks of a `cir.try_call` operation. + + The `cleanup` attribute indicates that clean up code must be run before the + values produced by this operation are used to dispatch the exception. This + cleanup code must be executed even if the exception is not caught. + This helps CIR to pass down more accurate information for LLVM lowering + to landingpads. + + Example: + + ```mlir + %exception_ptr, %type_id = cir.eh.inflight_exception + %exception_ptr, %type_id = cir.eh.inflight_exception [@_ZTIi, @_ZTIPKc] + %exception_ptr, %type_id = cir.eh.inflight_exception cleanup + `` + }]; + + let arguments = (ins UnitAttr:$cleanup, + OptionalAttr<FlatSymbolRefArrayAttr>:$catch_type_list); + let results = (outs CIR_VoidPtrType:$exception_ptr, CIR_UInt32:$type_id); + let assemblyFormat = [{ + (`cleanup` $cleanup^)? + ($catch_type_list^)? + attr-dict + }]; +} + //===----------------------------------------------------------------------===// // Atomic operations //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index 313184764f536..3e062add6633a 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -657,6 +657,9 @@ def CIR_RecordType : CIR_Type<"Record", "record", [ } llvm_unreachable("Invalid value for RecordType::getKind()"); } + mlir::Type getElementType(size_t idx) { + return getMembers()[idx]; + } std::string getPrefixedName() { return getKindAsStr() + "." + getName().getValue().str(); } diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp index ee6900141647f..4864069e8d24b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp @@ -684,7 +684,19 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, case X86::BI__builtin_ia32_sqrtpd256: case X86::BI__builtin_ia32_sqrtpd: case X86::BI__builtin_ia32_sqrtps256: - case X86::BI__builtin_ia32_sqrtps: + case X86::BI__builtin_ia32_sqrtps: { + auto loc = getLoc(E->getExprLoc()); + assert(E->getNumArgs() == 1 && "__builtin_ia32_sqrtps takes one argument"); + mlir::Value arg = emitScalarExpr(E->getArg(0)); + mlir::Type argTy = arg.getType(); + if (auto vecTy = argTy.dyn_cast<mlir::VectorType>()) { + assert(vecTy.getNumElements() == 4 && + vecTy.getElementType().isa<mlir::FloatType>() && + "__builtin_ia32_sqrtps expects <4 x float> / __m128"); + } + auto sqrt = builder.create<cir::SqrtOp>(loc, argTy, arg); + return sqrt.getResult(); + } case X86::BI__builtin_ia32_sqrtph256: case X86::BI__builtin_ia32_sqrtph: case X86::BI__builtin_ia32_sqrtph512: diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 22aada882defc..d1b73e56dee83 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -910,6 +910,28 @@ static mlir::LogicalResult checkReturnAndFunction(cir::ReturnOp op, return mlir::success(); } +mlir::LogicalResult cir::SqrtOp::verify() { + auto inTy = getInput().getType(); + auto outTy = getResult().getType(); + + if (inTy != outTy) + return emitOpError("input and result types must match"); + + // Accept scalar CIR/MLIR floating types. + if (inTy.isa<mlir::FloatType>()) + return mlir::success(); + + // Accept CIR vector of floats. + if (auto vecTy = inTy.dyn_cast<cir::VectorType>()) { + if (vecTy.getElementType().isa<mlir::FloatType>()) + return mlir::success(); + } + + return emitOpError( + "requires a floating-point scalar or vector-of-floating-point element type"); +} + + mlir::LogicalResult cir::ReturnOp::verify() { // Returns can be present in multiple different scopes, get the // wrapping function and start from there. diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index d43a462a25092..526e23a927c09 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1,4 +1,4 @@ -//====- LowerToLLVM.cpp - Lowering from CIR to LLVMIR ---------------------===// +//====- LowerToLLVM.cpp - Lowering from CIR to LLVMIR ---------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -18,6 +18,7 @@ #include "mlir/Conversion/LLVMCommon/TypeConverter.h" #include "mlir/Dialect/DLTI/DLTI.h" #include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/Dialect/LLVMIR/IR/LLVMOps.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/Dialect/LLVMIR/LLVMTypes.h" #include "mlir/IR/BuiltinAttributes.h" @@ -30,6 +31,7 @@ #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Export.h" #include "mlir/Transforms/DialectCon... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/169310 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
