Skip to content

Commit a5a32a0

Browse files
committed
[CIR] Add InlineAsmOp
1 parent 16ad202 commit a5a32a0

File tree

2 files changed

+285
-0
lines changed

2 files changed

+285
-0
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2254,6 +2254,89 @@ def CIR_StackRestoreOp : CIR_Op<"stackrestore"> {
22542254
let assemblyFormat = "$ptr attr-dict `:` qualified(type($ptr))";
22552255
}
22562256

2257+
//===----------------------------------------------------------------------===//
2258+
// InlineAsmOp
2259+
//===----------------------------------------------------------------------===//
2260+
2261+
def CIR_AsmFlavor : CIR_I32EnumAttr<"AsmFlavor", "ATT or Intel",
2262+
[I32EnumAttrCase<"x86_att", 0>,
2263+
I32EnumAttrCase<"x86_intel", 1>]>;
2264+
2265+
def CIR_InlineAsmOp : CIR_Op<"asm", [RecursiveMemoryEffects]> {
2266+
let description = [{
2267+
The `cir.asm` operation represents C/C++ asm inline.
2268+
2269+
CIR constraints strings follow barely the same rules that are established
2270+
for the C level assembler constraints with several differences caused by
2271+
clang::AsmStmt processing.
2272+
2273+
Thus, numbers that appears in the constraint string may also refer to:
2274+
- the output variable index referenced by the input operands.
2275+
- the index of early-clobber operand
2276+
2277+
Operand attributes are a storage, where each element corresponds to the
2278+
operand with the same index. The first index relates to the operation
2279+
result (if any).
2280+
Note, the operands themselves are stored as VariadicOfVariadic in the next
2281+
order: output, input and then in/out operands.
2282+
2283+
Note, when several output operands are present, the result type may be
2284+
represented as an anon record type.
2285+
2286+
Example:
2287+
```C++
2288+
__asm__("foo" : : : );
2289+
__asm__("bar $42 %[val]" : [val] "=r" (x), "+&r"(x));
2290+
__asm__("baz $42 %[val]" : [val] "=r" (x), "+&r"(x) : "[val]"(y));
2291+
```
2292+
2293+
```mlir
2294+
!rec_22anon2E022 = !cir.record<struct "anon.0" {!cir.int<s, 32>, !cir.int<s, 32>}>
2295+
!rec_22anon2E122 = !cir.record<struct "anon.1" {!cir.int<s, 32>, !cir.int<s, 32>}>
2296+
...
2297+
%0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init]
2298+
%1 = cir.alloca !s32i, !cir.ptr<!s32i>, ["y", init]
2299+
...
2300+
%2 = cir.load %0 : !cir.ptr<!s32i>, !s32i
2301+
%3 = cir.load %1 : !cir.ptr<!s32i>, !s32i
2302+
2303+
cir.asm(x86_att,
2304+
out = [],
2305+
in = [],
2306+
in_out = [],
2307+
{"foo" "~{dirflag},~{fpsr},~{flags}"}) side_effects
2308+
2309+
cir.asm(x86_att,
2310+
out = [],
2311+
in = [],
2312+
in_out = [%2 : !s32i],
2313+
{"bar $$42 $0" "=r,=&r,1,~{dirflag},~{fpsr},~{flags}"}) -> !rec_22anon2E022
2314+
2315+
cir.asm(x86_att,
2316+
out = [],
2317+
in = [%3 : !s32i],
2318+
in_out = [%2 : !s32i],
2319+
{"baz $$42 $0" "=r,=&r,0,1,~{dirflag},~{fpsr},~{flags}"}) -> !rec_22anon2E122
2320+
```
2321+
}];
2322+
2323+
let results = (outs Optional<CIR_AnyType>:$res);
2324+
2325+
let arguments =
2326+
(ins VariadicOfVariadic<AnyType, "operands_segments">:$asm_operands,
2327+
StrAttr:$asm_string, StrAttr:$constraints, UnitAttr:$side_effects,
2328+
CIR_AsmFlavor:$asm_flavor, ArrayAttr:$operand_attrs,
2329+
DenseI32ArrayAttr:$operands_segments);
2330+
2331+
let builders = [OpBuilder<(ins
2332+
"llvm::ArrayRef<mlir::ValueRange>":$asmOperands,
2333+
"llvm::StringRef":$asmString, "llvm::StringRef":$constraints,
2334+
"bool":$sideEffects, "AsmFlavor":$asmFlavor,
2335+
"llvm::ArrayRef<mlir::Attribute>":$operandAttrs)>];
2336+
2337+
let hasCustomAssemblyFormat = 1;
2338+
}
2339+
22572340
//===----------------------------------------------------------------------===//
22582341
// UnreachableOp
22592342
//===----------------------------------------------------------------------===//

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2419,6 +2419,208 @@ OpFoldResult RotateOp::fold(FoldAdaptor adaptor) {
24192419
return IntAttr::get(input.getContext(), input.getType(), resultValue);
24202420
}
24212421

