def LLVM_CallOp : LLVM_Op<"call",
[DeclareOpInterfaceMethods<FastmathFlagsInterface>,
- DeclareOpInterfaceMethods<CallOpInterface>]> {
+ DeclareOpInterfaceMethods<CallOpInterface>,
+ DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
let summary = "Call to an LLVM function.";
let description = [{
StringAttr::get($_builder.getContext(), callee), operands);
}]>];
let hasCustomAssemblyFormat = 1;
- let hasVerifier = 1;
}
+
def LLVM_ExtractElementOp : LLVM_Op<"extractelement", [NoSideEffect]> {
let arguments = (ins LLVM_AnyVector:$vector, AnyInteger:$position);
let results = (outs LLVM_Type:$res);
return getOperands().drop_front(getCallee().has_value() ? 0 : 1);
}
-LogicalResult CallOp::verify() {
+LogicalResult CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
if (getNumResults() > 1)
return emitOpError("must have 0 or 1 result");
fnType = ptrType.getElementType();
} else {
Operation *callee =
- SymbolTable::lookupNearestSymbolFrom(*this, calleeName.getAttr());
+ symbolTable.lookupNearestSymbolFrom(*this, calleeName.getAttr());
if (!callee)
return emitOpError()
<< "'" << calleeName.getValue()
func.func @call_non_function_type(%callee : !llvm.func<i8 (i8)>, %arg : i8) {
// expected-error@+1 {{expected function type}}
llvm.call %callee(%arg) : !llvm.func<i8 (i8)>
+ llvm.return
}
// -----
func.func @invalid_call() {
// expected-error@+1 {{'llvm.call' op must have either a `callee` attribute or at least an operand}}
"llvm.call"() : () -> ()
+ llvm.return
}
// -----
func.func @call_non_function_type(%callee : !llvm.func<i8 (i8)>, %arg : i8) {
// expected-error@+1 {{expected function type}}
llvm.call %callee(%arg) : !llvm.func<i8 (i8)>
+ llvm.return
}
// -----
func.func @call_unknown_symbol() {
// expected-error@+1 {{'llvm.call' op 'missing_callee' does not reference a symbol in the current scope}}
llvm.call @missing_callee() : () -> ()
+ llvm.return
}
// -----
func.func @call_non_llvm() {
// expected-error@+1 {{'llvm.call' op 'standard_func_callee' does not reference a valid LLVM function}}
llvm.call @standard_func_callee() : () -> ()
+ llvm.return
}
// -----
func.func @call_non_llvm_indirect(%arg0 : tensor<*xi32>) {
// expected-error@+1 {{'llvm.call' op operand #0 must be LLVM dialect-compatible type}}
"llvm.call"(%arg0) : (tensor<*xi32>) -> ()
+ llvm.return
}
// -----
func.func @callee_arg_mismatch(%arg0 : i32) {
// expected-error@+1 {{'llvm.call' op operand type mismatch for operand 0: 'i32' != 'i8'}}
llvm.call @callee_func(%arg0) : (i32) -> ()
+ llvm.return
}
// -----
func.func @indirect_callee_arg_mismatch(%arg0 : i32, %callee : !llvm.ptr<func<void(i8)>>) {
// expected-error@+1 {{'llvm.call' op operand type mismatch for operand 0: 'i32' != 'i8'}}
"llvm.call"(%callee, %arg0) : (!llvm.ptr<func<void(i8)>>, i32) -> ()
+ llvm.return
}
// -----
func.func @callee_return_mismatch() {
// expected-error@+1 {{'llvm.call' op result type mismatch: 'i32' != 'i8'}}
%res = llvm.call @callee_func() : () -> (i32)
+ llvm.return
}
// -----
func.func @indirect_callee_return_mismatch(%callee : !llvm.ptr<func<i8()>>) {
// expected-error@+1 {{'llvm.call' op result type mismatch: 'i32' != 'i8'}}
"llvm.call"(%callee) : (!llvm.ptr<func<i8()>>) -> (i32)
+ llvm.return
}
// -----
func.func @call_too_many_results(%callee : () -> (i32,i32)) {
// expected-error@+1 {{expected function with 0 or 1 result}}
llvm.call %callee() : () -> (i32, i32)
+ llvm.return
}
// -----
func.func @call_non_llvm_result(%callee : () -> (tensor<*xi32>)) {
// expected-error@+1 {{expected result to have LLVM type}}
llvm.call %callee() : () -> (tensor<*xi32>)
+ llvm.return
}
// -----
func.func @call_non_llvm_input(%callee : (tensor<*xi32>) -> (), %arg : tensor<*xi32>) {
// expected-error@+1 {{expected LLVM types as inputs}}
llvm.call %callee(%arg) : (tensor<*xi32>) -> ()
+ llvm.return
}
// -----