diff --git a/llvm/docs/SPIRVUsage.rst b/llvm/docs/SPIRVUsage.rst index 93c53a04bc447..6a27e0efaec7f 100644 --- a/llvm/docs/SPIRVUsage.rst +++ b/llvm/docs/SPIRVUsage.rst @@ -173,6 +173,8 @@ list of supported SPIR-V extensions, sorted alphabetically by their extension na - Adds decorations that can be applied to global (module scope) variables to help code generation for FPGA devices. * - ``SPV_INTEL_media_block_io`` - Adds additional subgroup block read and write functionality that allow applications to flexibly specify the width and height of the block to read from or write to a 2D image. + * - ``SPV_INTEL_memory_access_aliasing`` + - Adds instructions and decorations to specify memory access aliasing, similar to alias.scope and noalias LLVM metadata. * - ``SPV_INTEL_optnone`` - Adds OptNoneINTEL value for Function Control mask that indicates a request to not optimize the function. * - ``SPV_INTEL_split_barrier`` @@ -301,6 +303,10 @@ SPIR-V backend, along with their descriptions and argument details. - None - `[Type, Metadata]` - Assigns decoration to values by associating them with metadatas. Not emitted directly but used to support SPIR-V representation in LLVM IR. + * - `int_spv_assign_aliasing_decoration` + - None + - `[Type, 32-bit Integer, Metadata]` + - Assigns one of two memory aliasing decorations (specified by the second argument) to instructions using original aliasing metadata node. Not emitted directly but used to support SPIR-V representation in LLVM IR. * - `int_spv_track_constant` - Type - `[Type, Metadata]` diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td index 4c16e5e15bff0..7012ef3534c68 100644 --- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td +++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td @@ -138,4 +138,7 @@ let TargetPrefix = "spv" in { def int_spv_resource_store_typedbuffer : DefaultAttrsIntrinsic<[], [llvm_any_ty, llvm_i32_ty, llvm_anyvector_ty]>; + // Memory aliasing intrinsics + def int_spv_assign_aliasing_decoration : Intrinsic<[], [llvm_any_ty, llvm_i32_ty, llvm_metadata_ty], [ImmArg>]>; + } diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp index ae99ef1630647..f17c8a8fac14b 100644 --- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp @@ -611,6 +611,9 @@ void SPIRVAsmPrinter::outputModuleSections() { outputModuleSection(SPIRV::MB_DebugNames); // 7c. Debug: all OpModuleProcessed instructions. outputModuleSection(SPIRV::MB_DebugModuleProcessed); + // xxx. SPV_INTEL_memory_access_aliasing instructions go before 8. + // "All annotation instructions" + outputModuleSection(SPIRV::MB_AliasingInsts); // 8. All annotation instructions (all decorations). outputAnnotations(*M); // 9. All type declarations (OpTypeXXX instructions), all constant diff --git a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp index b5a3b1953d5a6..3039f975a4df2 100644 --- a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp @@ -695,6 +695,20 @@ bool SPIRVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder, return false; MIB.addUse(Arg.Regs[0]); } + + if (ST->canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing)) { + // Process aliasing metadata. + const CallBase *CI = Info.CB; + if (CI && CI->hasMetadata()) { + if (MDNode *MD = CI->getMetadata(LLVMContext::MD_alias_scope)) + GR->buildMemAliasingOpDecorate(ResVReg, MIRBuilder, + SPIRV::Decoration::AliasScopeINTEL, MD); + if (MDNode *MD = CI->getMetadata(LLVMContext::MD_noalias)) + GR->buildMemAliasingOpDecorate(ResVReg, MIRBuilder, + SPIRV::Decoration::NoAliasINTEL, MD); + } + } + return MIB.constrainAllUses(MIRBuilder.getTII(), *ST->getRegisterInfo(), *ST->getRegBankInfo()); } diff --git a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp index 333e0131ac228..8d1714932c3c6 100644 --- a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp @@ -53,6 +53,8 @@ static const std::map> SPIRV::Extension::Extension::SPV_INTEL_subgroups}, {"SPV_INTEL_media_block_io", SPIRV::Extension::Extension::SPV_INTEL_media_block_io}, + {"SPV_INTEL_memory_access_aliasing", + SPIRV::Extension::Extension::SPV_INTEL_memory_access_aliasing}, {"SPV_INTEL_joint_matrix", SPIRV::Extension::Extension::SPV_INTEL_joint_matrix}, {"SPV_KHR_uniform_group_instructions", diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp index 3e032f5ed4ba4..751ea5ab2dc47 100644 --- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp @@ -151,6 +151,7 @@ class SPIRVEmitIntrinsics unsigned OperandToReplace, IRBuilder<> &B); void insertPtrCastOrAssignTypeInstr(Instruction *I, IRBuilder<> &B); + bool shouldTryToAddMemAliasingDecoration(Instruction *Inst); void insertSpirvDecorations(Instruction *I, IRBuilder<> &B); void processGlobalValue(GlobalVariable &GV, IRBuilder<> &B); void processParamTypes(Function *F, IRBuilder<> &B); @@ -1169,6 +1170,7 @@ void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old, llvm_unreachable("illegal aggregate intrinsic user"); } } + New->copyMetadata(*Old); Old->eraseFromParent(); } @@ -1752,6 +1754,7 @@ Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &I) { Intrinsic::spv_store, {I.getValueOperand()->getType(), PtrOp->getType()}, {I.getValueOperand(), PtrOp, B.getInt16(Flags), B.getInt8(I.getAlign().value())}); + NewI->copyMetadata(I); I.eraseFromParent(); return NewI; } @@ -1955,6 +1958,37 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I, } } +bool SPIRVEmitIntrinsics::shouldTryToAddMemAliasingDecoration( + Instruction *Inst) { + const SPIRVSubtarget *STI = TM->getSubtargetImpl(*Inst->getFunction()); + if (!STI->canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing)) + return false; + // Add aliasing decorations to internal load and store intrinsics + // and atomic instructions, skipping atomic store as it won't have ID to + // attach the decoration. + CallInst *CI = dyn_cast(Inst); + if (!CI) + return false; + if (Function *Fun = CI->getCalledFunction()) { + if (Fun->isIntrinsic()) { + switch (Fun->getIntrinsicID()) { + case Intrinsic::spv_load: + case Intrinsic::spv_store: + return true; + default: + return false; + } + } + std::string Name = getOclOrSpirvBuiltinDemangledName(Fun->getName()); + const std::string Prefix = "__spirv_Atomic"; + const bool IsAtomic = Name.find(Prefix) == 0; + + if (!Fun->getReturnType()->isVoidTy() && IsAtomic) + return true; + } + return false; +} + void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *I, IRBuilder<> &B) { if (MDNode *MD = I->getMetadata("spirv.Decorations")) { @@ -1962,6 +1996,26 @@ void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *I, B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()}, {I, MetadataAsValue::get(I->getContext(), MD)}); } + // Lower alias.scope/noalias metadata + { + auto processMemAliasingDecoration = [&](unsigned Kind) { + if (MDNode *AliasListMD = I->getMetadata(Kind)) { + if (shouldTryToAddMemAliasingDecoration(I)) { + uint32_t Dec = Kind == LLVMContext::MD_alias_scope + ? SPIRV::Decoration::AliasScopeINTEL + : SPIRV::Decoration::NoAliasINTEL; + SmallVector Args = { + I, ConstantInt::get(B.getInt32Ty(), Dec), + MetadataAsValue::get(I->getContext(), AliasListMD)}; + setInsertPointAfterDef(B, I); + B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration, + {I->getType()}, {Args}); + } + } + }; + processMemAliasingDecoration(LLVMContext::MD_alias_scope); + processMemAliasingDecoration(LLVMContext::MD_noalias); + } } void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I, diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp index e9b517d3eeaaa..24f9912e40be5 100644 --- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp @@ -1759,6 +1759,75 @@ LLT SPIRVGlobalRegistry::getRegType(SPIRVType *SpvType) const { return LLT::scalar(64); } +// Aliasing list MD contains several scope MD nodes whithin it. Each scope MD +// has a selfreference and an extra MD node for aliasing domain and also it +// can contain an optional string operand. Domain MD contains a self-reference +// with an optional string operand. Here we unfold the list, creating SPIR-V +// aliasing instructions. +// TODO: add support for an optional string operand. +MachineInstr *SPIRVGlobalRegistry::getOrAddMemAliasingINTELInst( + MachineIRBuilder &MIRBuilder, const MDNode *AliasingListMD) { + if (AliasingListMD->getNumOperands() == 0) + return nullptr; + if (auto L = AliasInstMDMap.find(AliasingListMD); L != AliasInstMDMap.end()) + return L->second; + + SmallVector ScopeList; + MachineRegisterInfo *MRI = MIRBuilder.getMRI(); + for (const MDOperand &MDListOp : AliasingListMD->operands()) { + if (MDNode *ScopeMD = dyn_cast(MDListOp)) { + if (ScopeMD->getNumOperands() < 2) + return nullptr; + MDNode *DomainMD = dyn_cast(ScopeMD->getOperand(1)); + if (!DomainMD) + return nullptr; + auto *Domain = [&] { + auto D = AliasInstMDMap.find(DomainMD); + if (D != AliasInstMDMap.end()) + return D->second; + const Register Ret = MRI->createVirtualRegister(&SPIRV::IDRegClass); + auto MIB = + MIRBuilder.buildInstr(SPIRV::OpAliasDomainDeclINTEL).addDef(Ret); + return MIB.getInstr(); + }(); + AliasInstMDMap.insert(std::make_pair(DomainMD, Domain)); + auto *Scope = [&] { + auto S = AliasInstMDMap.find(ScopeMD); + if (S != AliasInstMDMap.end()) + return S->second; + const Register Ret = MRI->createVirtualRegister(&SPIRV::IDRegClass); + auto MIB = MIRBuilder.buildInstr(SPIRV::OpAliasScopeDeclINTEL) + .addDef(Ret) + .addUse(Domain->getOperand(0).getReg()); + return MIB.getInstr(); + }(); + AliasInstMDMap.insert(std::make_pair(ScopeMD, Scope)); + ScopeList.push_back(Scope); + } + } + + const Register Ret = MRI->createVirtualRegister(&SPIRV::IDRegClass); + auto MIB = + MIRBuilder.buildInstr(SPIRV::OpAliasScopeListDeclINTEL).addDef(Ret); + for (auto *Scope : ScopeList) + MIB.addUse(Scope->getOperand(0).getReg()); + auto List = MIB.getInstr(); + AliasInstMDMap.insert(std::make_pair(AliasingListMD, List)); + return List; +} + +void SPIRVGlobalRegistry::buildMemAliasingOpDecorate( + Register Reg, MachineIRBuilder &MIRBuilder, uint32_t Dec, + const MDNode *AliasingListMD) { + MachineInstr *AliasList = + getOrAddMemAliasingINTELInst(MIRBuilder, AliasingListMD); + if (!AliasList) + return; + MIRBuilder.buildInstr(SPIRV::OpDecorate) + .addUse(Reg) + .addImm(Dec) + .addUse(AliasList->getOperand(0).getReg()); +} void SPIRVGlobalRegistry::replaceAllUsesWith(Value *Old, Value *New, bool DeleteOld) { Old->replaceAllUsesWith(New); diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h index 778232e7013d4..89599f17ef737 100644 --- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h +++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h @@ -92,6 +92,9 @@ class SPIRVGlobalRegistry { // Maps OpVariable and OpFunction-related v-regs to its LLVM IR definition. DenseMap, const Value *> Reg2GO; + // map of aliasing decorations to aliasing metadata + std::unordered_map AliasInstMDMap; + // Add a new OpTypeXXX instruction without checking for duplicates. SPIRVType *createSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder, SPIRV::AccessQualifier::AccessQualifier AQ, @@ -621,6 +624,10 @@ class SPIRVGlobalRegistry { const TargetRegisterClass *getRegClass(SPIRVType *SpvType) const; LLT getRegType(SPIRVType *SpvType) const; + MachineInstr *getOrAddMemAliasingINTELInst(MachineIRBuilder &MIRBuilder, + const MDNode *AliasingListMD); + void buildMemAliasingOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, + uint32_t Dec, const MDNode *GVarMD); // Replace all uses of a |Old| with |New| updates the global registry type // mappings. void replaceAllUsesWith(Value *Old, Value *New, bool DeleteOld = true); diff --git a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp index 98689de2b0d46..f9c44049fa78b 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp @@ -97,6 +97,17 @@ bool SPIRVInstrInfo::isDecorationInstr(const MachineInstr &MI) const { } } +bool SPIRVInstrInfo::isAliasingInstr(const MachineInstr &MI) const { + switch (MI.getOpcode()) { + case SPIRV::OpAliasDomainDeclINTEL: + case SPIRV::OpAliasScopeDeclINTEL: + case SPIRV::OpAliasScopeListDeclINTEL: + return true; + default: + return false; + } +} + bool SPIRVInstrInfo::isHeaderInstr(const MachineInstr &MI) const { switch (MI.getOpcode()) { case SPIRV::OpCapability: @@ -115,7 +126,8 @@ bool SPIRVInstrInfo::isHeaderInstr(const MachineInstr &MI) const { case SPIRV::OpModuleProcessed: return true; default: - return isTypeDeclInstr(MI) || isConstantInstr(MI) || isDecorationInstr(MI); + return isTypeDeclInstr(MI) || isConstantInstr(MI) || + isDecorationInstr(MI) || isAliasingInstr(MI); } } diff --git a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.h b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.h index 577e7f6ae9ffb..1f0307680fa9a 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.h +++ b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.h @@ -34,6 +34,7 @@ class SPIRVInstrInfo : public SPIRVGenInstrInfo { bool isInlineAsmDefInstr(const MachineInstr &MI) const; bool isTypeDeclInstr(const MachineInstr &MI) const; bool isDecorationInstr(const MachineInstr &MI) const; + bool isAliasingInstr(const MachineInstr &MI) const; bool canUseFastMathFlags(const MachineInstr &MI) const; bool canUseNSW(const MachineInstr &MI) const; bool canUseNUW(const MachineInstr &MI) const; diff --git a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td index 5e9a9bd145bca..a8f862271dbab 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td +++ b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td @@ -948,3 +948,11 @@ def OpConvertHandleToSamplerINTEL: Op<6530, (outs ID:$res), (ins TYPE:$type, ID: "$res = OpConvertHandleToSamplerINTEL $type $operand">; def OpConvertHandleToSampledImageINTEL: Op<6531, (outs ID:$res), (ins TYPE:$type, ID:$operand), "$res = OpConvertHandleToSampledImageINTEL $type $operand">; + +// SPV_INTEL_memory_access_aliasing +def OpAliasDomainDeclINTEL: Op<5911, (outs ID:$res), (ins variable_ops), + "$res = OpAliasDomainDeclINTEL">; +def OpAliasScopeDeclINTEL: Op<5912, (outs ID:$res), (ins ID:$AliasDomain, variable_ops), + "$res = OpAliasScopeDeclINTEL $AliasDomain">; +def OpAliasScopeListDeclINTEL: Op<5913, (outs ID:$res), (ins variable_ops), + "$res = OpAliasScopeListDeclINTEL">; diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp index c52b67e72a88c..b188f36ca9a9e 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -1026,7 +1026,9 @@ bool SPIRVInstructionSelector::selectBitcast(Register ResVReg, } static void addMemoryOperands(MachineMemOperand *MemOp, - MachineInstrBuilder &MIB) { + MachineInstrBuilder &MIB, + MachineIRBuilder &MIRBuilder, + SPIRVGlobalRegistry &GR) { uint32_t SpvMemOp = static_cast(SPIRV::MemoryOperand::None); if (MemOp->isVolatile()) SpvMemOp |= static_cast(SPIRV::MemoryOperand::Volatile); @@ -1035,10 +1037,33 @@ static void addMemoryOperands(MachineMemOperand *MemOp, if (MemOp->getAlign().value()) SpvMemOp |= static_cast(SPIRV::MemoryOperand::Aligned); + [[maybe_unused]] MachineInstr *AliasList = nullptr; + [[maybe_unused]] MachineInstr *NoAliasList = nullptr; + const SPIRVSubtarget *ST = + static_cast(&MIRBuilder.getMF().getSubtarget()); + if (ST->canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing)) { + if (auto *MD = MemOp->getAAInfo().Scope) { + AliasList = GR.getOrAddMemAliasingINTELInst(MIRBuilder, MD); + if (AliasList) + SpvMemOp |= + static_cast(SPIRV::MemoryOperand::AliasScopeINTELMask); + } + if (auto *MD = MemOp->getAAInfo().NoAlias) { + NoAliasList = GR.getOrAddMemAliasingINTELInst(MIRBuilder, MD); + if (NoAliasList) + SpvMemOp |= + static_cast(SPIRV::MemoryOperand::NoAliasINTELMask); + } + } + if (SpvMemOp != static_cast(SPIRV::MemoryOperand::None)) { MIB.addImm(SpvMemOp); if (SpvMemOp & static_cast(SPIRV::MemoryOperand::Aligned)) MIB.addImm(MemOp->getAlign().value()); + if (AliasList) + MIB.addUse(AliasList->getOperand(0).getReg()); + if (NoAliasList) + MIB.addUse(NoAliasList->getOperand(0).getReg()); } } @@ -1087,7 +1112,8 @@ bool SPIRVInstructionSelector::selectLoad(Register ResVReg, TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS); addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB); } else { - addMemoryOperands(*I.memoperands_begin(), MIB); + MachineIRBuilder MIRBuilder(I); + addMemoryOperands(*I.memoperands_begin(), MIB, MIRBuilder, GR); } return MIB.constrainAllUses(TII, TRI, RBI); } @@ -1129,7 +1155,8 @@ bool SPIRVInstructionSelector::selectStore(MachineInstr &I) const { TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS); addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB); } else { - addMemoryOperands(*I.memoperands_begin(), MIB); + MachineIRBuilder MIRBuilder(I); + addMemoryOperands(*I.memoperands_begin(), MIB, MIRBuilder, GR); } return MIB.constrainAllUses(TII, TRI, RBI); } @@ -1206,8 +1233,10 @@ bool SPIRVInstructionSelector::selectMemOperation(Register ResVReg, .addUse(I.getOperand(0).getReg()) .addUse(SrcReg) .addUse(I.getOperand(2).getReg()); - if (I.getNumMemOperands()) - addMemoryOperands(*I.memoperands_begin(), MIB); + if (I.getNumMemOperands()) { + MachineIRBuilder MIRBuilder(I); + addMemoryOperands(*I.memoperands_begin(), MIB, MIRBuilder, GR); + } Result &= MIB.constrainAllUses(TII, TRI, RBI); if (ResVReg.isValid() && ResVReg != MIB->getOperand(0).getReg()) Result &= BuildCOPY(ResVReg, MIB->getOperand(0).getReg(), I); diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp index 32f817866d421..e0b348f0bba10 100644 --- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp @@ -566,6 +566,8 @@ void SPIRVModuleAnalysis::processOtherInstrs(const Module &M) { collectOtherInstr(MI, MAI, SPIRV::MB_DebugNames, IS); } else if (OpCode == SPIRV::OpEntryPoint) { collectOtherInstr(MI, MAI, SPIRV::MB_EntryPoints, IS); + } else if (TII->isAliasingInstr(MI)) { + collectOtherInstr(MI, MAI, SPIRV::MB_AliasingInsts, IS); } else if (TII->isDecorationInstr(MI)) { collectOtherInstr(MI, MAI, SPIRV::MB_Annotations, IS); collectFuncNames(MI, &*F); @@ -1251,6 +1253,13 @@ void addInstrRequirements(const MachineInstr &MI, } break; } + case SPIRV::OpAliasDomainDeclINTEL: + case SPIRV::OpAliasScopeDeclINTEL: + case SPIRV::OpAliasScopeListDeclINTEL: { + Reqs.addExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing); + Reqs.addCapability(SPIRV::Capability::MemoryAccessAliasingINTEL); + break; + } case SPIRV::OpBitReverse: case SPIRV::OpBitFieldInsert: case SPIRV::OpBitFieldSExtract: diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h index 35b8c9b386860..fd83a3e62e1f1 100644 --- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h +++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h @@ -35,6 +35,7 @@ enum ModuleSectionType { MB_DebugNames, // All OpName and OpMemberName intrs. MB_DebugStrings, // All OpString intrs. MB_DebugModuleProcessed, // All OpModuleProcessed instructions. + MB_AliasingInsts, // SPV_INTEL_memory_access_aliasing instructions. MB_Annotations, // OpDecorate, OpMemberDecorate etc. MB_TypeConstVars, // OpTypeXXX, OpConstantXXX, and global OpVariables. MB_NonSemanticGlobalDI, // OpExtInst with e.g. DebugSource, DebugTypeBasic. diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp index 5d70b9c2a4a59..baacd58b28028 100644 --- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp @@ -819,15 +819,24 @@ static void insertInlineAsm(MachineFunction &MF, SPIRVGlobalRegistry *GR, insertInlineAsmProcess(MF, GR, ST, MIRBuilder, ToProcess); } -static void insertSpirvDecorations(MachineFunction &MF, MachineIRBuilder MIB) { +static void insertSpirvDecorations(MachineFunction &MF, SPIRVGlobalRegistry *GR, + MachineIRBuilder MIB) { SmallVector ToErase; for (MachineBasicBlock &MBB : MF) { for (MachineInstr &MI : MBB) { - if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration)) + if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration) && + !isSpvIntrinsic(MI, Intrinsic::spv_assign_aliasing_decoration)) continue; MIB.setInsertPt(*MI.getParent(), MI.getNextNode()); - buildOpSpirvDecorations(MI.getOperand(1).getReg(), MIB, - MI.getOperand(2).getMetadata()); + if (isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration)) { + buildOpSpirvDecorations(MI.getOperand(1).getReg(), MIB, + MI.getOperand(2).getMetadata()); + } else { + GR->buildMemAliasingOpDecorate(MI.getOperand(1).getReg(), MIB, + MI.getOperand(2).getImm(), + MI.getOperand(3).getMetadata()); + } + ToErase.push_back(&MI); } } @@ -1043,7 +1052,7 @@ bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) { processInstrsWithTypeFolding(MF, GR, MIB); removeImplicitFallthroughs(MF, MIB); - insertSpirvDecorations(MF, MIB); + insertSpirvDecorations(MF, GR, MIB); insertInlineAsm(MF, GR, ST, MIB); selectOpBitcasts(MF, GR, MIB); diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td index c7cb0a50752fe..a871518e2094c 100644 --- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td +++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td @@ -311,6 +311,7 @@ defm SPV_INTEL_joint_matrix : ExtensionOperand<114>; defm SPV_INTEL_float_controls2 : ExtensionOperand<115>; defm SPV_INTEL_bindless_images : ExtensionOperand<116>; defm SPV_INTEL_long_composites : ExtensionOperand<117>; +defm SPV_INTEL_memory_access_aliasing : ExtensionOperand<118>; //===----------------------------------------------------------------------===// // Multiclass used to define Capabilities enum values and at the same time @@ -509,6 +510,7 @@ defm FloatingPointModeINTEL : CapabilityOperand<5583, 0, 0, [SPV_INTEL_float_con defm FunctionFloatControlINTEL : CapabilityOperand<5821, 0, 0, [SPV_INTEL_float_controls2], []>; defm LongCompositesINTEL : CapabilityOperand<6089, 0, 0, [SPV_INTEL_long_composites], []>; defm BindlessImagesINTEL : CapabilityOperand<6528, 0, 0, [SPV_INTEL_bindless_images], []>; +defm MemoryAccessAliasingINTEL : CapabilityOperand<5910, 0, 0, [SPV_INTEL_memory_access_aliasing], []>; //===----------------------------------------------------------------------===// // Multiclass used to define SourceLanguage enum values and at the same time @@ -1257,6 +1259,8 @@ defm ImplementInRegisterMapINTEL : DecorationOperand<6191, 0, 0, [], [GlobalVari defm FunctionRoundingModeINTEL : DecorationOperand<5822, 0, 0, [], [FunctionFloatControlINTEL]>; defm FunctionDenormModeINTEL : DecorationOperand<5823, 0, 0, [], [FunctionFloatControlINTEL]>; defm FunctionFloatingPointModeINTEL : DecorationOperand<6080, 0, 0, [], [FunctionFloatControlINTEL]>; +defm AliasScopeINTEL : DecorationOperand<5914, 0, 0, [], [MemoryAccessAliasingINTEL]>; +defm NoAliasINTEL : DecorationOperand<5915, 0, 0, [], [MemoryAccessAliasingINTEL]>; //===----------------------------------------------------------------------===// // Multiclass used to define BuiltIn enum values and at the same time @@ -1529,6 +1533,8 @@ defm Nontemporal : MemoryOperandOperand<0x4, 0, 0, [], []>; defm MakePointerAvailableKHR : MemoryOperandOperand<0x8, 0, 0, [], [VulkanMemoryModelKHR]>; defm MakePointerVisibleKHR : MemoryOperandOperand<0x10, 0, 0, [], [VulkanMemoryModelKHR]>; defm NonPrivatePointerKHR : MemoryOperandOperand<0x20, 0, 0, [], [VulkanMemoryModelKHR]>; +defm AliasScopeINTELMask : MemoryOperandOperand<0x10000, 0, 0, [], [MemoryAccessAliasingINTEL]>; +defm NoAliasINTELMask : MemoryOperandOperand<0x20000, 0, 0, [], [MemoryAccessAliasingINTEL]>; //===----------------------------------------------------------------------===// // Multiclass used to define Scope enum values and at the same time diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-barrier.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-barrier.ll new file mode 100644 index 0000000000000..51649288b7c62 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-barrier.ll @@ -0,0 +1,18 @@ +; The test checks if the backend won't crash + +; RUN: llc -O0 -mtriple=spirv64-unknown-unknown -verify-machineinstrs --spirv-ext=+SPV_INTEL_memory_access_aliasing %s -o - | FileCheck %s + +; CHECK: OpControlBarrier +; CHECK-NOT: MemoryAccessAliasingINTEL + +define spir_kernel void @barrier_simple() +{ + tail call spir_func void @_Z22__spirv_ControlBarrierjjj(i32 2, i32 2, i32 272), !noalias !1 + ret void +} + +declare dso_local spir_func void @_Z22__spirv_ControlBarrierjjj(i32, i32, i32) + +!1 = !{!2} +!2 = distinct !{!2, !3} +!3 = distinct !{!3} diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-empty-md.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-empty-md.ll new file mode 100644 index 0000000000000..d275d6c0ea77b --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-empty-md.ll @@ -0,0 +1,26 @@ +; Check that the backend doesn't fail on a translation of empty aliasing +; metadata + +; Check aliasing information translation on load and store + +; RUN: llc -O0 -mtriple=spirv64-unknown-unknown -verify-machineinstrs --spirv-ext=+SPV_INTEL_memory_access_aliasing %s -o - | FileCheck %s + +; CHECK-NOT: MemoryAccessAliasingINTEL +; CHECK-NOT: SPV_INTEL_memory_access_aliasing +; CHECK-NOT: OpAliasDomainDeclINTEL +; CHECK-NOT: OpAliasScopeDeclINTEL +; CHECK-NOT: OpAliasScopeListDeclINTEL + +define dso_local spir_kernel void @foo(ptr addrspace(1) noalias %_arg_, ptr addrspace(1) noalias %_arg_1, ptr addrspace(1) noalias %_arg_3) local_unnamed_addr { +entry: + %0 = addrspacecast ptr addrspace(1) %_arg_ to ptr addrspace(4) + %1 = addrspacecast ptr addrspace(1) %_arg_1 to ptr addrspace(4) + %2 = addrspacecast ptr addrspace(1) %_arg_3 to ptr addrspace(4) + %3 = load i32, ptr addrspace(4) %0, align 4, !alias.scope !1 + %4 = load i32, ptr addrspace(4) %1, align 4, !alias.scope !1 + %add.i = add nsw i32 %4, %3 + store i32 %add.i, ptr addrspace(4) %2, align 4, !noalias !1 + ret void +} + +!1 = !{} diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-load-store-atomic.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-load-store-atomic.ll new file mode 100644 index 0000000000000..e8f55dce97a07 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-load-store-atomic.ll @@ -0,0 +1,34 @@ +; Check aliasing information translation on atomic load and store + +; RUN: llc -O0 -mtriple=spirv64-unknown-unknown -verify-machineinstrs --spirv-ext=+SPV_INTEL_memory_access_aliasing %s -o - | FileCheck %s + +; CHECK: OpCapability MemoryAccessAliasingINTEL +; CHECK: OpExtension "SPV_INTEL_memory_access_aliasing" +; CHECK: %[[#Domain1:]] = OpAliasDomainDeclINTEL +; CHECK: %[[#Scope1:]] = OpAliasScopeDeclINTEL %[[#Domain1]] +; CHECK: %[[#List1:]] = OpAliasScopeListDeclINTEL %[[#Scope1]] +; CHECK: OpDecorate %[[#Load:]] NoAliasINTEL %[[#List1]] +; CHECK: %[[#Load:]] = OpAtomicLoad + +define spir_func i32 @test_load(ptr addrspace(4) %object) #0 { +entry: + %0 = call spir_func i32 @_Z18__spirv_AtomicLoadPU3AS4iii(ptr addrspace(4) %object, i32 1, i32 16), !noalias !1 + ret i32 %0 +} + +declare spir_func i32 @_Z18__spirv_AtomicLoadPU3AS4iii(ptr addrspace(4), i32, i32) + +define spir_func void @test_store(ptr addrspace(4) %object, ptr addrspace(4) %expected, i32 %desired) { +entry: + call spir_func void @_Z19__spirv_AtomicStorePU3AS4iiii(ptr addrspace(4) %object, i32 1, i32 16, i32 %desired), !noalias !4 + ret void +} + +declare spir_func void @_Z19__spirv_AtomicStorePU3AS4iiii(ptr addrspace(4), i32, i32, i32) + +!1 = !{!2} +!2 = distinct !{!2, !3} +!3 = distinct !{!3} +!4 = !{!5} +!5 = distinct !{!5, !6} +!6 = distinct !{!6} diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-load-store-struct.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-load-store-struct.ll new file mode 100644 index 0000000000000..e37793bafb821 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-load-store-struct.ll @@ -0,0 +1,25 @@ +; Test if alias scope metadata translates well for a load/store with structure object +; type (special case as such lowering uses spv_load/store intrinsics) + +; RUN: llc -O0 -mtriple=spirv64-unknown-unknown -verify-machineinstrs --spirv-ext=+SPV_INTEL_memory_access_aliasing %s -o - | FileCheck %s + +; CHECK: OpCapability MemoryAccessAliasingINTEL +; CHECK: OpExtension "SPV_INTEL_memory_access_aliasing" +; CHECK: %[[#Domain:]] = OpAliasDomainDeclINTEL +; CHECK: %[[#Scope:]] = OpAliasScopeDeclINTEL %[[#Domain]] +; CHECK: %[[#List:]] = OpAliasScopeListDeclINTEL %[[#Scope]] +; CHECK: %[[#]] = OpLoad %[[#]] %[[#]] Aligned|AliasScopeINTELMask 4 %[[#List]] +; CHECK: OpStore %[[#]] %[[#]] Aligned|NoAliasINTELMask 4 %[[#List]] + +define dso_local spir_kernel void @foo(ptr addrspace(1) noalias %_arg_, ptr addrspace(1) noalias %_arg_1) { +entry: + %0 = addrspacecast ptr addrspace(1) %_arg_ to ptr addrspace(4) + %1 = addrspacecast ptr addrspace(1) %_arg_1 to ptr addrspace(4) + %2 = load {i32, i32}, ptr addrspace(4) %0, align 4, !alias.scope !1 + store {i32, i32} %2, ptr addrspace(4) %1, align 4, !noalias !1 + ret void +} + +!1 = !{!2} +!2 = distinct !{!2, !3, !"foo: %this"} +!3 = distinct !{!3, !"foo"} diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-load-store.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-load-store.ll new file mode 100644 index 0000000000000..7487deb7f69f1 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-load-store.ll @@ -0,0 +1,65 @@ +; Check aliasing information translation on load and store + +; RUN: llc -O0 -mtriple=spirv64-unknown-unknown -verify-machineinstrs --spirv-ext=+SPV_INTEL_memory_access_aliasing %s -o - | FileCheck %s --check-prefix=CHECK-EXT +; RUN: llc -O0 -mtriple=spirv64-unknown-unknown -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK-NO-EXT + +; CHECK-EXT: OpCapability MemoryAccessAliasingINTEL +; CHECK-EXT: OpExtension "SPV_INTEL_memory_access_aliasing" +; CHECK-EXT: %[[#Domain1:]] = OpAliasDomainDeclINTEL +; CHECK-EXT: %[[#Scope1:]] = OpAliasScopeDeclINTEL %[[#Domain1]] +; CHECK-EXT: %[[#List1:]] = OpAliasScopeListDeclINTEL %[[#Scope1]] +; CHECK-EXT: %[[#Domain2:]] = OpAliasDomainDeclINTEL +; CHECK-EXT: %[[#Scope2:]] = OpAliasScopeDeclINTEL %[[#Domain2]] +; CHECK-EXT: %[[#List2:]] = OpAliasScopeListDeclINTEL %[[#Scope2]] +; CHECK-EXT: %[[#Domain3:]] = OpAliasDomainDeclINTEL +; CHECK-EXT: %[[#Scope2:]] = OpAliasScopeDeclINTEL %[[#Domain3]] +; CHECK-EXT: %[[#List3:]] = OpAliasScopeListDeclINTEL %[[#Scope2]] + +; CHECK-EXT: %[[#]] = OpLoad %[[#]] %[[#]] Aligned|AliasScopeINTELMask 4 %[[#List2]] +; CHECK-EXT: %[[#]] = OpLoad %[[#]] %[[#]] Aligned|AliasScopeINTELMask|NoAliasINTELMask 4 %[[#List2]] %[[#List1]] +; CHECK-EXT: OpStore %[[#]] %[[#]] Aligned|NoAliasINTELMask 4 %[[#List2]] + +; CHECK-EXT: %[[#]] = OpLoad %[[#]] %[[#]] Aligned|AliasScopeINTELMask 4 %[[#List3]] +; CHECK-EXT: %[[#]] = OpLoad %[[#]] %[[#]] Aligned|AliasScopeINTELMask 4 %[[#List3]] +; CHECK-EXT: OpStore %[[#]] %[[#]] Aligned|NoAliasINTELMask 4 %[[#List3]] + +; CHECK-NO-EXT-NOT: MemoryAccessAliasingINTEL +; CHECK-NO-EXT-NOT: SPV_INTEL_memory_access_aliasing +; CHECK-NO-EXT-NOT: OpAliasDomainDeclINTEL +; CHECK-NO-EXT-NOT: OpAliasScopeDeclINTEL +; CHECK-NO-EXT-NOT: OpAliasScopeListDeclINTEL + +define dso_local spir_kernel void @foo(ptr addrspace(1) noalias %_arg_, ptr addrspace(1) noalias %_arg_1, ptr addrspace(1) noalias %_arg_3) { +entry: + %0 = addrspacecast ptr addrspace(1) %_arg_ to ptr addrspace(4) + %1 = addrspacecast ptr addrspace(1) %_arg_1 to ptr addrspace(4) + %2 = addrspacecast ptr addrspace(1) %_arg_3 to ptr addrspace(4) + %3 = load i32, ptr addrspace(4) %0, align 4, !alias.scope !1 + %4 = load i32, ptr addrspace(4) %1, align 4, !alias.scope !1, !noalias !7 + %add.i = add nsw i32 %4, %3 + store i32 %add.i, ptr addrspace(4) %2, align 4, !noalias !1 + ret void +} + +define dso_local spir_kernel void @boo(ptr addrspace(1) noalias %_arg_, ptr addrspace(1) noalias %_arg_1, ptr addrspace(1) noalias %_arg_3, i32 %_arg_5) { +entry: + %0 = addrspacecast ptr addrspace(1) %_arg_ to ptr addrspace(4) + %1 = addrspacecast ptr addrspace(1) %_arg_1 to ptr addrspace(4) + %2 = addrspacecast ptr addrspace(1) %_arg_3 to ptr addrspace(4) + %3 = load i32, ptr addrspace(4) %0, align 4, !alias.scope !4 + %4 = load i32, ptr addrspace(4) %1, align 4, !alias.scope !4 + %add.i = add i32 %3, %_arg_5 + %add3.i = add i32 %add.i, %4 + store i32 %add3.i, ptr addrspace(4) %2, align 4, !noalias !4 + ret void +} + +!1 = !{!2} +!2 = distinct !{!2, !3, !"foo: %this"} +!3 = distinct !{!3, !"foo"} +!4 = !{!5} +!5 = distinct !{!5, !6, !"boo: %this"} +!6 = distinct !{!6, !"boo"} +!7 = !{!8} +!8 = distinct !{!8, !9, !"foo: %this"} +!9 = distinct !{!9, !"foo"} diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-masked-load-store.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-masked-load-store.ll new file mode 100644 index 0000000000000..dd0987fdfe75d --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-masked-load-store.ll @@ -0,0 +1,83 @@ +; Check aliasing information translation on function calls + +; RUN: llc -O0 -mtriple=spirv64-unknown-unknown -verify-machineinstrs --spirv-ext=+SPV_INTEL_memory_access_aliasing %s -o - | FileCheck %s --check-prefix=CHECK-EXT +; RUN: llc -O0 -mtriple=spirv64-unknown-unknown -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK-NO-EXT + +; CHECK-EXT: OpCapability MemoryAccessAliasingINTEL +; CHECK-EXT: OpExtension "SPV_INTEL_memory_access_aliasing" +; CHECK-EXT: %[[#Domain1:]] = OpAliasDomainDeclINTEL +; CHECK-EXT: %[[#Scope1:]] = OpAliasScopeDeclINTEL %[[#Domain1]] +; CHECK-EXT: %[[#List1:]] = OpAliasScopeListDeclINTEL %[[#Scope1]] +; CHECK-EXT: %[[#Domain2:]] = OpAliasDomainDeclINTEL +; CHECK-EXT: %[[#Scope2:]] = OpAliasScopeDeclINTEL %[[#Domain2]] +; CHECK-EXT: %[[#List2:]] = OpAliasScopeListDeclINTEL %[[#Scope2]] +; CHECK-EXT: %[[#Domain3:]] = OpAliasDomainDeclINTEL +; CHECK-EXT: %[[#Scope2:]] = OpAliasScopeDeclINTEL %[[#Domain3]] +; CHECK-EXT: %[[#List3:]] = OpAliasScopeListDeclINTEL %[[#Scope2]] +; CHECK-EXT: OpDecorate %[[#Fun1:]] AliasScopeINTEL %[[#List1]] +; CHECK-EXT: OpDecorate %[[#Fun2:]] AliasScopeINTEL %[[#List1]] +; CHECK-EXT: OpDecorate %[[#Fun2]] NoAliasINTEL %[[#List2]] +; CHECK-EXT: OpDecorate %[[#Fun3:]] NoAliasINTEL %[[#List1]] +; CHECK-EXT: OpDecorate %[[#Fun4:]] AliasScopeINTEL %[[#List3]] +; CHECK-EXT: OpDecorate %[[#Fun5:]] AliasScopeINTEL %[[#List3]] +; CHECK-EXT: OpDecorate %[[#Fun6:]] NoAliasINTEL %[[#List3]] +; CHECK-EXT: %[[#Fun1]] = OpFunctionCall +; CHECK-EXT: %[[#Fun2]] = OpFunctionCall +; CHECK-EXT: %[[#Fun3]] = OpFunctionCall +; CHECK-EXT: %[[#Fun4]] = OpFunctionCall +; CHECK-EXT: %[[#Fun5]] = OpFunctionCall +; CHECK-EXT: %[[#Fun6]] = OpFunctionCall + +; CHECK-NO-EXT-NOT: MemoryAccessAliasingINTEL +; CHECK-NO-EXT-NOT: SPV_INTEL_memory_access_aliasing +; CHECK-NO-EXT-NOT: OpAliasDomainDeclINTEL +; CHECK-NO-EXT-NOT: OpAliasScopeDeclINTEL +; CHECK-NO-EXT-NOT: OpAliasScopeListDeclINTEL + +define dso_local spir_kernel void @foo(ptr addrspace(1) noalias %_arg_, ptr addrspace(1) noalias %_arg_1, ptr addrspace(1) noalias %_arg_3) { +entry: + %0 = addrspacecast ptr addrspace(1) %_arg_ to ptr addrspace(4) + %1 = addrspacecast ptr addrspace(1) %_arg_1 to ptr addrspace(4) + %2 = addrspacecast ptr addrspace(1) %_arg_3 to ptr addrspace(4) + %3 = call i32 @wrappedload(ptr addrspace(4) %0), !alias.scope !1 + %4 = call i32 @wrappedload(ptr addrspace(4) %1), !alias.scope !1, !noalias !7 + %add.i = add nsw i32 %4, %3 + call void @wrappedstore(i32 %add.i, ptr addrspace(4) %2), !noalias !1 + ret void +} + +define dso_local spir_kernel void @boo(ptr addrspace(1) noalias %_arg_, ptr addrspace(1) noalias %_arg_1, ptr addrspace(1) noalias %_arg_3, i32 %_arg_5) { +entry: + %0 = addrspacecast ptr addrspace(1) %_arg_ to ptr addrspace(4) + %1 = addrspacecast ptr addrspace(1) %_arg_1 to ptr addrspace(4) + %2 = addrspacecast ptr addrspace(1) %_arg_3 to ptr addrspace(4) + %3 = call i32 @wrappedload(ptr addrspace(4) %0), !alias.scope !4 + %4 = call i32 @wrappedload(ptr addrspace(4) %1), !alias.scope !4 + %add.i = add i32 %3, %_arg_5 + %add3.i = add i32 %add.i, %4 + call void @wrappedstore(i32 %add3.i, ptr addrspace(4) %2), !noalias !4 + ret void +} + +define dso_local spir_func i32 @wrappedload(ptr addrspace(4) %0) { +entry: + %1 = load i32, ptr addrspace(4) %0, align 4 + ret i32 %1 +} + +; Function Attrs: norecurse nounwind readnone +define dso_local spir_func void @wrappedstore(i32 %0, ptr addrspace(4) %1) { +entry: + store i32 %0, ptr addrspace(4) %1, align 4 + ret void +} + +!1 = !{!2} +!2 = distinct !{!2, !3, !"foo: %this"} +!3 = distinct !{!3, !"foo"} +!4 = !{!5} +!5 = distinct !{!5, !6, !"boo: %this"} +!6 = distinct !{!6, !"boo"} +!7 = !{!8} +!8 = distinct !{!8, !9, !"foo: %this"} +!9 = distinct !{!9, !"foo"}