Skip to content

Commit 9d89c6e

Browse files
committed
Update base for Update on "[CIR][IR] Implement cir.continue operation"
Detaches the representation of the C/C++ `continue` statement into a separate operation. This simplifies mostly lowering and verifications related to `continue` statements, as well as the definition and lowering of the `cir.yield` operation. A few checks regarding region terminators were also removed from the lowering stage, since they are already enforced by MLIR. [ghstack-poisoned]
2 parents 7c54a88 + 0e4bbf1 commit 9d89c6e

29 files changed

+1777
-270
lines changed

clang/include/clang/CIR/Dialect/IR/CIRDialect.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "clang/CIR/Dialect/IR/CIRTypes.h"
3333

3434
#include "clang/CIR/Interfaces/ASTAttrInterfaces.h"
35+
#include "clang/CIR/Interfaces/CIROpInterfaces.h"
3536

3637
namespace mlir {
3738
namespace OpTrait {

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 171 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ include "clang/CIR/Dialect/IR/CIRTypes.td"
1919
include "clang/CIR/Dialect/IR/CIRAttrs.td"
2020

2121
include "clang/CIR/Interfaces/ASTAttrInterfaces.td"
22+
include "clang/CIR/Interfaces/CIROpInterfaces.td"
2223

23-
include "mlir/Interfaces/CallInterfaces.td"
2424
include "mlir/Interfaces/ControlFlowInterfaces.td"
2525
include "mlir/Interfaces/FunctionInterfaces.td"
2626
include "mlir/Interfaces/InferTypeOpInterface.td"
@@ -1672,14 +1672,39 @@ def GetMemberOp : CIR_Op<"get_member"> {
16721672
let hasVerifier = 1;
16731673
}
16741674

1675+
//===----------------------------------------------------------------------===//
1676+
// VecInsertOp
1677+
//===----------------------------------------------------------------------===//
1678+
1679+
def VecInsertOp : CIR_Op<"vec.insert", [Pure,
1680+
TypesMatchWith<"argument type matches vector element type", "vec", "value",
1681+
"$_self.cast<VectorType>().getEltType()">,
1682+
AllTypesMatch<["result", "vec"]>]> {
1683+
1684+
let summary = "Insert one element into a vector object";
1685+
let description = [{
1686+
The `cir.vec.insert` operation replaces the element of the given vector at
1687+
the given index with the given value. The new vector with the inserted
1688+
element is returned.
1689+
}];
1690+
1691+
let arguments = (ins CIR_VectorType:$vec, AnyType:$value, CIR_IntType:$index);
1692+
let results = (outs CIR_VectorType:$result);
1693+
1694+
let assemblyFormat = [{
1695+
$value `,` $vec `[` $index `:` type($index) `]` attr-dict `:` type($vec)
1696+
}];
1697+
1698+
let hasVerifier = 0;
1699+
}
1700+
16751701
//===----------------------------------------------------------------------===//
16761702
// VecExtractOp
16771703
//===----------------------------------------------------------------------===//
16781704

16791705
def VecExtractOp : CIR_Op<"vec.extract", [Pure,
1680-
TypesMatchWith<"type of 'result' matches element type of 'vec'",
1681-
"vec", "result",
1682-
"$_self.cast<VectorType>().getEltType()">]> {
1706+
TypesMatchWith<"type of 'result' matches element type of 'vec'", "vec",
1707+
"result", "$_self.cast<VectorType>().getEltType()">]> {
16831708

16841709
let summary = "Extract one element from a vector object";
16851710
let description = [{
@@ -1691,7 +1716,7 @@ def VecExtractOp : CIR_Op<"vec.extract", [Pure,
16911716
let results = (outs CIR_AnyType:$result);
16921717

16931718
let assemblyFormat = [{
1694-
$vec `[` $index `:` type($index) `]` type($vec) `->` type($result) attr-dict
1719+
$vec `[` $index `:` type($index) `]` attr-dict `:` type($vec)
16951720
}];
16961721

16971722
let hasVerifier = 0;
@@ -1909,12 +1934,43 @@ def FuncOp : CIR_Op<"func", [
19091934
}
19101935

19111936
//===----------------------------------------------------------------------===//
1912-
// CallOp
1937+
// CallOp and TryCallOp
19131938
//===----------------------------------------------------------------------===//
19141939

1915-
def CallOp : CIR_Op<"call",
1916-
[DeclareOpInterfaceMethods<CallOpInterface>,
1917-
DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
1940+
class CIR_CallOp<string mnemonic> :
1941+
Op<CIR_Dialect, mnemonic,
1942+
[DeclareOpInterfaceMethods<CIRCallOpInterface>,
1943+
DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
1944+
let extraClassDeclaration = [{
1945+
/// Get the argument operands to the called function.
1946+
OperandRange getArgOperands() {
1947+
return {arg_operand_begin(), arg_operand_end()};
1948+
}
1949+
1950+
MutableOperandRange getArgOperandsMutable() {
1951+
llvm_unreachable("NYI");
1952+
}
1953+
1954+
/// Return the callee of this operation
1955+
CallInterfaceCallable getCallableForCallee() {
1956+
return (*this)->getAttrOfType<SymbolRefAttr>("callee");
1957+
}
1958+
1959+
/// Set the callee for this operation.
1960+
void setCalleeFromCallable(::mlir::CallInterfaceCallable callee) {
1961+
if (auto calling =
1962+
(*this)->getAttrOfType<mlir::SymbolRefAttr>(getCalleeAttrName()))
1963+
(*this)->setAttr(getCalleeAttrName(), callee.get<mlir::SymbolRefAttr>());
1964+
setOperand(0, callee.get<mlir::Value>());
1965+
}
1966+
}];
1967+
1968+
let hasCustomAssemblyFormat = 1;
1969+
let skipDefaultBuilders = 1;
1970+
let hasVerifier = 0;
1971+
}
1972+
1973+
def CallOp : CIR_CallOp<"call"> {
19181974
let summary = "call operation";
19191975
let description = [{
19201976
The `call` operation represents a direct call to a function that is within
@@ -1966,39 +2022,56 @@ def CallOp : CIR_Op<"call",
19662022
$_state.addAttribute("callee", callee);
19672023
$_state.addTypes(resType);
19682024
}]>];
2025+
}
19692026

1970-
let extraClassDeclaration = [{
1971-
mlir::Value getIndirectCallee() {
1972-
assert(!getCallee() && "only works for indirect call");
1973-
return *arg_operand_begin();
1974-
}
2027+
def TryCallOp : CIR_CallOp<"try_call"> {
2028+
let summary = "try call operation";
2029+
let description = [{
2030+
Works very similar to `cir.call` but passes down an exception object
2031+
in case anything is thrown by the callee. Upon the callee throwing,
2032+
`cir.try_call` goes to current `cir.scope`'s `abort` label, otherwise
2033+
execution follows to the `continue` label.
19752034

1976-
operand_iterator arg_operand_begin() {
1977-
auto arg_begin = operand_begin();
1978-
if (!getCallee())
1979-
arg_begin++;
1980-
return arg_begin;
1981-
}
1982-
operand_iterator arg_operand_end() { return operand_end(); }
2035+
To walk the operands for this operation, use `getNumArgOperands()`,
2036+
`getArgOperand()`, `getArgOperands()`, `arg_operand_begin()` and
2037+
`arg_operand_begin()`. Avoid using `getNumOperands()`, `getOperand()`,
2038+
`operand_begin()`, etc, direclty - might be misleading given the
2039+
exception object address is also part of the raw operation's operands.
2040+
``
19832041

1984-
/// Return the operand at index 'i', accounts for indirect call.
1985-
Value getArgOperand(unsigned i) {
1986-
if (!getCallee())
1987-
i++;
1988-
return getOperand(i);
1989-
}
2042+
Example:
19902043

1991-
/// Return the number of operands, , accounts for indirect call.
1992-
unsigned getNumArgOperands() {
1993-
if (!getCallee())
1994-
return this->getOperation()->getNumOperands()-1;
1995-
return this->getOperation()->getNumOperands();
1996-
}
2044+
```mlir
2045+
%r = cir.try_call @division(%1, %2), ^continue_A, ^abort, %0
2046+
```
19972047
}];
19982048

1999-
let hasCustomAssemblyFormat = 1;
2000-
let skipDefaultBuilders = 1;
2001-
let hasVerifier = 0;
2049+
let arguments = (ins OptionalAttr<FlatSymbolRefAttr>:$callee,
2050+
Variadic<CIR_AnyType>:$operands,
2051+
OptionalAttr<ASTCallExprInterface>:$ast);
2052+
let results = (outs Variadic<CIR_AnyType>);
2053+
2054+
let builders = [
2055+
OpBuilder<(ins "FuncOp":$callee, CArg<"ValueRange", "{}">:$operands), [{
2056+
$_state.addOperands(operands);
2057+
$_state.addAttribute("callee", SymbolRefAttr::get(callee));
2058+
if (!callee.getFunctionType().isVoid())
2059+
$_state.addTypes(callee.getFunctionType().getReturnType());
2060+
}]>,
2061+
OpBuilder<(ins "Value":$ind_target,
2062+
"FuncType":$fn_type,
2063+
CArg<"ValueRange", "{}">:$operands), [{
2064+
$_state.addOperands(ValueRange{ind_target});
2065+
$_state.addOperands(operands);
2066+
if (!fn_type.isVoid())
2067+
$_state.addTypes(fn_type.getReturnType());
2068+
}]>,
2069+
OpBuilder<(ins "SymbolRefAttr":$callee, "mlir::Type":$resType,
2070+
CArg<"ValueRange", "{}">:$operands), [{
2071+
$_state.addOperands(operands);
2072+
$_state.addAttribute("callee", callee);
2073+
$_state.addTypes(resType);
2074+
}]>];
20022075
}
20032076

20042077
//===----------------------------------------------------------------------===//
@@ -2386,29 +2459,33 @@ def IterEndOp : CIR_Op<"iterator_end"> {
23862459
}
23872460

23882461
//===----------------------------------------------------------------------===//
2389-
// FAbsOp
2462+
// Floating Point Ops
23902463
//===----------------------------------------------------------------------===//
23912464

2392-
def FAbsOp : CIR_Op<"fabs", [Pure, SameOperandsAndResultType]> {
2465+
class UnaryFPToFPBuiltinOp<string mnemonic>
2466+
: CIR_Op<mnemonic, [Pure, SameOperandsAndResultType]> {
23932467
let arguments = (ins AnyFloat:$src);
23942468
let results = (outs AnyFloat:$result);
2395-
let summary = "Returns absolute value for floating-point input.";
2396-
let description = [{
2397-
Equivalent to libc's `fabs` and LLVM's intrinsic with the same name.
2398-
2399-
Examples:
2400-
2401-
```mlir
2402-
%1 = cir.const(1.0 : f64) : f64
2403-
%2 = cir.fabs %1 : f64
2404-
```
2405-
}];
2406-
2407-
let assemblyFormat = [{
2408-
$src `:` type($src) attr-dict
2409-
}];
2410-
let hasVerifier = 0;
2411-
}
2469+
let summary = "libc builtin equivalent ignoring "
2470+
"floating point exceptions and errno";
2471+
let assemblyFormat = "$src `:` type($src) attr-dict";
2472+
}
2473+
2474+
def CeilOp : UnaryFPToFPBuiltinOp<"ceil">;
2475+
def CosOp : UnaryFPToFPBuiltinOp<"cos">;
2476+
def ExpOp : UnaryFPToFPBuiltinOp<"exp">;
2477+
def Exp2Op : UnaryFPToFPBuiltinOp<"exp2">;
2478+
def FloorOp : UnaryFPToFPBuiltinOp<"floor">;
2479+
def FAbsOp : UnaryFPToFPBuiltinOp<"fabs">;
2480+
def LogOp : UnaryFPToFPBuiltinOp<"log">;
2481+
def Log10Op : UnaryFPToFPBuiltinOp<"log10">;
2482+
def Log2Op : UnaryFPToFPBuiltinOp<"log2">;
2483+
def NearbyintOp : UnaryFPToFPBuiltinOp<"nearbyint">;
2484+
def RintOp : UnaryFPToFPBuiltinOp<"rint">;
2485+
def RoundOp : UnaryFPToFPBuiltinOp<"round">;
2486+
def SinOp : UnaryFPToFPBuiltinOp<"sin">;
2487+
def SqrtOp : UnaryFPToFPBuiltinOp<"sqrt">;
2488+
def TruncOp : UnaryFPToFPBuiltinOp<"trunc">;
24122489

24132490
//===----------------------------------------------------------------------===//
24142491
// Variadic Operations
@@ -2573,29 +2650,11 @@ def StackRestoreOp : CIR_Op<"stack_restore"> {
25732650
let assemblyFormat = "$ptr attr-dict `:` qualified(type($ptr))";
25742651
}
25752652

2576-
//===----------------------------------------------------------------------===//
2577-
// Operations Lowered Directly to LLVM IR
2578-
//
2579-
// These operations are hacks to get around missing features in LLVM's dialect.
2580-
// Use it sparingly and remove it once the features are added.
2581-
//===----------------------------------------------------------------------===//
2582-
2583-
def ZeroInitConstOp : CIR_Op<"llvmir.zeroinit", [Pure]>,
2584-
Results<(outs AnyType:$result)> {
2585-
let summary = "Zero initializes a constant value of a given type";
2586-
let description = [{
2587-
This operation circumvents the lack of a zeroinitializer operation in LLVM
2588-
Dialect. It can zeroinitialize any LLVM type.
2589-
}];
2590-
let assemblyFormat = "attr-dict `:` type($result)";
2591-
let hasVerifier = 0;
2592-
}
2593-
25942653
def AsmATT : I32EnumAttrCase<"x86_att", 0>;
25952654
def AsmIntel : I32EnumAttrCase<"x86_intel", 1>;
25962655

25972656
def AsmFlavor : I32EnumAttr<
2598-
"AsmDialect",
2657+
"AsmFlavor",
25992658
"ATT or Intel",
26002659
[AsmATT, AsmIntel]> {
26012660
let cppNamespace = "::mlir::cir";
@@ -2605,26 +2664,57 @@ def CIR_InlineAsmOp : CIR_Op<"asm", [RecursiveMemoryEffects]> {
26052664
let description = [{
26062665
The `cir.asm` operation represents C/C++ asm inline.
26072666

2667+
CIR constraints strings follow barelly the same rules that are established
2668+
for the C level assembler constraints with several differences caused by
2669+
clang::AsmStmt processing.
2670+
2671+
Thus, numbers that appears in the constraint string may also refer to:
2672+
- the output variable index referenced by the input operands.
2673+
- the index of early-clobber operand
2674+
26082675
Example:
26092676
```C++
2610-
__asm__ volatile("xyz" : : : );
2611-
```
2612-
2677+
__asm__("foo" : : : );
2678+
__asm__("bar $42 %[val]" : [val] "=r" (x), "+&r"(x));
2679+
__asm__("baz $42 %[val]" : [val] "=r" (x), "+&r"(x) : "[val]"(y));
26132680
```
2681+
26142682
```mlir
2615-
cir.asm(x86_att, {"xyz"}) -> !void
2683+
cir.asm(x86_att, {"foo" ""})
2684+
cir.asm(x86_att, {"bar $$42 $0" "=r,=&r,1"})
2685+
cir.asm(x86_att, {"baz $$42 $0" "=r,=&r,0,1"})
26162686
```
26172687
}];
26182688

26192689
let results = (outs Optional<CIR_AnyType>:$res);
26202690

26212691
let arguments = (
26222692
ins StrAttr:$asm_string,
2623-
AsmFlavor:$asm_flavor);
2693+
StrAttr:$constraints,
2694+
AsmFlavor:$asm_flavor);
26242695

26252696
let assemblyFormat = [{
2626-
`(`$asm_flavor`,` `{` $asm_string `}` `)` attr-dict `:` type($res)
2627-
}];
2697+
`(`$asm_flavor`,` `{` $asm_string $constraints `}` `)` attr-dict
2698+
`:` type($res)
2699+
}];
2700+
}
2701+
2702+
//===----------------------------------------------------------------------===//
2703+
// Operations Lowered Directly to LLVM IR
2704+
//
2705+
// These operations are hacks to get around missing features in LLVM's dialect.
2706+
// Use it sparingly and remove it once the features are added.
2707+
//===----------------------------------------------------------------------===//
2708+
2709+
def ZeroInitConstOp : CIR_Op<"llvmir.zeroinit", [Pure]>,
2710+
Results<(outs AnyType:$result)> {
2711+
let summary = "Zero initializes a constant value of a given type";
2712+
let description = [{
2713+
This operation circumvents the lack of a zeroinitializer operation in LLVM
2714+
Dialect. It can zeroinitialize any LLVM type.
2715+
}];
2716+
let assemblyFormat = "attr-dict `:` type($result)";
2717+
let hasVerifier = 0;
26282718
}
26292719

26302720
#endif // MLIR_CIR_DIALECT_CIR_OPS
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//===- CIROpInterfaces.h - CIR Op Interfaces --------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef MLIR_INTERFACES_CIR_OP_H_
10+
#define MLIR_INTERFACES_CIR_OP_H_
11+
12+
#include "mlir/IR/Attributes.h"
13+
#include "mlir/IR/Operation.h"
14+
#include "mlir/IR/Value.h"
15+
#include "mlir/Interfaces/CallInterfaces.h"
16+
17+
#include "clang/AST/Attr.h"
18+
#include "clang/AST/DeclTemplate.h"
19+
#include "clang/AST/Mangle.h"
20+
21+
namespace mlir {
22+
namespace cir {} // namespace cir
23+
} // namespace mlir
24+
25+
/// Include the generated interface declarations.
26+
#include "clang/CIR/Interfaces/CIROpInterfaces.h.inc"
27+
28+
namespace mlir {
29+
namespace cir {} // namespace cir
30+
} // namespace mlir
31+
32+
#endif // MLIR_INTERFACES_CIR_OP_H_

0 commit comments

Comments
 (0)