Skip to content

Commit

Permalink
ccall: add support for automatic llvmcall mangling (#44697)
Browse files Browse the repository at this point in the history
Sometimes the mangling changes by version, or is unclear, so we allow that to auto-upgrade here.
Code from llvm-alloc-opt.cpp.
Fix #44694
  • Loading branch information
vtjnash authored Mar 23, 2022
1 parent 6366f40 commit a5fe945
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 14 deletions.
39 changes: 31 additions & 8 deletions src/ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1927,14 +1927,37 @@ jl_cgval_t function_sig_t::emit_a_ccall(
}
else {
assert(symarg.f_name != NULL);
const char* f_name = symarg.f_name;
bool f_extern = (strncmp(f_name, "extern ", 7) == 0);
if (f_extern)
f_name += 7;
llvmf = jl_Module->getOrInsertFunction(f_name, functype).getCallee();
if (!f_extern && (!isa<Function>(llvmf) ||
cast<Function>(llvmf)->getIntrinsicID() ==
Intrinsic::not_intrinsic)) {
StringRef f_name(symarg.f_name);
bool f_extern = f_name.consume_front("extern ");
llvmf = NULL;
if (f_extern) {
llvmf = jl_Module->getOrInsertFunction(f_name, functype).getCallee();
if (!isa<Function>(llvmf) || cast<Function>(llvmf)->isIntrinsic() || cast<Function>(llvmf)->getFunctionType() != functype)
llvmf = NULL;
}
else if (f_name.startswith("llvm.")) {
// compute and verify auto-mangling for intrinsic name
auto ID = Function::lookupIntrinsicID(f_name);
if (ID != Intrinsic::not_intrinsic) {
// Accumulate an array of overloaded types for the given intrinsic
// and compute the new name mangling schema
SmallVector<Type*, 4> overloadTys;
SmallVector<Intrinsic::IITDescriptor, 8> Table;
getIntrinsicInfoTableEntries(ID, Table);
ArrayRef<Intrinsic::IITDescriptor> TableRef = Table;
auto res = Intrinsic::matchIntrinsicSignature(functype, TableRef, overloadTys);
if (res == Intrinsic::MatchIntrinsicTypes_Match) {
bool matchvararg = !Intrinsic::matchIntrinsicVarArg(functype->isVarArg(), TableRef);
if (matchvararg) {
Function *intrinsic = Intrinsic::getDeclaration(jl_Module, ID, overloadTys);
assert(intrinsic->getFunctionType() == functype);
if (intrinsic->getName() == f_name || Intrinsic::getBaseName(ID) == f_name)
llvmf = intrinsic;
}
}
}
}
if (llvmf == NULL) {
emit_error(ctx, "llvmcall only supports intrinsic calls");
return jl_cgval_t(ctx.builder.getContext());
}
Expand Down
4 changes: 2 additions & 2 deletions src/llvm-alloc-opt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -517,8 +517,8 @@ void Optimizer::replaceIntrinsicUseWith(IntrinsicInst *call, Intrinsic::ID ID,
auto res = Intrinsic::matchIntrinsicSignature(newfType, TableRef, overloadTys);
assert(res == Intrinsic::MatchIntrinsicTypes_Match);
(void)res;
bool matchvararg = Intrinsic::matchIntrinsicVarArg(newfType->isVarArg(), TableRef);
assert(!matchvararg);
bool matchvararg = !Intrinsic::matchIntrinsicVarArg(newfType->isVarArg(), TableRef);
assert(matchvararg);
(void)matchvararg;
}
auto newF = Intrinsic::getDeclaration(call->getModule(), ID, overloadTys);
Expand Down
24 changes: 20 additions & 4 deletions test/llvmcall2.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,26 @@ function ceilfloor(x::Float64)
end
@test ceilfloor(7.4) == 8.0

# support for calling external functions
begin
f() = ccall("time", llvmcall, Cvoid, (Ptr{Cvoid},), C_NULL)
@test_throws ErrorException f()
let err = ErrorException("llvmcall only supports intrinsic calls")
# support for calling external functions
@test_throws err @eval ccall("time", llvmcall, Cvoid, (Ptr{Cvoid},), C_NULL)
g() = ccall("extern time", llvmcall, Cvoid, (Ptr{Cvoid},), C_NULL)
g()
@test_throws err @eval ccall("extern llvm.floor", llvmcall, Float64, (Float64,), 0.0)

# support for mangling
@test (@eval ccall("llvm.floor.f64", llvmcall, Float64, (Float64,), 0.0)) === 0.0
@test (@eval ccall("llvm.floor", llvmcall, Float64, (Float64,), 0.0),
ccall("llvm.floor", llvmcall, Float32, (Float32,), 0.0)) === (0.0, 0.0f0)
@test_throws err @eval ccall("llvm.floor.f64", llvmcall, Float32, (Float64,), 0.0)
@test_throws err @eval ccall("llvm.floor.f64", llvmcall, Float32, (Float32,), 0.0f0)
@test_throws err @eval ccall("llvm.floor.f64", llvmcall, Float64, (Float32,), 0.0f0)
@test_throws err @eval ccall("llvm.floor.f64", llvmcall, Float64, (Int,), 0)
@test_throws err @eval ccall("llvm.floor.f64", llvmcall, Int, (Int,), 0)
@test_throws err @eval ccall("llvm.floor", llvmcall, Float64, (Float32,), 0.0f0)
@test_throws err @eval ccall("llvm.floor", llvmcall, Float64, (Int,), 0)
@test_throws err @eval ccall("llvm.floor", llvmcall, Int, (Int,), 0)

@test_throws err (@eval ccall("llvm.floor.f64", llvmcall, Float64, (Float64, Float64...,), 0.0)) === 0.0
@test_throws err (@eval ccall("llvm.floor", llvmcall, Float64, (Float64, Float64...,), 0.0)) === 0.0
end

0 comments on commit a5fe945

Please sign in to comment.