Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
42 changes: 42 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,47 @@ 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) {
return create<cir::AllocaOp>(loc, addrType, type, name, alignment);
}

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
113 changes: 113 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,119 @@ 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 of the `const` attribute indicates that the local variable is
declared with C/C++ `const` keyword.

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

Example:

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

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

let arguments = (ins
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)>
];

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

let assemblyFormat = [{
$allocaType `,` qualified(type($addr)) `,`
`[` $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.

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);
let results = (outs CIR_AnyType:$result);

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

// FIXME: add verifier.
}

//===----------------------------------------------------------------------===//
// ReturnOp
//===----------------------------------------------------------------------===//
Expand Down
23 changes: 23 additions & 0 deletions clang/include/clang/CIR/MissingFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,35 @@ struct MissingFeatures {
// This isn't needed until we add support for bools.
static bool convertTypeForMemory() { return false; }

// CIRGenFunction implementation details
static bool cgfSymbolTable() { return false; }

// Unhandled global/linkage information.
static bool opGlobalDSOLocal() { return false; }
static bool opGlobalThreadLocal() { return false; }
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 opAllocaPreciseLifetime() { return false; }
static bool opAllocaTLS() { return false; }
static bool opAllocaOpenMPThreadPrivate() { return false; }
static bool opAllocaEscapeByReference() { return false; }
static bool opAllocaReference() { return false; }

// Misc
static bool scalarConversionOpts() { return false; }
static bool tryEmitAsConstant() { 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 CLANG_LIB_CIR_ADDRESS_H
#define 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 // CLANG_LIB_CIR_ADDRESS_H
Loading