2019-01-15 10:53:22 -08:00
|
|
|
//===- LLVMDialect.cpp - LLVM IR Ops and Dialect registration -------------===//
|
|
|
|
//
|
2019-12-23 09:35:36 -08:00
|
|
|
// Part of the MLIR Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2019-01-15 10:53:22 -08:00
|
|
|
//
|
2019-12-23 09:35:36 -08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2019-01-15 10:53:22 -08:00
|
|
|
//
|
|
|
|
// This file defines the types and operation details for the LLVM IR dialect in
|
|
|
|
// MLIR, and the LLVM IR dialect. It also registers the dialect.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2019-08-19 11:00:47 -07:00
|
|
|
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
|
2019-04-02 15:33:54 -07:00
|
|
|
#include "mlir/IR/Builders.h"
|
2019-11-01 14:47:42 -07:00
|
|
|
#include "mlir/IR/DialectImplementation.h"
|
2019-11-28 11:50:47 -08:00
|
|
|
#include "mlir/IR/FunctionImplementation.h"
|
2019-01-15 10:53:22 -08:00
|
|
|
#include "mlir/IR/MLIRContext.h"
|
2019-05-22 13:41:23 -07:00
|
|
|
#include "mlir/IR/Module.h"
|
2019-07-15 06:55:53 -07:00
|
|
|
#include "mlir/IR/StandardTypes.h"
|
2019-01-15 10:53:22 -08:00
|
|
|
|
|
|
|
#include "llvm/AsmParser/Parser.h"
|
2019-03-06 09:34:53 -08:00
|
|
|
#include "llvm/IR/Attributes.h"
|
2019-04-02 15:33:54 -07:00
|
|
|
#include "llvm/IR/Function.h"
|
2019-01-15 10:53:22 -08:00
|
|
|
#include "llvm/IR/Type.h"
|
2019-05-22 14:56:07 -07:00
|
|
|
#include "llvm/Support/Mutex.h"
|
2019-01-15 10:53:22 -08:00
|
|
|
#include "llvm/Support/SourceMgr.h"
|
|
|
|
|
|
|
|
using namespace mlir;
|
|
|
|
using namespace mlir::LLVM;
|
|
|
|
|
2019-08-19 11:00:47 -07:00
|
|
|
#include "mlir/Dialect/LLVMIR/LLVMOpsEnums.cpp.inc"
|
2019-07-15 05:45:08 -07:00
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
2019-08-08 18:29:23 -07:00
|
|
|
// Printing/parsing for LLVM::CmpOp.
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printICmpOp(OpAsmPrinter &p, ICmpOp &op) {
|
|
|
|
p << op.getOperationName() << " \"" << stringifyICmpPredicate(op.predicate())
|
|
|
|
<< "\" " << *op.getOperand(0) << ", " << *op.getOperand(1);
|
|
|
|
p.printOptionalAttrDict(op.getAttrs(), {"predicate"});
|
|
|
|
p << " : " << op.lhs()->getType();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printFCmpOp(OpAsmPrinter &p, FCmpOp &op) {
|
|
|
|
p << op.getOperationName() << " \"" << stringifyFCmpPredicate(op.predicate())
|
|
|
|
<< "\" " << *op.getOperand(0) << ", " << *op.getOperand(1);
|
|
|
|
p.printOptionalAttrDict(op.getAttrs(), {"predicate"});
|
|
|
|
p << " : " << op.lhs()->getType();
|
2019-08-08 18:29:23 -07:00
|
|
|
}
|
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
// <operation> ::= `llvm.icmp` string-literal ssa-use `,` ssa-use
|
|
|
|
// attribute-dict? `:` type
|
2019-08-08 18:29:23 -07:00
|
|
|
// <operation> ::= `llvm.fcmp` string-literal ssa-use `,` ssa-use
|
|
|
|
// attribute-dict? `:` type
|
|
|
|
template <typename CmpPredicateType>
|
2019-09-20 19:47:05 -07:00
|
|
|
static ParseResult parseCmpOp(OpAsmParser &parser, OperationState &result) {
|
2019-09-20 11:36:49 -07:00
|
|
|
Builder &builder = parser.getBuilder();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
Attribute predicate;
|
|
|
|
SmallVector<NamedAttribute, 4> attrs;
|
|
|
|
OpAsmParser::OperandType lhs, rhs;
|
|
|
|
Type type;
|
|
|
|
llvm::SMLoc predicateLoc, trailingTypeLoc;
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.getCurrentLocation(&predicateLoc) ||
|
|
|
|
parser.parseAttribute(predicate, "predicate", attrs) ||
|
|
|
|
parser.parseOperand(lhs) || parser.parseComma() ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseOperand(rhs) || parser.parseOptionalAttrDict(attrs) ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.parseColon() || parser.getCurrentLocation(&trailingTypeLoc) ||
|
|
|
|
parser.parseType(type) ||
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.resolveOperand(lhs, type, result.operands) ||
|
|
|
|
parser.resolveOperand(rhs, type, result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
// Replace the string attribute `predicate` with an integer attribute.
|
|
|
|
auto predicateStr = predicate.dyn_cast<StringAttr>();
|
|
|
|
if (!predicateStr)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(predicateLoc,
|
|
|
|
"expected 'predicate' attribute of string type");
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-08-08 18:29:23 -07:00
|
|
|
int64_t predicateValue = 0;
|
|
|
|
if (std::is_same<CmpPredicateType, ICmpPredicate>()) {
|
|
|
|
Optional<ICmpPredicate> predicate =
|
|
|
|
symbolizeICmpPredicate(predicateStr.getValue());
|
|
|
|
if (!predicate)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(predicateLoc)
|
2019-08-08 18:29:23 -07:00
|
|
|
<< "'" << predicateStr.getValue()
|
|
|
|
<< "' is an incorrect value of the 'predicate' attribute";
|
|
|
|
predicateValue = static_cast<int64_t>(predicate.getValue());
|
|
|
|
} else {
|
|
|
|
Optional<FCmpPredicate> predicate =
|
|
|
|
symbolizeFCmpPredicate(predicateStr.getValue());
|
|
|
|
if (!predicate)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(predicateLoc)
|
2019-08-08 18:29:23 -07:00
|
|
|
<< "'" << predicateStr.getValue()
|
|
|
|
<< "' is an incorrect value of the 'predicate' attribute";
|
|
|
|
predicateValue = static_cast<int64_t>(predicate.getValue());
|
|
|
|
}
|
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
attrs[0].second = parser.getBuilder().getI64IntegerAttr(predicateValue);
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
// The result type is either i1 or a vector type <? x i1> if the inputs are
|
|
|
|
// vectors.
|
2019-05-13 12:42:25 -07:00
|
|
|
auto *dialect = builder.getContext()->getRegisteredDialect<LLVMDialect>();
|
2019-05-22 14:56:07 -07:00
|
|
|
auto resultType = LLVMType::getInt1Ty(dialect);
|
2019-04-02 15:33:54 -07:00
|
|
|
auto argType = type.dyn_cast<LLVM::LLVMType>();
|
|
|
|
if (!argType)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(trailingTypeLoc, "expected LLVM IR dialect type");
|
2019-04-02 15:33:54 -07:00
|
|
|
if (argType.getUnderlyingType()->isVectorTy())
|
2019-05-22 14:56:07 -07:00
|
|
|
resultType = LLVMType::getVectorTy(
|
|
|
|
resultType, argType.getUnderlyingType()->getVectorNumElements());
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.attributes = attrs;
|
|
|
|
result.addTypes({resultType});
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::AllocaOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printAllocaOp(OpAsmPrinter &p, AllocaOp &op) {
|
2019-05-22 14:56:07 -07:00
|
|
|
auto elemTy = op.getType().cast<LLVM::LLVMType>().getPointerElementTy();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
auto funcTy = FunctionType::get({op.arraySize()->getType()}, {op.getType()},
|
|
|
|
op.getContext());
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
p << op.getOperationName() << ' ' << *op.arraySize() << " x " << elemTy;
|
2019-08-18 18:54:50 -07:00
|
|
|
if (op.alignment().hasValue() && op.alignment()->getSExtValue() != 0)
|
2019-09-20 20:43:02 -07:00
|
|
|
p.printOptionalAttrDict(op.getAttrs());
|
2019-08-18 18:54:50 -07:00
|
|
|
else
|
2019-09-20 20:43:02 -07:00
|
|
|
p.printOptionalAttrDict(op.getAttrs(), {"alignment"});
|
|
|
|
p << " : " << funcTy;
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.alloca` ssa-use `x` type attribute-dict?
|
|
|
|
// `:` type `,` type
|
2019-09-20 19:47:05 -07:00
|
|
|
static ParseResult parseAllocaOp(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
SmallVector<NamedAttribute, 4> attrs;
|
|
|
|
OpAsmParser::OperandType arraySize;
|
|
|
|
Type type, elemType;
|
|
|
|
llvm::SMLoc trailingTypeLoc;
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseOperand(arraySize) || parser.parseKeyword("x") ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseType(elemType) || parser.parseOptionalAttrDict(attrs) ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.parseColon() || parser.getCurrentLocation(&trailingTypeLoc) ||
|
|
|
|
parser.parseType(type))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
// Extract the result type from the trailing function type.
|
|
|
|
auto funcType = type.dyn_cast<FunctionType>();
|
|
|
|
if (!funcType || funcType.getNumInputs() != 1 ||
|
|
|
|
funcType.getNumResults() != 1)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(
|
2019-04-02 15:33:54 -07:00
|
|
|
trailingTypeLoc,
|
|
|
|
"expected trailing function type with one argument and one result");
|
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
if (parser.resolveOperand(arraySize, funcType.getInput(0), result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.attributes = attrs;
|
|
|
|
result.addTypes({funcType.getResult(0)});
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::GEPOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printGEPOp(OpAsmPrinter &p, GEPOp &op) {
|
2019-05-24 13:28:55 -07:00
|
|
|
SmallVector<Type, 8> types(op.getOperandTypes());
|
|
|
|
auto funcTy = FunctionType::get(types, op.getType(), op.getContext());
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-12-12 15:31:39 -08:00
|
|
|
p << op.getOperationName() << ' ' << *op.base() << '['
|
|
|
|
<< op.getOperands().drop_front() << ']';
|
2019-09-20 20:43:02 -07:00
|
|
|
p.printOptionalAttrDict(op.getAttrs());
|
|
|
|
p << " : " << funcTy;
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.getelementptr` ssa-use `[` ssa-use-list `]`
|
|
|
|
// attribute-dict? `:` type
|
2019-09-20 19:47:05 -07:00
|
|
|
static ParseResult parseGEPOp(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
SmallVector<NamedAttribute, 4> attrs;
|
|
|
|
OpAsmParser::OperandType base;
|
|
|
|
SmallVector<OpAsmParser::OperandType, 8> indices;
|
|
|
|
Type type;
|
|
|
|
llvm::SMLoc trailingTypeLoc;
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseOperand(base) ||
|
|
|
|
parser.parseOperandList(indices, OpAsmParser::Delimiter::Square) ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseOptionalAttrDict(attrs) || parser.parseColon() ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
// Deconstruct the trailing function type to extract the types of the base
|
|
|
|
// pointer and result (same type) and the types of the indices.
|
|
|
|
auto funcType = type.dyn_cast<FunctionType>();
|
|
|
|
if (!funcType || funcType.getNumResults() != 1 ||
|
|
|
|
funcType.getNumInputs() == 0)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(trailingTypeLoc,
|
|
|
|
"expected trailing function type with at least "
|
|
|
|
"one argument and one result");
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
if (parser.resolveOperand(base, funcType.getInput(0), result.operands) ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.resolveOperands(indices, funcType.getInputs().drop_front(),
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.getNameLoc(), result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.attributes = attrs;
|
|
|
|
result.addTypes(funcType.getResults());
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::LoadOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printLoadOp(OpAsmPrinter &p, LoadOp &op) {
|
|
|
|
p << op.getOperationName() << ' ' << *op.addr();
|
|
|
|
p.printOptionalAttrDict(op.getAttrs());
|
|
|
|
p << " : " << op.addr()->getType();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Extract the pointee type from the LLVM pointer type wrapped in MLIR. Return
|
|
|
|
// the resulting type wrapped in MLIR, or nullptr on error.
|
2019-09-20 11:36:49 -07:00
|
|
|
static Type getLoadStoreElementType(OpAsmParser &parser, Type type,
|
2019-04-02 15:33:54 -07:00
|
|
|
llvm::SMLoc trailingTypeLoc) {
|
|
|
|
auto llvmTy = type.dyn_cast<LLVM::LLVMType>();
|
|
|
|
if (!llvmTy)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(trailingTypeLoc, "expected LLVM IR dialect type"),
|
2019-04-02 15:33:54 -07:00
|
|
|
nullptr;
|
2019-05-22 14:56:07 -07:00
|
|
|
if (!llvmTy.getUnderlyingType()->isPointerTy())
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(trailingTypeLoc, "expected LLVM pointer type"),
|
2019-04-02 15:33:54 -07:00
|
|
|
nullptr;
|
2019-05-22 14:56:07 -07:00
|
|
|
return llvmTy.getPointerElementTy();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.load` ssa-use attribute-dict? `:` type
|
2019-09-20 19:47:05 -07:00
|
|
|
static ParseResult parseLoadOp(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
SmallVector<NamedAttribute, 4> attrs;
|
|
|
|
OpAsmParser::OperandType addr;
|
|
|
|
Type type;
|
|
|
|
llvm::SMLoc trailingTypeLoc;
|
|
|
|
|
2019-11-05 13:32:07 -08:00
|
|
|
if (parser.parseOperand(addr) || parser.parseOptionalAttrDict(attrs) ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.parseColon() || parser.getCurrentLocation(&trailingTypeLoc) ||
|
|
|
|
parser.parseType(type) ||
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.resolveOperand(addr, type, result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
Type elemTy = getLoadStoreElementType(parser, type, trailingTypeLoc);
|
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.attributes = attrs;
|
|
|
|
result.addTypes(elemTy);
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::StoreOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printStoreOp(OpAsmPrinter &p, StoreOp &op) {
|
|
|
|
p << op.getOperationName() << ' ' << *op.value() << ", " << *op.addr();
|
|
|
|
p.printOptionalAttrDict(op.getAttrs());
|
|
|
|
p << " : " << op.addr()->getType();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.store` ssa-use `,` ssa-use attribute-dict? `:` type
|
2019-09-20 19:47:05 -07:00
|
|
|
static ParseResult parseStoreOp(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
SmallVector<NamedAttribute, 4> attrs;
|
|
|
|
OpAsmParser::OperandType addr, value;
|
|
|
|
Type type;
|
|
|
|
llvm::SMLoc trailingTypeLoc;
|
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseOperand(value) || parser.parseComma() ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseOperand(addr) || parser.parseOptionalAttrDict(attrs) ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.parseColon() || parser.getCurrentLocation(&trailingTypeLoc) ||
|
|
|
|
parser.parseType(type))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
Type elemTy = getLoadStoreElementType(parser, type, trailingTypeLoc);
|
|
|
|
if (!elemTy)
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
if (parser.resolveOperand(value, elemTy, result.operands) ||
|
|
|
|
parser.resolveOperand(addr, type, result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.attributes = attrs;
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::CallOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printCallOp(OpAsmPrinter &p, CallOp &op) {
|
2019-04-02 15:33:54 -07:00
|
|
|
auto callee = op.callee();
|
|
|
|
bool isDirect = callee.hasValue();
|
|
|
|
|
|
|
|
// Print the direct callee if present as a function attribute, or an indirect
|
|
|
|
// callee (first operand) otherwise.
|
2019-09-20 20:43:02 -07:00
|
|
|
p << op.getOperationName() << ' ';
|
2019-04-02 15:33:54 -07:00
|
|
|
if (isDirect)
|
2019-10-08 17:44:39 -07:00
|
|
|
p.printSymbolName(callee.getValue());
|
2019-04-02 15:33:54 -07:00
|
|
|
else
|
2019-09-20 20:43:02 -07:00
|
|
|
p << *op.getOperand(0);
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-12-12 15:31:39 -08:00
|
|
|
p << '(' << op.getOperands().drop_front(isDirect ? 0 : 1) << ')';
|
2019-09-20 20:43:02 -07:00
|
|
|
p.printOptionalAttrDict(op.getAttrs(), {"callee"});
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-05-22 13:41:23 -07:00
|
|
|
// Reconstruct the function MLIR function type from operand and result types.
|
2019-05-24 13:28:55 -07:00
|
|
|
SmallVector<Type, 1> resultTypes(op.getResultTypes());
|
|
|
|
SmallVector<Type, 8> argTypes(
|
|
|
|
llvm::drop_begin(op.getOperandTypes(), isDirect ? 0 : 1));
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
p << " : " << FunctionType::get(argTypes, resultTypes, op.getContext());
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.call` (function-id | ssa-use) `(` ssa-use-list `)`
|
|
|
|
// attribute-dict? `:` function-type
|
2019-09-20 19:47:05 -07:00
|
|
|
static ParseResult parseCallOp(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
SmallVector<NamedAttribute, 4> attrs;
|
|
|
|
SmallVector<OpAsmParser::OperandType, 8> operands;
|
|
|
|
Type type;
|
2019-07-11 11:41:04 -07:00
|
|
|
SymbolRefAttr funcAttr;
|
2019-05-29 13:33:22 -07:00
|
|
|
llvm::SMLoc trailingTypeLoc;
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
// Parse an operand list that will, in practice, contain 0 or 1 operand. In
|
|
|
|
// case of an indirect call, there will be 1 operand before `(`. In case of a
|
|
|
|
// direct call, there will be no operands and the parser will stop at the
|
|
|
|
// function identifier without complaining.
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseOperandList(operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
bool isDirect = operands.empty();
|
|
|
|
|
|
|
|
// Optionally parse a function identifier.
|
|
|
|
if (isDirect)
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseAttribute(funcAttr, "callee", attrs))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseOperandList(operands, OpAsmParser::Delimiter::Paren) ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseOptionalAttrDict(attrs) || parser.parseColon() ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
auto funcType = type.dyn_cast<FunctionType>();
|
|
|
|
if (!funcType)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(trailingTypeLoc, "expected function type");
|
2019-04-02 15:33:54 -07:00
|
|
|
if (isDirect) {
|
|
|
|
// Make sure types match.
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.resolveOperands(operands, funcType.getInputs(),
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.getNameLoc(), result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addTypes(funcType.getResults());
|
2019-04-02 15:33:54 -07:00
|
|
|
} else {
|
|
|
|
// Construct the LLVM IR Dialect function type that the first operand
|
|
|
|
// should match.
|
|
|
|
if (funcType.getNumResults() > 1)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(trailingTypeLoc,
|
|
|
|
"expected function with 0 or 1 result");
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
Builder &builder = parser.getBuilder();
|
2019-05-13 12:42:25 -07:00
|
|
|
auto *llvmDialect =
|
|
|
|
builder.getContext()->getRegisteredDialect<LLVM::LLVMDialect>();
|
2019-05-22 14:56:07 -07:00
|
|
|
LLVM::LLVMType llvmResultType;
|
2019-04-02 15:33:54 -07:00
|
|
|
if (funcType.getNumResults() == 0) {
|
2019-05-22 14:56:07 -07:00
|
|
|
llvmResultType = LLVM::LLVMType::getVoidTy(llvmDialect);
|
2019-04-02 15:33:54 -07:00
|
|
|
} else {
|
2019-05-22 14:56:07 -07:00
|
|
|
llvmResultType = funcType.getResult(0).dyn_cast<LLVM::LLVMType>();
|
|
|
|
if (!llvmResultType)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(trailingTypeLoc,
|
|
|
|
"expected result to have LLVM type");
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2019-05-22 14:56:07 -07:00
|
|
|
SmallVector<LLVM::LLVMType, 8> argTypes;
|
2019-04-02 15:33:54 -07:00
|
|
|
argTypes.reserve(funcType.getNumInputs());
|
|
|
|
for (int i = 0, e = funcType.getNumInputs(); i < e; ++i) {
|
|
|
|
auto argType = funcType.getInput(i).dyn_cast<LLVM::LLVMType>();
|
|
|
|
if (!argType)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(trailingTypeLoc,
|
|
|
|
"expected LLVM types as inputs");
|
2019-05-22 14:56:07 -07:00
|
|
|
argTypes.push_back(argType);
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
2019-05-22 14:56:07 -07:00
|
|
|
auto llvmFuncType = LLVM::LLVMType::getFunctionTy(llvmResultType, argTypes,
|
|
|
|
/*isVarArg=*/false);
|
|
|
|
auto wrappedFuncType = llvmFuncType.getPointerTo();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
auto funcArguments =
|
|
|
|
ArrayRef<OpAsmParser::OperandType>(operands).drop_front();
|
|
|
|
|
|
|
|
// Make sure that the first operand (indirect callee) matches the wrapped
|
|
|
|
// LLVM IR function type, and that the types of the other call operands
|
|
|
|
// match the types of the function arguments.
|
2019-09-20 19:47:05 -07:00
|
|
|
if (parser.resolveOperand(operands[0], wrappedFuncType, result.operands) ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.resolveOperands(funcArguments, funcType.getInputs(),
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.getNameLoc(), result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addTypes(llvmResultType);
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.attributes = attrs;
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2019-08-09 05:24:47 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::ExtractElementOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Expects vector to be of wrapped LLVM vector type and position to be of
|
|
|
|
// wrapped LLVM i32 type.
|
2019-09-20 19:47:05 -07:00
|
|
|
void LLVM::ExtractElementOp::build(Builder *b, OperationState &result,
|
2019-12-23 14:45:01 -08:00
|
|
|
Value vector, Value position,
|
2019-08-09 05:24:47 -07:00
|
|
|
ArrayRef<NamedAttribute> attrs) {
|
|
|
|
auto wrappedVectorType = vector->getType().cast<LLVM::LLVMType>();
|
|
|
|
auto llvmType = wrappedVectorType.getVectorElementType();
|
|
|
|
build(b, result, llvmType, vector, position);
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addAttributes(attrs);
|
2019-08-09 05:24:47 -07:00
|
|
|
}
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printExtractElementOp(OpAsmPrinter &p, ExtractElementOp &op) {
|
2019-11-25 14:44:20 -08:00
|
|
|
p << op.getOperationName() << ' ' << *op.vector() << "[" << *op.position()
|
|
|
|
<< " : " << op.position()->getType() << "]";
|
2019-09-20 20:43:02 -07:00
|
|
|
p.printOptionalAttrDict(op.getAttrs());
|
|
|
|
p << " : " << op.vector()->getType();
|
2019-08-09 05:24:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.extractelement` ssa-use `, ` ssa-use
|
|
|
|
// attribute-dict? `:` type
|
2019-09-20 11:36:49 -07:00
|
|
|
static ParseResult parseExtractElementOp(OpAsmParser &parser,
|
2019-09-20 19:47:05 -07:00
|
|
|
OperationState &result) {
|
2019-08-09 05:24:47 -07:00
|
|
|
llvm::SMLoc loc;
|
|
|
|
OpAsmParser::OperandType vector, position;
|
2019-11-25 14:44:20 -08:00
|
|
|
Type type, positionType;
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.getCurrentLocation(&loc) || parser.parseOperand(vector) ||
|
2019-11-25 14:44:20 -08:00
|
|
|
parser.parseLSquare() || parser.parseOperand(position) ||
|
|
|
|
parser.parseColonType(positionType) || parser.parseRSquare() ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseOptionalAttrDict(result.attributes) ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.parseColonType(type) ||
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.resolveOperand(vector, type, result.operands) ||
|
2019-11-25 14:44:20 -08:00
|
|
|
parser.resolveOperand(position, positionType, result.operands))
|
2019-08-09 05:24:47 -07:00
|
|
|
return failure();
|
|
|
|
auto wrappedVectorType = type.dyn_cast<LLVM::LLVMType>();
|
|
|
|
if (!wrappedVectorType ||
|
|
|
|
!wrappedVectorType.getUnderlyingType()->isVectorTy())
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(
|
2019-08-09 05:24:47 -07:00
|
|
|
loc, "expected LLVM IR dialect vector type for operand #1");
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addTypes(wrappedVectorType.getVectorElementType());
|
2019-08-09 05:24:47 -07:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::ExtractValueOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printExtractValueOp(OpAsmPrinter &p, ExtractValueOp &op) {
|
|
|
|
p << op.getOperationName() << ' ' << *op.container() << op.position();
|
|
|
|
p.printOptionalAttrDict(op.getAttrs(), {"position"});
|
|
|
|
p << " : " << op.container()->getType();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Extract the type at `position` in the wrapped LLVM IR aggregate type
|
|
|
|
// `containerType`. Position is an integer array attribute where each value
|
|
|
|
// is a zero-based position of the element in the aggregate type. Return the
|
|
|
|
// resulting type wrapped in MLIR, or nullptr on error.
|
2019-09-20 11:36:49 -07:00
|
|
|
static LLVM::LLVMType getInsertExtractValueElementType(OpAsmParser &parser,
|
2019-04-02 15:33:54 -07:00
|
|
|
Type containerType,
|
|
|
|
Attribute positionAttr,
|
|
|
|
llvm::SMLoc attributeLoc,
|
|
|
|
llvm::SMLoc typeLoc) {
|
|
|
|
auto wrappedContainerType = containerType.dyn_cast<LLVM::LLVMType>();
|
|
|
|
if (!wrappedContainerType)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(typeLoc, "expected LLVM IR Dialect type"), nullptr;
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
auto positionArrayAttr = positionAttr.dyn_cast<ArrayAttr>();
|
|
|
|
if (!positionArrayAttr)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(attributeLoc, "expected an array attribute"),
|
2019-04-02 15:33:54 -07:00
|
|
|
nullptr;
|
|
|
|
|
|
|
|
// Infer the element type from the structure type: iteratively step inside the
|
|
|
|
// type by taking the element type, indexed by the position attribute for
|
2019-10-20 00:11:03 -07:00
|
|
|
// structures. Check the position index before accessing, it is supposed to
|
|
|
|
// be in bounds.
|
2019-04-02 15:33:54 -07:00
|
|
|
for (Attribute subAttr : positionArrayAttr) {
|
|
|
|
auto positionElementAttr = subAttr.dyn_cast<IntegerAttr>();
|
|
|
|
if (!positionElementAttr)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(attributeLoc,
|
|
|
|
"expected an array of integer literals"),
|
2019-04-02 15:33:54 -07:00
|
|
|
nullptr;
|
|
|
|
int position = positionElementAttr.getInt();
|
2019-05-22 14:56:07 -07:00
|
|
|
auto *llvmContainerType = wrappedContainerType.getUnderlyingType();
|
2019-04-02 15:33:54 -07:00
|
|
|
if (llvmContainerType->isArrayTy()) {
|
2019-05-13 18:10:48 -07:00
|
|
|
if (position < 0 || static_cast<unsigned>(position) >=
|
|
|
|
llvmContainerType->getArrayNumElements())
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(attributeLoc, "position out of bounds"),
|
2019-04-02 15:33:54 -07:00
|
|
|
nullptr;
|
2019-05-22 14:56:07 -07:00
|
|
|
wrappedContainerType = wrappedContainerType.getArrayElementType();
|
2019-04-02 15:33:54 -07:00
|
|
|
} else if (llvmContainerType->isStructTy()) {
|
2019-05-13 18:10:48 -07:00
|
|
|
if (position < 0 || static_cast<unsigned>(position) >=
|
|
|
|
llvmContainerType->getStructNumElements())
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(attributeLoc, "position out of bounds"),
|
2019-04-02 15:33:54 -07:00
|
|
|
nullptr;
|
2019-05-22 14:56:07 -07:00
|
|
|
wrappedContainerType =
|
|
|
|
wrappedContainerType.getStructElementType(position);
|
2019-04-02 15:33:54 -07:00
|
|
|
} else {
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(typeLoc,
|
|
|
|
"expected wrapped LLVM IR structure/array type"),
|
2019-04-02 15:33:54 -07:00
|
|
|
nullptr;
|
|
|
|
}
|
|
|
|
}
|
2019-05-22 14:56:07 -07:00
|
|
|
return wrappedContainerType;
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.extractvalue` ssa-use
|
|
|
|
// `[` integer-literal (`,` integer-literal)* `]`
|
|
|
|
// attribute-dict? `:` type
|
2019-09-20 11:36:49 -07:00
|
|
|
static ParseResult parseExtractValueOp(OpAsmParser &parser,
|
2019-09-20 19:47:05 -07:00
|
|
|
OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
SmallVector<NamedAttribute, 4> attrs;
|
|
|
|
OpAsmParser::OperandType container;
|
|
|
|
Type containerType;
|
|
|
|
Attribute positionAttr;
|
|
|
|
llvm::SMLoc attributeLoc, trailingTypeLoc;
|
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseOperand(container) ||
|
|
|
|
parser.getCurrentLocation(&attributeLoc) ||
|
|
|
|
parser.parseAttribute(positionAttr, "position", attrs) ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseOptionalAttrDict(attrs) || parser.parseColon() ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.getCurrentLocation(&trailingTypeLoc) ||
|
|
|
|
parser.parseType(containerType) ||
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.resolveOperand(container, containerType, result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
auto elementType = getInsertExtractValueElementType(
|
|
|
|
parser, containerType, positionAttr, attributeLoc, trailingTypeLoc);
|
|
|
|
if (!elementType)
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.attributes = attrs;
|
|
|
|
result.addTypes(elementType);
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2019-08-09 05:24:47 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::InsertElementOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printInsertElementOp(OpAsmPrinter &p, InsertElementOp &op) {
|
2019-11-25 14:44:20 -08:00
|
|
|
p << op.getOperationName() << ' ' << *op.value() << ", " << *op.vector()
|
|
|
|
<< "[" << *op.position() << " : " << op.position()->getType() << "]";
|
2019-09-20 20:43:02 -07:00
|
|
|
p.printOptionalAttrDict(op.getAttrs());
|
|
|
|
p << " : " << op.vector()->getType();
|
2019-08-09 05:24:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.insertelement` ssa-use `,` ssa-use `,` ssa-use
|
|
|
|
// attribute-dict? `:` type
|
2019-09-20 11:36:49 -07:00
|
|
|
static ParseResult parseInsertElementOp(OpAsmParser &parser,
|
2019-09-20 19:47:05 -07:00
|
|
|
OperationState &result) {
|
2019-08-09 05:24:47 -07:00
|
|
|
llvm::SMLoc loc;
|
|
|
|
OpAsmParser::OperandType vector, value, position;
|
2019-11-25 14:44:20 -08:00
|
|
|
Type vectorType, positionType;
|
|
|
|
if (parser.getCurrentLocation(&loc) || parser.parseOperand(value) ||
|
|
|
|
parser.parseComma() || parser.parseOperand(vector) ||
|
|
|
|
parser.parseLSquare() || parser.parseOperand(position) ||
|
|
|
|
parser.parseColonType(positionType) || parser.parseRSquare() ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseOptionalAttrDict(result.attributes) ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.parseColonType(vectorType))
|
2019-08-09 05:24:47 -07:00
|
|
|
return failure();
|
|
|
|
|
|
|
|
auto wrappedVectorType = vectorType.dyn_cast<LLVM::LLVMType>();
|
|
|
|
if (!wrappedVectorType ||
|
|
|
|
!wrappedVectorType.getUnderlyingType()->isVectorTy())
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(
|
2019-08-09 05:24:47 -07:00
|
|
|
loc, "expected LLVM IR dialect vector type for operand #1");
|
|
|
|
auto valueType = wrappedVectorType.getVectorElementType();
|
|
|
|
if (!valueType)
|
|
|
|
return failure();
|
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
if (parser.resolveOperand(vector, vectorType, result.operands) ||
|
|
|
|
parser.resolveOperand(value, valueType, result.operands) ||
|
2019-11-25 14:44:20 -08:00
|
|
|
parser.resolveOperand(position, positionType, result.operands))
|
2019-08-09 05:24:47 -07:00
|
|
|
return failure();
|
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addTypes(vectorType);
|
2019-08-09 05:24:47 -07:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::InsertValueOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printInsertValueOp(OpAsmPrinter &p, InsertValueOp &op) {
|
|
|
|
p << op.getOperationName() << ' ' << *op.value() << ", " << *op.container()
|
|
|
|
<< op.position();
|
|
|
|
p.printOptionalAttrDict(op.getAttrs(), {"position"});
|
|
|
|
p << " : " << op.container()->getType();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.insertvaluevalue` ssa-use `,` ssa-use
|
|
|
|
// `[` integer-literal (`,` integer-literal)* `]`
|
|
|
|
// attribute-dict? `:` type
|
2019-09-20 11:36:49 -07:00
|
|
|
static ParseResult parseInsertValueOp(OpAsmParser &parser,
|
2019-09-20 19:47:05 -07:00
|
|
|
OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
OpAsmParser::OperandType container, value;
|
|
|
|
Type containerType;
|
|
|
|
Attribute positionAttr;
|
|
|
|
llvm::SMLoc attributeLoc, trailingTypeLoc;
|
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseOperand(value) || parser.parseComma() ||
|
|
|
|
parser.parseOperand(container) ||
|
|
|
|
parser.getCurrentLocation(&attributeLoc) ||
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.parseAttribute(positionAttr, "position", result.attributes) ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
|
|
|
|
parser.getCurrentLocation(&trailingTypeLoc) ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.parseType(containerType))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
auto valueType = getInsertExtractValueElementType(
|
|
|
|
parser, containerType, positionAttr, attributeLoc, trailingTypeLoc);
|
|
|
|
if (!valueType)
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
if (parser.resolveOperand(container, containerType, result.operands) ||
|
|
|
|
parser.resolveOperand(value, valueType, result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addTypes(containerType);
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::SelectOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printSelectOp(OpAsmPrinter &p, SelectOp &op) {
|
|
|
|
p << op.getOperationName() << ' ' << *op.condition() << ", "
|
|
|
|
<< *op.trueValue() << ", " << *op.falseValue();
|
|
|
|
p.printOptionalAttrDict(op.getAttrs());
|
|
|
|
p << " : " << op.condition()->getType() << ", " << op.trueValue()->getType();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.select` ssa-use `,` ssa-use `,` ssa-use
|
|
|
|
// attribute-dict? `:` type, type
|
2019-09-20 19:47:05 -07:00
|
|
|
static ParseResult parseSelectOp(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
OpAsmParser::OperandType condition, trueValue, falseValue;
|
|
|
|
Type conditionType, argType;
|
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseOperand(condition) || parser.parseComma() ||
|
|
|
|
parser.parseOperand(trueValue) || parser.parseComma() ||
|
|
|
|
parser.parseOperand(falseValue) ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseOptionalAttrDict(result.attributes) ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.parseColonType(conditionType) || parser.parseComma() ||
|
|
|
|
parser.parseType(argType))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
if (parser.resolveOperand(condition, conditionType, result.operands) ||
|
|
|
|
parser.resolveOperand(trueValue, argType, result.operands) ||
|
|
|
|
parser.resolveOperand(falseValue, argType, result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addTypes(argType);
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::BrOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printBrOp(OpAsmPrinter &p, BrOp &op) {
|
|
|
|
p << op.getOperationName() << ' ';
|
|
|
|
p.printSuccessorAndUseList(op.getOperation(), 0);
|
|
|
|
p.printOptionalAttrDict(op.getAttrs());
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.br` bb-id (`[` ssa-use-and-type-list `]`)?
|
|
|
|
// attribute-dict?
|
2019-09-20 19:47:05 -07:00
|
|
|
static ParseResult parseBrOp(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
Block *dest;
|
2019-12-23 14:45:01 -08:00
|
|
|
SmallVector<Value, 4> operands;
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseSuccessorAndUseList(dest, operands) ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseOptionalAttrDict(result.attributes))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addSuccessor(dest, operands);
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::CondBrOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printCondBrOp(OpAsmPrinter &p, CondBrOp &op) {
|
|
|
|
p << op.getOperationName() << ' ' << *op.getOperand(0) << ", ";
|
|
|
|
p.printSuccessorAndUseList(op.getOperation(), 0);
|
|
|
|
p << ", ";
|
|
|
|
p.printSuccessorAndUseList(op.getOperation(), 1);
|
|
|
|
p.printOptionalAttrDict(op.getAttrs());
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.cond_br` ssa-use `,`
|
|
|
|
// bb-id (`[` ssa-use-and-type-list `]`)? `,`
|
|
|
|
// bb-id (`[` ssa-use-and-type-list `]`)? attribute-dict?
|
2019-09-20 19:47:05 -07:00
|
|
|
static ParseResult parseCondBrOp(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
Block *trueDest;
|
|
|
|
Block *falseDest;
|
2019-12-23 14:45:01 -08:00
|
|
|
SmallVector<Value, 4> trueOperands;
|
|
|
|
SmallVector<Value, 4> falseOperands;
|
2019-04-02 15:33:54 -07:00
|
|
|
OpAsmParser::OperandType condition;
|
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
Builder &builder = parser.getBuilder();
|
2019-05-13 12:42:25 -07:00
|
|
|
auto *llvmDialect =
|
|
|
|
builder.getContext()->getRegisteredDialect<LLVM::LLVMDialect>();
|
2019-05-22 14:56:07 -07:00
|
|
|
auto i1Type = LLVM::LLVMType::getInt1Ty(llvmDialect);
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseOperand(condition) || parser.parseComma() ||
|
|
|
|
parser.parseSuccessorAndUseList(trueDest, trueOperands) ||
|
|
|
|
parser.parseComma() ||
|
|
|
|
parser.parseSuccessorAndUseList(falseDest, falseOperands) ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseOptionalAttrDict(result.attributes) ||
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.resolveOperand(condition, i1Type, result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addSuccessor(trueDest, trueOperands);
|
|
|
|
result.addSuccessor(falseDest, falseOperands);
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::ReturnOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printReturnOp(OpAsmPrinter &p, ReturnOp &op) {
|
|
|
|
p << op.getOperationName();
|
|
|
|
p.printOptionalAttrDict(op.getAttrs());
|
2019-04-02 15:33:54 -07:00
|
|
|
assert(op.getNumOperands() <= 1);
|
|
|
|
|
|
|
|
if (op.getNumOperands() == 0)
|
|
|
|
return;
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
p << ' ' << *op.getOperand(0) << " : " << op.getOperand(0)->getType();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.return` ssa-use-list attribute-dict? `:`
|
|
|
|
// type-list-no-parens
|
2019-09-20 19:47:05 -07:00
|
|
|
static ParseResult parseReturnOp(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
SmallVector<OpAsmParser::OperandType, 1> operands;
|
|
|
|
Type type;
|
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseOperandList(operands) ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseOptionalAttrDict(result.attributes))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
if (operands.empty())
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseColonType(type) ||
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.resolveOperand(operands[0], type, result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::UndefOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printUndefOp(OpAsmPrinter &p, UndefOp &op) {
|
|
|
|
p << op.getOperationName();
|
|
|
|
p.printOptionalAttrDict(op.getAttrs());
|
|
|
|
p << " : " << op.res()->getType();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2019-09-03 09:10:24 -07:00
|
|
|
// <operation> ::= `llvm.mlir.undef` attribute-dict? : type
|
2019-09-20 19:47:05 -07:00
|
|
|
static ParseResult parseUndefOp(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
Type type;
|
|
|
|
|
2019-11-05 13:32:07 -08:00
|
|
|
if (parser.parseOptionalAttrDict(result.attributes) ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.parseColonType(type))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addTypes(type);
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2019-08-12 06:10:29 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printer, parser and verifier for LLVM::AddressOfOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
GlobalOp AddressOfOp::getGlobal() {
|
2019-12-16 01:35:03 -08:00
|
|
|
Operation *module = getParentOp();
|
|
|
|
while (module && !satisfiesLLVMModule(module))
|
|
|
|
module = module->getParentOp();
|
2019-08-12 06:10:29 -07:00
|
|
|
assert(module && "unexpected operation outside of a module");
|
2019-12-16 01:35:03 -08:00
|
|
|
return dyn_cast_or_null<LLVM::GlobalOp>(
|
|
|
|
mlir::SymbolTable::lookupSymbolIn(module, global_name()));
|
2019-08-12 06:10:29 -07:00
|
|
|
}
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printAddressOfOp(OpAsmPrinter &p, AddressOfOp op) {
|
|
|
|
p << op.getOperationName() << " @" << op.global_name();
|
|
|
|
p.printOptionalAttrDict(op.getAttrs(), {"global_name"});
|
|
|
|
p << " : " << op.getResult()->getType();
|
2019-08-12 06:10:29 -07:00
|
|
|
}
|
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
static ParseResult parseAddressOfOp(OpAsmParser &parser,
|
2019-09-20 19:47:05 -07:00
|
|
|
OperationState &result) {
|
2019-08-12 06:10:29 -07:00
|
|
|
Attribute symRef;
|
|
|
|
Type type;
|
2019-09-20 19:47:05 -07:00
|
|
|
if (parser.parseAttribute(symRef, "global_name", result.attributes) ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseOptionalAttrDict(result.attributes) ||
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.parseColonType(type) || parser.addTypeToList(type, result.types))
|
2019-08-12 06:10:29 -07:00
|
|
|
return failure();
|
|
|
|
|
|
|
|
if (!symRef.isa<SymbolRefAttr>())
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(parser.getNameLoc(), "expected symbol reference");
|
2019-08-12 06:10:29 -07:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
static LogicalResult verify(AddressOfOp op) {
|
|
|
|
auto global = op.getGlobal();
|
|
|
|
if (!global)
|
2019-09-03 09:10:24 -07:00
|
|
|
return op.emitOpError(
|
|
|
|
"must reference a global defined by 'llvm.mlir.global'");
|
2019-08-12 06:10:29 -07:00
|
|
|
|
2019-12-06 01:08:40 -08:00
|
|
|
if (global.getType().getPointerTo(global.addr_space().getZExtValue()) !=
|
|
|
|
op.getResult()->getType())
|
2019-08-12 06:10:29 -07:00
|
|
|
return op.emitOpError(
|
|
|
|
"the type must be a pointer to the type of the referred global");
|
|
|
|
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::ConstantOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printConstantOp(OpAsmPrinter &p, ConstantOp &op) {
|
|
|
|
p << op.getOperationName() << '(' << op.value() << ')';
|
|
|
|
p.printOptionalAttrDict(op.getAttrs(), {"value"});
|
|
|
|
p << " : " << op.res()->getType();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2019-09-03 09:10:24 -07:00
|
|
|
// <operation> ::= `llvm.mlir.constant` `(` attribute `)` attribute-list? : type
|
2019-09-20 11:36:49 -07:00
|
|
|
static ParseResult parseConstantOp(OpAsmParser &parser,
|
2019-09-20 19:47:05 -07:00
|
|
|
OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
Attribute valueAttr;
|
|
|
|
Type type;
|
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseLParen() ||
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.parseAttribute(valueAttr, "value", result.attributes) ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseRParen() || parser.parseOptionalAttrDict(result.attributes) ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.parseColonType(type))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addTypes(type);
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2019-08-09 05:01:23 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Builder, printer and verifier for LLVM::GlobalOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-12-03 00:26:13 -08:00
|
|
|
/// Returns the name used for the linkge attribute. This *must* correspond to
|
|
|
|
/// the name of the attribute in ODS.
|
|
|
|
static StringRef getLinkageAttrName() { return "linkage"; }
|
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
void GlobalOp::build(Builder *builder, OperationState &result, LLVMType type,
|
2019-12-02 03:27:38 -08:00
|
|
|
bool isConstant, Linkage linkage, StringRef name,
|
2019-12-06 12:00:01 -08:00
|
|
|
Attribute value, unsigned addrSpace,
|
|
|
|
ArrayRef<NamedAttribute> attrs) {
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addAttribute(SymbolTable::getSymbolAttrName(),
|
|
|
|
builder->getStringAttr(name));
|
2019-10-17 20:08:01 -07:00
|
|
|
result.addAttribute("type", TypeAttr::get(type));
|
2019-08-09 05:01:23 -07:00
|
|
|
if (isConstant)
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addAttribute("constant", builder->getUnitAttr());
|
2019-09-24 01:19:21 -07:00
|
|
|
if (value)
|
|
|
|
result.addAttribute("value", value);
|
2019-12-03 00:26:13 -08:00
|
|
|
result.addAttribute(getLinkageAttrName(), builder->getI64IntegerAttr(
|
|
|
|
static_cast<int64_t>(linkage)));
|
2019-12-06 12:00:01 -08:00
|
|
|
if (addrSpace != 0)
|
|
|
|
result.addAttribute("addr_space", builder->getI32IntegerAttr(addrSpace));
|
2019-09-20 19:47:05 -07:00
|
|
|
result.attributes.append(attrs.begin(), attrs.end());
|
2019-11-05 15:10:28 -08:00
|
|
|
result.addRegion();
|
2019-08-09 05:01:23 -07:00
|
|
|
}
|
|
|
|
|
2019-12-03 00:26:13 -08:00
|
|
|
// Returns the textual representation of the given linkage.
|
|
|
|
static StringRef linkageToStr(LLVM::Linkage linkage) {
|
2019-12-02 03:27:38 -08:00
|
|
|
switch (linkage) {
|
|
|
|
case LLVM::Linkage::Private:
|
2019-12-03 00:26:13 -08:00
|
|
|
return "private";
|
2019-12-02 03:27:38 -08:00
|
|
|
case LLVM::Linkage::Internal:
|
2019-12-03 00:26:13 -08:00
|
|
|
return "internal";
|
2019-12-02 03:27:38 -08:00
|
|
|
case LLVM::Linkage::AvailableExternally:
|
2019-12-03 00:26:13 -08:00
|
|
|
return "available_externally";
|
2019-12-02 03:27:38 -08:00
|
|
|
case LLVM::Linkage::Linkonce:
|
2019-12-03 00:26:13 -08:00
|
|
|
return "linkonce";
|
2019-12-02 03:27:38 -08:00
|
|
|
case LLVM::Linkage::Weak:
|
2019-12-03 00:26:13 -08:00
|
|
|
return "weak";
|
2019-12-02 03:27:38 -08:00
|
|
|
case LLVM::Linkage::Common:
|
2019-12-03 00:26:13 -08:00
|
|
|
return "common";
|
2019-12-02 03:27:38 -08:00
|
|
|
case LLVM::Linkage::Appending:
|
2019-12-03 00:26:13 -08:00
|
|
|
return "appending";
|
2019-12-02 03:27:38 -08:00
|
|
|
case LLVM::Linkage::ExternWeak:
|
2019-12-03 00:26:13 -08:00
|
|
|
return "extern_weak";
|
2019-12-02 03:27:38 -08:00
|
|
|
case LLVM::Linkage::LinkonceODR:
|
2019-12-03 00:26:13 -08:00
|
|
|
return "linkonce_odr";
|
2019-12-02 03:27:38 -08:00
|
|
|
case LLVM::Linkage::WeakODR:
|
2019-12-03 00:26:13 -08:00
|
|
|
return "weak_odr";
|
2019-12-02 03:27:38 -08:00
|
|
|
case LLVM::Linkage::External:
|
2019-12-03 00:26:13 -08:00
|
|
|
return "external";
|
2019-12-02 03:27:38 -08:00
|
|
|
}
|
|
|
|
llvm_unreachable("unknown linkage type");
|
|
|
|
}
|
|
|
|
|
2019-12-03 00:26:13 -08:00
|
|
|
// Prints the keyword for the linkage type using the printer.
|
|
|
|
static void printLinkage(OpAsmPrinter &p, LLVM::Linkage linkage) {
|
|
|
|
p << linkageToStr(linkage);
|
|
|
|
}
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printGlobalOp(OpAsmPrinter &p, GlobalOp op) {
|
|
|
|
p << op.getOperationName() << ' ';
|
2019-12-02 03:27:38 -08:00
|
|
|
printLinkage(p, op.linkage());
|
|
|
|
p << ' ';
|
2019-08-09 05:01:23 -07:00
|
|
|
if (op.constant())
|
2019-09-20 20:43:02 -07:00
|
|
|
p << "constant ";
|
2019-10-08 17:44:39 -07:00
|
|
|
p.printSymbolName(op.sym_name());
|
|
|
|
p << '(';
|
2019-09-21 01:19:43 -07:00
|
|
|
if (auto value = op.getValueOrNull())
|
|
|
|
p.printAttribute(value);
|
2019-09-20 20:43:02 -07:00
|
|
|
p << ')';
|
2019-12-02 03:27:38 -08:00
|
|
|
p.printOptionalAttrDict(op.getAttrs(),
|
|
|
|
{SymbolTable::getSymbolAttrName(), "type", "constant",
|
2019-12-03 00:26:13 -08:00
|
|
|
"value", getLinkageAttrName()});
|
2019-08-09 08:59:45 -07:00
|
|
|
|
|
|
|
// Print the trailing type unless it's a string global.
|
2019-09-21 01:19:43 -07:00
|
|
|
if (op.getValueOrNull().dyn_cast_or_null<StringAttr>())
|
2019-08-09 08:59:45 -07:00
|
|
|
return;
|
2019-12-12 15:31:39 -08:00
|
|
|
p << " : " << op.type();
|
2019-11-05 15:10:28 -08:00
|
|
|
|
|
|
|
Region &initializer = op.getInitializerRegion();
|
|
|
|
if (!initializer.empty())
|
|
|
|
p.printRegion(initializer, /*printEntryBlockArgs=*/false);
|
2019-08-09 05:01:23 -07:00
|
|
|
}
|
|
|
|
|
2019-12-02 03:27:38 -08:00
|
|
|
// Parses one of the keywords provided in the list `keywords` and returns the
|
|
|
|
// position of the parsed keyword in the list. If none of the keywords from the
|
|
|
|
// list is parsed, returns -1.
|
|
|
|
static int parseOptionalKeywordAlternative(OpAsmParser &parser,
|
|
|
|
ArrayRef<StringRef> keywords) {
|
|
|
|
for (auto en : llvm::enumerate(keywords)) {
|
|
|
|
if (succeeded(parser.parseOptionalKeyword(en.value())))
|
|
|
|
return en.index();
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parses one of the linkage keywords and, if succeeded, appends the "linkage"
|
|
|
|
// integer attribute with the corresponding value to `result`.
|
|
|
|
//
|
|
|
|
// linkage ::= `private` | `internal` | `available_externally` | `linkonce`
|
|
|
|
// | `weak` | `common` | `appending` | `extern_weak`
|
|
|
|
// | `linkonce_odr` | `weak_odr` | `external
|
|
|
|
static ParseResult parseOptionalLinkageKeyword(OpAsmParser &parser,
|
|
|
|
OperationState &result) {
|
|
|
|
int index = parseOptionalKeywordAlternative(
|
|
|
|
parser, {"private", "internal", "available_externally", "linkonce",
|
|
|
|
"weak", "common", "appending", "extern_weak", "linkonce_odr",
|
|
|
|
"weak_odr", "external"});
|
|
|
|
if (index == -1)
|
|
|
|
return failure();
|
2019-12-03 00:26:13 -08:00
|
|
|
result.addAttribute(getLinkageAttrName(),
|
|
|
|
parser.getBuilder().getI64IntegerAttr(index));
|
2019-12-02 03:27:38 -08:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
// operation ::= `llvm.mlir.global` linkage `constant`? `@` identifier
|
|
|
|
// `(` attribute? `)` attribute-list? (`:` type)? region?
|
2019-08-09 08:59:45 -07:00
|
|
|
//
|
|
|
|
// The type can be omitted for string attributes, in which case it will be
|
|
|
|
// inferred from the value of the string as [strlen(value) x i8].
|
2019-09-20 19:47:05 -07:00
|
|
|
static ParseResult parseGlobalOp(OpAsmParser &parser, OperationState &result) {
|
2019-12-02 03:27:38 -08:00
|
|
|
if (failed(parseOptionalLinkageKeyword(parser, result)))
|
|
|
|
return parser.emitError(parser.getCurrentLocation(), "expected linkage");
|
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
if (succeeded(parser.parseOptionalKeyword("constant")))
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addAttribute("constant", parser.getBuilder().getUnitAttr());
|
2019-08-09 05:01:23 -07:00
|
|
|
|
|
|
|
StringAttr name;
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseSymbolName(name, SymbolTable::getSymbolAttrName(),
|
2019-09-20 19:47:05 -07:00
|
|
|
result.attributes) ||
|
2019-09-21 01:19:43 -07:00
|
|
|
parser.parseLParen())
|
|
|
|
return failure();
|
|
|
|
|
|
|
|
Attribute value;
|
|
|
|
if (parser.parseOptionalRParen()) {
|
|
|
|
if (parser.parseAttribute(value, "value", result.attributes) ||
|
|
|
|
parser.parseRParen())
|
|
|
|
return failure();
|
|
|
|
}
|
|
|
|
|
|
|
|
SmallVector<Type, 1> types;
|
2019-11-05 13:32:07 -08:00
|
|
|
if (parser.parseOptionalAttrDict(result.attributes) ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.parseOptionalColonTypeList(types))
|
2019-08-09 05:01:23 -07:00
|
|
|
return failure();
|
|
|
|
|
2019-08-09 08:59:45 -07:00
|
|
|
if (types.size() > 1)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(parser.getNameLoc(), "expected zero or one type");
|
2019-08-09 08:59:45 -07:00
|
|
|
|
2019-11-05 15:10:28 -08:00
|
|
|
Region &initRegion = *result.addRegion();
|
2019-08-09 08:59:45 -07:00
|
|
|
if (types.empty()) {
|
2019-09-21 01:19:43 -07:00
|
|
|
if (auto strAttr = value.dyn_cast_or_null<StringAttr>()) {
|
2019-09-20 11:36:49 -07:00
|
|
|
MLIRContext *context = parser.getBuilder().getContext();
|
2019-08-09 08:59:45 -07:00
|
|
|
auto *dialect = context->getRegisteredDialect<LLVMDialect>();
|
|
|
|
auto arrayType = LLVM::LLVMType::getArrayTy(
|
|
|
|
LLVM::LLVMType::getInt8Ty(dialect), strAttr.getValue().size());
|
|
|
|
types.push_back(arrayType);
|
|
|
|
} else {
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(parser.getNameLoc(),
|
|
|
|
"type can only be omitted for string globals");
|
2019-08-09 08:59:45 -07:00
|
|
|
}
|
2019-11-05 15:10:28 -08:00
|
|
|
} else if (parser.parseOptionalRegion(initRegion, /*arguments=*/{},
|
|
|
|
/*argTypes=*/{})) {
|
|
|
|
return failure();
|
2019-08-09 08:59:45 -07:00
|
|
|
}
|
|
|
|
|
2019-10-17 20:08:01 -07:00
|
|
|
result.addAttribute("type", TypeAttr::get(types[0]));
|
2019-08-09 05:01:23 -07:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
static LogicalResult verify(GlobalOp op) {
|
|
|
|
if (!llvm::PointerType::isValidElementType(op.getType().getUnderlyingType()))
|
|
|
|
return op.emitOpError(
|
|
|
|
"expects type to be a valid element type for an LLVM pointer");
|
2019-12-17 07:05:06 -08:00
|
|
|
if (op.getParentOp() && !satisfiesLLVMModule(op.getParentOp()))
|
2019-08-09 05:01:23 -07:00
|
|
|
return op.emitOpError("must appear at the module level");
|
2019-09-21 01:19:43 -07:00
|
|
|
|
|
|
|
if (auto strAttr = op.getValueOrNull().dyn_cast_or_null<StringAttr>()) {
|
2019-08-09 08:59:45 -07:00
|
|
|
auto type = op.getType();
|
|
|
|
if (!type.getUnderlyingType()->isArrayTy() ||
|
|
|
|
!type.getArrayElementType().getUnderlyingType()->isIntegerTy(8) ||
|
|
|
|
type.getArrayNumElements() != strAttr.getValue().size())
|
|
|
|
return op.emitOpError(
|
|
|
|
"requires an i8 array type of the length equal to that of the string "
|
|
|
|
"attribute");
|
|
|
|
}
|
2019-11-05 15:10:28 -08:00
|
|
|
|
|
|
|
if (Block *b = op.getInitializerBlock()) {
|
|
|
|
ReturnOp ret = cast<ReturnOp>(b->getTerminator());
|
|
|
|
if (ret.operand_type_begin() == ret.operand_type_end())
|
|
|
|
return op.emitOpError("initializer region cannot return void");
|
|
|
|
if (*ret.operand_type_begin() != op.getType())
|
|
|
|
return op.emitOpError("initializer region type ")
|
|
|
|
<< *ret.operand_type_begin() << " does not match global type "
|
|
|
|
<< op.getType();
|
|
|
|
|
|
|
|
if (op.getValueOrNull())
|
|
|
|
return op.emitOpError("cannot have both initializer value and region");
|
|
|
|
}
|
2019-08-09 05:01:23 -07:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2019-08-09 05:24:47 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::ShuffleVectorOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Expects vector to be of wrapped LLVM vector type and position to be of
|
|
|
|
// wrapped LLVM i32 type.
|
2019-12-23 14:45:01 -08:00
|
|
|
void LLVM::ShuffleVectorOp::build(Builder *b, OperationState &result, Value v1,
|
|
|
|
Value v2, ArrayAttr mask,
|
2019-08-09 05:24:47 -07:00
|
|
|
ArrayRef<NamedAttribute> attrs) {
|
|
|
|
auto wrappedContainerType1 = v1->getType().cast<LLVM::LLVMType>();
|
|
|
|
auto vType = LLVMType::getVectorTy(
|
|
|
|
wrappedContainerType1.getVectorElementType(), mask.size());
|
|
|
|
build(b, result, vType, v1, v2, mask);
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addAttributes(attrs);
|
2019-08-09 05:24:47 -07:00
|
|
|
}
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printShuffleVectorOp(OpAsmPrinter &p, ShuffleVectorOp &op) {
|
|
|
|
p << op.getOperationName() << ' ' << *op.v1() << ", " << *op.v2() << " "
|
|
|
|
<< op.mask();
|
|
|
|
p.printOptionalAttrDict(op.getAttrs(), {"mask"});
|
|
|
|
p << " : " << op.v1()->getType() << ", " << op.v2()->getType();
|
2019-08-09 05:24:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.shufflevector` ssa-use `, ` ssa-use
|
|
|
|
// `[` integer-literal (`,` integer-literal)* `]`
|
|
|
|
// attribute-dict? `:` type
|
2019-09-20 11:36:49 -07:00
|
|
|
static ParseResult parseShuffleVectorOp(OpAsmParser &parser,
|
2019-09-20 19:47:05 -07:00
|
|
|
OperationState &result) {
|
2019-08-09 05:24:47 -07:00
|
|
|
llvm::SMLoc loc;
|
|
|
|
SmallVector<NamedAttribute, 4> attrs;
|
|
|
|
OpAsmParser::OperandType v1, v2;
|
|
|
|
Attribute maskAttr;
|
|
|
|
Type typeV1, typeV2;
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.getCurrentLocation(&loc) || parser.parseOperand(v1) ||
|
|
|
|
parser.parseComma() || parser.parseOperand(v2) ||
|
|
|
|
parser.parseAttribute(maskAttr, "mask", attrs) ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseOptionalAttrDict(attrs) || parser.parseColonType(typeV1) ||
|
|
|
|
parser.parseComma() || parser.parseType(typeV2) ||
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.resolveOperand(v1, typeV1, result.operands) ||
|
|
|
|
parser.resolveOperand(v2, typeV2, result.operands))
|
2019-08-09 05:24:47 -07:00
|
|
|
return failure();
|
|
|
|
auto wrappedContainerType1 = typeV1.dyn_cast<LLVM::LLVMType>();
|
|
|
|
if (!wrappedContainerType1 ||
|
|
|
|
!wrappedContainerType1.getUnderlyingType()->isVectorTy())
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(
|
2019-08-09 05:24:47 -07:00
|
|
|
loc, "expected LLVM IR dialect vector type for operand #1");
|
|
|
|
auto vType =
|
|
|
|
LLVMType::getVectorTy(wrappedContainerType1.getVectorElementType(),
|
|
|
|
maskAttr.cast<ArrayAttr>().size());
|
2019-09-20 19:47:05 -07:00
|
|
|
result.attributes = attrs;
|
|
|
|
result.addTypes(vType);
|
2019-08-09 05:24:47 -07:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
2019-12-19 12:16:19 -08:00
|
|
|
// Implementations for LLVM::LLVMFuncOp.
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-12-19 12:16:19 -08:00
|
|
|
// Add the entry block to the function.
|
|
|
|
Block *LLVMFuncOp::addEntryBlock() {
|
|
|
|
assert(empty() && "function already has an entry block");
|
|
|
|
assert(!isVarArg() && "unimplemented: non-external variadic functions");
|
|
|
|
|
|
|
|
auto *entry = new Block;
|
|
|
|
push_back(entry);
|
|
|
|
|
|
|
|
LLVMType type = getType();
|
|
|
|
for (unsigned i = 0, e = type.getFunctionNumParams(); i < e; ++i)
|
|
|
|
entry->addArgument(type.getFunctionParamType(i));
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
void LLVMFuncOp::build(Builder *builder, OperationState &result, StringRef name,
|
2019-12-03 00:26:13 -08:00
|
|
|
LLVMType type, LLVM::Linkage linkage,
|
|
|
|
ArrayRef<NamedAttribute> attrs,
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
ArrayRef<NamedAttributeList> argAttrs) {
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addRegion();
|
|
|
|
result.addAttribute(SymbolTable::getSymbolAttrName(),
|
|
|
|
builder->getStringAttr(name));
|
2019-10-17 20:08:01 -07:00
|
|
|
result.addAttribute("type", TypeAttr::get(type));
|
2019-12-03 00:26:13 -08:00
|
|
|
result.addAttribute(getLinkageAttrName(), builder->getI64IntegerAttr(
|
|
|
|
static_cast<int64_t>(linkage)));
|
2019-09-20 19:47:05 -07:00
|
|
|
result.attributes.append(attrs.begin(), attrs.end());
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
if (argAttrs.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
unsigned numInputs = type.getUnderlyingType()->getFunctionNumParams();
|
|
|
|
assert(numInputs == argAttrs.size() &&
|
|
|
|
"expected as many argument attribute lists as arguments");
|
|
|
|
SmallString<8> argAttrName;
|
|
|
|
for (unsigned i = 0; i < numInputs; ++i)
|
|
|
|
if (auto argDict = argAttrs[i].getDictionary())
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addAttribute(getArgAttrName(i, argAttrName), argDict);
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
}
|
|
|
|
|
2019-12-03 00:26:13 -08:00
|
|
|
// Builds an LLVM function type from the given lists of input and output types.
|
2019-08-05 01:57:27 -07:00
|
|
|
// Returns a null type if any of the types provided are non-LLVM types, or if
|
|
|
|
// there is more than one output type.
|
2019-12-03 00:26:13 -08:00
|
|
|
static Type buildLLVMFunctionType(OpAsmParser &parser, llvm::SMLoc loc,
|
|
|
|
ArrayRef<Type> inputs, ArrayRef<Type> outputs,
|
|
|
|
impl::VariadicFlag variadicFlag) {
|
|
|
|
Builder &b = parser.getBuilder();
|
2019-08-05 01:57:27 -07:00
|
|
|
if (outputs.size() > 1) {
|
2019-12-03 00:26:13 -08:00
|
|
|
parser.emitError(loc, "failed to construct function type: expected zero or "
|
|
|
|
"one function result");
|
2019-08-05 01:57:27 -07:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert inputs to LLVM types, exit early on error.
|
|
|
|
SmallVector<LLVMType, 4> llvmInputs;
|
|
|
|
for (auto t : inputs) {
|
|
|
|
auto llvmTy = t.dyn_cast<LLVMType>();
|
|
|
|
if (!llvmTy) {
|
2019-12-03 00:26:13 -08:00
|
|
|
parser.emitError(loc, "failed to construct function type: expected LLVM "
|
|
|
|
"type for function arguments");
|
2019-08-05 01:57:27 -07:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
llvmInputs.push_back(llvmTy);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the dialect from the input type, if any exist. Look it up in the
|
|
|
|
// context otherwise.
|
|
|
|
LLVMDialect *dialect =
|
|
|
|
llvmInputs.empty() ? b.getContext()->getRegisteredDialect<LLVMDialect>()
|
|
|
|
: &llvmInputs.front().getDialect();
|
|
|
|
|
|
|
|
// No output is denoted as "void" in LLVM type system.
|
|
|
|
LLVMType llvmOutput = outputs.empty() ? LLVMType::getVoidTy(dialect)
|
|
|
|
: outputs.front().dyn_cast<LLVMType>();
|
|
|
|
if (!llvmOutput) {
|
2019-12-03 00:26:13 -08:00
|
|
|
parser.emitError(loc, "failed to construct function type: expected LLVM "
|
|
|
|
"type for function results");
|
2019-08-05 01:57:27 -07:00
|
|
|
return {};
|
|
|
|
}
|
2019-08-08 12:11:27 -07:00
|
|
|
return LLVMType::getFunctionTy(llvmOutput, llvmInputs,
|
|
|
|
variadicFlag.isVariadic());
|
2019-08-05 01:57:27 -07:00
|
|
|
}
|
|
|
|
|
2019-12-03 00:26:13 -08:00
|
|
|
// Parses an LLVM function.
|
|
|
|
//
|
|
|
|
// operation ::= `llvm.func` linkage? function-signature function-attributes?
|
|
|
|
// function-body
|
|
|
|
//
|
|
|
|
static ParseResult parseLLVMFuncOp(OpAsmParser &parser,
|
|
|
|
OperationState &result) {
|
|
|
|
// Default to external linkage if no keyword is provided.
|
|
|
|
if (failed(parseOptionalLinkageKeyword(parser, result)))
|
|
|
|
result.addAttribute(getLinkageAttrName(),
|
|
|
|
parser.getBuilder().getI64IntegerAttr(
|
|
|
|
static_cast<int64_t>(LLVM::Linkage::External)));
|
|
|
|
|
|
|
|
StringAttr nameAttr;
|
|
|
|
SmallVector<OpAsmParser::OperandType, 8> entryArgs;
|
|
|
|
SmallVector<SmallVector<NamedAttribute, 2>, 1> argAttrs;
|
|
|
|
SmallVector<SmallVector<NamedAttribute, 2>, 1> resultAttrs;
|
|
|
|
SmallVector<Type, 8> argTypes;
|
|
|
|
SmallVector<Type, 4> resultTypes;
|
|
|
|
bool isVariadic;
|
|
|
|
|
|
|
|
auto signatureLocation = parser.getCurrentLocation();
|
|
|
|
if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
|
|
|
|
result.attributes) ||
|
|
|
|
impl::parseFunctionSignature(parser, /*allowVariadic=*/true, entryArgs,
|
|
|
|
argTypes, argAttrs, isVariadic, resultTypes,
|
|
|
|
resultAttrs))
|
|
|
|
return failure();
|
|
|
|
|
|
|
|
auto type =
|
|
|
|
buildLLVMFunctionType(parser, signatureLocation, argTypes, resultTypes,
|
|
|
|
impl::VariadicFlag(isVariadic));
|
|
|
|
if (!type)
|
|
|
|
return failure();
|
|
|
|
result.addAttribute(impl::getTypeAttrName(), TypeAttr::get(type));
|
|
|
|
|
|
|
|
if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
|
|
|
|
return failure();
|
|
|
|
impl::addArgAndResultAttrs(parser.getBuilder(), result, argAttrs,
|
|
|
|
resultAttrs);
|
|
|
|
|
|
|
|
auto *body = result.addRegion();
|
|
|
|
return parser.parseOptionalRegion(
|
2019-12-18 09:28:48 -08:00
|
|
|
*body, entryArgs, entryArgs.empty() ? ArrayRef<Type>() : argTypes);
|
2019-12-03 00:26:13 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Print the LLVMFuncOp. Collects argument and result types and passes them to
|
|
|
|
// helper functions. Drops "void" result since it cannot be parsed back. Skips
|
|
|
|
// the external linkage since it is the default value.
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printLLVMFuncOp(OpAsmPrinter &p, LLVMFuncOp op) {
|
2019-12-03 00:26:13 -08:00
|
|
|
p << op.getOperationName() << ' ';
|
|
|
|
if (op.linkage() != LLVM::Linkage::External) {
|
|
|
|
printLinkage(p, op.linkage());
|
|
|
|
p << ' ';
|
|
|
|
}
|
|
|
|
p.printSymbolName(op.getName());
|
|
|
|
|
2019-08-05 01:57:27 -07:00
|
|
|
LLVMType fnType = op.getType();
|
|
|
|
SmallVector<Type, 8> argTypes;
|
|
|
|
SmallVector<Type, 1> resTypes;
|
|
|
|
argTypes.reserve(fnType.getFunctionNumParams());
|
|
|
|
for (unsigned i = 0, e = fnType.getFunctionNumParams(); i < e; ++i)
|
|
|
|
argTypes.push_back(fnType.getFunctionParamType(i));
|
|
|
|
|
|
|
|
LLVMType returnType = fnType.getFunctionResultType();
|
|
|
|
if (!returnType.getUnderlyingType()->isVoidTy())
|
|
|
|
resTypes.push_back(returnType);
|
|
|
|
|
2019-12-03 00:26:13 -08:00
|
|
|
impl::printFunctionSignature(p, op, argTypes, op.isVarArg(), resTypes);
|
|
|
|
impl::printFunctionAttributes(p, op, argTypes.size(), resTypes.size(),
|
|
|
|
{getLinkageAttrName()});
|
|
|
|
|
|
|
|
// Print the body if this is not an external function.
|
|
|
|
Region &body = op.body();
|
|
|
|
if (!body.empty())
|
|
|
|
p.printRegion(body, /*printEntryBlockArgs=*/false,
|
|
|
|
/*printBlockTerminators=*/true);
|
2019-08-05 01:57:27 -07:00
|
|
|
}
|
|
|
|
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
// Hook for OpTrait::FunctionLike, called after verifying that the 'type'
|
|
|
|
// attribute is present. This can check for preconditions of the
|
|
|
|
// getNumArguments hook not failing.
|
|
|
|
LogicalResult LLVMFuncOp::verifyType() {
|
|
|
|
auto llvmType = getTypeAttr().getValue().dyn_cast_or_null<LLVMType>();
|
|
|
|
if (!llvmType || !llvmType.getUnderlyingType()->isFunctionTy())
|
|
|
|
return emitOpError("requires '" + getTypeAttrName() +
|
|
|
|
"' attribute of wrapped LLVM function type");
|
|
|
|
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hook for OpTrait::FunctionLike, returns the number of function arguments.
|
|
|
|
// Depends on the type attribute being correct as checked by verifyType
|
|
|
|
unsigned LLVMFuncOp::getNumFuncArguments() {
|
|
|
|
return getType().getUnderlyingType()->getFunctionNumParams();
|
|
|
|
}
|
|
|
|
|
2019-10-18 16:02:56 -07:00
|
|
|
// Hook for OpTrait::FunctionLike, returns the number of function results.
|
|
|
|
// Depends on the type attribute being correct as checked by verifyType
|
|
|
|
unsigned LLVMFuncOp::getNumFuncResults() {
|
|
|
|
llvm::FunctionType *funcType =
|
|
|
|
cast<llvm::FunctionType>(getType().getUnderlyingType());
|
|
|
|
// We model LLVM functions that return void as having zero results,
|
|
|
|
// and all others as having one result.
|
|
|
|
// If we modeled a void return as one result, then it would be possible to
|
|
|
|
// attach an MLIR result attribute to it, and it isn't clear what semantics we
|
|
|
|
// would assign to that.
|
|
|
|
if (funcType->getReturnType()->isVoidTy())
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-12-03 00:26:13 -08:00
|
|
|
// Verifies LLVM- and implementation-specific properties of the LLVM func Op:
|
|
|
|
// - functions don't have 'common' linkage
|
|
|
|
// - external functions have 'external' or 'extern_weak' linkage;
|
|
|
|
// - vararg is (currently) only supported for external functions;
|
|
|
|
// - entry block arguments are of LLVM types and match the function signature.
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
static LogicalResult verify(LLVMFuncOp op) {
|
2019-12-03 00:26:13 -08:00
|
|
|
if (op.linkage() == LLVM::Linkage::Common)
|
|
|
|
return op.emitOpError()
|
|
|
|
<< "functions cannot have '" << linkageToStr(LLVM::Linkage::Common)
|
|
|
|
<< "' linkage";
|
|
|
|
|
|
|
|
if (op.isExternal()) {
|
|
|
|
if (op.linkage() != LLVM::Linkage::External &&
|
|
|
|
op.linkage() != LLVM::Linkage::ExternWeak)
|
|
|
|
return op.emitOpError()
|
|
|
|
<< "external functions must have '"
|
|
|
|
<< linkageToStr(LLVM::Linkage::External) << "' or '"
|
|
|
|
<< linkageToStr(LLVM::Linkage::ExternWeak) << "' linkage";
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
return success();
|
2019-12-03 00:26:13 -08:00
|
|
|
}
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
|
2019-08-08 09:41:48 -07:00
|
|
|
if (op.isVarArg())
|
|
|
|
return op.emitOpError("only external functions can be variadic");
|
|
|
|
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
auto *funcType = cast<llvm::FunctionType>(op.getType().getUnderlyingType());
|
|
|
|
unsigned numArguments = funcType->getNumParams();
|
|
|
|
Block &entryBlock = op.front();
|
|
|
|
for (unsigned i = 0; i < numArguments; ++i) {
|
|
|
|
Type argType = entryBlock.getArgument(i)->getType();
|
|
|
|
auto argLLVMType = argType.dyn_cast<LLVMType>();
|
|
|
|
if (!argLLVMType)
|
|
|
|
return op.emitOpError("entry block argument #")
|
|
|
|
<< i << " is not of LLVM type";
|
|
|
|
if (funcType->getParamType(i) != argLLVMType.getUnderlyingType())
|
|
|
|
return op.emitOpError("the type of entry block argument #")
|
|
|
|
<< i << " does not match the function signature";
|
|
|
|
}
|
|
|
|
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
2019-10-11 06:13:25 -07:00
|
|
|
// Printing, parsing and verification for LLVM::NullOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
static void printNullOp(OpAsmPrinter &p, LLVM::NullOp op) {
|
|
|
|
p << NullOp::getOperationName();
|
|
|
|
p.printOptionalAttrDict(op.getAttrs());
|
2019-12-12 15:31:39 -08:00
|
|
|
p << " : " << op.getType();
|
2019-10-11 06:13:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> = `llvm.mlir.null` : type
|
|
|
|
static ParseResult parseNullOp(OpAsmParser &parser, OperationState &result) {
|
|
|
|
Type type;
|
2019-11-05 13:32:07 -08:00
|
|
|
return failure(parser.parseOptionalAttrDict(result.attributes) ||
|
2019-10-11 06:13:25 -07:00
|
|
|
parser.parseColonType(type) ||
|
|
|
|
parser.addTypeToList(type, result.types));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only LLVM pointer types are supported.
|
|
|
|
static LogicalResult verify(LLVM::NullOp op) {
|
|
|
|
auto llvmType = op.getType().dyn_cast<LLVM::LLVMType>();
|
|
|
|
if (!llvmType || !llvmType.isPointerTy())
|
|
|
|
return op.emitOpError("expected LLVM IR pointer type");
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
2019-04-02 15:33:54 -07:00
|
|
|
// LLVMDialect initialization, type parsing, and registration.
|
|
|
|
//===----------------------------------------------------------------------===//
|
2019-01-15 10:53:22 -08:00
|
|
|
|
2019-05-22 14:56:07 -07:00
|
|
|
namespace mlir {
|
|
|
|
namespace LLVM {
|
|
|
|
namespace detail {
|
|
|
|
struct LLVMDialectImpl {
|
|
|
|
LLVMDialectImpl() : module("LLVMDialectModule", llvmContext) {}
|
|
|
|
|
|
|
|
llvm::LLVMContext llvmContext;
|
|
|
|
llvm::Module module;
|
|
|
|
|
2019-06-24 12:03:44 -07:00
|
|
|
/// A set of LLVMTypes that are cached on construction to avoid any lookups or
|
|
|
|
/// locking.
|
|
|
|
LLVMType int1Ty, int8Ty, int16Ty, int32Ty, int64Ty, int128Ty;
|
2019-10-11 18:35:02 -07:00
|
|
|
LLVMType doubleTy, floatTy, halfTy, fp128Ty, x86_fp80Ty;
|
2019-06-24 12:03:44 -07:00
|
|
|
LLVMType voidTy;
|
|
|
|
|
2019-05-22 14:56:07 -07:00
|
|
|
/// A smart mutex to lock access to the llvm context. Unlike MLIR, LLVM is not
|
|
|
|
/// multi-threaded and requires locked access to prevent race conditions.
|
|
|
|
llvm::sys::SmartMutex<true> mutex;
|
|
|
|
};
|
|
|
|
} // end namespace detail
|
|
|
|
} // end namespace LLVM
|
|
|
|
} // end namespace mlir
|
|
|
|
|
2019-01-15 10:53:22 -08:00
|
|
|
LLVMDialect::LLVMDialect(MLIRContext *context)
|
2019-05-13 12:42:25 -07:00
|
|
|
: Dialect(getDialectNamespace(), context),
|
2019-05-22 14:56:07 -07:00
|
|
|
impl(new detail::LLVMDialectImpl()) {
|
2019-01-15 10:53:22 -08:00
|
|
|
addTypes<LLVMType>();
|
|
|
|
addOperations<
|
2019-03-20 17:25:34 -07:00
|
|
|
#define GET_OP_LIST
|
2019-08-19 11:00:47 -07:00
|
|
|
#include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc"
|
2019-01-15 10:53:22 -08:00
|
|
|
>();
|
2019-03-31 23:30:22 -07:00
|
|
|
|
|
|
|
// Support unknown operations because not all LLVM operations are registered.
|
|
|
|
allowUnknownOperations();
|
2019-06-24 12:03:44 -07:00
|
|
|
|
|
|
|
// Cache some of the common LLVM types to avoid the need for lookups/locking.
|
|
|
|
auto &llvmContext = impl->llvmContext;
|
|
|
|
/// Integer Types.
|
|
|
|
impl->int1Ty = LLVMType::get(context, llvm::Type::getInt1Ty(llvmContext));
|
|
|
|
impl->int8Ty = LLVMType::get(context, llvm::Type::getInt8Ty(llvmContext));
|
|
|
|
impl->int16Ty = LLVMType::get(context, llvm::Type::getInt16Ty(llvmContext));
|
|
|
|
impl->int32Ty = LLVMType::get(context, llvm::Type::getInt32Ty(llvmContext));
|
|
|
|
impl->int64Ty = LLVMType::get(context, llvm::Type::getInt64Ty(llvmContext));
|
|
|
|
impl->int128Ty = LLVMType::get(context, llvm::Type::getInt128Ty(llvmContext));
|
|
|
|
/// Float Types.
|
|
|
|
impl->doubleTy = LLVMType::get(context, llvm::Type::getDoubleTy(llvmContext));
|
|
|
|
impl->floatTy = LLVMType::get(context, llvm::Type::getFloatTy(llvmContext));
|
|
|
|
impl->halfTy = LLVMType::get(context, llvm::Type::getHalfTy(llvmContext));
|
2019-10-11 18:35:02 -07:00
|
|
|
impl->fp128Ty = LLVMType::get(context, llvm::Type::getFP128Ty(llvmContext));
|
|
|
|
impl->x86_fp80Ty =
|
|
|
|
LLVMType::get(context, llvm::Type::getX86_FP80Ty(llvmContext));
|
2019-06-24 12:03:44 -07:00
|
|
|
/// Other Types.
|
|
|
|
impl->voidTy = LLVMType::get(context, llvm::Type::getVoidTy(llvmContext));
|
2019-02-25 13:16:24 -08:00
|
|
|
}
|
|
|
|
|
2019-05-22 14:56:07 -07:00
|
|
|
LLVMDialect::~LLVMDialect() {}
|
|
|
|
|
2019-03-20 17:25:34 -07:00
|
|
|
#define GET_OP_CLASSES
|
2019-08-19 11:00:47 -07:00
|
|
|
#include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc"
|
2019-03-20 17:25:34 -07:00
|
|
|
|
2019-05-22 14:56:07 -07:00
|
|
|
llvm::LLVMContext &LLVMDialect::getLLVMContext() { return impl->llvmContext; }
|
|
|
|
llvm::Module &LLVMDialect::getLLVMModule() { return impl->module; }
|
|
|
|
|
2019-02-25 13:16:24 -08:00
|
|
|
/// Parse a type registered to this dialect.
|
2019-11-01 15:39:30 -07:00
|
|
|
Type LLVMDialect::parseType(DialectAsmParser &parser) const {
|
2019-11-01 14:47:42 -07:00
|
|
|
StringRef tyData = parser.getFullSymbolSpec();
|
|
|
|
|
2019-05-22 14:56:07 -07:00
|
|
|
// LLVM is not thread-safe, so lock access to it.
|
|
|
|
llvm::sys::SmartScopedLock<true> lock(impl->mutex);
|
|
|
|
|
2019-02-25 13:16:24 -08:00
|
|
|
llvm::SMDiagnostic errorMessage;
|
2019-05-22 14:56:07 -07:00
|
|
|
llvm::Type *type = llvm::parseType(tyData, errorMessage, impl->module);
|
2019-02-25 13:16:24 -08:00
|
|
|
if (!type)
|
2019-11-01 15:39:30 -07:00
|
|
|
return (parser.emitError(parser.getNameLoc(), errorMessage.getMessage()),
|
|
|
|
nullptr);
|
2019-03-29 14:06:51 -07:00
|
|
|
return LLVMType::get(getContext(), type);
|
2019-02-25 13:16:24 -08:00
|
|
|
}
|
2019-01-15 10:53:22 -08:00
|
|
|
|
2019-02-25 13:16:24 -08:00
|
|
|
/// Print a type registered to this dialect.
|
2019-11-01 14:47:42 -07:00
|
|
|
void LLVMDialect::printType(Type type, DialectAsmPrinter &os) const {
|
2019-02-25 13:16:24 -08:00
|
|
|
auto llvmType = type.dyn_cast<LLVMType>();
|
|
|
|
assert(llvmType && "printing wrong type");
|
|
|
|
assert(llvmType.getUnderlyingType() && "no underlying LLVM type");
|
2019-11-01 14:47:42 -07:00
|
|
|
llvmType.getUnderlyingType()->print(os.getStream());
|
2019-01-15 10:53:22 -08:00
|
|
|
}
|
|
|
|
|
2019-03-06 09:34:53 -08:00
|
|
|
/// Verify LLVMIR function argument attributes.
|
2019-07-11 15:05:19 -07:00
|
|
|
LogicalResult LLVMDialect::verifyRegionArgAttribute(Operation *op,
|
|
|
|
unsigned regionIdx,
|
|
|
|
unsigned argIdx,
|
|
|
|
NamedAttribute argAttr) {
|
2019-03-06 09:34:53 -08:00
|
|
|
// Check that llvm.noalias is a boolean attribute.
|
2019-03-06 11:05:43 -08:00
|
|
|
if (argAttr.first == "llvm.noalias" && !argAttr.second.isa<BoolAttr>())
|
2019-07-11 15:05:19 -07:00
|
|
|
return op->emitError()
|
2019-05-06 09:46:11 -07:00
|
|
|
<< "llvm.noalias argument attribute of non boolean type";
|
2019-04-02 14:02:32 -07:00
|
|
|
return success();
|
2019-03-06 09:34:53 -08:00
|
|
|
}
|
|
|
|
|
2019-01-15 10:53:22 -08:00
|
|
|
static DialectRegistration<LLVMDialect> llvmDialect;
|
2019-05-22 14:56:07 -07:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// LLVMType.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace mlir {
|
|
|
|
namespace LLVM {
|
|
|
|
namespace detail {
|
|
|
|
struct LLVMTypeStorage : public ::mlir::TypeStorage {
|
|
|
|
LLVMTypeStorage(llvm::Type *ty) : underlyingType(ty) {}
|
|
|
|
|
|
|
|
// LLVM types are pointer-unique.
|
|
|
|
using KeyTy = llvm::Type *;
|
|
|
|
bool operator==(const KeyTy &key) const { return key == underlyingType; }
|
|
|
|
|
|
|
|
static LLVMTypeStorage *construct(TypeStorageAllocator &allocator,
|
|
|
|
llvm::Type *ty) {
|
|
|
|
return new (allocator.allocate<LLVMTypeStorage>()) LLVMTypeStorage(ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Type *underlyingType;
|
|
|
|
};
|
|
|
|
} // end namespace detail
|
|
|
|
} // end namespace LLVM
|
|
|
|
} // end namespace mlir
|
|
|
|
|
|
|
|
LLVMType LLVMType::get(MLIRContext *context, llvm::Type *llvmType) {
|
|
|
|
return Base::get(context, FIRST_LLVM_TYPE, llvmType);
|
|
|
|
}
|
|
|
|
|
2019-06-24 12:03:44 -07:00
|
|
|
/// Get an LLVMType with an llvm type that may cause changes to the underlying
|
|
|
|
/// llvm context when constructed.
|
|
|
|
LLVMType LLVMType::getLocked(LLVMDialect *dialect,
|
2019-12-18 09:28:48 -08:00
|
|
|
function_ref<llvm::Type *()> typeBuilder) {
|
2019-06-24 12:03:44 -07:00
|
|
|
// Lock access to the llvm context and build the type.
|
|
|
|
llvm::sys::SmartScopedLock<true> lock(dialect->impl->mutex);
|
|
|
|
return get(dialect->getContext(), typeBuilder());
|
|
|
|
}
|
|
|
|
|
2019-05-22 14:56:07 -07:00
|
|
|
LLVMDialect &LLVMType::getDialect() {
|
|
|
|
return static_cast<LLVMDialect &>(Type::getDialect());
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Type *LLVMType::getUnderlyingType() const {
|
|
|
|
return getImpl()->underlyingType;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Array type utilities.
|
|
|
|
LLVMType LLVMType::getArrayElementType() {
|
|
|
|
return get(getContext(), getUnderlyingType()->getArrayElementType());
|
|
|
|
}
|
2019-08-09 08:59:45 -07:00
|
|
|
unsigned LLVMType::getArrayNumElements() {
|
|
|
|
return getUnderlyingType()->getArrayNumElements();
|
|
|
|
}
|
2019-08-20 01:59:58 -07:00
|
|
|
bool LLVMType::isArrayTy() { return getUnderlyingType()->isArrayTy(); }
|
2019-05-22 14:56:07 -07:00
|
|
|
|
2019-08-09 05:24:47 -07:00
|
|
|
/// Vector type utilities.
|
|
|
|
LLVMType LLVMType::getVectorElementType() {
|
|
|
|
return get(getContext(), getUnderlyingType()->getVectorElementType());
|
|
|
|
}
|
2019-08-20 01:59:58 -07:00
|
|
|
bool LLVMType::isVectorTy() { return getUnderlyingType()->isVectorTy(); }
|
2019-08-09 05:24:47 -07:00
|
|
|
|
2019-08-05 01:57:27 -07:00
|
|
|
/// Function type utilities.
|
|
|
|
LLVMType LLVMType::getFunctionParamType(unsigned argIdx) {
|
|
|
|
return get(getContext(), getUnderlyingType()->getFunctionParamType(argIdx));
|
|
|
|
}
|
|
|
|
unsigned LLVMType::getFunctionNumParams() {
|
|
|
|
return getUnderlyingType()->getFunctionNumParams();
|
|
|
|
}
|
|
|
|
LLVMType LLVMType::getFunctionResultType() {
|
|
|
|
return get(
|
|
|
|
getContext(),
|
|
|
|
llvm::cast<llvm::FunctionType>(getUnderlyingType())->getReturnType());
|
|
|
|
}
|
2019-08-20 01:59:58 -07:00
|
|
|
bool LLVMType::isFunctionTy() { return getUnderlyingType()->isFunctionTy(); }
|
2019-08-05 01:57:27 -07:00
|
|
|
|
2019-05-22 14:56:07 -07:00
|
|
|
/// Pointer type utilities.
|
|
|
|
LLVMType LLVMType::getPointerTo(unsigned addrSpace) {
|
|
|
|
// Lock access to the dialect as this may modify the LLVM context.
|
2019-06-24 12:03:44 -07:00
|
|
|
return getLocked(&getDialect(), [=] {
|
|
|
|
return getUnderlyingType()->getPointerTo(addrSpace);
|
|
|
|
});
|
2019-05-22 14:56:07 -07:00
|
|
|
}
|
|
|
|
LLVMType LLVMType::getPointerElementTy() {
|
|
|
|
return get(getContext(), getUnderlyingType()->getPointerElementType());
|
|
|
|
}
|
2019-08-20 01:59:58 -07:00
|
|
|
bool LLVMType::isPointerTy() { return getUnderlyingType()->isPointerTy(); }
|
2019-05-22 14:56:07 -07:00
|
|
|
|
|
|
|
/// Struct type utilities.
|
|
|
|
LLVMType LLVMType::getStructElementType(unsigned i) {
|
|
|
|
return get(getContext(), getUnderlyingType()->getStructElementType(i));
|
|
|
|
}
|
2019-10-19 01:52:51 -07:00
|
|
|
unsigned LLVMType::getStructNumElements() {
|
|
|
|
return getUnderlyingType()->getStructNumElements();
|
|
|
|
}
|
2019-08-20 01:59:58 -07:00
|
|
|
bool LLVMType::isStructTy() { return getUnderlyingType()->isStructTy(); }
|
2019-05-22 14:56:07 -07:00
|
|
|
|
|
|
|
/// Utilities used to generate floating point types.
|
|
|
|
LLVMType LLVMType::getDoubleTy(LLVMDialect *dialect) {
|
2019-06-24 12:03:44 -07:00
|
|
|
return dialect->impl->doubleTy;
|
2019-05-22 14:56:07 -07:00
|
|
|
}
|
|
|
|
LLVMType LLVMType::getFloatTy(LLVMDialect *dialect) {
|
2019-06-24 12:03:44 -07:00
|
|
|
return dialect->impl->floatTy;
|
2019-05-22 14:56:07 -07:00
|
|
|
}
|
|
|
|
LLVMType LLVMType::getHalfTy(LLVMDialect *dialect) {
|
2019-06-24 12:03:44 -07:00
|
|
|
return dialect->impl->halfTy;
|
2019-05-22 14:56:07 -07:00
|
|
|
}
|
2019-10-11 18:35:02 -07:00
|
|
|
LLVMType LLVMType::getFP128Ty(LLVMDialect *dialect) {
|
|
|
|
return dialect->impl->fp128Ty;
|
|
|
|
}
|
|
|
|
LLVMType LLVMType::getX86_FP80Ty(LLVMDialect *dialect) {
|
|
|
|
return dialect->impl->x86_fp80Ty;
|
|
|
|
}
|
2019-05-22 14:56:07 -07:00
|
|
|
|
|
|
|
/// Utilities used to generate integer types.
|
|
|
|
LLVMType LLVMType::getIntNTy(LLVMDialect *dialect, unsigned numBits) {
|
2019-06-24 12:03:44 -07:00
|
|
|
switch (numBits) {
|
|
|
|
case 1:
|
|
|
|
return dialect->impl->int1Ty;
|
|
|
|
case 8:
|
|
|
|
return dialect->impl->int8Ty;
|
|
|
|
case 16:
|
|
|
|
return dialect->impl->int16Ty;
|
|
|
|
case 32:
|
|
|
|
return dialect->impl->int32Ty;
|
|
|
|
case 64:
|
|
|
|
return dialect->impl->int64Ty;
|
|
|
|
case 128:
|
|
|
|
return dialect->impl->int128Ty;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-05-22 14:56:07 -07:00
|
|
|
// Lock access to the dialect as this may modify the LLVM context.
|
2019-06-24 12:03:44 -07:00
|
|
|
return getLocked(dialect, [=] {
|
|
|
|
return llvm::Type::getIntNTy(dialect->getLLVMContext(), numBits);
|
|
|
|
});
|
2019-05-22 14:56:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Utilities used to generate other miscellaneous types.
|
|
|
|
LLVMType LLVMType::getArrayTy(LLVMType elementType, uint64_t numElements) {
|
|
|
|
// Lock access to the dialect as this may modify the LLVM context.
|
2019-06-24 12:03:44 -07:00
|
|
|
return getLocked(&elementType.getDialect(), [=] {
|
|
|
|
return llvm::ArrayType::get(elementType.getUnderlyingType(), numElements);
|
|
|
|
});
|
2019-05-22 14:56:07 -07:00
|
|
|
}
|
|
|
|
LLVMType LLVMType::getFunctionTy(LLVMType result, ArrayRef<LLVMType> params,
|
|
|
|
bool isVarArg) {
|
|
|
|
SmallVector<llvm::Type *, 8> llvmParams;
|
|
|
|
for (auto param : params)
|
|
|
|
llvmParams.push_back(param.getUnderlyingType());
|
|
|
|
|
|
|
|
// Lock access to the dialect as this may modify the LLVM context.
|
2019-06-24 12:03:44 -07:00
|
|
|
return getLocked(&result.getDialect(), [=] {
|
|
|
|
return llvm::FunctionType::get(result.getUnderlyingType(), llvmParams,
|
|
|
|
isVarArg);
|
|
|
|
});
|
2019-05-22 14:56:07 -07:00
|
|
|
}
|
|
|
|
LLVMType LLVMType::getStructTy(LLVMDialect *dialect,
|
|
|
|
ArrayRef<LLVMType> elements, bool isPacked) {
|
|
|
|
SmallVector<llvm::Type *, 8> llvmElements;
|
|
|
|
for (auto elt : elements)
|
|
|
|
llvmElements.push_back(elt.getUnderlyingType());
|
|
|
|
|
|
|
|
// Lock access to the dialect as this may modify the LLVM context.
|
2019-06-24 12:03:44 -07:00
|
|
|
return getLocked(dialect, [=] {
|
|
|
|
return llvm::StructType::get(dialect->getLLVMContext(), llvmElements,
|
|
|
|
isPacked);
|
|
|
|
});
|
2019-05-22 14:56:07 -07:00
|
|
|
}
|
|
|
|
LLVMType LLVMType::getVectorTy(LLVMType elementType, unsigned numElements) {
|
|
|
|
// Lock access to the dialect as this may modify the LLVM context.
|
2019-06-24 12:03:44 -07:00
|
|
|
return getLocked(&elementType.getDialect(), [=] {
|
|
|
|
return llvm::VectorType::get(elementType.getUnderlyingType(), numElements);
|
|
|
|
});
|
2019-05-22 14:56:07 -07:00
|
|
|
}
|
|
|
|
LLVMType LLVMType::getVoidTy(LLVMDialect *dialect) {
|
2019-06-24 12:03:44 -07:00
|
|
|
return dialect->impl->voidTy;
|
2019-05-22 14:56:07 -07:00
|
|
|
}
|
2019-08-20 07:51:32 -07:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Utility functions.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-12-23 14:45:01 -08:00
|
|
|
Value mlir::LLVM::createGlobalString(Location loc, OpBuilder &builder,
|
|
|
|
StringRef name, StringRef value,
|
|
|
|
LLVM::Linkage linkage,
|
|
|
|
LLVM::LLVMDialect *llvmDialect) {
|
2019-08-20 07:51:32 -07:00
|
|
|
assert(builder.getInsertionBlock() &&
|
|
|
|
builder.getInsertionBlock()->getParentOp() &&
|
2019-10-20 00:11:03 -07:00
|
|
|
"expected builder to point to a block constrained in an op");
|
2019-08-20 07:51:32 -07:00
|
|
|
auto module =
|
|
|
|
builder.getInsertionBlock()->getParentOp()->getParentOfType<ModuleOp>();
|
|
|
|
assert(module && "builder points to an op outside of a module");
|
|
|
|
|
|
|
|
// Create the global at the entry of the module.
|
|
|
|
OpBuilder moduleBuilder(module.getBodyRegion());
|
|
|
|
auto type = LLVM::LLVMType::getArrayTy(LLVM::LLVMType::getInt8Ty(llvmDialect),
|
|
|
|
value.size());
|
|
|
|
auto global = moduleBuilder.create<LLVM::GlobalOp>(
|
2019-12-02 03:27:38 -08:00
|
|
|
loc, type, /*isConstant=*/true, linkage, name,
|
|
|
|
builder.getStringAttr(value));
|
2019-08-20 07:51:32 -07:00
|
|
|
|
|
|
|
// Get the pointer to the first character in the global string.
|
2019-12-23 14:45:01 -08:00
|
|
|
Value globalPtr = builder.create<LLVM::AddressOfOp>(loc, global);
|
|
|
|
Value cst0 = builder.create<LLVM::ConstantOp>(
|
2019-08-20 07:51:32 -07:00
|
|
|
loc, LLVM::LLVMType::getInt64Ty(llvmDialect),
|
|
|
|
builder.getIntegerAttr(builder.getIndexType(), 0));
|
2019-12-23 14:45:01 -08:00
|
|
|
return builder.create<LLVM::GEPOp>(loc,
|
|
|
|
LLVM::LLVMType::getInt8PtrTy(llvmDialect),
|
|
|
|
globalPtr, ArrayRef<Value>({cst0, cst0}));
|
2019-08-20 07:51:32 -07:00
|
|
|
}
|
2019-12-16 01:35:03 -08:00
|
|
|
|
|
|
|
bool mlir::LLVM::satisfiesLLVMModule(Operation *op) {
|
|
|
|
return op->hasTrait<OpTrait::SymbolTable>() &&
|
|
|
|
op->hasTrait<OpTrait::IsIsolatedFromAbove>();
|
|
|
|
}
|