Skip to content

[Flang][MLIR] Add basic initial support for alloca and program address space handling in FIR->LLVMIR codegen #77518

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 17, 2024
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
2 changes: 2 additions & 0 deletions flang/include/flang/Optimizer/CodeGen/CGPasses.td
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ def FIRToLLVMLowering : Pass<"fir-to-llvm-ir", "mlir::ModuleOp"> {
let options = [
Option<"forcedTargetTriple", "target", "std::string", /*default=*/"",
"Override module's target triple.">,
Option<"forcedDataLayout", "datalayout", "std::string", /*default=*/"",
"Override module's data layout.">,
Option<"applyTBAA", "apply-tbaa", "bool", /*default=*/"false",
"Attach TBAA tags to memory accessing operations.">
];
Expand Down
98 changes: 81 additions & 17 deletions flang/lib/Optimizer/CodeGen/CodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "mlir/IR/Matchers.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Target/LLVMIR/Import.h"
#include "mlir/Target/LLVMIR/ModuleTranslation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/TypeSwitch.h"
Expand All @@ -61,14 +62,40 @@ namespace fir {

// TODO: This should really be recovered from the specified target.
static constexpr unsigned defaultAlign = 8;
static constexpr unsigned defaultAddressSpace = 0u;

/// `fir.box` attribute values as defined for CFI_attribute_t in
/// flang/ISO_Fortran_binding.h.
static constexpr unsigned kAttrPointer = CFI_attribute_pointer;
static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable;

static inline mlir::Type getLlvmPtrType(mlir::MLIRContext *context) {
return mlir::LLVM::LLVMPointerType::get(context);
static inline unsigned
getAllocaAddressSpace(mlir::ConversionPatternRewriter &rewriter) {
mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp();
assert(parentOp != nullptr &&
"expected insertion block to have parent operation");
if (auto module = parentOp->getParentOfType<mlir::ModuleOp>())
if (mlir::Attribute addrSpace =
mlir::DataLayout(module).getAllocaMemorySpace())
return llvm::cast<mlir::IntegerAttr>(addrSpace).getUInt();
return defaultAddressSpace;
}

static inline unsigned
getProgramAddressSpace(mlir::ConversionPatternRewriter &rewriter) {
mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp();
assert(parentOp != nullptr &&
"expected insertion block to have parent operation");
if (auto module = parentOp->getParentOfType<mlir::ModuleOp>())
if (mlir::Attribute addrSpace =
mlir::DataLayout(module).getProgramMemorySpace())
return llvm::cast<mlir::IntegerAttr>(addrSpace).getUInt();
return defaultAddressSpace;
}

static inline mlir::Type getLlvmPtrType(mlir::MLIRContext *context,
unsigned addressSpace = 0) {
return mlir::LLVM::LLVMPointerType::get(context, addressSpace);
}

static inline mlir::Type getI8Type(mlir::MLIRContext *context) {
Expand Down Expand Up @@ -368,19 +395,37 @@ class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
return getBlockForAllocaInsert(op->getParentOp());
}

// Generate an alloca of size 1 for an object of type \p llvmObjectTy.
mlir::LLVM::AllocaOp
genAllocaWithType(mlir::Location loc, mlir::Type llvmObjectTy,
unsigned alignment,
mlir::ConversionPatternRewriter &rewriter) const {
// Generate an alloca of size 1 for an object of type \p llvmObjectTy in the
// allocation address space provided for the architecture in the DataLayout
// specification. If the address space is different from the devices
// program address space we perform a cast. In the case of most architectures
// the program and allocation address space will be the default of 0 and no
// cast will be emitted.
mlir::Value genAllocaAndAddrCastWithType(
mlir::Location loc, mlir::Type llvmObjectTy, unsigned alignment,
mlir::ConversionPatternRewriter &rewriter) const {
auto thisPt = rewriter.saveInsertionPoint();
mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp();
mlir::Block *insertBlock = getBlockForAllocaInsert(parentOp);
rewriter.setInsertionPointToStart(insertBlock);
auto size = genI32Constant(loc, rewriter, 1);
mlir::Type llvmPtrTy = ::getLlvmPtrType(llvmObjectTy.getContext());
auto al = rewriter.create<mlir::LLVM::AllocaOp>(
loc, llvmPtrTy, llvmObjectTy, size, alignment);
unsigned allocaAs = getAllocaAddressSpace(rewriter);
unsigned programAs = getProgramAddressSpace(rewriter);

mlir::Value al = rewriter.create<mlir::LLVM::AllocaOp>(
loc, ::getLlvmPtrType(llvmObjectTy.getContext(), allocaAs),
llvmObjectTy, size, alignment);

// if our allocation address space, is not the same as the program address
// space, then we must emit a cast to the program address space before use.
// An example case would be on AMDGPU, where the allocation address space is
// the numeric value 5 (private), and the program address space is 0
// (generic).
if (allocaAs != programAs) {
al = rewriter.create<mlir::LLVM::AddrSpaceCastOp>(
loc, ::getLlvmPtrType(llvmObjectTy.getContext(), programAs), al);
}

rewriter.restoreInsertionPoint(thisPt);
return al;
}
Expand Down Expand Up @@ -532,20 +577,34 @@ struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> {
size = rewriter.create<mlir::LLVM::MulOp>(
loc, ity, size, integerCast(loc, rewriter, ity, operands[i]));
}
mlir::Type llvmPtrTy = ::getLlvmPtrType(alloc.getContext());

unsigned allocaAs = getAllocaAddressSpace(rewriter);
unsigned programAs = getProgramAddressSpace(rewriter);

// NOTE: we used to pass alloc->getAttrs() in the builder for non opaque
// pointers! Only propagate pinned and bindc_name to help debugging, but
// this should have no functional purpose (and passing the operand segment
// attribute like before is certainly bad).
auto llvmAlloc = rewriter.create<mlir::LLVM::AllocaOp>(
loc, llvmPtrTy, llvmObjectType, size);
loc, ::getLlvmPtrType(alloc.getContext(), allocaAs), llvmObjectType,
size);
if (alloc.getPinned())
llvmAlloc->setDiscardableAttr(alloc.getPinnedAttrName(),
alloc.getPinnedAttr());
if (alloc.getBindcName())
llvmAlloc->setDiscardableAttr(alloc.getBindcNameAttrName(),
alloc.getBindcNameAttr());
rewriter.replaceOp(alloc, llvmAlloc);
if (allocaAs == programAs) {
rewriter.replaceOp(alloc, llvmAlloc);
} else {
// if our allocation address space, is not the same as the program address
// space, then we must emit a cast to the program address space before
// use. An example case would be on AMDGPU, where the allocation address
// space is the numeric value 5 (private), and the program address space
// is 0 (generic).
rewriter.replaceOpWithNewOp<mlir::LLVM::AddrSpaceCastOp>(
alloc, ::getLlvmPtrType(alloc.getContext(), programAs), llvmAlloc);
}
return mlir::success();
}
};
Expand Down Expand Up @@ -1691,8 +1750,8 @@ struct EmboxCommonConversion : public FIROpConversion<OP> {
if (isInGlobalOp(rewriter))
return boxValue;
mlir::Type llvmBoxTy = boxValue.getType();
auto alloca =
this->genAllocaWithType(loc, llvmBoxTy, defaultAlign, rewriter);
auto alloca = this->genAllocaAndAddrCastWithType(loc, llvmBoxTy,
defaultAlign, rewriter);
auto storeOp = rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, alloca);
this->attachTBAATag(storeOp, boxTy, boxTy, nullptr);
return alloca;
Expand Down Expand Up @@ -3110,11 +3169,11 @@ struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
else
attachTBAATag(boxValue, boxTy, boxTy, nullptr);
auto newBoxStorage =
genAllocaWithType(loc, llvmLoadTy, defaultAlign, rewriter);
genAllocaAndAddrCastWithType(loc, llvmLoadTy, defaultAlign, rewriter);
auto storeOp =
rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, newBoxStorage);
attachTBAATag(storeOp, boxTy, boxTy, nullptr);
rewriter.replaceOp(load, newBoxStorage.getResult());
rewriter.replaceOp(load, newBoxStorage);
} else {
auto loadOp = rewriter.create<mlir::LLVM::LoadOp>(
load.getLoc(), llvmLoadTy, adaptor.getOperands(), load->getAttrs());
Expand Down Expand Up @@ -3808,6 +3867,11 @@ class FIRToLLVMLowering
if (!forcedTargetTriple.empty())
fir::setTargetTriple(mod, forcedTargetTriple);

if (!forcedDataLayout.empty()) {
llvm::DataLayout dl(forcedDataLayout);
fir::support::setMLIRDataLayout(mod, dl);
}

// Run dynamic pass pipeline for converting Math dialect
// operations into other dialects (llvm, func, etc.).
// Some conversions of Math operations cannot be done
Expand Down
Loading