Skip to content

Commit 8d3a707

Browse files
[MLIR][LLVM] Improve inline asm importer (llvm#139989)
Add support for importing more information into InlineAsmOp: elementtype, side effects, align stack, asm dialect and operand attrs.
1 parent de0bcd0 commit 8d3a707

File tree

5 files changed

+111
-6
lines changed

5 files changed

+111
-6
lines changed

mlir/include/mlir/Target/LLVMIR/ModuleImport.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,9 @@ class ModuleImport {
330330
/// Converts a single debug intrinsic.
331331
LogicalResult processDebugIntrinsic(llvm::DbgVariableIntrinsic *dbgIntr,
332332
DominanceInfo &domInfo);
333+
/// Converts LLMV IR asm inline call operand's attributes into an array of
334+
/// MLIR attributes to be utilized in `llvm.inline_asm`.
335+
ArrayAttr convertAsmInlineOperandAttrs(const llvm::CallBase &llvmCall);
333336
/// Converts an LLVM intrinsic to an MLIR LLVM dialect operation if an MLIR
334337
/// counterpart exists. Otherwise, returns failure.
335338
LogicalResult convertIntrinsic(llvm::CallInst *inst);

mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,8 @@ convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder,
515515
if (!attr)
516516
continue;
517517
DictionaryAttr dAttr = cast<DictionaryAttr>(attr);
518+
if (dAttr.empty())
519+
continue;
518520
TypeAttr tAttr =
519521
cast<TypeAttr>(dAttr.get(InlineAsmOp::getElementTypeAttrName()));
520522
llvm::AttrBuilder b(moduleTranslation.getLLVMContext());

mlir/lib/Target/LLVMIR/ModuleImport.cpp

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2073,6 +2073,40 @@ LogicalResult ModuleImport::convertIntrinsic(llvm::CallInst *inst) {
20732073
return emitError(loc) << "unhandled intrinsic: " << diag(*inst);
20742074
}
20752075

2076+
ArrayAttr
2077+
ModuleImport::convertAsmInlineOperandAttrs(const llvm::CallBase &llvmCall) {
2078+
const auto *ia = cast<llvm::InlineAsm>(llvmCall.getCalledOperand());
2079+
unsigned argIdx = 0;
2080+
SmallVector<mlir::Attribute> opAttrs;
2081+
bool hasIndirect = false;
2082+
2083+
for (const llvm::InlineAsm::ConstraintInfo &ci : ia->ParseConstraints()) {
2084+
// Only deal with constraints that correspond to call arguments.
2085+
if (ci.Type == llvm::InlineAsm::isLabel || !ci.hasArg())
2086+
continue;
2087+
2088+
// Only increment `argIdx` in terms of constraints containing arguments,
2089+
// which are guaranteed to happen in the same order of the call arguments.
2090+
if (ci.isIndirect) {
2091+
if (llvm::Type *paramEltType = llvmCall.getParamElementType(argIdx)) {
2092+
SmallVector<mlir::NamedAttribute> attrs;
2093+
attrs.push_back(builder.getNamedAttr(
2094+
mlir::LLVM::InlineAsmOp::getElementTypeAttrName(),
2095+
mlir::TypeAttr::get(convertType(paramEltType))));
2096+
opAttrs.push_back(builder.getDictionaryAttr(attrs));
2097+
hasIndirect = true;
2098+
}
2099+
} else {
2100+
opAttrs.push_back(builder.getDictionaryAttr({}));
2101+
}
2102+
argIdx++;
2103+
}
2104+
2105+
// Avoid emitting an array where all entries are empty dictionaries.
2106+
return hasIndirect ? ArrayAttr::get(mlirModule->getContext(), opAttrs)
2107+
: nullptr;
2108+
}
2109+
20762110
LogicalResult ModuleImport::convertInstruction(llvm::Instruction *inst) {
20772111
// Convert all instructions that do not provide an MLIR builder.
20782112
Location loc = translateLoc(inst->getDebugLoc());
@@ -2159,14 +2193,17 @@ LogicalResult ModuleImport::convertInstruction(llvm::Instruction *inst) {
21592193
Type resultTy = convertType(callInst->getType());
21602194
if (!resultTy)
21612195
return failure();
2196+
ArrayAttr operandAttrs = convertAsmInlineOperandAttrs(*callInst);
21622197
return builder
21632198
.create<InlineAsmOp>(
21642199
loc, resultTy, *operands,
21652200
builder.getStringAttr(asmI->getAsmString()),
21662201
builder.getStringAttr(asmI->getConstraintString()),
2167-
/*has_side_effects=*/true,
2168-
/*is_align_stack=*/false, /*asm_dialect=*/nullptr,
2169-
/*operand_attrs=*/nullptr)
2202+
asmI->hasSideEffects(), asmI->isAlignStack(),
2203+
AsmDialectAttr::get(
2204+
mlirModule.getContext(),
2205+
convertAsmDialectFromLLVM(asmI->getDialect())),
2206+
operandAttrs)
21702207
.getOperation();
21712208
}
21722209
bool isIncompatibleCall;

mlir/test/Target/LLVMIR/Import/instructions.ll

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -542,14 +542,55 @@ define void @indirect_vararg_call(ptr addrspace(42) %fn) {
542542
; CHECK-LABEL: @inlineasm
543543
; CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]
544544
define i32 @inlineasm(i32 %arg1) {
545-
; CHECK: %[[RES:.+]] = llvm.inline_asm has_side_effects "bswap $0", "=r,r" %[[ARG1]] : (i32) -> i32
546-
%1 = call i32 asm "bswap $0", "=r,r"(i32 %arg1)
545+
; CHECK: %[[RES:.+]] = llvm.inline_asm has_side_effects is_align_stack asm_dialect = intel "bswap $0", "=r,r" %[[ARG1]] : (i32) -> i32
546+
%1 = call i32 asm sideeffect alignstack inteldialect "bswap $0", "=r,r"(i32 %arg1)
547547
; CHECK: return %[[RES]]
548548
ret i32 %1
549549
}
550550

551551
; // -----
552552

553+
; CHECK-LABEL: @inlineasm2
554+
define void @inlineasm2() {
555+
%p = alloca ptr, align 8
556+
; CHECK: {{.*}} = llvm.alloca %0 x !llvm.ptr {alignment = 8 : i64} : (i32) -> !llvm.ptr
557+
; CHECK-NEXT: llvm.inline_asm has_side_effects asm_dialect = att operand_attrs = [{elementtype = !llvm.ptr}] "", "*m,~{memory}" {{.*}} : (!llvm.ptr) -> !llvm.void
558+
call void asm sideeffect "", "*m,~{memory}"(ptr elementtype(ptr) %p)
559+
ret void
560+
}
561+
562+
; // -----
563+
564+
; CHECK: llvm.func @inlineasm3
565+
; CHECK-SAME:(%[[A0:.*]]: !llvm.ptr, %[[A1:.*]]: i64, %[[A2:.*]]: !llvm.ptr, %[[A3:.*]]: i64) {
566+
define void @inlineasm3(
567+
ptr %ptr0,
568+
i64 %b,
569+
ptr %ptr1,
570+
i64 %c
571+
) {
572+
; CHECK: llvm.inline_asm asm_dialect = att operand_attrs =
573+
; CHECK-SAME: [{elementtype = !llvm.array<16 x i64>}, {},
574+
; CHECK-SAME: {elementtype = !llvm.array<16 x i64>}, {}, {}, {},
575+
; CHECK-SAME: {elementtype = !llvm.array<16 x i64>}]
576+
; CHECK-SAME: "ldr x4, [$2], #8 \0A\09ldr x5, [$1] \0A\09mul x6, x4, $4 \0A\09",
577+
; CHECK-SAME: "=r,=r,=r,=*m,r,*m,0,1,2,*m,~{x4},~{x5},~{x6},~{x7},~{cc}"
578+
; CHECK-SAME: %[[A0]], %[[A1]], %[[A2]], %[[A3]], %[[A0]], %[[A2]], %[[A0]] :
579+
; CHECK-SAME: (!llvm.ptr, i64, !llvm.ptr, i64, !llvm.ptr, !llvm.ptr, !llvm.ptr) -> !llvm.struct<(i64, ptr, ptr)>
580+
%r = call { i64, ptr, ptr } asm "ldr x4, [$2], #8 \0A\09ldr x5, [$1] \0A\09mul x6, x4, $4 \0A\09",
581+
"=r,=r,=r,=*m,r,*m,0,1,2,*m,~{x4},~{x5},~{x6},~{x7},~{cc}"(
582+
ptr elementtype([16 x i64]) %ptr0,
583+
i64 %b,
584+
ptr elementtype([16 x i64]) %ptr1,
585+
i64 %c,
586+
ptr %ptr0,
587+
ptr %ptr1,
588+
ptr elementtype([16 x i64]) %ptr0)
589+
ret void
590+
}
591+
592+
; // -----
593+
553594
; CHECK-LABEL: @gep_static_idx
554595
; CHECK-SAME: %[[PTR:[a-zA-Z0-9]+]]
555596
define void @gep_static_idx(ptr %ptr) {

mlir/test/Target/LLVMIR/llvmir.mlir

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2056,7 +2056,7 @@ module attributes {} {}
20562056
// -----
20572057

20582058
// CHECK-LABEL: @useInlineAsm
2059-
llvm.func @useInlineAsm(%arg0: i32) {
2059+
llvm.func @useInlineAsm(%arg0: i32, %arg1 : !llvm.ptr) {
20602060
// Constraints string is checked at LLVM InlineAsm instruction construction time.
20612061
// So we can't just use "bar" everywhere, number of in/out arguments has to match.
20622062

@@ -2081,6 +2081,28 @@ llvm.func @useInlineAsm(%arg0: i32) {
20812081
// CHECK-NEXT: call { i8, i8 } asm "foo", "=r,=r,r"(i32 {{.*}})
20822082
%5 = llvm.inline_asm "foo", "=r,=r,r" %arg0 : (i32) -> !llvm.struct<(i8, i8)>
20832083

2084+
// CHECK-NEXT: call void asm sideeffect "", "*m,~{memory}"(ptr elementtype(ptr) %1)
2085+
%6 = llvm.inline_asm has_side_effects operand_attrs = [{elementtype = !llvm.ptr}] "", "*m,~{memory}" %arg1 : (!llvm.ptr) -> !llvm.void
2086+
2087+
llvm.return
2088+
}
2089+
2090+
// -----
2091+
2092+
// CHECK: @useInlineAsm2(ptr %[[A0:.*]], i64 %[[A1:.*]], ptr %[[A2:.*]], i64 %[[A3:.*]]) {
2093+
llvm.func @useInlineAsm2(%arg0: !llvm.ptr, %arg1: i64, %arg2: !llvm.ptr, %arg3: i64) {
2094+
// CHECK: call { i64, ptr, ptr } asm sideeffect
2095+
// CHECK-SAME: "ldr x4, [$2], #8 \0A\09ldr x5, [$1] \0A\09mul x6, x4, $4 \0A\09",
2096+
// CHECK-SAME: "=r,=r,=r,=*m,r,*m,0,1,2,*m,~{x4},~{x5},~{x6},~{x7},~{cc}"
2097+
// CHECK-SAME:(ptr elementtype([16 x i64]) %[[A0]], i64 %[[A1]], ptr elementtype([16 x i64]) %[[A2]],
2098+
// CHECK-SAME: i64 %[[A3]], ptr %[[A0]], ptr %[[A2]], ptr elementtype([16 x i64]) %[[A0]])
2099+
%0 = llvm.inline_asm has_side_effects operand_attrs = [
2100+
{elementtype = !llvm.array<16 x i64>}, {}, {elementtype = !llvm.array<16 x i64>},
2101+
{}, {}, {}, {elementtype = !llvm.array<16 x i64>}]
2102+
"ldr x4, [$2], #8 \0A\09ldr x5, [$1] \0A\09mul x6, x4, $4 \0A\09",
2103+
"=r,=r,=r,=*m,r,*m,0,1,2,*m,~{x4},~{x5},~{x6},~{x7},~{cc}"
2104+
%arg0, %arg1, %arg2, %arg3, %arg0, %arg2, %arg0 :
2105+
(!llvm.ptr, i64, !llvm.ptr, i64, !llvm.ptr, !llvm.ptr, !llvm.ptr) -> !llvm.struct<(i64, ptr, ptr)>
20842106
llvm.return
20852107
}
20862108

0 commit comments

Comments
 (0)