Skip to content

Commit dc0becc

Browse files
el-evmmha
andauthored
[CIR] Add InlineAsmOp lowering to LLVM (#153387)
- Part of #153267 Added support for lowering `InlineAsmOp` directly to LLVM IR --------- Co-authored-by: Morris Hafner <[email protected]>
1 parent ac0ad50 commit dc0becc

File tree

3 files changed

+167
-0
lines changed

3 files changed

+167
-0
lines changed

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2276,6 +2276,8 @@ void ConvertCIRToLLVMPass::runOnOperation() {
22762276
patterns.add<CIRToLLVMCastOpLowering>(converter, patterns.getContext(), dl);
22772277
patterns.add<CIRToLLVMPtrStrideOpLowering>(converter, patterns.getContext(),
22782278
dl);
2279+
patterns.add<CIRToLLVMInlineAsmOpLowering>(converter, patterns.getContext(),
2280+
dl);
22792281
patterns.add<
22802282
// clang-format off
22812283
CIRToLLVMAssumeOpLowering,
@@ -2956,6 +2958,68 @@ mlir::LogicalResult CIRToLLVMGetBitfieldOpLowering::matchAndRewrite(
29562958
return mlir::success();
29572959
}
29582960

2961+
mlir::LogicalResult CIRToLLVMInlineAsmOpLowering::matchAndRewrite(
2962+
cir::InlineAsmOp op, OpAdaptor adaptor,
2963+
mlir::ConversionPatternRewriter &rewriter) const {
2964+
mlir::Type llResTy;
2965+
if (op.getNumResults())
2966+
llResTy = getTypeConverter()->convertType(op.getType(0));
2967+
2968+
cir::AsmFlavor dialect = op.getAsmFlavor();
2969+
mlir::LLVM::AsmDialect llDialect = dialect == cir::AsmFlavor::x86_att
2970+
? mlir::LLVM::AsmDialect::AD_ATT
2971+
: mlir::LLVM::AsmDialect::AD_Intel;
2972+
2973+
SmallVector<mlir::Attribute> opAttrs;
2974+
StringRef llvmAttrName = mlir::LLVM::InlineAsmOp::getElementTypeAttrName();
2975+
2976+
// this is for the lowering to LLVM from LLVM dialect. Otherwise, if we
2977+
// don't have the result (i.e. void type as a result of operation), the
2978+
// element type attribute will be attached to the whole instruction, but not
2979+
// to the operand
2980+
if (!op.getNumResults())
2981+
opAttrs.push_back(mlir::Attribute());
2982+
2983+
SmallVector<mlir::Value> llvmOperands;
2984+
SmallVector<mlir::Value> cirOperands;
2985+
for (auto const&[llvmOp, cirOp] :
2986+
zip(adaptor.getAsmOperands(), op.getAsmOperands())) {
2987+
append_range(llvmOperands, llvmOp);
2988+
append_range(cirOperands, cirOp);
2989+
}
2990+
2991+
// so far we infer the llvm dialect element type attr from
2992+
// CIR operand type.
2993+
for (auto const&[cirOpAttr, cirOp] : zip(op.getOperandAttrs(), cirOperands)) {
2994+
if (!cirOpAttr) {
2995+
opAttrs.push_back(mlir::Attribute());
2996+
continue;
2997+
}
2998+
2999+
llvm::SmallVector<mlir::NamedAttribute, 1> attrs;
3000+
cir::PointerType typ =
3001+
mlir::cast<cir::PointerType>(cirOp.getType());
3002+
mlir::TypeAttr typAttr = mlir::TypeAttr::get(convertTypeForMemory(
3003+
*getTypeConverter(), dataLayout, typ.getPointee()));
3004+
3005+
attrs.push_back(rewriter.getNamedAttr(llvmAttrName, typAttr));
3006+
mlir::DictionaryAttr newDict = rewriter.getDictionaryAttr(attrs);
3007+
opAttrs.push_back(newDict);
3008+
}
3009+
3010+
rewriter.replaceOpWithNewOp<mlir::LLVM::InlineAsmOp>(
3011+
op, llResTy, llvmOperands, op.getAsmStringAttr(), op.getConstraintsAttr(),
3012+
op.getSideEffectsAttr(),
3013+
/*is_align_stack*/ mlir::UnitAttr(),
3014+
/*tail_call_kind*/
3015+
mlir::LLVM::TailCallKindAttr::get(
3016+
getContext(), mlir::LLVM::tailcallkind::TailCallKind::None),
3017+
mlir::LLVM::AsmDialectAttr::get(getContext(), llDialect),
3018+
rewriter.getArrayAttr(opAttrs));
3019+
3020+
return mlir::success();
3021+
}
3022+
29593023
std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {
29603024
return std::make_unique<ConvertCIRToLLVMPass>();
29613025
}

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,23 @@ class CIRToLLVMFAbsOpLowering : public mlir::OpConversionPattern<cir::FAbsOp> {
667667
mlir::ConversionPatternRewriter &) const override;
668668
};
669669

670+
class CIRToLLVMInlineAsmOpLowering
671+
: public mlir::OpConversionPattern<cir::InlineAsmOp> {
672+
mlir::DataLayout const &dataLayout;
673+
674+
public:
675+
CIRToLLVMInlineAsmOpLowering(const mlir::TypeConverter &typeConverter,
676+
mlir::MLIRContext *context,
677+
mlir::DataLayout const &dataLayout)
678+
: OpConversionPattern(typeConverter, context), dataLayout(dataLayout) {}
679+
680+
using mlir::OpConversionPattern<cir::InlineAsmOp>::OpConversionPattern;
681+
682+
mlir::LogicalResult
683+
matchAndRewrite(cir::InlineAsmOp op, OpAdaptor,
684+
mlir::ConversionPatternRewriter &) const override;
685+
};
686+
670687
} // namespace direct
671688
} // namespace cir
672689

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// RUN: cir-translate %s -cir-to-llvmir --target x86_64-unknown-linux-gnu --disable-cc-lowering | FileCheck %s
2+
3+
!s32i = !cir.int<s, 32>
4+
!u32i = !cir.int<u, 32>
5+
6+
module {
7+
cir.func @f1() {
8+
// CHECK: call void asm "", "~{dirflag},~{fpsr},~{flags}"()
9+
cir.asm(x86_att,
10+
out = [],
11+
in = [],
12+
in_out = [],
13+
{"" "~{dirflag},~{fpsr},~{flags}"})
14+
cir.return
15+
}
16+
17+
cir.func @f2() {
18+
// CHECK: call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"()
19+
cir.asm(x86_att,
20+
out = [],
21+
in = [],
22+
in_out = [],
23+
{"" "~{dirflag},~{fpsr},~{flags}"}) side_effects
24+
cir.return
25+
}
26+
27+
cir.func @f3() {
28+
// CHECK: call void asm sideeffect "abc", "~{dirflag},~{fpsr},~{flags}"()
29+
cir.asm(x86_att,
30+
out = [],
31+
in = [],
32+
in_out = [],
33+
{"abc" "~{dirflag},~{fpsr},~{flags}"}) side_effects
34+
cir.return
35+
}
36+
37+
cir.func @f4(%arg0: !s32i) {
38+
%0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init] {alignment = 4 : i64}
39+
cir.store %arg0, %0 : !s32i, !cir.ptr<!s32i>
40+
// CHECK: call void asm sideeffect "", "*m,~{dirflag},~{fpsr},~{flags}"(ptr elementtype(i32) %2)
41+
cir.asm(x86_att,
42+
out = [],
43+
in = [%0 : !cir.ptr<!s32i> (maybe_memory)],
44+
in_out = [],
45+
{"" "*m,~{dirflag},~{fpsr},~{flags}"}) side_effects
46+
cir.return
47+
}
48+
49+
cir.func @f5() {
50+
// CHECK: call void asm inteldialect "", "~{dirflag},~{fpsr},~{flags}"()
51+
cir.asm(x86_intel,
52+
out = [],
53+
in = [],
54+
in_out = [],
55+
{"" "~{dirflag},~{fpsr},~{flags}"})
56+
cir.return
57+
}
58+
59+
cir.func @f6() -> !s32i {
60+
%0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init] {alignment = 4 : i64}
61+
// CHECK: %2 = call i32 asm sideeffect "movl $$42, $0", "=r,~{dirflag},~{fpsr},~{flags}"()
62+
%1 = cir.asm(x86_att,
63+
out = [],
64+
in = [],
65+
in_out = [],
66+
{"movl $$42, $0" "=r,~{dirflag},~{fpsr},~{flags}"}) side_effects -> !s32i
67+
cir.store align(4) %1, %0 : !s32i, !cir.ptr<!s32i>
68+
%3 = cir.load align(4) %0 : !cir.ptr<!s32i>, !s32i
69+
cir.return %3 : !s32i
70+
}
71+
72+
cir.func @f7(%arg0: !u32i) -> !u32i {
73+
%0 = cir.alloca !u32i, !cir.ptr<!u32i>, ["x", init] {alignment = 4 : i64}
74+
cir.store %arg0, %0 : !u32i, !cir.ptr<!u32i>
75+
%1 = cir.load align(4) %0 : !cir.ptr<!u32i>, !u32i
76+
// CHECK: %4 = call i32 asm sideeffect "addl $$42, $0", "=r,0,~{dirflag},~{fpsr},~{flags}"(i32 %3)
77+
%2 = cir.asm(x86_att,
78+
out = [],
79+
in = [],
80+
in_out = [%1 : !u32i],
81+
{"addl $$42, $0" "=r,0,~{dirflag},~{fpsr},~{flags}"}) side_effects -> !u32i
82+
cir.store align(4) %2, %0 : !u32i, !cir.ptr<!u32i>
83+
%3 = cir.load align(4) %0 : !cir.ptr<!u32i>, !u32i
84+
cir.return %3 : !u32i
85+
}
86+
}

0 commit comments

Comments
 (0)