[Mlir-commits] [mlir] 6c5ae8e - [mlir] Support opaque types in LLVM IR -> MLIR translation

Alex Zinenko llvmlistbot at llvm.org
Fri Apr 15 08:51:37 PDT 2022


Author: Alex Zinenko
Date: 2022-04-15T17:51:31+02:00
New Revision: 6c5ae8e9744b6dab85efab404b0338fe70b0bd73

URL: https://github.com/llvm/llvm-project/commit/6c5ae8e9744b6dab85efab404b0338fe70b0bd73
DIFF: https://github.com/llvm/llvm-project/commit/6c5ae8e9744b6dab85efab404b0338fe70b0bd73.diff

LOG: [mlir] Support opaque types in LLVM IR -> MLIR translation

LLVM IR is moving towards adoption of opaque pointer types. These require extra
information to be passed when constructing some operations, in particular GEP
and Alloca. Adapt the builders of said operations and modify the translation
code to handle both opaque and non-opaque pointers.

This incidentally adds the translation for Alloca alignment and fixes the translation
of struct-related GEP indices that must be constant.

Reviewed By: wsmoses

Differential Revision: https://reviews.llvm.org/D123792

Added: 
    mlir/test/Target/LLVMIR/import-opaque.ll

Modified: 
    mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
    mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
    mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
    mlir/lib/Target/LLVMIR/TypeFromLLVM.cpp
    mlir/test/Target/LLVMIR/import.ll

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index af5714dae3786..e41c18742fc26 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -266,14 +266,29 @@ def LLVM_AllocaOp : LLVM_Op<"alloca">, MemoryOpWithAlignmentBase {
   }];
   let builders = [
     OpBuilder<(ins "Type":$resultType, "Value":$arraySize,
-      "unsigned":$alignment),
+               "unsigned":$alignment),
     [{
+      assert(!resultType.cast<LLVMPointerType>().isOpaque() &&
+             "pass the allocated type explicitly if opaque pointers are used");
       if (alignment == 0)
         return build($_builder, $_state, resultType, arraySize, IntegerAttr(),
                      TypeAttr());
       build($_builder, $_state, resultType, arraySize,
         $_builder.getI64IntegerAttr(alignment), TypeAttr());
-  }]>];
+    }]>,
+    OpBuilder<(ins "Type":$resultType, "Type":$elementType, "Value":$arraySize,
+               CArg<"unsigned", "0">:$alignment),
+    [{
+      TypeAttr elemTypeAttr =
+          resultType.cast<LLVMPointerType>().isOpaque() ?
+          TypeAttr::get(elementType) : TypeAttr();
+      build($_builder, $_state, resultType, arraySize,
+            alignment == 0 ? IntegerAttr()
+                           : $_builder.getI64IntegerAttr(alignment),
+            elemTypeAttr);
+
+    }]>
+    ];
   let hasCustomAssemblyFormat = 1;
   let hasVerifier = 1;
 }
