diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -266,14 +266,29 @@ }]; let builders = [ OpBuilder<(ins "Type":$resultType, "Value":$arraySize, - "unsigned":$alignment), + "unsigned":$alignment), [{ + assert(!resultType.cast().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().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 @@ OpBuilder<(ins "Type":$resultType, "Value":$basePtr, "ValueRange":$indices, "ArrayRef":$structIndices, CArg<"ArrayRef", "{}">:$attributes)>, + OpBuilder<(ins "Type":$resultType, "Type":$basePtrType, "Value":$basePtr, + "ValueRange":$indices, "ArrayRef":$structIndices, + CArg<"ArrayRef", "{}">:$attributes)> ]; let llvmBuilder = [{ SmallVector indices; diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -194,7 +194,7 @@ 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}); @@ -464,14 +464,24 @@ Value basePtr, ValueRange indices, ArrayRef structIndices, ArrayRef attributes) { + auto ptrType = + extractVectorElementType(basePtr.getType()).cast(); + 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 structIndices, + ArrayRef attributes) { SmallVector remainingIndices; SmallVector updatedStructIndices(structIndices.begin(), structIndices.end()); SmallVector structRelatedPositions; - auto ptrType = - extractVectorElementType(basePtr.getType()).cast(); - assert(!ptrType.isOpaque() && "expected non-opaque pointer"); - findKnownStructIndices(ptrType.getElementType(), structRelatedPositions); + findKnownStructIndices(elementType, structRelatedPositions); SmallVector operandsToErase; for (unsigned pos : structRelatedPositions) { @@ -517,6 +527,10 @@ result.addAttributes(attributes); result.addAttribute("structIndices", builder.getI32TensorAttr(updatedStructIndices)); + if (extractVectorElementType(basePtr.getType()) + .cast() + .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 --- a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp +++ b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp @@ -671,7 +671,6 @@ 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 @@ v = op->getResult(0); return success(); } + case llvm::Instruction::Alloca: { + Value size = processValue(inst->getOperand(0)); + if (!size) + return failure(); + + auto *allocaInst = cast(inst); + v = b.create(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,26 @@ case llvm::Instruction::GetElementPtr: { // FIXME: Support inbounds GEPs. llvm::GetElementPtrInst *gep = cast(inst); - SmallVector 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 staticIndices; + SmallVector dynamicIndices; + for (auto *op : llvm::drop_begin(gep->operand_values())) { + if (auto *constantInt = dyn_cast(op)) { + staticIndices.push_back( + static_cast(constantInt->getValue().getZExtValue())); + } else { + staticIndices.push_back(GEPOp::kDynamicIndex); + dynamicIndices.push_back(processValue(op)); + if (!dynamicIndices.back()) + return failure(); + } } + Type type = processType(inst->getType()); if (!type) return failure(); - v = b.create(loc, type, ops[0], - llvm::makeArrayRef(ops).drop_front()); + v = b.create(loc, type, processType(gep->getSourceElementType()), + basePtr, dynamicIndices, staticIndices); return success(); } } diff --git a/mlir/lib/Target/LLVMIR/TypeFromLLVM.cpp b/mlir/lib/Target/LLVMIR/TypeFromLLVM.cpp --- a/mlir/lib/Target/LLVMIR/TypeFromLLVM.cpp +++ b/mlir/lib/Target/LLVMIR/TypeFromLLVM.cpp @@ -95,8 +95,12 @@ /// 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 --- /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 --- a/mlir/test/Target/LLVMIR/import.ll +++ b/mlir/test/Target/LLVMIR/import.ll @@ -22,8 +22,7 @@ @g4 = external global i32, align 8 ; CHECK: llvm.mlir.global internal constant @int_gep() {dso_local} : !llvm.ptr { ; CHECK-DAG: %[[addr:[0-9]+]] = llvm.mlir.addressof @g4 : !llvm.ptr -; CHECK-DAG: %[[c2:[0-9]+]] = llvm.mlir.constant(2 : i32) : i32 -; CHECK-NEXT: %[[gepinit:[0-9]+]] = llvm.getelementptr %[[addr]][%[[c2]]] : (!llvm.ptr, i32) -> !llvm.ptr +; CHECK-NEXT: %[[gepinit:[0-9]+]] = llvm.getelementptr %[[addr]][2] : (!llvm.ptr) -> !llvm.ptr ; CHECK-NEXT: llvm.return %[[gepinit]] : !llvm.ptr ; CHECK-NEXT: } @int_gep = internal constant i32* getelementptr (i32, i32* @g4, i32 2) @@ -326,7 +325,7 @@ ; 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>> to !llvm.ptr - ; CHECK: %[[a3:[0-9]+]] = llvm.alloca %{{[0-9]+}} x i8 : (i32) -> !llvm.ptr + ; CHECK: %[[a3:[0-9]+]] = llvm.alloca %{{[0-9]+}} x i8 {alignment = 1 : i64} : (i32) -> !llvm.ptr %1 = alloca i8 ; CHECK: llvm.invoke @foo(%[[a3]]) to ^bb2 unwind ^bb1 : (!llvm.ptr) -> () invoke void @foo(i8* %1) to label %4 unwind label %2