Skip to content

Commit 906c077

Browse files
committed
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 f0b96a5 + 9d89c6e commit 906c077

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"
@@ -1675,14 +1675,39 @@ def GetMemberOp : CIR_Op<"get_member"> {
16751675
let hasVerifier = 1;
16761676
}
16771677

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

16821708
def VecExtractOp : CIR_Op<"vec.extract", [Pure,
1683-
TypesMatchWith<"type of 'result' matches element type of 'vec'",
1684-
"vec", "result",
1685-
"$_self.cast<VectorType>().getEltType()">]> {
1709+
TypesMatchWith<"type of 'result' matches element type of 'vec'", "vec",
1710+
"result", "$_self.cast<VectorType>().getEltType()">]> {
16861711

16871712
let summary = "Extract one element from a vector object";
16881713
let description = [{
@@ -1694,7 +1719,7 @@ def VecExtractOp : CIR_Op<"vec.extract", [Pure,
16941719
let results = (outs CIR_AnyType:$result);
16951720

16961721
let assemblyFormat = [{
1697-
$vec `[` $index `:` type($index) `]` type($vec) `->` type($result) attr-dict
1722+
$vec `[` $index `:` type($index) `]` attr-dict `:` type($vec)
16981723
}];
16991724

17001725
let hasVerifier = 0;
@@ -1912,12 +1937,43 @@ def FuncOp : CIR_Op<"func", [
19121937
}
19131938

19141939
//===----------------------------------------------------------------------===//
1915-
// CallOp
1940+
// CallOp and TryCallOp
19161941
//===----------------------------------------------------------------------===//
19171942

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

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

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

1987-
/// Return the operand at index 'i', accounts for indirect call.
1988-
Value getArgOperand(unsigned i) {
1989-
if (!getCallee())
1990-
i++;
1991-
return getOperand(i);
1992-
}
2045+
Example:
19932046

1994-
/// Return the number of operands, , accounts for indirect call.
1995-
unsigned getNumArgOperands() {
1996-
if (!getCallee())
1997-
return this->getOperation()->getNumOperands()-1;
1998-
return this->getOperation()->getNumOperands();
1999-
}
2047+
```mlir
2048+
%r = cir.try_call @division(%1, %2), ^continue_A, ^abort, %0
2049+
```
20002050
}];
20012051

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

20072080
//===----------------------------------------------------------------------===//
@@ -2389,29 +2462,33 @@ def IterEndOp : CIR_Op<"iterator_end"> {
23892462
}
23902463

23912464
//===----------------------------------------------------------------------===//
2392-
// FAbsOp
2465+
// Floating Point Ops
23932466
//===----------------------------------------------------------------------===//
23942467

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

24162493
//===----------------------------------------------------------------------===//
24172494
// Variadic Operations
@@ -2576,29 +2653,11 @@ def StackRestoreOp : CIR_Op<"stack_restore"> {
25762653
let assemblyFormat = "$ptr attr-dict `:` qualified(type($ptr))";
25772654
}
25782655

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

26002659
def AsmFlavor : I32EnumAttr<
2601-
"AsmDialect",
2660+
"AsmFlavor",
26022661
"ATT or Intel",
26032662
[AsmATT, AsmIntel]> {
26042663
let cppNamespace = "::mlir::cir";
@@ -2608,26 +2667,57 @@ def CIR_InlineAsmOp : CIR_Op<"asm", [RecursiveMemoryEffects]> {
26082667
let description = [{
26092668
The `cir.asm` operation represents C/C++ asm inline.
26102669

2670+
CIR constraints strings follow barelly the same rules that are established
2671+
for the C level assembler constraints with several differences caused by
2672+
clang::AsmStmt processing.
2673+
2674+
Thus, numbers that appears in the constraint string may also refer to:
2675+
- the output variable index referenced by the input operands.
2676+
- the index of early-clobber operand
2677+
26112678
Example:
26122679
```C++
2613-
__asm__ volatile("xyz" : : : );
2614-
```
2615-
2680+
__asm__("foo" : : : );
2681+
__asm__("bar $42 %[val]" : [val] "=r" (x), "+&r"(x));
2682+
__asm__("baz $42 %[val]" : [val] "=r" (x), "+&r"(x) : "[val]"(y));
26162683
```
2684+
26172685
```mlir
2618-
cir.asm(x86_att, {"xyz"}) -> !void
2686+
cir.asm(x86_att, {"foo" ""})
2687+
cir.asm(x86_att, {"bar $$42 $0" "=r,=&r,1"})
2688+
cir.asm(x86_att, {"baz $$42 $0" "=r,=&r,0,1"})
26192689
```
26202690
}];
26212691

26222692
let results = (outs Optional<CIR_AnyType>:$res);
26232693

26242694
let arguments = (
26252695
ins StrAttr:$asm_string,
2626-
AsmFlavor:$asm_flavor);
2696+
StrAttr:$constraints,
2697+
AsmFlavor:$asm_flavor);
26272698

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

26332723
#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)