Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LLVM_CLANG_CIR_DIALECT_BUILDER_CIRBASEBUILDER_H
#define LLVM_CLANG_CIR_DIALECT_BUILDER_CIRBASEBUILDER_H

#include "clang/AST/CharUnits.h"
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
Expand Down Expand Up @@ -51,6 +52,49 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return cir::ConstPtrAttr::get(
getContext(), mlir::cast<cir::PointerType>(type), valueAttr);
}

mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType,
mlir::Type type, llvm::StringRef name,
mlir::IntegerAttr alignment,
mlir::Value dynAllocSize) {
return create<cir::AllocaOp>(loc, addrType, type, name, alignment,
dynAllocSize);
}

cir::LoadOp createLoad(mlir::Location loc, mlir::Value ptr,
bool isVolatile = false, uint64_t alignment = 0) {
mlir::IntegerAttr intAttr;
if (alignment)
intAttr = mlir::IntegerAttr::get(
mlir::IntegerType::get(ptr.getContext(), 64), alignment);

return create<cir::LoadOp>(loc, ptr);
}

//
// Block handling helpers
// ----------------------
//
static OpBuilder::InsertPoint getBestAllocaInsertPoint(mlir::Block *block) {
auto last =
std::find_if(block->rbegin(), block->rend(), [](mlir::Operation &op) {
// TODO: Add LabelOp missing feature here
return mlir::isa<cir::AllocaOp>(&op);
});

if (last != block->rend())
return OpBuilder::InsertPoint(block, ++mlir::Block::iterator(&*last));
return OpBuilder::InsertPoint(block, block->begin());
};

mlir::IntegerAttr getSizeFromCharUnits(mlir::MLIRContext *ctx,
clang::CharUnits size) {
// Note that mlir::IntegerType is used instead of cir::IntType here
// because we don't need sign information for this to be useful, so keep
// it simple.
return mlir::IntegerAttr::get(mlir::IntegerType::get(ctx, 64),
size.getQuantity());
}
};

} // namespace cir
Expand Down
15 changes: 15 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,21 @@ def CIR_BoolAttr : CIR_Attr<"Bool", "bool", [TypedAttrInterface]> {
}];
}

//===----------------------------------------------------------------------===//
// UndefAttr
//===----------------------------------------------------------------------===//

def UndefAttr : CIR_Attr<"Undef", "undef", [TypedAttrInterface]> {
let summary = "Represent an undef constant";
let description = [{
The UndefAttr represents an undef constant, corresponding to LLVM's notion
of undef.
}];

let parameters = (ins AttributeSelfTypeParameter<"">:$type);
let assemblyFormat = [{}];
}

//===----------------------------------------------------------------------===//
// IntegerAttr
//===----------------------------------------------------------------------===//
Expand Down
143 changes: 143 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,149 @@ def ConstantOp : CIR_Op<"const",
let hasFolder = 1;
}

//===----------------------------------------------------------------------===//
// AllocaOp
//===----------------------------------------------------------------------===//

class AllocaTypesMatchWith<string summary, string lhsArg, string rhsArg,
string transform, string comparator = "std::equal_to<>()">
: PredOpTrait<summary, CPred<
comparator # "(" #
!subst("$_self", "$" # lhsArg # ".getType()", transform) #
", $" # rhsArg # ")">> {
string lhs = lhsArg;
string rhs = rhsArg;
string transformer = transform;
}

def AllocaOp : CIR_Op<"alloca", [
AllocaTypesMatchWith<"'allocaType' matches pointee type of 'addr'",
"addr", "allocaType",
"cast<PointerType>($_self).getPointee()">,
DeclareOpInterfaceMethods<PromotableAllocationOpInterface>]> {
let summary = "Defines a scope-local variable";
let description = [{
The `cir.alloca` operation defines a scope-local variable.

The presence `init` attribute indicates that the local variable represented
by this alloca was originally initialized in C/C++ source code. In such
cases, the first use contains the initialization (a cir.store, a cir.call
to a ctor, etc).

The presence of the `const` attribute indicates that the local variable is
declared with C/C++ `const` keyword.

The `dynAllocSize` specifies the size to dynamically allocate on the stack
and ignores the allocation size based on the original type. This is useful
when handling VLAs and is omitted when declaring regular local variables.

The result type is a pointer to the input's type.

Example:

```mlir
// int count = 3;
%0 = cir.alloca i32, !cir.ptr<i32>, ["count", init] {alignment = 4 : i64}

// int *ptr;
%1 = cir.alloca !cir.ptr<i32>, !cir.ptr<!cir.ptr<i32>>, ["ptr"] {alignment = 8 : i64}
...
```
}];

let arguments = (ins
Optional<PrimitiveInt>:$dynAllocSize,
TypeAttr:$allocaType,
StrAttr:$name,
UnitAttr:$init,
UnitAttr:$constant,
ConfinedAttr<OptionalAttr<I64Attr>, [IntMinValue<0>]>:$alignment,
OptionalAttr<ArrayAttr>:$annotations
);

let results = (outs Res<CIR_PointerType, "",
[MemAlloc<AutomaticAllocationScopeResource>]>:$addr);

let skipDefaultBuilders = 1;
let builders = [
OpBuilder<(ins "mlir::Type":$addr, "mlir::Type":$allocaType,
"llvm::StringRef":$name,
"mlir::IntegerAttr":$alignment)>,

OpBuilder<(ins "mlir::Type":$addr,
"mlir::Type":$allocaType,
"llvm::StringRef":$name,
"mlir::IntegerAttr":$alignment,
"mlir::Value":$dynAllocSize),
[{
if (dynAllocSize)
$_state.addOperands(dynAllocSize);
build($_builder, $_state, addr, allocaType, name, alignment);
}]>
];

let extraClassDeclaration = [{
// Whether the alloca input type is a pointer.
bool isPointerType() { return ::mlir::isa<::cir::PointerType>(getAllocaType()); }

bool isDynamic() { return (bool)getDynAllocSize(); }
}];

let assemblyFormat = [{
$allocaType `,` qualified(type($addr)) `,`
($dynAllocSize^ `:` type($dynAllocSize) `,`)?
`[` $name
(`,` `init` $init^)?
(`,` `const` $constant^)?
`]`
($annotations^)? attr-dict
}];

let hasVerifier = 0;
}