2422+
//===----------------------------------------------------------------------===//
2423+
// InlineAsmOp
2424+
//===----------------------------------------------------------------------===//
2425+
2426+
void cir::InlineAsmOp::print(OpAsmPrinter &p) {
2427+
p << '(' << getAsmFlavor() << ", ";
2428+
p.increaseIndent();
2429+
p.printNewline();
2430+
2431+
llvm::SmallVector<std::string, 3> names{"out", "in", "in_out"};
2432+
auto *nameIt = names.begin();
2433+
auto *attrIt = getOperandAttrs().begin();
2434+
2435+
for (auto ops : getAsmOperands()) {
2436+
p << *nameIt << " = ";
2437+
2438+
p << '[';
2439+
llvm::interleaveComma(llvm::make_range(ops.begin(), ops.end()), p,
2440+
[&](Value value) {
2441+
p.printOperand(value);
2442+
p << " : " << value.getType();
2443+
if (*attrIt)
2444+
p << " (maybe_memory)";
2445+
attrIt++;
2446+
});
2447+
p << "],";
2448+
p.printNewline();
2449+
++nameIt;
2450+
}
2451+
2452+
p << "{";
2453+
p.printString(getAsmString());
2454+
p << " ";
2455+
p.printString(getConstraints());
2456+
p << "}";
2457+
p.decreaseIndent();
2458+
p << ')';
2459+
if (getSideEffects())
2460+
p << " side_effects";
2461+
2462+
llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
2463+
elidedAttrs.push_back("asm_flavor");
2464+
elidedAttrs.push_back("asm_string");
2465+
elidedAttrs.push_back("constraints");
2466+
elidedAttrs.push_back("operand_attrs");
2467+
elidedAttrs.push_back("operands_segments");
2468+
elidedAttrs.push_back("side_effects");
2469+
p.printOptionalAttrDict(getOperation()->getAttrs(), elidedAttrs);
2470+
2471+
if (auto v = getRes())
2472+
p << " -> " << v.getType();
2473+
}
2474+
2475+
void cir::InlineAsmOp::build(OpBuilder &odsBuilder, OperationState &odsState,
2476+
ArrayRef<ValueRange> asmOperands,
2477+
StringRef asmString, StringRef constraints,
2478+
bool sideEffects, cir::AsmFlavor asmFlavor,
2479+
ArrayRef<Attribute> operandAttrs) {
2480+
// Set up the operands_segments for VariadicOfVariadic
2481+
SmallVector<int32_t> segments;
2482+
for (auto operandRange : asmOperands) {
2483+
segments.push_back(operandRange.size());
2484+
odsState.addOperands(operandRange);
2485+
}
2486+
2487+
odsState.addAttribute(
2488+
"operands_segments",
2489+
DenseI32ArrayAttr::get(odsBuilder.getContext(), segments));
2490+
odsState.addAttribute("asm_string", odsBuilder.getStringAttr(asmString));
2491+
odsState.addAttribute("constraints", odsBuilder.getStringAttr(constraints));
2492+
odsState.addAttribute("asm_flavor",
2493+
AsmFlavorAttr::get(odsBuilder.getContext(), asmFlavor));
2494+
2495+
if (sideEffects)
2496+
odsState.addAttribute("side_effects", odsBuilder.getUnitAttr());
2497+
2498+
odsState.addAttribute("operand_attrs", odsBuilder.getArrayAttr(operandAttrs));
2499+
}
2500+
2501+
ParseResult cir::InlineAsmOp::parse(OpAsmParser &parser,
2502+
OperationState &result) {
2503+
llvm::SmallVector<mlir::Attribute> operandAttrs;
2504+
llvm::SmallVector<int32_t> operandsGroupSizes;
2505+
std::string asmString, constraints;
2506+
Type resType;
2507+
auto *ctxt = parser.getBuilder().getContext();
2508+
2509+
auto error = [&](const Twine &msg) -> LogicalResult {
2510+
return parser.emitError(parser.getCurrentLocation(), msg);
2511+
};
2512+
2513+
auto expected = [&](const std::string &c) {
2514+
return error("expected '" + c + "'");
2515+
};
2516+
2517+
if (parser.parseLParen().failed())
2518+
return expected("(");
2519+
2520+
auto flavor = FieldParser<AsmFlavor, AsmFlavor>::parse(parser);
2521+
if (failed(flavor))
2522+
return error("Unknown AsmFlavor");
2523+
2524+
if (parser.parseComma().failed())
2525+
return expected(",");
2526+
2527+
auto parseValue = [&](Value &v) {
2528+
OpAsmParser::UnresolvedOperand op;
2529+
2530+
if (parser.parseOperand(op) || parser.parseColon())
2531+
return mlir::failure();
2532+
2533+
Type typ;
2534+
if (parser.parseType(typ).failed())
2535+
return error("can't parse operand type");
2536+
llvm::SmallVector<mlir::Value> tmp;
2537+
if (parser.resolveOperand(op, typ, tmp))
2538+
return error("can't resolve operand");
2539+
v = tmp[0];
2540+
return mlir::success();
2541+
};
2542+
2543+
auto parseOperands = [&](llvm::StringRef name) {
2544+
if (parser.parseKeyword(name).failed())
2545+
return error("expected " + name + " operands here");
2546+
if (parser.parseEqual().failed())
2547+
return expected("=");
2548+
if (parser.parseLSquare().failed())
2549+
return expected("[");
2550+
2551+
int size = 0;
2552+
if (parser.parseOptionalRSquare().succeeded()) {
2553+
operandsGroupSizes.push_back(size);
2554+
if (parser.parseComma())
2555+
return expected(",");
2556+
return mlir::success();
2557+
}
2558+
2559+
if (parser.parseCommaSeparatedList([&]() {
2560+
Value val;
2561+
if (parseValue(val).succeeded()) {
2562+
result.operands.push_back(val);
2563+
size++;
2564+
2565+
if (parser.parseOptionalLParen().failed()) {
2566+
operandAttrs.push_back(mlir::Attribute());
2567+
return mlir::success();
2568+
}
2569+
2570+
if (parser.parseKeyword("maybe_memory").succeeded()) {
2571+
operandAttrs.push_back(mlir::UnitAttr::get(ctxt));
2572+
if (parser.parseRParen())
2573+
return expected(")");
2574+
return mlir::success();
2575+
}
2576+
}
2577+
return mlir::failure();
2578+
}))
2579+
return mlir::failure();
2580+
2581+
if (parser.parseRSquare().failed() || parser.parseComma().failed())
2582+
return expected("]");
2583+
operandsGroupSizes.push_back(size);
2584+
return mlir::success();
2585+
};
2586+
2587+
if (parseOperands("out").failed() || parseOperands("in").failed() ||
2588+
parseOperands("in_out").failed())
2589+
return error("failed to parse operands");
2590+
2591+
if (parser.parseLBrace())
2592+
return expected("{");
2593+
if (parser.parseString(&asmString))
2594+
return error("asm string parsing failed");
2595+
if (parser.parseString(&constraints))
2596+
return error("constraints string parsing failed");
2597+
if (parser.parseRBrace())
2598+
return expected("}");
2599+
if (parser.parseRParen())
2600+
return expected(")");
2601+
2602+
if (parser.parseOptionalKeyword("side_effects").succeeded())
2603+
result.attributes.set("side_effects", UnitAttr::get(ctxt));
2604+
2605+
if (parser.parseOptionalArrow().succeeded() &&
2606+
parser.parseType(resType).failed())
2607+
return mlir::failure();
2608+
2609+
if (parser.parseOptionalAttrDict(result.attributes))
2610+
return mlir::failure();
2611+
2612+
result.attributes.set("asm_flavor", AsmFlavorAttr::get(ctxt, *flavor));
2613+
result.attributes.set("asm_string", StringAttr::get(ctxt, asmString));
2614+
result.attributes.set("constraints", StringAttr::get(ctxt, constraints));
2615+
result.attributes.set("operand_attrs", ArrayAttr::get(ctxt, operandAttrs));
2616+
result.getOrAddProperties<InlineAsmOp::Properties>().operands_segments =
2617+
parser.getBuilder().getDenseI32ArrayAttr(operandsGroupSizes);
2618+
if (resType)
2619+
result.addTypes(TypeRange{resType});
2620+
2621+
return mlir::success();
2622+
}
2623+
24222624
//===----------------------------------------------------------------------===//
24232625
// TableGen'd op method definitions
24242626
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)