Skip to content

Commit fc90a55

Browse files
committed
[CIR] Add InlineAsmOp
1 parent 98164d4 commit fc90a55

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
@@ -2239,6 +2239,89 @@ def CIR_StackRestoreOp : CIR_Op<"stackrestore"> {
22392239
let assemblyFormat = "$ptr attr-dict `:` qualified(type($ptr))";
22402240
}
22412241

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

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

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

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

0 commit comments

Comments
 (0)