diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -12,6 +12,7 @@ #include "flang/Optimizer/CodeGen/CodeGen.h" #include "PassDetail.h" +#include "flang/ISO_Fortran_binding.h" #include "flang/Optimizer/Dialect/FIROps.h" #include "flang/Optimizer/Dialect/FIRType.h" #include "flang/Optimizer/Support/FIRContext.h" @@ -29,6 +30,10 @@ // fir::LLVMTypeConverter for converting to LLVM IR dialect types. #include "TypeConverter.h" +/// `fir.box` attribute values as defined in flang/ISO_Fortran_binding.h. +static constexpr unsigned kAttrPointer = CFI_attribute_pointer; +static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable; + namespace { /// FIR conversion pattern template template @@ -51,16 +56,17 @@ return rewriter.create(loc, ity, cattr); } - /// Construct code sequence to get the rank from a box. - mlir::Value getRankFromBox(mlir::Location loc, mlir::Value box, - mlir::Type resultTy, - mlir::ConversionPatternRewriter &rewriter) const { + /// Construct code sequence to extract the specifc value from a `fir.box`. + mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box, + mlir::Type resultTy, + mlir::ConversionPatternRewriter &rewriter, + unsigned boxValue) const { mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); - mlir::LLVM::ConstantOp cRank = - genConstantOffset(loc, rewriter, kRankPosInBox); + mlir::LLVM::ConstantOp cValuePos = + genConstantOffset(loc, rewriter, boxValue); auto pty = mlir::LLVM::LLVMPointerType::get(resultTy); auto p = rewriter.create( - loc, pty, mlir::ValueRange{box, c0, cRank}); + loc, pty, mlir::ValueRange{box, c0, cValuePos}); return rewriter.create(loc, resultTy, p); } @@ -116,6 +122,24 @@ return rewriter.create(loc, ty, p); } + // Load the attribute from the `fir.box` and perform a logical `and` with the + // mask value. The value returned is the result the integer comparison (NE) + // between the logical `and` result and 0. + mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box, + mlir::ConversionPatternRewriter &rewriter, + unsigned maskValue) const { + mlir::Type attrTy = rewriter.getI32Type(); + mlir::Value attribute = + getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox); + mlir::LLVM::ConstantOp attrMask = + genConstantOffset(loc, rewriter, maskValue); + auto maskRes = + rewriter.create(loc, attrTy, attribute, attrMask); + mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); + return rewriter.create( + loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0); + } + template mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty, mlir::ConversionPatternRewriter &rewriter, @@ -218,7 +242,62 @@ mlir::Value a = adaptor.getOperands()[0]; auto loc = boxelesz.getLoc(); auto ty = convertType(boxelesz.getType()); - rewriter.replaceOp(boxelesz, loadElementSizeFromBox(loc, ty, a, rewriter)); + auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox); + rewriter.replaceOp(boxelesz, elemSize); + return success(); + } +}; + +/// Lower `fir.box_isalloc` to a sequence of operations to determined if the +/// boxed value was from an ALLOCATABLE entity. +struct BoxIsAllocOpConversion : public FIROpConversion { + using FIROpConversion::FIROpConversion; + + mlir::LogicalResult + matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { + mlir::Value box = adaptor.getOperands()[0]; + auto loc = boxisalloc.getLoc(); + mlir::Value check = + genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable); + rewriter.replaceOp(boxisalloc, check); + return success(); + } +}; + +/// Lower `fir.box_isarray` to a sequence of operations to determined if the +/// boxed is an array. +/// It uses the same sequences as `fir.box_rank` to extract the rank value and +/// compare it to 0. +struct BoxIsArrayOpConversion : public FIROpConversion { + using FIROpConversion::FIROpConversion; + + mlir::LogicalResult + matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { + mlir::Value a = adaptor.getOperands()[0]; + auto loc = boxisarray.getLoc(); + auto rank = + getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox); + auto c0 = genConstantOffset(loc, rewriter, 0); + rewriter.replaceOpWithNewOp( + boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0); + return success(); + } +}; + +/// Lower `fir.box_isptr` to a sequence of operations to determined if the +/// boxed value was from a POINTER entity. +struct BoxIsPtrOpConversion : public FIROpConversion { + using FIROpConversion::FIROpConversion; + + mlir::LogicalResult + matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { + mlir::Value box = adaptor.getOperands()[0]; + auto loc = boxisptr.getLoc(); + mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer); + rewriter.replaceOp(boxisptr, check); return success(); } }; @@ -234,7 +313,7 @@ mlir::Value a = adaptor.getOperands()[0]; auto loc = boxrank.getLoc(); mlir::Type ty = convertType(boxrank.getType()); - auto result = getRankFromBox(loc, a, ty, rewriter); + auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox); rewriter.replaceOp(boxrank, result); return success(); } @@ -997,7 +1076,8 @@ mlir::OwningRewritePatternList pattern(context); pattern.insert< AddcOpConversion, AddrOfOpConversion, BoxAddrOpConversion, - BoxDimsOpConversion, BoxEleSizeOpConversion, BoxRankOpConversion, + BoxDimsOpConversion, BoxEleSizeOpConversion, BoxIsAllocOpConversion, + BoxIsArrayOpConversion, BoxIsPtrOpConversion, BoxRankOpConversion, CallOpConversion, ConvertOpConversion, DivcOpConversion, ExtractValueOpConversion, HasValueOpConversion, GlobalOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion, LoadOpConversion, diff --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir --- a/flang/test/Fir/convert-to-llvm.fir +++ b/flang/test/Fir/convert-to-llvm.fir @@ -763,3 +763,64 @@ // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][%[[C0]], %[[CELESIZE]]] : (!llvm.ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>, i32, i32) -> !llvm.ptr // CHECK: %[[ELE_SIZE:.*]] = llvm.load %[[GEP]] : !llvm.ptr // CHECK: llvm.return %[[ELE_SIZE]] : i32 + +// ----- + +// Test `fir.box_isarray` conversion. + +func @box_isarray(%arg0: !fir.box>) -> i1 { + %0 = fir.box_isarray %arg0 : (!fir.box>) -> i1 + return %0 : i1 +} + +// CHECK-LABEL: llvm.func @box_isarray( +// CHECK-SAME: %[[ARG0:.*]]: !llvm.ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>) -> i1 +// CHECK: %[[C0:.*]] = llvm.mlir.constant(0 : i32) : i32 +// CHECK: %[[RANKPOS:.*]] = llvm.mlir.constant(3 : i32) : i32 +// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][%[[C0]], %[[RANKPOS]]] : (!llvm.ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>, i32, i32) -> !llvm.ptr +// CHECK: %[[RANK:.*]] = llvm.load %[[GEP]] : !llvm.ptr +// CHECK: %[[C0_ISARRAY:.*]] = llvm.mlir.constant(0 : i32) : i32 +// CHECK: %[[IS_ARRAY:.*]] = llvm.icmp "ne" %[[RANK]], %[[C0_ISARRAY]] : i32 +// CHECK: llvm.return %[[IS_ARRAY]] : i1 + +// ----- + +// Test `fir.box_isalloc` conversion. + +func @box_isalloc(%arg0: !fir.box>) -> i1 { + %0 = fir.box_isalloc %arg0 : (!fir.box>) -> i1 + return %0 : i1 +} + +// CHECK-LABEL: llvm.func @box_isalloc( +// CHECK-SAME: %[[ARG0:.*]]: !llvm.ptr, i64, i32, i8, i8, i8, i8)>>) -> i1 +// CHECK: %[[C0:.*]] = llvm.mlir.constant(0 : i32) : i32 +// CHECK: %[[ATTRPOS:.*]] = llvm.mlir.constant(5 : i32) : i32 +// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][%[[C0]], %[[ATTRPOS]]] : (!llvm.ptr, i64, i32, i8, i8, i8, i8)>>, i32, i32) -> !llvm.ptr +// CHECK: %[[ATTR:.*]] = llvm.load %[[GEP]] : !llvm.ptr +// CHECK: %[[ATTR_ISALLOC:.*]] = llvm.mlir.constant(2 : i32) : i32 +// CHECK: %[[AND:.*]] = llvm.and %[[ATTR]], %[[ATTR_ISALLOC]] : i32 +// CHECK: %[[CMP_C0:.*]] = llvm.mlir.constant(0 : i32) : i32 +// CHECK: %[[IS_ALLOC:.*]] = llvm.icmp "ne" %[[AND]], %[[CMP_C0]] : i32 +// CHECK: llvm.return %[[IS_ALLOC]] : i1 + +// ----- + +// Test `fir.box_isptr` conversion. + +func @box_isptr(%arg0: !fir.box>) -> i1 { + %0 = fir.box_isptr %arg0 : (!fir.box>) -> i1 + return %0 : i1 +} + +// CHECK-LABEL: llvm.func @box_isptr( +// CHECK-SAME: %[[ARG0:.*]]: !llvm.ptr, i64, i32, i8, i8, i8, i8)>>) -> i1 +// CHECK: %[[C0:.*]] = llvm.mlir.constant(0 : i32) : i32 +// CHECK: %[[ATTRPOS:.*]] = llvm.mlir.constant(5 : i32) : i32 +// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][%[[C0]], %[[ATTRPOS]]] : (!llvm.ptr, i64, i32, i8, i8, i8, i8)>>, i32, i32) -> !llvm.ptr +// CHECK: %[[ATTR:.*]] = llvm.load %[[GEP]] : !llvm.ptr +// CHECK: %[[ATTR_ISALLOC:.*]] = llvm.mlir.constant(1 : i32) : i32 +// CHECK: %[[AND:.*]] = llvm.and %[[ATTR]], %[[ATTR_ISALLOC]] : i32 +// CHECK: %[[CMP_C0:.*]] = llvm.mlir.constant(0 : i32) : i32 +// CHECK: %[[IS_ALLOC:.*]] = llvm.icmp "ne" %[[AND]], %[[CMP_C0]] : i32 +// CHECK: llvm.return %[[IS_ALLOC]] : i1