Skip to content

Commit

Permalink
feat: Handle address spaces in the createCheerp*llocate family of int…
Browse files Browse the repository at this point in the history
…rinsics

For now we just add an AS argument to createCheerpAllocate, with default
0, and we type-erase the first argument for the original function.
With proper address spaces it's impractical to keep this type
consistent.
  • Loading branch information
yuri91 committed Dec 19, 2024
1 parent 6509c55 commit 86473ee
Show file tree
Hide file tree
Showing 11 changed files with 72 additions and 61 deletions.
36 changes: 20 additions & 16 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3427,7 +3427,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
QualType returnType=retCE->getType();
Tys[0] = ConvertType(returnType);
elementType = ConvertType(returnType->getPointeeType());
CallBase* CB = cheerp::createCheerpAllocate(Builder, nullptr, elementType, Size);
unsigned AS = getContext().getTargetAddressSpace(returnType->getPointeeType().getAddressSpace());
CallBase* CB = cheerp::createCheerpAllocate(Builder, nullptr, elementType, Size, AS);
return RValue::get(CB);
}
}
Expand Down Expand Up @@ -12549,9 +12550,7 @@ Value *CodeGenFunction::EmitCheerpBuiltinExpr(unsigned BuiltinID,
else if (BuiltinID == Cheerp::BI__builtin_cheerp_deallocate) {
// This is only used in SemaCoroutine, so we just care for the genericjs
// case, and for now only void* argument
llvm::Type *Tys[] = { VoidPtrTy, Ops[0]->getType() };
Function *F = CGM.getIntrinsic(Intrinsic::cheerp_deallocate, Tys);
return EmitCallOrInvoke(F, {ConstantPointerNull::get(VoidPtrTy), Ops[0]});
return cheerp::createCheerpDeallocate(Builder, nullptr, nullptr, Ops[0]);
}
else if (BuiltinID == Cheerp::BI__builtin_cheerp_throw) {
llvm::Type *Tys[] = { Ops[0]->getType() };
Expand Down Expand Up @@ -12684,24 +12683,25 @@ Value *CodeGenFunction::EmitCheerpBuiltinExpr(unsigned BuiltinID,
ParentMap PM(FD ? FD->getBody() : const_cast<Expr*>(VD->getInit()));
const Stmt* parent=PM.getParent(E);
// We need an explicit cast after the call, void* can't be used
llvm::Type *Tys[] = { VoidPtrTy, VoidPtrTy };
const CastExpr* retCE=dyn_cast_or_null<CastExpr>(parent);
llvm::Type* elementType = nullptr;
unsigned AS = 0;
if (!retCE || retCE->getType()->isVoidPointerType()) {
if (!asmjs) {
CGM.getDiags().Report(E->getBeginLoc(), diag::err_cheerp_alloc_requires_cast);
return 0;
}
AS = getContext().getTargetAddressSpace(E->getType()->getPointeeType().getAddressSpace());
} else {
elementType = ConvertTypeForMem(retCE->getType()->getPointeeType());
Tys[0] = ConvertType(retCE->getType());
AS = getContext().getTargetAddressSpace(retCE->getType()->getPointeeType().getAddressSpace());
}
llvm::Function* Malloc = nullptr;
llvm::Constant* Malloc = nullptr;
// in Wasm, we pass the original allocation function as argument 0
if (asmjs || (elementType->isStructTy() && cast<llvm::StructType>(elementType)->hasAsmJS())) {
Malloc = dyn_cast<Function>(CGM.getModule().getOrInsertFunction("malloc", Int8PtrTy, Int32Ty).getCallee());
Malloc = cast<Constant>(CGM.getModule().getOrInsertFunction("malloc", Int8PtrTy, Int32Ty).getCallee());
}
llvm::CallBase* CB = cheerp::createCheerpAllocate(Builder, Malloc, elementType, Ops[0]);
llvm::CallBase* CB = cheerp::createCheerpAllocate(Builder, Malloc, elementType, Ops[0], AS);
return CB;
}
else if (BuiltinID == Builtin::BIcalloc) {
Expand All @@ -12714,23 +12714,26 @@ Value *CodeGenFunction::EmitCheerpBuiltinExpr(unsigned BuiltinID,
// We need an explicit cast after the call, void* can't be used
const CastExpr* retCE=dyn_cast_or_null<CastExpr>(parent);
llvm::Type* elementType = nullptr;
unsigned AS = 0;
if (!retCE || retCE->getType()->isVoidPointerType()) {
if (!asmjs) {
CGM.getDiags().Report(E->getBeginLoc(), diag::err_cheerp_alloc_requires_cast);
return 0;
}
AS = getContext().getTargetAddressSpace(E->getType()->getPointeeType().getAddressSpace());
} else {
elementType = ConvertTypeForMem(retCE->getType()->getPointeeType());
AS = getContext().getTargetAddressSpace(retCE->getType()->getPointeeType().getAddressSpace());
}
llvm::Function* Malloc = nullptr;
llvm::Constant* Malloc = nullptr;
// in Wasm, we pass the original allocation function as argument 0
// in this case malloc and not calloc since we explicitly memset after
if (asmjs || (elementType->isStructTy() && cast<llvm::StructType>(elementType)->hasAsmJS())) {
Malloc = dyn_cast<llvm::Function>(CGM.getModule().getOrInsertFunction("malloc", Int8PtrTy, Int32Ty).getCallee());
Malloc = cast<llvm::Constant>(CGM.getModule().getOrInsertFunction("malloc", Int8PtrTy, Int32Ty).getCallee());
}
// Compute the size in bytes
llvm::Value* sizeInBytes = Builder.CreateMul(Ops[0], Ops[1]);
llvm::CallBase* CB = cheerp::createCheerpAllocate(Builder, Malloc, elementType, sizeInBytes);
llvm::CallBase* CB = cheerp::createCheerpAllocate(Builder, Malloc, elementType, sizeInBytes, AS);
Builder.CreateMemSet(CB, ConstantInt::get(Int8Ty, 0), sizeInBytes, MaybeAlign(1), false, NULL, NULL, NULL,
CGBuilderTy::CheerpTypeInfo::get(getTarget().isByteAddressable(), elementType));
return CB;
Expand Down Expand Up @@ -12785,7 +12788,7 @@ Value *CodeGenFunction::EmitCheerpBuiltinExpr(unsigned BuiltinID,
llvm::Type *RetTy = Builder.getInt8PtrTy();
llvm::Type *Arg0Ty = Builder.getInt8PtrTy();
llvm::Type *Arg1Ty = Builder.getInt32Ty();
llvm::Function* origReallocFunc = dyn_cast<llvm::Function>(CGM.getModule().getOrInsertFunction("realloc", RetTy, Arg0Ty, Arg1Ty).getCallee());
llvm::Constant* origReallocFunc = cast<llvm::Function>(CGM.getModule().getOrInsertFunction("realloc", RetTy, Arg0Ty, Arg1Ty).getCallee());
CallBase* CB = cheerp::createCheerpReallocate(Builder, origReallocFunc, elementType, Ops[0], Ops[1]);
return CB;
} else {
Expand All @@ -12797,7 +12800,8 @@ Value *CodeGenFunction::EmitCheerpBuiltinExpr(unsigned BuiltinID,
Builder.CreateCondBr(opIsNull, mallocBlock, reallocBlock);
Builder.SetInsertPoint(mallocBlock);

CallBase* mallocRet = cheerp::createCheerpAllocate(Builder, nullptr, elementType, Ops[1]);
unsigned AS = getContext().getTargetAddressSpace(reallocType->getPointeeType().getAddressSpace());
CallBase* mallocRet = cheerp::createCheerpAllocate(Builder, nullptr, elementType, Ops[1], AS);
Builder.CreateBr(endBlock);
Builder.SetInsertPoint(reallocBlock);
CallBase* reallocRet = cheerp::createCheerpReallocate(Builder, nullptr, elementType, Ops[0], Ops[1]);
Expand All @@ -12819,12 +12823,12 @@ Value *CodeGenFunction::EmitCheerpBuiltinExpr(unsigned BuiltinID,
Ops[0]=EmitScalarExpr(argCE->getSubExpr());
}
}
llvm::Function* Free = nullptr;
llvm::Constant* Free = nullptr;
// in Wasm, we pass the original deallocation function as argument 0
// For free, we always pass this argument unless the element type is a genericjs struct,
// because the pointer may have come from Wasm originally
if (asmjs || (elementType && elementType->isStructTy() && !cast<llvm::StructType>(elementType)->hasAsmJS())) {
Free = dyn_cast<llvm::Function>(CGM.getModule().getOrInsertFunction("free", VoidTy, Int8PtrTy).getCallee());
Free = cast<llvm::Constant>(CGM.getModule().getOrInsertFunction("free", VoidTy, Int8PtrTy).getCallee());
}
llvm::CallBase* CB = cheerp::createCheerpDeallocate(Builder, Free, elementType, Ops[0]);
return CB;
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/CodeGen/CGException.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,12 +393,12 @@ namespace {
FreeException(llvm::Value *exn) : exn(exn) {}
void Emit(CodeGenFunction &CGF, Flags flags) override {
if (CGF.getLangOpts().Cheerp) {
llvm::Function* origFunc = nullptr;
llvm::Constant* origFunc = nullptr;
if (CGF.getTarget().getTriple().isCheerpWasm()) {
llvm::FunctionType *FreeTy =
llvm::FunctionType::get(CGF.VoidTy, CGF.VoidPtrTy, /*isVarArg=*/false);

origFunc = cast<llvm::Function>(CGF.CGM.CreateRuntimeFunction(FreeTy, "free").getCallee());
origFunc = cast<llvm::Constant>(CGF.CGM.CreateRuntimeFunction(FreeTy, "free").getCallee());
}
cheerp::createCheerpDeallocate(CGF.Builder, origFunc, nullptr, exn);
} else {
Expand Down
10 changes: 5 additions & 5 deletions clang/lib/CodeGen/CGExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1374,19 +1374,19 @@ static RValue EmitNewDeleteCall(CodeGenFunction &CGF,
{
// Forge a call to a special type safe allocator intrinsic
QualType retType = CGF.getContext().getPointerType(allocType);
llvm::Function* origFunc = nullptr;
llvm::Constant* origFunc = nullptr;
if (asmjs || (allocType->getAsTagDecl() && allocType->getAsTagDecl()->hasAttr<AsmJSAttr>())) {
origFunc = cast<llvm::Function>(CalleePtr);
origFunc = CalleePtr;
}
llvm::Type* elementType = CGF.ConvertTypeForMem(retType->getPointeeType());
CallOrInvoke = cheerp::createCheerpAllocate(CGF.Builder, origFunc, elementType, Args[0].getKnownRValue().getScalarVal(), use_array);
CallOrInvoke = cheerp::createCheerpAllocate(CGF.Builder, origFunc, elementType, Args[0].getKnownRValue().getScalarVal(), 0, use_array);
RV = RValue::get(CallOrInvoke);
}
else if(IsDelete && cheerp && !(asmjs && (user_defined_new || fancy_new)))
{
llvm::Function* origFunc = nullptr;
llvm::Constant* origFunc = nullptr;
if (asmjs || !(allocType->getAsTagDecl() && allocType->getAsTagDecl()->hasAttr<GenericJSAttr>())) {
origFunc = cast<llvm::Function>(CalleePtr);
origFunc = CalleePtr;
}
QualType argType = CGF.getContext().getPointerType(allocType);
llvm::Type* elementType = CGF.ConvertTypeForMem(argType->getPointeeType());
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/CodeGen/ItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1412,7 +1412,7 @@ void ItaniumCXXABI::emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) {
llvm::CallInst* ExceptionPtr = nullptr;
llvm::Value* Size = llvm::ConstantInt::get(SizeTy, TypeSize);
if (CGM.getLangOpts().Cheerp) {
llvm::Function* origFunc = nullptr;
llvm::Constant* origFunc = nullptr;
// We want to know if this exception is supposed to be allocated as a wasm
// or js object
// TODO: do it better when we have address spaces
Expand All @@ -1430,7 +1430,7 @@ void ItaniumCXXABI::emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) {
llvm::FunctionType *MallocTy =
llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int32Ty, /*isVarArg=*/false);

origFunc = cast<llvm::Function>(CGF.CGM.CreateRuntimeFunction(MallocTy, "malloc").getCallee());
origFunc = cast<llvm::Constant>(CGF.CGM.CreateRuntimeFunction(MallocTy, "malloc").getCallee());
}
ExceptionPtr = cheerp::createCheerpAllocate(CGF.Builder, origFunc, elemTy, Size);
} else {
Expand Down
7 changes: 4 additions & 3 deletions llvm/include/llvm/Cheerp/Utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,19 +280,20 @@ inline bool isGEP(const llvm::Value* v)
}

llvm::CallInst* createCheerpAllocate(llvm::IRBuilderBase& Builder,
llvm::Function* origFunc,
llvm::Constant* origFunc,
llvm::Type* elementType,
llvm::Value* sizeArg,
unsigned AS = 0,
bool use_array = false);

llvm::CallInst* createCheerpReallocate(llvm::IRBuilderBase& Builder,
llvm::Function* origFunc,
llvm::Constant* origFunc,
llvm::Type* elementType,
llvm::Value* ptrArg,
llvm::Value* sizeArg);

llvm::CallInst* createCheerpDeallocate(llvm::IRBuilderBase& Builder,
llvm::Function* origFunc,
llvm::Constant* origFunc,
llvm::Type* elementType,
llvm::Value* ptrArg);

Expand Down
8 changes: 4 additions & 4 deletions llvm/include/llvm/IR/IntrinsicsCheerp.td
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ def int_cheerp_cast_user : Intrinsic<[llvm_anyptr_ty],

// Type safe memory allocation
def int_cheerp_allocate : Intrinsic<[llvm_anyptr_ty],
[llvm_anyptr_ty,llvm_i32_ty]>;
[llvm_ptr_ty,llvm_i32_ty]>;
def int_cheerp_allocate_array : Intrinsic<[llvm_anyptr_ty],
[llvm_anyptr_ty,llvm_i32_ty]>;
[llvm_ptr_ty,llvm_i32_ty]>;
def int_cheerp_get_array_len : Intrinsic<[llvm_i32_ty],
[llvm_anyptr_ty]>;
def int_cheerp_reallocate : Intrinsic<[llvm_anyptr_ty],
[llvm_anyptr_ty,llvm_anyptr_ty, llvm_i32_ty]>;
[llvm_ptr_ty,llvm_anyptr_ty, llvm_i32_ty]>;
def int_cheerp_deallocate : Intrinsic<[],
[llvm_anyptr_ty, llvm_anyptr_ty]>;
[llvm_ptr_ty, llvm_anyptr_ty]>;
def int_cheerp_coro_alloc : Intrinsic<[llvm_ptr_ty],
[llvm_i32_ty]>;

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/CheerpUtils/GlobalDepsAnalyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ bool GlobalDepsAnalyzer::runOnModule( llvm::Module & module )
II == Intrinsic::cheerp_deallocate ) &&
!isa<ConstantPointerNull>(ci->getArgOperand(0)))
{
Function* OrigFunc = dyn_cast<Function>(ci->getOperand(0));
Function* OrigFunc = dyn_cast<Function>(ci->getOperand(0)->stripPointerCastsSafe());
assert(OrigFunc);
if (llcPass)
{
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/CheerpUtils/PointerPasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,7 @@ bool FreeAndDeleteRemoval::runOnModule(Module& M)
}
else if (!elemTy || !cheerp::TypeSupport::isAsmJSPointed(elemTy))
{
Function* origF = cast<Function>(call->getArgOperand(0));
Function* origF = cast<Function>(call->getArgOperand(0)->stripPointerCastsSafe());
call->setArgOperand(0, getOrCreateGenericJSFree(M, origF));
}
}
Expand Down
22 changes: 11 additions & 11 deletions llvm/lib/CheerpUtils/TypeOptimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1117,16 +1117,11 @@ Function* TypeOptimizer::rewriteIntrinsic(Function* F, FunctionType* FT)
SmallVector<Type*, 3> newTys;
switch(F->getIntrinsicID())
{
case Intrinsic::cheerp_reallocate:
{
Type* localTys[] = { FT->getReturnType(), FT->getParamType(0), FT->getParamType(1)};
newTys.insert(newTys.end(),localTys,localTys+3);
break;
}
case Intrinsic::cheerp_deallocate:
case Intrinsic::cheerp_allocate:
case Intrinsic::cheerp_allocate_array:
{
Type* localTys[] = { FT->getParamType(0), FT->getParamType(1)};
newTys.insert(newTys.end(),localTys,localTys+2);
Type* localTys[] = { FT->getReturnType()};
newTys.insert(newTys.end(),localTys,localTys+1);
break;
}
case Intrinsic::cheerp_upcast_collapsed:
Expand All @@ -1135,13 +1130,17 @@ Function* TypeOptimizer::rewriteIntrinsic(Function* F, FunctionType* FT)
case Intrinsic::cheerp_virtualcast:
case Intrinsic::cheerp_make_complete_object:
case Intrinsic::cheerp_make_regular:
case Intrinsic::cheerp_allocate:
case Intrinsic::cheerp_allocate_array:
{
Type* localTys[] = { FT->getReturnType(), FT->getParamType(0)};
newTys.insert(newTys.end(),localTys,localTys+2);
break;
}
case Intrinsic::cheerp_reallocate:
{
Type* localTys[] = { FT->getReturnType(), FT->getParamType(1)};
newTys.insert(newTys.end(),localTys,localTys+2);
break;
}
case Intrinsic::cheerp_downcast_current:
case Intrinsic::cheerp_get_array_len:
case Intrinsic::cheerp_pointer_kind:
Expand All @@ -1154,6 +1153,7 @@ Function* TypeOptimizer::rewriteIntrinsic(Function* F, FunctionType* FT)
}
case Intrinsic::invariant_start:
case Intrinsic::invariant_end:
case Intrinsic::cheerp_deallocate:
{
Type* localTys[] = { FT->getParamType(1) };
newTys.insert(newTys.end(),localTys,localTys+1);
Expand Down
34 changes: 20 additions & 14 deletions llvm/lib/CheerpUtils/Utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -611,17 +611,19 @@ uint32_t getIntFromValue(const Value* v)


CallInst* createCheerpAllocate(IRBuilderBase& Builder,
Function* origFunc,
Constant* origFunc,
Type* elementType,
Value* sizeArg,
unsigned AS,
bool use_array)
{
unsigned AS = 0;
PointerType* PtrTy = Builder.getInt8PtrTy();
auto Intr = use_array? Intrinsic::cheerp_allocate_array : Intrinsic::cheerp_allocate;
PointerType* origFuncTy = origFunc? origFunc->getFunctionType()->getPointerTo(origFunc->getAddressSpace()) : Builder.getInt8PtrTy();
Type* retTy = elementType? elementType->getPointerTo(AS) : Builder.getInt8PtrTy(AS);
Type* Tys[] = { retTy, origFuncTy };
Constant* origFuncArg = origFunc? (Constant*)origFunc : (Constant*)ConstantPointerNull::get(origFuncTy);
Type* Tys[] = { retTy };
Constant* origFuncArg = origFunc?
(Constant*)Builder.CreatePointerBitCastOrAddrSpaceCast(origFunc, PtrTy) :
(Constant*)ConstantPointerNull::get(PtrTy);
CallInst* Call = Builder.CreateIntrinsic(Intr, Tys, {origFuncArg, sizeArg});
if (elementType)
{
Expand All @@ -630,16 +632,18 @@ CallInst* createCheerpAllocate(IRBuilderBase& Builder,
return Call;
}
llvm::CallInst* createCheerpReallocate(llvm::IRBuilderBase& Builder,
llvm::Function* origFunc,
llvm::Constant* origFunc,
llvm::Type* elementType,
llvm::Value* ptrArg,
llvm::Value* sizeArg)
{
unsigned AS = 0;
PointerType* origFuncTy = origFunc? origFunc->getFunctionType()->getPointerTo(origFunc->getAddressSpace()) : Builder.getInt8PtrTy();
PointerType* PtrTy = Builder.getInt8PtrTy();
unsigned AS = cast<PointerType>(ptrArg->getType())->getAddressSpace();
Type* retTy = elementType? elementType->getPointerTo(AS) : Builder.getInt8PtrTy(AS);
Type* Tys[] = { retTy, origFuncTy, ptrArg->getType() };
Constant* origFuncArg = origFunc? (Constant*)origFunc : (Constant*)ConstantPointerNull::get(origFuncTy);
Type* Tys[] = { retTy, ptrArg->getType() };
Constant* origFuncArg = origFunc?
(Constant*)Builder.CreatePointerBitCastOrAddrSpaceCast(origFunc, PtrTy) :
(Constant*)ConstantPointerNull::get(PtrTy);
CallInst* Call = Builder.CreateIntrinsic(Intrinsic::cheerp_reallocate, Tys, {origFuncArg, ptrArg, sizeArg});
if (elementType)
{
Expand All @@ -650,13 +654,15 @@ llvm::CallInst* createCheerpReallocate(llvm::IRBuilderBase& Builder,
}

llvm::CallInst* createCheerpDeallocate(llvm::IRBuilderBase& Builder,
llvm::Function* origFunc,
llvm::Constant* origFunc,
llvm::Type* elementType,
llvm::Value* ptrArg)
{
PointerType* origFuncTy = origFunc? origFunc->getFunctionType()->getPointerTo(origFunc->getAddressSpace()) : Builder.getInt8PtrTy();
Type* Tys[] = { origFuncTy, ptrArg->getType() };
Constant* origFuncArg = origFunc? (Constant*)origFunc : (Constant*)ConstantPointerNull::get(origFuncTy);
PointerType* PtrTy = Builder.getInt8PtrTy();
Type* Tys[] = { ptrArg->getType() };
Constant* origFuncArg = origFunc?
(Constant*)Builder.CreatePointerBitCastOrAddrSpaceCast(origFunc, PtrTy) :
(Constant*)ConstantPointerNull::get(PtrTy);
CallInst* Call = Builder.CreateIntrinsic(Intrinsic::cheerp_deallocate, Tys, {origFuncArg, ptrArg});
if (elementType)
{
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Transforms/Coroutines/CoroFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1565,9 +1565,9 @@ static void createFramePtr(coro::Shape &Shape) {
if (Shape.CheerpCoroAlloc) {
// CHEERP: Replace cheerp_coro_alloc with cheerp_allocate, now that we know the
// final frame type
Function* Malloc = nullptr;
Constant* Malloc = nullptr;
if (FrameTy->hasAsmJS()) {
Malloc = cast<Function>(M->getOrInsertFunction("malloc", Builder.getInt8PtrTy(), Builder.getInt32Ty()).getCallee());
Malloc = cast<Constant>(M->getOrInsertFunction("malloc", Builder.getInt8PtrTy(), Builder.getInt32Ty()).getCallee());
}
Builder.SetInsertPoint(Shape.CheerpCoroAlloc);
CallBase* Alloc = cheerp::createCheerpAllocate(Builder, Malloc, FrameTy, Shape.CheerpCoroAlloc->getOperand(0));
Expand Down

0 comments on commit 86473ee

Please sign in to comment.