//===----------------------------------------------------------------------===//
// LoadOp
//===----------------------------------------------------------------------===//

def LoadOp : CIR_Op<"load", [
TypesMatchWith<"type of 'result' matches pointee type of 'addr'",
"addr", "result",
"cast<PointerType>($_self).getPointee()">,
DeclareOpInterfaceMethods<PromotableMemOpInterface>]> {

let summary = "Load value from memory adddress";
let description = [{
`cir.load` reads a value (lvalue to rvalue conversion) given an address
backed up by a `cir.ptr` type. A unit attribute `deref` can be used to
mark the resulting value as used by another operation to dereference
a pointer. A unit attribute `volatile` can be used to indicate a volatile
loading. Load can be marked atomic by using `atomic(<mem_order>)`.

`align` can be used to specify an alignment that's different from the
default, which is computed from `result`'s type ABI data layout.

Example:

```mlir

// Read from local variable, address in %0.
%1 = cir.load %0 : !cir.ptr<i32>, i32
```
}];

let arguments = (ins Arg<CIR_PointerType, "the address to load from",
[MemRead]>:$addr
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The closing paren probably belongs in the line above?

let results = (outs CIR_AnyType:$result);

let assemblyFormat = [{
$addr `:` qualified(type($addr)) `,` type($result) attr-dict
}];

// FIXME: add verifier.
}

//===----------------------------------------------------------------------===//
// ReturnOp
//===----------------------------------------------------------------------===//
Expand Down
18 changes: 18 additions & 0 deletions clang/include/clang/CIR/MissingFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,24 @@ struct MissingFeatures {
static bool opGlobalConstant() { return false; }
static bool opGlobalAlignment() { return false; }
static bool opGlobalLinkage() { return false; }

// Load attributes
static bool opLoadThreadLocal() { return false; }
static bool opLoadEmitScalarRangeCheck() { return false; }
static bool opLoadBooleanRepresentation() { return false; }

// AllocaOp handling
static bool opAllocaVarDeclContext() { return false; }
static bool opAllocaStaticLocal() { return false; }
static bool opAllocaNonGC() { return false; }
static bool opAllocaImpreciseLifetime() { return false; }
static bool opAllocaTLS() { return false; }
static bool opAllocaOpenMPThreadPrivate() { return false; }
static bool opAllocaEscapeByReference() { return false; }
static bool opAllocaReference() { return false; }

// Options for casts
static bool scalarConversionOpts() { return false; }
};

} // namespace cir
Expand Down
76 changes: 76 additions & 0 deletions clang/lib/CIR/CodeGen/Address.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//===----------------------------------------------------------------------===//
//
// 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 class provides a simple wrapper for a pair of a pointer and an
// alignment.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_LIB_CIR_ADDRESS_H
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where did we fall on using the 'LLVM_' in header guards? I thought we weren't doing it anymore?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. I wasn't sure about that.

#define LLVM_CLANG_LIB_CIR_ADDRESS_H

#include "mlir/IR/Value.h"
#include "clang/AST/CharUnits.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "llvm/ADT/PointerIntPair.h"

namespace clang::CIRGen {

class Address {

// The boolean flag indicates whether the pointer is known to be non-null.
llvm::PointerIntPair<mlir::Value, 1, bool> pointerAndKnownNonNull;

/// The expected CIR type of the pointer. Carrying accurate element type
/// information in Address makes it more convenient to work with Address
/// values and allows frontend assertions to catch simple mistakes.
mlir::Type elementType;

clang::CharUnits alignment;

protected:
Address(std::nullptr_t) : elementType(nullptr) {}

public:
Address(mlir::Value pointer, mlir::Type elementType,
clang::CharUnits alignment)
: pointerAndKnownNonNull(pointer, false), elementType(elementType),
alignment(alignment) {
assert(mlir::isa<cir::PointerType>(pointer.getType()) &&
"Expected cir.ptr type");

assert(pointer && "Pointer cannot be null");
assert(elementType && "Element type cannot be null");
assert(!alignment.isZero() && "Alignment cannot be zero");

assert(mlir::cast<cir::PointerType>(pointer.getType()).getPointee() ==
elementType);
}

static Address invalid() { return Address(nullptr); }
bool isValid() const {
return pointerAndKnownNonNull.getPointer() != nullptr;
}

mlir::Value getPointer() const {
assert(isValid());
return pointerAndKnownNonNull.getPointer();
}

mlir::Type getElementType() const {
assert(isValid());
assert(mlir::cast<cir::PointerType>(
pointerAndKnownNonNull.getPointer().getType())
.getPointee() == elementType);
return elementType;
}
};

} // namespace clang::CIRGen

#endif // LLVM_CLANG_LIB_CIR_ADDRESS_H
Loading