[clang] [CIR][X86] Implement lowering for sqrt builtins (PR #169310)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 24 02:19:37 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
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
More information about the cfe-commits
mailing list