@@ -291,6 +306,9 @@ def LLVM_GEPOp : LLVM_Op<"getelementptr", [NoSideEffect]> {
     OpBuilder<(ins "Type":$resultType, "Value":$basePtr, "ValueRange":$indices,
                "ArrayRef<int32_t>":$structIndices,
                CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes)>,
+    OpBuilder<(ins "Type":$resultType, "Type":$basePtrType, "Value":$basePtr,
+               "ValueRange":$indices, "ArrayRef<int32_t>":$structIndices,
+               CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes)>
   ];
   let llvmBuilder = [{
     SmallVector<llvm::Value *> indices;
@@ -313,7 +331,19 @@ def LLVM_GEPOp : LLVM_Op<"getelementptr", [NoSideEffect]> {
 
   let extraClassDeclaration = [{
     constexpr static int kDynamicIndex = std::numeric_limits<int32_t>::min();
+
+    /// Returns the type pointed to by the pointer argument of this GEP.
     Type getSourceElementType();
+
+    /// Populates `indices` with positions of GEP indices that correspond to
+    /// LLVMStructTypes potentially nested in the given `sourceElementType`,
+    /// which is the type pointed to by the pointer argument of a GEP. If
+    /// `structSizes` is provided, it is populated with sizes of the indexed
+    /// structs for bounds verification purposes.
+    static void findKnownStructIndices(
+        Type sourceElementType, SmallVectorImpl<unsigned> &indices,
+        SmallVectorImpl<unsigned> *structSizes = nullptr);
+
   }];
   let hasFolder = 1;
   let hasVerifier = 1;

diff  --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 97157d8fca2d8..4211828d06fb8 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -194,7 +194,7 @@ void AllocaOp::print(OpAsmPrinter &p) {
 
   p << ' ' << getArraySize() << " x " << elemTy;
   if (getAlignment().hasValue() && *getAlignment() != 0)
-    p.printOptionalAttrDict((*this)->getAttrs());
+    p.printOptionalAttrDict((*this)->getAttrs(), {kElemTypeAttrName});
   else
     p.printOptionalAttrDict((*this)->getAttrs(),
                             {"alignment", kElemTypeAttrName});
@@ -432,10 +432,9 @@ static void recordStructIndices(Type type, unsigned currentIndex,
 /// be either an LLVMPointer type or a vector thereof. If `structSizes` is
 /// provided, it is populated with sizes of the indexed structs for bounds
 /// verification purposes.
-static void
-findKnownStructIndices(Type sourceElementType,
-                       SmallVectorImpl<unsigned> &indices,
-                       SmallVectorImpl<unsigned> *structSizes = nullptr) {
+void GEPOp::findKnownStructIndices(Type sourceElementType,
+                                   SmallVectorImpl<unsigned> &indices,
+                                   SmallVectorImpl<unsigned> *structSizes) {
   SmallPtrSet<Type, 4> visited;
   recordStructIndices(sourceElementType, /*currentIndex=*/1, indices,
                       structSizes, visited);
@@ -464,14 +463,24 @@ void GEPOp::build(OpBuilder &builder, OperationState &result, Type resultType,
                   Value basePtr, ValueRange indices,
                   ArrayRef<int32_t> structIndices,
                   ArrayRef<NamedAttribute> attributes) {
+  auto ptrType =
+      extractVectorElementType(basePtr.getType()).cast<LLVMPointerType>();
+  assert(!ptrType.isOpaque() &&
+         "expected non-opaque pointer, provide elementType explicitly when "
+         "opaque pointers are used");
+  build(builder, result, resultType, ptrType.getElementType(), basePtr, indices,
+        structIndices, attributes);
+}
+
+void GEPOp::build(OpBuilder &builder, OperationState &result, Type resultType,
+                  Type elementType, Value basePtr, ValueRange indices,
+                  ArrayRef<int32_t> structIndices,
+                  ArrayRef<NamedAttribute> attributes) {
   SmallVector<Value> remainingIndices;
   SmallVector<int32_t> updatedStructIndices(structIndices.begin(),
                                             structIndices.end());
   SmallVector<unsigned> structRelatedPositions;
-  auto ptrType =
-      extractVectorElementType(basePtr.getType()).cast<LLVMPointerType>();
-  assert(!ptrType.isOpaque() && "expected non-opaque pointer");
-  findKnownStructIndices(ptrType.getElementType(), structRelatedPositions);
+  findKnownStructIndices(elementType, structRelatedPositions);
 
   SmallVector<unsigned> operandsToErase;
   for (unsigned pos : structRelatedPositions) {
@@ -517,6 +526,10 @@ void GEPOp::build(OpBuilder &builder, OperationState &result, Type resultType,
   result.addAttributes(attributes);
   result.addAttribute("structIndices",
                       builder.getI32TensorAttr(updatedStructIndices));
+  if (extractVectorElementType(basePtr.getType())
+          .cast<LLVMPointerType>()
+          .isOpaque())
+    result.addAttribute(kElemTypeAttrName, TypeAttr::get(elementType));
   result.addOperands(basePtr);
   result.addOperands(remainingIndices);
 }

diff  --git a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
index bda695c35ddbb..1bc8115bdf18a 100644
--- a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
+++ b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
@@ -671,7 +671,6 @@ LogicalResult Importer::processInstruction(llvm::Instruction *inst) {
   case llvm::Instruction::And:
   case llvm::Instruction::Or:
   case llvm::Instruction::Xor:
-  case llvm::Instruction::Alloca:
   case llvm::Instruction::Load:
   case llvm::Instruction::Store:
   case llvm::Instruction::Ret:
@@ -711,6 +710,17 @@ LogicalResult Importer::processInstruction(llvm::Instruction *inst) {
       v = op->getResult(0);
     return success();
   }
+  case llvm::Instruction::Alloca: {
+    Value size = processValue(inst->getOperand(0));
+    if (!size)
+      return failure();
+
+    auto *allocaInst = cast<llvm::AllocaInst>(inst);
+    v = b.create<AllocaOp>(loc, processType(inst->getType()),
+                           processType(allocaInst->getAllocatedType()), size,
+                           allocaInst->getAlign().value());
+    return success();
+  }
   case llvm::Instruction::ICmp: {
     Value lhs = processValue(inst->getOperand(0));
     Value rhs = processValue(inst->getOperand(1));
@@ -859,18 +869,34 @@ LogicalResult Importer::processInstruction(llvm::Instruction *inst) {
   case llvm::Instruction::GetElementPtr: {
     // FIXME: Support inbounds GEPs.
     llvm::GetElementPtrInst *gep = cast<llvm::GetElementPtrInst>(inst);
-    SmallVector<Value, 4> ops;
-    for (auto *op : gep->operand_values()) {
-      Value value = processValue(op);
-      if (!value)
-        return failure();
-      ops.push_back(value);
+    Value basePtr = processValue(gep->getOperand(0));
+    SmallVector<int32_t> staticIndices;
+    SmallVector<Value> dynamicIndices;
+    Type sourceElementType = processType(gep->getSourceElementType());
+    SmallVector<unsigned> staticIndexPositions;
+    GEPOp::findKnownStructIndices(sourceElementType, staticIndexPositions);
+
+    for (const auto &en :
+         llvm::enumerate(llvm::drop_begin(gep->operand_values()))) {
+      llvm::Value *operand = en.value();
+      if (llvm::find(staticIndexPositions, en.index()) ==
+          staticIndexPositions.end()) {
+        staticIndices.push_back(GEPOp::kDynamicIndex);
+        dynamicIndices.push_back(processValue(operand));
+        if (!dynamicIndices.back())
+          return failure();
+      } else {
+        auto *constantInt = cast<llvm::ConstantInt>(operand);
+        staticIndices.push_back(
+            static_cast<int32_t>(constantInt->getValue().getZExtValue()));
+      }
     }
+
     Type type = processType(inst->getType());
     if (!type)
       return failure();
-    v = b.create<GEPOp>(loc, type, ops[0],
-                        llvm::makeArrayRef(ops).drop_front());
+    v = b.create<GEPOp>(loc, type, sourceElementType, basePtr, dynamicIndices,
+                        staticIndices);
     return success();
   }
   }

diff  --git a/mlir/lib/Target/LLVMIR/TypeFromLLVM.cpp b/mlir/lib/Target/LLVMIR/TypeFromLLVM.cpp
index 210ff9e4ebd05..07de408da7a31 100644
--- a/mlir/lib/Target/LLVMIR/TypeFromLLVM.cpp
+++ b/mlir/lib/Target/LLVMIR/TypeFromLLVM.cpp
@@ -95,8 +95,12 @@ class TypeFromLLVMIRTranslatorImpl {
 
   /// Translates the given pointer type.
   Type translate(llvm::PointerType *type) {
+    if (type->isOpaque())
+      return LLVM::LLVMPointerType::get(&context, type->getAddressSpace());
+
     return LLVM::LLVMPointerType::get(
-        translateType(type->getPointerElementType()), type->getAddressSpace());
+        translateType(type->getNonOpaquePointerElementType()),
+        type->getAddressSpace());
   }
 
   /// Translates the given structure type.

diff  --git a/mlir/test/Target/LLVMIR/import-opaque.ll b/mlir/test/Target/LLVMIR/import-opaque.ll
new file mode 100644
index 0000000000000..f732697dc93a9
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/import-opaque.ll
@@ -0,0 +1,53 @@
+; RUN: mlir-translate -import-llvm -split-input-file -opaque-pointers %s | FileCheck %s
+
+; CHECK-LABEL: @opaque_ptr_load
+define i32 @opaque_ptr_load(ptr %0) {
+  ; CHECK: = llvm.load %{{.*}} : !llvm.ptr -> i32
+  %2 = load i32, ptr %0, align 4
+  ret i32 %2
+}
+
+; // -----
+
+; CHECK-LABEL: @opaque_ptr_store
+define void @opaque_ptr_store(i32 %0, ptr %1) {
+  ; CHECK: llvm.store %{{.*}}, %{{.*}} : i32, !llvm.ptr
+  store i32 %0, ptr %1, align 4
+  ret void
+}
+
+; // -----
+
+; CHECK-LABEL: @opaque_ptr_ptr_store
+define void @opaque_ptr_ptr_store(ptr %0, ptr %1) {
+  ; CHECK: llvm.store %{{.*}}, %{{.*}} : !llvm.ptr, !llvm.ptr
+  store ptr %0, ptr %1, align 8
+  ret void
+}
+
+; // -----
+
+; CHECK-LABEL: @opaque_ptr_alloca
+define ptr @opaque_ptr_alloca(i32 %0) {
+  ; CHECK: = llvm.alloca %{{.*}} x f32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
+  %2 = alloca float, i32 %0, align 4
+  ret ptr %2
+}
+
+; // -----
+
+; CHECK-LABEL: @opaque_ptr_gep
+define ptr @opaque_ptr_gep(ptr %0, i32 %1) {
+  ; CHECK: = llvm.getelementptr %{{.*}}[%{{.*}}] : (!llvm.ptr, i32) -> !llvm.ptr, f32
+  %3 = getelementptr float, ptr %0, i32 %1
+  ret ptr %3
+}
+
+; // -----
+
+; CHECK-LABEL: @opaque_ptr_gep
+define ptr @opaque_ptr_gep_struct(ptr %0, i32 %1){
+  ; CHECK: = llvm.getelementptr %{{.*}}[%{{.*}}, 0, 1] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<(struct<(f32, f64)>, struct<(i32, i64)>)>
+  %3 = getelementptr { { float, double }, { i32, i64 } }, ptr %0, i32 %1, i32 0, i32 1
+  ret ptr %3
+}

diff  --git a/mlir/test/Target/LLVMIR/import.ll b/mlir/test/Target/LLVMIR/import.ll
index 35176a301b88d..46566a93f24bb 100644
--- a/mlir/test/Target/LLVMIR/import.ll
+++ b/mlir/test/Target/LLVMIR/import.ll
@@ -326,7 +326,7 @@ declare i32 @__gxx_personality_v0(...)
 ; CHECK-LABEL: @invokeLandingpad
 define i32 @invokeLandingpad() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
   ; CHECK: %[[a1:[0-9]+]] = llvm.bitcast %{{[0-9]+}} : !llvm.ptr<ptr<ptr<i8>>> to !llvm.ptr<i8>
-  ; CHECK: %[[a3:[0-9]+]] = llvm.alloca %{{[0-9]+}} x i8 : (i32) -> !llvm.ptr<i8>
+  ; CHECK: %[[a3:[0-9]+]] = llvm.alloca %{{[0-9]+}} x i8 {alignment = 1 : i64} : (i32) -> !llvm.ptr<i8>
   %1 = alloca i8
   ; CHECK: llvm.invoke @foo(%[[a3]]) to ^bb2 unwind ^bb1 : (!llvm.ptr<i8>) -> ()
   invoke void @foo(i8* %1) to label %4 unwind label %2


        


More information about the Mlir-commits mailing list