Skip to content

Commit a5fe945

Browse files
authored
ccall: add support for automatic llvmcall mangling (#44697)
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
1 parent 6366f40 commit a5fe945

File tree

3 files changed

+53
-14
lines changed

3 files changed

+53
-14
lines changed

src/ccall.cpp

+31-8
Original file line numberDiff line numberDiff line change
@@ -1927,14 +1927,37 @@ jl_cgval_t function_sig_t::emit_a_ccall(
19271927
}
19281928
else {
19291929
assert(symarg.f_name != NULL);
1930-
const char* f_name = symarg.f_name;
1931-
bool f_extern = (strncmp(f_name, "extern ", 7) == 0);
1932-
if (f_extern)
1933-
f_name += 7;
1934-
llvmf = jl_Module->getOrInsertFunction(f_name, functype).getCallee();
1935-
if (!f_extern && (!isa<Function>(llvmf) ||
1936-
cast<Function>(llvmf)->getIntrinsicID() ==
1937-
Intrinsic::not_intrinsic)) {
1930+
StringRef f_name(symarg.f_name);
1931+
bool f_extern = f_name.consume_front("extern ");
1932+
llvmf = NULL;
1933+
if (f_extern) {
1934+
llvmf = jl_Module->getOrInsertFunction(f_name, functype).getCallee();
1935+
if (!isa<Function>(llvmf) || cast<Function>(llvmf)->isIntrinsic() || cast<Function>(llvmf)->getFunctionType() != functype)
1936+
llvmf = NULL;
1937+
}
1938+
else if (f_name.startswith("llvm.")) {
1939+
// compute and verify auto-mangling for intrinsic name
1940+
auto ID = Function::lookupIntrinsicID(f_name);
1941+
if (ID != Intrinsic::not_intrinsic) {
1942+
// Accumulate an array of overloaded types for the given intrinsic
1943+
// and compute the new name mangling schema
1944+
SmallVector<Type*, 4> overloadTys;
1945+
SmallVector<Intrinsic::IITDescriptor, 8> Table;
1946+
getIntrinsicInfoTableEntries(ID, Table);
1947+
ArrayRef<Intrinsic::IITDescriptor> TableRef = Table;
1948+
auto res = Intrinsic::matchIntrinsicSignature(functype, TableRef, overloadTys);
1949+
if (res == Intrinsic::MatchIntrinsicTypes_Match) {
1950+
bool matchvararg = !Intrinsic::matchIntrinsicVarArg(functype->isVarArg(), TableRef);
1951+
if (matchvararg) {
1952+
Function *intrinsic = Intrinsic::getDeclaration(jl_Module, ID, overloadTys);
1953+
assert(intrinsic->getFunctionType() == functype);
1954+
if (intrinsic->getName() == f_name || Intrinsic::getBaseName(ID) == f_name)
1955+
llvmf = intrinsic;
1956+
}
1957+
}
1958+
}
1959+
}
1960+
if (llvmf == NULL) {
19381961
emit_error(ctx, "llvmcall only supports intrinsic calls");
19391962
return jl_cgval_t(ctx.builder.getContext());
19401963
}

src/llvm-alloc-opt.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -517,8 +517,8 @@ void Optimizer::replaceIntrinsicUseWith(IntrinsicInst *call, Intrinsic::ID ID,
517517
auto res = Intrinsic::matchIntrinsicSignature(newfType, TableRef, overloadTys);
518518
assert(res == Intrinsic::MatchIntrinsicTypes_Match);
519519
(void)res;
520-
bool matchvararg = Intrinsic::matchIntrinsicVarArg(newfType->isVarArg(), TableRef);
521-
assert(!matchvararg);
520+
bool matchvararg = !Intrinsic::matchIntrinsicVarArg(newfType->isVarArg(), TableRef);
521+
assert(matchvararg);
522522
(void)matchvararg;
523523
}
524524
auto newF = Intrinsic::getDeclaration(call->getModule(), ID, overloadTys);

test/llvmcall2.jl

+20-4
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,26 @@ function ceilfloor(x::Float64)
3737
end
3838
@test ceilfloor(7.4) == 8.0
3939

40-
# support for calling external functions
41-
begin
42-
f() = ccall("time", llvmcall, Cvoid, (Ptr{Cvoid},), C_NULL)
43-
@test_throws ErrorException f()
40+
let err = ErrorException("llvmcall only supports intrinsic calls")
41+
# support for calling external functions
42+
@test_throws err @eval ccall("time", llvmcall, Cvoid, (Ptr{Cvoid},), C_NULL)
4443
g() = ccall("extern time", llvmcall, Cvoid, (Ptr{Cvoid},), C_NULL)
4544
g()
45+
@test_throws err @eval ccall("extern llvm.floor", llvmcall, Float64, (Float64,), 0.0)
46+
47+
# support for mangling
48+
@test (@eval ccall("llvm.floor.f64", llvmcall, Float64, (Float64,), 0.0)) === 0.0
49+
@test (@eval ccall("llvm.floor", llvmcall, Float64, (Float64,), 0.0),
50+
ccall("llvm.floor", llvmcall, Float32, (Float32,), 0.0)) === (0.0, 0.0f0)
51+
@test_throws err @eval ccall("llvm.floor.f64", llvmcall, Float32, (Float64,), 0.0)
52+
@test_throws err @eval ccall("llvm.floor.f64", llvmcall, Float32, (Float32,), 0.0f0)
53+
@test_throws err @eval ccall("llvm.floor.f64", llvmcall, Float64, (Float32,), 0.0f0)
54+
@test_throws err @eval ccall("llvm.floor.f64", llvmcall, Float64, (Int,), 0)
55+
@test_throws err @eval ccall("llvm.floor.f64", llvmcall, Int, (Int,), 0)
56+
@test_throws err @eval ccall("llvm.floor", llvmcall, Float64, (Float32,), 0.0f0)
57+
@test_throws err @eval ccall("llvm.floor", llvmcall, Float64, (Int,), 0)
58+
@test_throws err @eval ccall("llvm.floor", llvmcall, Int, (Int,), 0)
59+
60+
@test_throws err (@eval ccall("llvm.floor.f64", llvmcall, Float64, (Float64, Float64...,), 0.0)) === 0.0
61+
@test_throws err (@eval ccall("llvm.floor", llvmcall, Float64, (Float64, Float64...,), 0.0)) === 0.0
4662
end

0 commit comments

Comments
 (0)