Skip to content

Commit 9a28783

Browse files
el-evandykaylormmha
authored
[CIR] Add InlineAsmOp (#153362)
- Part of #153267 --------- Co-authored-by: Andy Kaylor <[email protected]> Co-authored-by: Morris Hafner <[email protected]>
1 parent efce767 commit 9a28783

File tree

3 files changed

+396
-0
lines changed

3 files changed

+396
-0
lines changed

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

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2254,6 +2254,87 @@ 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 the same rules that are established for
2270+
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+
The operands themselves are stored as VariadicOfVariadic in the following
2281+
order: output, input and then in/out operands. When several output operands
2282+
are present, the result type may be represented as an anonymous record type.
2283+
2284+
Example:
2285+
```C++
2286+
__asm__("foo" : : : );
2287+
__asm__("bar $42 %[val]" : [val] "=r" (x), "+&r"(x));
2288+
__asm__("baz $42 %[val]" : [val] "=r" (x), "+&r"(x) : "[val]"(y));
2289+
```
2290+
2291+
```mlir
2292+
!rec_22anon2E022 = !cir.record<struct "anon.0" {!cir.int<s, 32>, !cir.int<s, 32>}>
2293+
!rec_22anon2E122 = !cir.record<struct "anon.1" {!cir.int<s, 32>, !cir.int<s, 32>}>
2294+
...
2295+
%0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init]
2296+
%1 = cir.alloca !s32i, !cir.ptr<!s32i>, ["y", init]
2297+
...
2298+
%2 = cir.load %0 : !cir.ptr<!s32i>, !s32i
2299+
%3 = cir.load %1 : !cir.ptr<!s32i>, !s32i
2300+
2301+
cir.asm(x86_att,
2302+
out = [],
2303+
in = [],
2304+
in_out = [],
2305+
{"foo" "~{dirflag},~{fpsr},~{flags}"}) side_effects
2306+
2307+
cir.asm(x86_att,
2308+
out = [],
2309+
in = [],
2310+
in_out = [%2 : !s32i],
2311+
{"bar $$42 $0" "=r,=&r,1,~{dirflag},~{fpsr},~{flags}"}) -> !rec_22anon2E022
2312+
2313+
cir.asm(x86_att,
2314+
out = [],
2315+
in = [%3 : !s32i],
2316+
in_out = [%2 : !s32i],
2317+
{"baz $$42 $0" "=r,=&r,0,1,~{dirflag},~{fpsr},~{flags}"}) -> !rec_22anon2E122
2318+
```
2319+
}];
2320+
2321+
let results = (outs Optional<CIR_AnyType>:$res);
2322+
2323+
let arguments =
2324+
(ins VariadicOfVariadic<AnyType, "operands_segments">:$asm_operands,
2325+
StrAttr:$asm_string, StrAttr:$constraints, UnitAttr:$side_effects,
2326+
CIR_AsmFlavor:$asm_flavor, ArrayAttr:$operand_attrs,
2327+
DenseI32ArrayAttr:$operands_segments);
2328+
2329+
let builders = [OpBuilder<(ins
2330+
"llvm::ArrayRef<mlir::ValueRange>":$asmOperands,
2331+
"llvm::StringRef":$asmString, "llvm::StringRef":$constraints,
2332+
"bool":$sideEffects, "AsmFlavor":$asmFlavor,
2333+
"llvm::ArrayRef<mlir::Attribute>":$operandAttrs)>];
2334+
2335+
let hasCustomAssemblyFormat = 1;
2336+
}
2337+
22572338
//===----------------------------------------------------------------------===//
22582339
// UnreachableOp
22592340
//===----------------------------------------------------------------------===//

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

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2419,6 +2419,209 @@ 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 (mlir::OperandRange 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+
std::array elidedAttrs{
2463+
llvm::StringRef("asm_flavor"), llvm::StringRef("asm_string"),
2464+
llvm::StringRef("constraints"), llvm::StringRef("operand_attrs"),
2465+
llvm::StringRef("operands_segments"), llvm::StringRef("side_effects")};
2466+
p.printOptionalAttrDict(getOperation()->getAttrs(), elidedAttrs);
2467+
2468+
if (auto v = getRes())
2469+
p << " -> " << v.getType();
2470+
}
2471+
2472+
void cir::InlineAsmOp::build(OpBuilder &odsBuilder, OperationState &odsState,
2473+
ArrayRef<ValueRange> asmOperands,
2474+
StringRef asmString, StringRef constraints,
2475+
bool sideEffects, cir::AsmFlavor asmFlavor,
2476+
ArrayRef<Attribute> operandAttrs) {
2477+
// Set up the operands_segments for VariadicOfVariadic
2478+
SmallVector<int32_t> segments;
2479+
for (auto operandRange : asmOperands) {
2480+
segments.push_back(operandRange.size());
2481+
odsState.addOperands(operandRange);
2482+
}
2483+
2484+
odsState.addAttribute(
2485+
"operands_segments",
2486+
DenseI32ArrayAttr::get(odsBuilder.getContext(), segments));
2487+
odsState.addAttribute("asm_string", odsBuilder.getStringAttr(asmString));
2488+
odsState.addAttribute("constraints", odsBuilder.getStringAttr(constraints));
2489+
odsState.addAttribute("asm_flavor",
2490+
AsmFlavorAttr::get(odsBuilder.getContext(), asmFlavor));
2491+
2492+
if (sideEffects)
2493+
odsState.addAttribute("side_effects", odsBuilder.getUnitAttr());
2494+
2495+
odsState.addAttribute("operand_attrs", odsBuilder.getArrayAttr(operandAttrs));
2496+
}
2497+
2498+
ParseResult cir::InlineAsmOp::parse(OpAsmParser &parser,
2499+
OperationState &result) {
2500+
llvm::SmallVector<mlir::Attribute> operandAttrs;
2501+
llvm::SmallVector<int32_t> operandsGroupSizes;
2502+
std::string asmString, constraints;
2503+
Type resType;
2504+
MLIRContext *ctxt = parser.getBuilder().getContext();
2505+
2506+
auto error = [&](const Twine &msg) -> LogicalResult {
2507+
return parser.emitError(parser.getCurrentLocation(), msg);
2508+
};
2509+
2510+
auto expected = [&](const std::string &c) {
2511+
return error("expected '" + c + "'");
2512+
};
2513+
2514+
if (parser.parseLParen().failed())
2515+
return expected("(");
2516+
2517+
auto flavor = FieldParser<AsmFlavor, AsmFlavor>::parse(parser);
2518+
if (failed(flavor))
2519+
return error("Unknown AsmFlavor");
2520+
2521+
if (parser.parseComma().failed())
2522+
return expected(",");
2523+
2524+
auto parseValue = [&](Value &v) {
2525+
OpAsmParser::UnresolvedOperand op;
2526+
2527+
if (parser.parseOperand(op) || parser.parseColon())
2528+
return error("can't parse operand");
2529+
2530+
Type typ;
2531+
if (parser.parseType(typ).failed())
2532+
return error("can't parse operand type");
2533+
llvm::SmallVector<mlir::Value> tmp;
2534+
if (parser.resolveOperand(op, typ, tmp))
2535+
return error("can't resolve operand");
2536+
v = tmp[0];
2537+
return mlir::success();
2538+
};
2539+
2540+
auto parseOperands = [&](llvm::StringRef name) {
2541+
if (parser.parseKeyword(name).failed())
2542+
return error("expected " + name + " operands here");
2543+
if (parser.parseEqual().failed())
2544+
return expected("=");
2545+
if (parser.parseLSquare().failed())
2546+
return expected("[");
2547+
2548+
int size = 0;
2549+
if (parser.parseOptionalRSquare().succeeded()) {
2550+
operandsGroupSizes.push_back(size);
2551+
if (parser.parseComma())
2552+
return expected(",");
2553+
return mlir::success();
2554+
}
2555+
2556+
auto parseOperand = [&]() {
2557+
Value val;
2558+
if (parseValue(val).succeeded()) {
2559+
result.operands.push_back(val);
2560+
size++;
2561+
2562+
if (parser.parseOptionalLParen().failed()) {
2563+
operandAttrs.push_back(mlir::Attribute());
2564+
return mlir::success();
2565+
}
2566+
2567+
if (parser.parseKeyword("maybe_memory").succeeded()) {
2568+
operandAttrs.push_back(mlir::UnitAttr::get(ctxt));
2569+
if (parser.parseRParen())
2570+
return expected(")");
2571+
return mlir::success();
2572+
} else {
2573+
return expected("maybe_memory");
2574+
}
2575+
}
2576+
return mlir::failure();
2577+
};
2578+
2579+
if (parser.parseCommaSeparatedList(parseOperand).failed())
2580+
return mlir::failure();
2581+
2582+
if (parser.parseRSquare().failed() || parser.parseComma().failed())
2583+
return expected("]");
2584+
operandsGroupSizes.push_back(size);
2585+
return mlir::success();
2586+
};
2587+
2588+
if (parseOperands("out").failed() || parseOperands("in").failed() ||
2589+
parseOperands("in_out").failed())
2590+
return error("failed to parse operands");
2591+
2592+
if (parser.parseLBrace())
2593+
return expected("{");
2594+
if (parser.parseString(&asmString))
2595+
return error("asm string parsing failed");
2596+
if (parser.parseString(&constraints))
2597+
return error("constraints string parsing failed");
2598+
if (parser.parseRBrace())
2599+
return expected("}");
2600+
if (parser.parseRParen())
2601+
return expected(")");
2602+
2603+
if (parser.parseOptionalKeyword("side_effects").succeeded())
2604+
result.attributes.set("side_effects", UnitAttr::get(ctxt));
2605+
2606+
if (parser.parseOptionalArrow().succeeded() &&
2607+
parser.parseType(resType).failed())
2608+
return mlir::failure();
2609+
2610+
if (parser.parseOptionalAttrDict(result.attributes).failed())
2611+
return mlir::failure();
2612+
2613+
result.attributes.set("asm_flavor", AsmFlavorAttr::get(ctxt, *flavor));
2614+
result.attributes.set("asm_string", StringAttr::get(ctxt, asmString));
2615+
result.attributes.set("constraints", StringAttr::get(ctxt, constraints));
2616+
result.attributes.set("operand_attrs", ArrayAttr::get(ctxt, operandAttrs));
2617+
result.getOrAddProperties<InlineAsmOp::Properties>().operands_segments =
2618+
parser.getBuilder().getDenseI32ArrayAttr(operandsGroupSizes);
2619+
if (resType)
2620+
result.addTypes(TypeRange{resType});
2621+
2622+
return mlir::success();
2623+
}
2624+
24222625
//===----------------------------------------------------------------------===//
24232626
// TableGen'd op method definitions
24242627
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)