diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp index 2611a9491c412..f4bfda4932b16 100644 --- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp @@ -1633,8 +1633,14 @@ static bool generateICarryBorrowInst(const SPIRV::IncomingCall *Call, } MachineRegisterInfo *MRI = MIRBuilder.getMRI(); - Register ResReg = MRI->createGenericVirtualRegister(LLT::scalar(64)); - MRI->setRegClass(ResReg, &SPIRV::iIDRegClass); + Register ResReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass); + if (const TargetRegisterClass *DstRC = + MRI->getRegClassOrNull(Call->Arguments[1])) { + MRI->setRegClass(ResReg, DstRC); + MRI->setType(ResReg, MRI->getType(Call->Arguments[1])); + } else { + MRI->setType(ResReg, LLT::scalar(64)); + } GR->assignSPIRVTypeToVReg(RetType, ResReg, MIRBuilder.getMF()); MIRBuilder.buildInstr(Opcode) .addDef(ResReg) diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp index fabedb5e06c1d..5f72a41ddb864 100644 --- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp @@ -96,7 +96,6 @@ inline Register createTypeVReg(MachineIRBuilder &MIRBuilder) { } SPIRVType *SPIRVGlobalRegistry::getOpTypeBool(MachineIRBuilder &MIRBuilder) { - return createOpType(MIRBuilder, [&](MachineIRBuilder &MIRBuilder) { return MIRBuilder.buildInstr(SPIRV::OpTypeBool) .addDef(createTypeVReg(MIRBuilder)); @@ -166,8 +165,11 @@ SPIRVType *SPIRVGlobalRegistry::createOpType( auto LastInsertedType = LastInsertedTypeMap.find(CurMF); if (LastInsertedType != LastInsertedTypeMap.end()) { - MIRBuilder.setInsertPt(*MIRBuilder.getMF().begin(), - LastInsertedType->second->getIterator()); + auto It = LastInsertedType->second->getIterator(); + auto NewMBB = MIRBuilder.getMF().begin(); + MIRBuilder.setInsertPt(*NewMBB, It->getNextNode() + ? It->getNextNode()->getIterator() + : NewMBB->end()); } else { MIRBuilder.setInsertPt(*MIRBuilder.getMF().begin(), MIRBuilder.getMF().begin()->begin()); @@ -269,24 +271,27 @@ Register SPIRVGlobalRegistry::getOrCreateConstFP(APFloat Val, MachineInstr &I, // machine instruction, a new constant instruction should be created. if (!New && (!I.getOperand(0).isReg() || Res != I.getOperand(0).getReg())) return Res; - MachineInstrBuilder MIB; - MachineBasicBlock &BB = *I.getParent(); - // In OpenCL OpConstantNull - Scalar floating point: +0.0 (all bits 0) - if (Val.isPosZero() && ZeroAsNull) { - MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull)) - .addDef(Res) - .addUse(getSPIRVTypeID(SpvType)); - } else { - MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantF)) - .addDef(Res) - .addUse(getSPIRVTypeID(SpvType)); - addNumImm( - APInt(BitWidth, CI->getValueAPF().bitcastToAPInt().getZExtValue()), - MIB); - } - const auto &ST = CurMF->getSubtarget(); - constrainSelectedInstRegOperands(*MIB, *ST.getInstrInfo(), - *ST.getRegisterInfo(), *ST.getRegBankInfo()); + MachineIRBuilder MIRBuilder(I); + createOpType(MIRBuilder, [&](MachineIRBuilder &MIRBuilder) { + MachineInstrBuilder MIB; + // In OpenCL OpConstantNull - Scalar floating point: +0.0 (all bits 0) + if (Val.isPosZero() && ZeroAsNull) { + MIB = MIRBuilder.buildInstr(SPIRV::OpConstantNull) + .addDef(Res) + .addUse(getSPIRVTypeID(SpvType)); + } else { + MIB = MIRBuilder.buildInstr(SPIRV::OpConstantF) + .addDef(Res) + .addUse(getSPIRVTypeID(SpvType)); + addNumImm( + APInt(BitWidth, CI->getValueAPF().bitcastToAPInt().getZExtValue()), + MIB); + } + const auto &ST = CurMF->getSubtarget(); + constrainSelectedInstRegOperands( + *MIB, *ST.getInstrInfo(), *ST.getRegisterInfo(), *ST.getRegBankInfo()); + return MIB; + }); return Res; } @@ -305,21 +310,25 @@ Register SPIRVGlobalRegistry::getOrCreateConstInt(uint64_t Val, MachineInstr &I, // machine instruction, a new constant instruction should be created. if (!New && (!I.getOperand(0).isReg() || Res != I.getOperand(0).getReg())) return Res; - MachineInstrBuilder MIB; - MachineBasicBlock &BB = *I.getParent(); - if (Val || !ZeroAsNull) { - MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI)) - .addDef(Res) - .addUse(getSPIRVTypeID(SpvType)); - addNumImm(APInt(BitWidth, Val), MIB); - } else { - MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull)) - .addDef(Res) - .addUse(getSPIRVTypeID(SpvType)); - } - const auto &ST = CurMF->getSubtarget(); - constrainSelectedInstRegOperands(*MIB, *ST.getInstrInfo(), - *ST.getRegisterInfo(), *ST.getRegBankInfo()); + + MachineIRBuilder MIRBuilder(I); + createOpType(MIRBuilder, [&](MachineIRBuilder &MIRBuilder) { + MachineInstrBuilder MIB; + if (Val || !ZeroAsNull) { + MIB = MIRBuilder.buildInstr(SPIRV::OpConstantI) + .addDef(Res) + .addUse(getSPIRVTypeID(SpvType)); + addNumImm(APInt(BitWidth, Val), MIB); + } else { + MIB = MIRBuilder.buildInstr(SPIRV::OpConstantNull) + .addDef(Res) + .addUse(getSPIRVTypeID(SpvType)); + } + const auto &ST = CurMF->getSubtarget(); + constrainSelectedInstRegOperands( + *MIB, *ST.getInstrInfo(), *ST.getRegisterInfo(), *ST.getRegBankInfo()); + return MIB; + }); return Res; } @@ -347,21 +356,24 @@ Register SPIRVGlobalRegistry::buildConstantInt(uint64_t Val, MIRBuilder.buildConstant(Res, *ConstInt); } else { Register SpvTypeReg = getSPIRVTypeID(SpvType); - MachineInstrBuilder MIB; - if (Val || !ZeroAsNull) { - MIB = MIRBuilder.buildInstr(SPIRV::OpConstantI) - .addDef(Res) - .addUse(SpvTypeReg); - addNumImm(APInt(BitWidth, Val), MIB); - } else { - MIB = MIRBuilder.buildInstr(SPIRV::OpConstantNull) - .addDef(Res) - .addUse(SpvTypeReg); - } - const auto &Subtarget = CurMF->getSubtarget(); - constrainSelectedInstRegOperands(*MIB, *Subtarget.getInstrInfo(), - *Subtarget.getRegisterInfo(), - *Subtarget.getRegBankInfo()); + createOpType(MIRBuilder, [&](MachineIRBuilder &MIRBuilder) { + MachineInstrBuilder MIB; + if (Val || !ZeroAsNull) { + MIB = MIRBuilder.buildInstr(SPIRV::OpConstantI) + .addDef(Res) + .addUse(SpvTypeReg); + addNumImm(APInt(BitWidth, Val), MIB); + } else { + MIB = MIRBuilder.buildInstr(SPIRV::OpConstantNull) + .addDef(Res) + .addUse(SpvTypeReg); + } + const auto &Subtarget = CurMF->getSubtarget(); + constrainSelectedInstRegOperands(*MIB, *Subtarget.getInstrInfo(), + *Subtarget.getRegisterInfo(), + *Subtarget.getRegBankInfo()); + return MIB; + }); } } return Res; @@ -385,12 +397,14 @@ Register SPIRVGlobalRegistry::buildConstantFP(APFloat Val, MF.getRegInfo().setRegClass(Res, &SPIRV::fIDRegClass); assignSPIRVTypeToVReg(SpvType, Res, MF); DT.add(ConstFP, &MF, Res); - - MachineInstrBuilder MIB; - MIB = MIRBuilder.buildInstr(SPIRV::OpConstantF) - .addDef(Res) - .addUse(getSPIRVTypeID(SpvType)); - addNumImm(ConstFP->getValueAPF().bitcastToAPInt(), MIB); + createOpType(MIRBuilder, [&](MachineIRBuilder &MIRBuilder) { + MachineInstrBuilder MIB; + MIB = MIRBuilder.buildInstr(SPIRV::OpConstantF) + .addDef(Res) + .addUse(getSPIRVTypeID(SpvType)); + addNumImm(ConstFP->getValueAPF().bitcastToAPInt(), MIB); + return MIB; + }); } return Res; @@ -439,23 +453,26 @@ Register SPIRVGlobalRegistry::getOrCreateCompositeOrNull( CurMF->getRegInfo().setRegClass(SpvVecConst, getRegClass(SpvType)); assignSPIRVTypeToVReg(SpvType, SpvVecConst, *CurMF); DT.add(CA, CurMF, SpvVecConst); - MachineInstrBuilder MIB; - MachineBasicBlock &BB = *I.getParent(); - if (!IsNull) { - MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantComposite)) - .addDef(SpvVecConst) - .addUse(getSPIRVTypeID(SpvType)); - for (unsigned i = 0; i < ElemCnt; ++i) - MIB.addUse(SpvScalConst); - } else { - MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull)) - .addDef(SpvVecConst) - .addUse(getSPIRVTypeID(SpvType)); - } - const auto &Subtarget = CurMF->getSubtarget(); - constrainSelectedInstRegOperands(*MIB, *Subtarget.getInstrInfo(), - *Subtarget.getRegisterInfo(), - *Subtarget.getRegBankInfo()); + MachineIRBuilder MIRBuilder(I); + createOpType(MIRBuilder, [&](MachineIRBuilder &MIRBuilder) { + MachineInstrBuilder MIB; + if (!IsNull) { + MIB = MIRBuilder.buildInstr(SPIRV::OpConstantComposite) + .addDef(SpvVecConst) + .addUse(getSPIRVTypeID(SpvType)); + for (unsigned i = 0; i < ElemCnt; ++i) + MIB.addUse(SpvScalConst); + } else { + MIB = MIRBuilder.buildInstr(SPIRV::OpConstantNull) + .addDef(SpvVecConst) + .addUse(getSPIRVTypeID(SpvType)); + } + const auto &Subtarget = CurMF->getSubtarget(); + constrainSelectedInstRegOperands(*MIB, *Subtarget.getInstrInfo(), + *Subtarget.getRegisterInfo(), + *Subtarget.getRegBankInfo()); + return MIB; + }); return SpvVecConst; } return Res; @@ -544,17 +561,20 @@ Register SPIRVGlobalRegistry::getOrCreateIntCompositeOrNull( if (EmitIR) { MIRBuilder.buildSplatBuildVector(SpvVecConst, SpvScalConst); } else { - if (Val) { - auto MIB = MIRBuilder.buildInstr(SPIRV::OpConstantComposite) - .addDef(SpvVecConst) - .addUse(getSPIRVTypeID(SpvType)); - for (unsigned i = 0; i < ElemCnt; ++i) - MIB.addUse(SpvScalConst); - } else { - MIRBuilder.buildInstr(SPIRV::OpConstantNull) - .addDef(SpvVecConst) - .addUse(getSPIRVTypeID(SpvType)); - } + createOpType(MIRBuilder, [&](MachineIRBuilder &MIRBuilder) { + if (Val) { + auto MIB = MIRBuilder.buildInstr(SPIRV::OpConstantComposite) + .addDef(SpvVecConst) + .addUse(getSPIRVTypeID(SpvType)); + for (unsigned i = 0; i < ElemCnt; ++i) + MIB.addUse(SpvScalConst); + return MIB; + } else { + return MIRBuilder.buildInstr(SPIRV::OpConstantNull) + .addDef(SpvVecConst) + .addUse(getSPIRVTypeID(SpvType)); + } + }); } return SpvVecConst; } @@ -592,9 +612,11 @@ SPIRVGlobalRegistry::getOrCreateConstNullPtr(MachineIRBuilder &MIRBuilder, Res = CurMF->getRegInfo().createGenericVirtualRegister(LLTy); CurMF->getRegInfo().setRegClass(Res, &SPIRV::pIDRegClass); assignSPIRVTypeToVReg(SpvType, Res, *CurMF); - MIRBuilder.buildInstr(SPIRV::OpConstantNull) - .addDef(Res) - .addUse(getSPIRVTypeID(SpvType)); + createOpType(MIRBuilder, [&](MachineIRBuilder &MIRBuilder) { + return MIRBuilder.buildInstr(SPIRV::OpConstantNull) + .addDef(Res) + .addUse(getSPIRVTypeID(SpvType)); + }); DT.add(CP, CurMF, Res); } return Res; @@ -614,12 +636,14 @@ Register SPIRVGlobalRegistry::buildConstantSampler( ResReg.isValid() ? ResReg : MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass); - auto Res = MIRBuilder.buildInstr(SPIRV::OpConstantSampler) - .addDef(Sampler) - .addUse(getSPIRVTypeID(SampTy)) - .addImm(AddrMode) - .addImm(Param) - .addImm(FilerMode); + auto Res = createOpType(MIRBuilder, [&](MachineIRBuilder &MIRBuilder) { + return MIRBuilder.buildInstr(SPIRV::OpConstantSampler) + .addDef(Sampler) + .addUse(getSPIRVTypeID(SampTy)) + .addImm(AddrMode) + .addImm(Param) + .addImm(FilerMode); + }); assert(Res->getOperand(0).isReg()); return Res->getOperand(0).getReg(); } @@ -1551,14 +1575,17 @@ SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVPointerType( if (Reg.isValid()) return getSPIRVTypeForVReg(Reg); // create a new type - auto MIB = BuildMI(MIRBuilder.getMBB(), MIRBuilder.getInsertPt(), - MIRBuilder.getDebugLoc(), - MIRBuilder.getTII().get(SPIRV::OpTypePointer)) - .addDef(createTypeVReg(CurMF->getRegInfo())) - .addImm(static_cast(SC)) - .addUse(getSPIRVTypeID(BaseType)); - DT.add(PointerElementType, AddressSpace, CurMF, getSPIRVTypeID(MIB)); - return finishCreatingSPIRVType(LLVMTy, MIB); + return createOpType(MIRBuilder, [&](MachineIRBuilder &MIRBuilder) { + auto MIB = BuildMI(MIRBuilder.getMBB(), MIRBuilder.getInsertPt(), + MIRBuilder.getDebugLoc(), + MIRBuilder.getTII().get(SPIRV::OpTypePointer)) + .addDef(createTypeVReg(CurMF->getRegInfo())) + .addImm(static_cast(SC)) + .addUse(getSPIRVTypeID(BaseType)); + DT.add(PointerElementType, AddressSpace, CurMF, getSPIRVTypeID(MIB)); + finishCreatingSPIRVType(LLVMTy, MIB); + return MIB; + }); } SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVPointerType( diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp index 3a98b74b3d675..b64030508cfc1 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -309,6 +309,7 @@ class SPIRVInstructionSelector : public InstructionSelector { SPIRVType *widenTypeToVec4(const SPIRVType *Type, MachineInstr &I) const; void extractSubvector(Register &ResVReg, const SPIRVType *ResType, Register &ReadReg, MachineInstr &InsertionPoint) const; + bool BuildCOPY(Register DestReg, Register SrcReg, MachineInstr &I) const; }; } // end anonymous namespace @@ -449,6 +450,19 @@ static bool mayApplyGenericSelection(unsigned Opcode) { return isTypeFoldingSupported(Opcode); } +bool SPIRVInstructionSelector::BuildCOPY(Register DestReg, Register SrcReg, + MachineInstr &I) const { + const TargetRegisterClass *DstRC = MRI->getRegClassOrNull(DestReg); + const TargetRegisterClass *SrcRC = MRI->getRegClassOrNull(SrcReg); + if (DstRC != SrcRC && SrcRC) + MRI->setRegClass(DestReg, SrcRC); + return BuildMI(*I.getParent(), I, I.getDebugLoc(), + TII.get(TargetOpcode::COPY)) + .addDef(DestReg) + .addUse(SrcReg) + .constrainAllUses(TII, TRI, RBI); +} + bool SPIRVInstructionSelector::spvSelect(Register ResVReg, const SPIRVType *ResType, MachineInstr &I) const { @@ -1074,10 +1088,7 @@ bool SPIRVInstructionSelector::selectMemOperation(Register ResVReg, addMemoryOperands(*I.memoperands_begin(), MIB); Result &= MIB.constrainAllUses(TII, TRI, RBI); if (ResVReg.isValid() && ResVReg != MIB->getOperand(0).getReg()) - Result &= - BuildMI(BB, I, I.getDebugLoc(), TII.get(TargetOpcode::COPY), ResVReg) - .addUse(MIB->getOperand(0).getReg()) - .constrainAllUses(TII, TRI, RBI); + Result &= BuildCOPY(ResVReg, MIB->getOperand(0).getReg(), I); return Result; } @@ -1414,10 +1425,7 @@ bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg, // don't generate a cast for a null that may be represented by OpTypeInt if (SrcPtrTy->getOpcode() != SPIRV::OpTypePointer || ResType->getOpcode() != SPIRV::OpTypePointer) - return BuildMI(BB, I, DL, TII.get(TargetOpcode::COPY)) - .addDef(ResVReg) - .addUse(SrcPtr) - .constrainAllUses(TII, TRI, RBI); + return BuildCOPY(ResVReg, SrcPtr, I); SPIRV::StorageClass::StorageClass SrcSC = GR.getPointerStorageClass(SrcPtrTy); SPIRV::StorageClass::StorageClass DstSC = GR.getPointerStorageClass(ResType); @@ -1455,20 +1463,13 @@ bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg, // don't generate a cast between identical storage classes if (SrcSC == DstSC) - return BuildMI(BB, I, DL, TII.get(TargetOpcode::COPY)) - .addDef(ResVReg) - .addUse(SrcPtr) - .constrainAllUses(TII, TRI, RBI); + return BuildCOPY(ResVReg, SrcPtr, I); if ((SrcSC == SPIRV::StorageClass::Function && DstSC == SPIRV::StorageClass::Private) || (DstSC == SPIRV::StorageClass::Function && - SrcSC == SPIRV::StorageClass::Private)) { - return BuildMI(BB, I, DL, TII.get(TargetOpcode::COPY)) - .addDef(ResVReg) - .addUse(SrcPtr) - .constrainAllUses(TII, TRI, RBI); - } + SrcSC == SPIRV::StorageClass::Private)) + return BuildCOPY(ResVReg, SrcPtr, I); // Casting from an eligible pointer to Generic. if (DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SrcSC)) @@ -1643,11 +1644,7 @@ bool SPIRVInstructionSelector::selectAnyOrAll(Register ResVReg, bool IsVectorTy = InputType->getOpcode() == SPIRV::OpTypeVector; if (IsBoolTy && !IsVectorTy) { assert(ResVReg == I.getOperand(0).getReg()); - return BuildMI(*I.getParent(), I, I.getDebugLoc(), - TII.get(TargetOpcode::COPY)) - .addDef(ResVReg) - .addUse(InputRegister) - .constrainAllUses(TII, TRI, RBI); + return BuildCOPY(ResVReg, InputRegister, I); } bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat); @@ -2162,6 +2159,7 @@ bool SPIRVInstructionSelector::selectBuildVector(Register ResVReg, report_fatal_error( "There must be at least two constituent operands in a vector"); + MRI->setRegClass(ResVReg, GR.getRegClass(ResType)); auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(IsConst ? SPIRV::OpConstantComposite : SPIRV::OpCompositeConstruct)) @@ -2195,6 +2193,7 @@ bool SPIRVInstructionSelector::selectSplatVector(Register ResVReg, report_fatal_error( "There must be at least two constituent operands in a vector"); + MRI->setRegClass(ResVReg, GR.getRegClass(ResType)); auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(IsConst ? SPIRV::OpConstantComposite : SPIRV::OpCompositeConstruct)) @@ -2364,7 +2363,7 @@ bool SPIRVInstructionSelector::selectSelect(Register ResVReg, bool IsScalarBool = GR.isScalarOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool); unsigned Opcode = - IsScalarBool ? SPIRV::OpSelectSISCond : SPIRV::OpSelectSIVCond; + IsScalarBool ? SPIRV::OpSelectSISCond : SPIRV::OpSelectVIVCond; return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode)) .addDef(ResVReg) .addUse(GR.getSPIRVTypeID(ResType)) @@ -2402,17 +2401,8 @@ bool SPIRVInstructionSelector::selectExt(Register ResVReg, return selectSelect(ResVReg, ResType, I, IsSigned); SPIRVType *SrcType = GR.getSPIRVTypeForVReg(SrcReg); - if (SrcType == ResType) { - const TargetRegisterClass *DstRC = MRI->getRegClassOrNull(ResVReg); - const TargetRegisterClass *SrcRC = MRI->getRegClassOrNull(SrcReg); - if (DstRC != SrcRC && SrcRC) - MRI->setRegClass(ResVReg, SrcRC); - return BuildMI(*I.getParent(), I, I.getDebugLoc(), - TII.get(TargetOpcode::COPY)) - .addDef(ResVReg) - .addUse(SrcReg) - .constrainAllUses(TII, TRI, RBI); - } + if (SrcType == ResType) + return BuildCOPY(ResVReg, SrcReg, I); unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert; return selectUnOp(ResVReg, ResType, I, Opcode); @@ -2512,17 +2502,8 @@ bool SPIRVInstructionSelector::selectTrunc(Register ResVReg, const SPIRVType *ArgType = GR.getSPIRVTypeForVReg(IntReg); if (GR.isScalarOrVectorOfType(ResVReg, SPIRV::OpTypeBool)) return selectIntToBool(IntReg, ResVReg, I, ArgType, ResType); - if (ArgType == ResType) { - const TargetRegisterClass *DstRC = MRI->getRegClassOrNull(ResVReg); - const TargetRegisterClass *SrcRC = MRI->getRegClassOrNull(IntReg); - if (DstRC != SrcRC && SrcRC) - MRI->setRegClass(ResVReg, SrcRC); - return BuildMI(*I.getParent(), I, I.getDebugLoc(), - TII.get(TargetOpcode::COPY)) - .addDef(ResVReg) - .addUse(IntReg) - .constrainAllUses(TII, TRI, RBI); - } + if (ArgType == ResType) + return BuildCOPY(ResVReg, IntReg, I); bool IsSigned = GR.isScalarOrVectorSigned(ResType); unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert; return selectUnOp(ResVReg, ResType, I, Opcode); @@ -2544,12 +2525,7 @@ bool SPIRVInstructionSelector::selectConst(Register ResVReg, if (TyOpcode == SPIRV::OpTypeInt) { assert(Imm.getBitWidth() <= 64 && "Unsupported integer width!"); Register Reg = GR.getOrCreateConstInt(Imm.getZExtValue(), I, ResType, TII); - if (Reg == ResVReg) - return true; - return BuildMI(BB, I, I.getDebugLoc(), TII.get(TargetOpcode::COPY)) - .addDef(ResVReg) - .addUse(Reg) - .constrainAllUses(TII, TRI, RBI); + return Reg == ResVReg ? true : BuildCOPY(ResVReg, Reg, I); } auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI)) .addDef(ResVReg) @@ -2701,7 +2677,7 @@ bool SPIRVInstructionSelector::wrapIntoSpecConstantOp( continue; } // Create a new register for the wrapper - WrapReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass); + WrapReg = MRI->createVirtualRegister(GR.getRegClass(OpType)); GR.add(OpDefine, MF, WrapReg); CompositeArgs.push_back(WrapReg); // Decorate the wrapper register and generate a new instruction @@ -2766,6 +2742,7 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg, if (!wrapIntoSpecConstantOp(I, CompositeArgs)) return false; } + MRI->setRegClass(ResVReg, GR.getRegClass(ResType)); auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode)) .addDef(ResVReg) .addUse(GR.getSPIRVTypeID(ResType)); @@ -2845,10 +2822,7 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg, .addUse(I.getOperand(2).getReg()) .constrainAllUses(TII, TRI, RBI); else - return BuildMI(BB, I, I.getDebugLoc(), TII.get(TargetOpcode::COPY), - ResVReg) - .addUse(I.getOperand(2).getReg()) - .constrainAllUses(TII, TRI, RBI); + return BuildCOPY(ResVReg, I.getOperand(2).getReg(), I); break; case Intrinsic::spv_thread_id: return selectSpvThreadId(ResVReg, ResType, I); @@ -3388,7 +3362,10 @@ bool SPIRVInstructionSelector::selectPhi(Register ResVReg, MIB.addUse(I.getOperand(i + 0).getReg()); MIB.addMBB(I.getOperand(i + 1).getMBB()); } - return MIB.constrainAllUses(TII, TRI, RBI); + bool Res = MIB.constrainAllUses(TII, TRI, RBI); + MIB->setDesc(TII.get(TargetOpcode::PHI)); + MIB->removeOperand(1); + return Res; } bool SPIRVInstructionSelector::selectGlobalValue( @@ -3467,10 +3444,7 @@ bool SPIRVInstructionSelector::selectGlobalValue( .constrainAllUses(TII, TRI, RBI); } assert(NewReg != ResVReg); - return BuildMI(BB, I, I.getDebugLoc(), TII.get(TargetOpcode::COPY)) - .addDef(ResVReg) - .addUse(NewReg) - .constrainAllUses(TII, TRI, RBI); + return BuildCOPY(ResVReg, NewReg, I); } auto GlobalVar = cast(GV); assert(GlobalVar->getName() != "llvm.global.annotations"); diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp index 4ee71c703f90b..4dea4056799fe 100644 --- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp @@ -1770,6 +1770,27 @@ static void addMBBNames(const Module &M, const SPIRVInstrInfo &TII, } } +// patching Instruction::PHI to SPIRV::OpPhi +static void patchPhis(const Module &M, SPIRVGlobalRegistry *GR, + const SPIRVInstrInfo &TII, MachineModuleInfo *MMI) { + for (auto F = M.begin(), E = M.end(); F != E; ++F) { + MachineFunction *MF = MMI->getMachineFunction(*F); + if (!MF) + continue; + for (auto &MBB : *MF) { + for (MachineInstr &MI : MBB) { + if (MI.getOpcode() != TargetOpcode::PHI) + continue; + MI.setDesc(TII.get(SPIRV::OpPhi)); + Register ResTypeReg = GR->getSPIRVTypeID( + GR->getSPIRVTypeForVReg(MI.getOperand(0).getReg(), MF)); + MI.insert(MI.operands_begin() + 1, + {MachineOperand::CreateReg(ResTypeReg, false)}); + } + } + } +} + struct SPIRV::ModuleAnalysisInfo SPIRVModuleAnalysis::MAI; void SPIRVModuleAnalysis::getAnalysisUsage(AnalysisUsage &AU) const { @@ -1788,6 +1809,8 @@ bool SPIRVModuleAnalysis::runOnModule(Module &M) { setBaseInfo(M); + patchPhis(M, GR, *TII, MMI); + addMBBNames(M, *TII, MMI, *ST, MAI); addDecorations(M, *TII, MMI, *ST, MAI); diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp index d5299043d9ef2..ceccf55d1de4d 100644 --- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp @@ -466,8 +466,13 @@ void processInstr(MachineInstr &MI, MachineIRBuilder &MIB, for (auto &Op : MI.operands()) { if (!Op.isReg() || Op.isDef()) continue; - auto IdOpInfo = createNewIdReg(nullptr, Op.getReg(), MRI, *GR); - MIB.buildInstr(IdOpInfo.second).addDef(IdOpInfo.first).addUse(Op.getReg()); + Register OpReg = Op.getReg(); + SPIRVType *SpvType = GR->getSPIRVTypeForVReg(OpReg); + auto IdOpInfo = createNewIdReg(SpvType, OpReg, MRI, *GR); + MIB.buildInstr(IdOpInfo.second).addDef(IdOpInfo.first).addUse(OpReg); + const TargetRegisterClass *RC = GR->getRegClass(SpvType); + if (RC != MRI.getRegClassOrNull(OpReg)) + MRI.setRegClass(OpReg, RC); Op.setReg(IdOpInfo.first); } } diff --git a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp index 8f38d4b8307da..d9d0d00cc71e4 100644 --- a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp @@ -130,13 +130,8 @@ FunctionPass *SPIRVPassConfig::createTargetRegisterAllocator(bool) { return nullptr; } -// Disable passes that may break CFG. +// A place to disable passes that may break CFG. void SPIRVPassConfig::addMachineSSAOptimization() { - // Some standard passes that optimize machine instructions in SSA form uses - // MI.isPHI() that doesn't account for OpPhi in SPIR-V and so are able to - // break the CFG (e.g., MachineSink). - disablePass(&MachineSinkingID); - TargetPassConfig::addMachineSSAOptimization(); } diff --git a/llvm/test/CodeGen/SPIRV/branching/if-merging.ll b/llvm/test/CodeGen/SPIRV/branching/if-merging.ll index eb8ca515c5822..18fbe417addf8 100644 --- a/llvm/test/CodeGen/SPIRV/branching/if-merging.ll +++ b/llvm/test/CodeGen/SPIRV/branching/if-merging.ll @@ -1,4 +1,4 @@ -; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s ;; NOTE: This does not check for structured control-flow operations. diff --git a/llvm/test/CodeGen/SPIRV/branching/if-non-merging.ll b/llvm/test/CodeGen/SPIRV/branching/if-non-merging.ll index f978c44888e0f..b664a65a5829c 100644 --- a/llvm/test/CodeGen/SPIRV/branching/if-non-merging.ll +++ b/llvm/test/CodeGen/SPIRV/branching/if-non-merging.ll @@ -1,4 +1,4 @@ -; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s ; CHECK-DAG: [[I32:%.+]] = OpTypeInt 32 ; CHECK-DAG: [[BOOL:%.+]] = OpTypeBool diff --git a/llvm/test/CodeGen/SPIRV/branching/switch-range-check.ll b/llvm/test/CodeGen/SPIRV/branching/switch-range-check.ll index 9981e0d86eaa3..25c2c8627de4e 100644 --- a/llvm/test/CodeGen/SPIRV/branching/switch-range-check.ll +++ b/llvm/test/CodeGen/SPIRV/branching/switch-range-check.ll @@ -1,4 +1,4 @@ -; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %} ; CHECK: OpFunction diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-type-basic.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-type-basic.ll index d29cdefe0d8c6..6073b0c2b9276 100644 --- a/llvm/test/CodeGen/SPIRV/debug-info/debug-type-basic.ll +++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-type-basic.ll @@ -11,33 +11,33 @@ ; CHECK-MIR-DAG: [[str_bool:%[0-9]+\:id\(s32\)]] = OpString 1819242338, 0 ; CHECK-MIR-DAG: [[size_8bits:%[0-9]+\:iid\(s32\)]] = OpConstantI [[type_i32]], 8 ; CHECK-MIR-DAG: [[encoding_boolean:%[0-9]+\:iid\(s32\)]] = OpConstantI [[type_i32]], 2 -; CHECK-MIR: OpExtInst [[type_void]], 3, 2, [[str_bool]], [[size_8bits]], [[encoding_boolean]], [[flag_zero]] +; CHECK-MIR-DAG: OpExtInst [[type_void]], 3, 2, [[str_bool]], [[size_8bits]], [[encoding_boolean]], [[flag_zero]] ; CHECK-MIR-DAG: [[str_int:%[0-9]+\:id\(s32\)]] = OpString 7630441 ; CHECK-MIR-DAG: [[size_32bits:%[0-9]+\:iid\(s32\)]] = OpConstantI [[type_i32]], 32 ; CHECK-MIR-DAG: [[encoding_signed:%[0-9]+\:iid\(s32\)]] = OpConstantI [[type_i32]], 4 -; CHECK-MIR: OpExtInst [[type_void]], 3, 2, [[str_int]], [[size_32bits]], [[encoding_signed]], [[flag_zero]] +; CHECK-MIR-DAG: OpExtInst [[type_void]], 3, 2, [[str_int]], [[size_32bits]], [[encoding_signed]], [[flag_zero]] ; CHECK-MIR-DAG: [[str_short:%[0-9]+\:id\(s32\)]] = OpString 1919903859, 116 ; CHECK-MIR-DAG: [[size_16bits:%[0-9]+\:iid\(s32\)]] = OpConstantI [[type_i32]], 16 -; CHECK-MIR: OpExtInst [[type_void]], 3, 2, [[str_short]], [[size_16bits]], [[encoding_signed]], [[flag_zero]] +; CHECK-MIR-DAG: OpExtInst [[type_void]], 3, 2, [[str_short]], [[size_16bits]], [[encoding_signed]], [[flag_zero]] ; CHECK-MIR-DAG: [[str_char:%[0-9]+\:id\(s32\)]] = OpString 1918986339, 0 -; CHECK-MIR: OpExtInst [[type_void]], 3, 2, [[str_char]], [[size_8bits]], [[encoding_signedchar]], [[flag_zero]] +; CHECK-MIR-DAG: OpExtInst [[type_void]], 3, 2, [[str_char]], [[size_8bits]], [[encoding_signedchar]], [[flag_zero]] ; CHECK-MIR-DAG: [[str_long:%[0-9]+\:id\(s32\)]] = OpString 1735290732, 0 ; CHECK-MIR-DAG: [[size_64bits:%[0-9]+\:iid\(s32\)]] = OpConstantI [[type_i32]], 64 -; CHECK-MIR: OpExtInst [[type_void]], 3, 2, [[str_long]], [[size_64bits]], [[encoding_signed]], [[flag_zero]] +; CHECK-MIR-DAG: OpExtInst [[type_void]], 3, 2, [[str_long]], [[size_64bits]], [[encoding_signed]], [[flag_zero]] ; CHECK-MIR-DAG: [[str_uint:%[0-9]+\:id\(s32\)]] = OpString 1769172597, 1684368999, 1953392928, 0 ; CHECK-MIR-DAG: [[encoding_unsigned:%[0-9]+\:iid\(s32\)]] = OpConstantI [[type_i32]], 6 -; CHECK-MIR: OpExtInst [[type_void]], 3, 2, [[str_uint]], [[size_32bits]], [[encoding_unsigned]], [[flag_zero]] +; CHECK-MIR-DAG: OpExtInst [[type_void]], 3, 2, [[str_uint]], [[size_32bits]], [[encoding_unsigned]], [[flag_zero]] ; CHECK-MIR-DAG: [[str_ushort:%[0-9]+\:id\(s32\)]] = OpString 1769172597, 1684368999, 1869116192, 29810 -; CHECK-MIR: OpExtInst [[type_void]], 3, 2, [[str_ushort]], [[size_16bits]], [[encoding_unsigned]], [[flag_zero]] +; CHECK-MIR-DAG: OpExtInst [[type_void]], 3, 2, [[str_ushort]], [[size_16bits]], [[encoding_unsigned]], [[flag_zero]] ; CHECK-MIR-DAG: [[str_uchar:%[0-9]+\:id\(s32\)]] = OpString 1769172597, 1684368999, 1634231072, 114 ; CHECK-MIR-DAG: [[encoding_unsignedchar:%[0-9]+\:iid\(s32\)]] = OpConstantI [[type_i32]], 7 -; CHECK-MIR: OpExtInst [[type_void]], 3, 2, [[str_uchar]], [[size_8bits]], [[encoding_unsignedchar]], [[flag_zero]] +; CHECK-MIR-DAG: OpExtInst [[type_void]], 3, 2, [[str_uchar]], [[size_8bits]], [[encoding_unsignedchar]], [[flag_zero]] ; CHECK-MIR-DAG: [[str_ulong:%[0-9]+\:id\(s32\)]] = OpString 1769172597, 1684368999, 1852795936, 103 -; CHECK-MIR: OpExtInst [[type_void]], 3, 2, [[str_ulong]], [[size_64bits]], [[encoding_unsigned]], [[flag_zero]] +; CHECK-MIR-DAG: OpExtInst [[type_void]], 3, 2, [[str_ulong]], [[size_64bits]], [[encoding_unsigned]], [[flag_zero]] ; CHECK-MIR-DAG: [[str_float:%[0-9]+\:id\(s32\)]] = OpString 1634692198, 116 -; CHECK-MIR: OpExtInst [[type_void]], 3, 2, [[str_float]], [[size_32bits]], [[encoding_float]], [[flag_zero]] +; CHECK-MIR-DAG: OpExtInst [[type_void]], 3, 2, [[str_float]], [[size_32bits]], [[encoding_float]], [[flag_zero]] ; CHECK-MIR-DAG: [[str_double:%[0-9]+\:id\(s32\)]] = OpString 1651863396, 25964 -; CHECK-MIR: OpExtInst [[type_void]], 3, 2, [[str_double]], [[size_64bits]], [[encoding_float]], [[flag_zero]] +; CHECK-MIR-DAG: OpExtInst [[type_void]], 3, 2, [[str_double]], [[size_64bits]], [[encoding_float]], [[flag_zero]] ; CHECK-SPIRV: [[ext_inst_non_semantic:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" ; CHECK-SPIRV-DAG: [[str_bool:%[0-9]+]] = OpString "bool" diff --git a/llvm/test/CodeGen/SPIRV/half_no_extension.ll b/llvm/test/CodeGen/SPIRV/half_no_extension.ll index a5b0ec9c92d23..63cecbc7399ae 100644 --- a/llvm/test/CodeGen/SPIRV/half_no_extension.ll +++ b/llvm/test/CodeGen/SPIRV/half_no_extension.ll @@ -5,10 +5,11 @@ ;; vstorea_half4_rtp( data, 0, f ); ;; } -; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %} -; CHECK-SPIRV: OpCapability Float16Buffer -; CHECK-SPIRV-NOT: OpCapability Float16 +; CHECK-DAG: OpCapability Float16Buffer +; CHECK-DAG: OpCapability Float16 define spir_kernel void @test(<4 x float> addrspace(1)* %p, half addrspace(1)* %f) { entry: diff --git a/llvm/test/CodeGen/SPIRV/keep-tracked-const.ll b/llvm/test/CodeGen/SPIRV/keep-tracked-const.ll index 0c25d8a67aca0..0dc86233f8e16 100644 --- a/llvm/test/CodeGen/SPIRV/keep-tracked-const.ll +++ b/llvm/test/CodeGen/SPIRV/keep-tracked-const.ll @@ -1,6 +1,6 @@ ; This test case ensures that cleaning of temporary constants doesn't purge tracked ones. -; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %} ; CHECK-SPIRV: %[[#Int:]] = OpTypeInt 32 0 diff --git a/llvm/test/CodeGen/SPIRV/phi-insert-point.ll b/llvm/test/CodeGen/SPIRV/phi-insert-point.ll index 41cc514f4dbae..70d121cdf4b3a 100644 --- a/llvm/test/CodeGen/SPIRV/phi-insert-point.ll +++ b/llvm/test/CodeGen/SPIRV/phi-insert-point.ll @@ -2,7 +2,7 @@ ; operand are inserted at the correct positions, and don't break rules of ; instruction domination and PHI nodes grouping at top of basic block. -; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %} ; CHECK-DAG: OpName %[[#Foo:]] "foo" diff --git a/llvm/test/CodeGen/SPIRV/phi-ptrcast-dominate.ll b/llvm/test/CodeGen/SPIRV/phi-ptrcast-dominate.ll index 102eb76356fe3..bc090ce55fbec 100644 --- a/llvm/test/CodeGen/SPIRV/phi-ptrcast-dominate.ll +++ b/llvm/test/CodeGen/SPIRV/phi-ptrcast-dominate.ll @@ -3,7 +3,7 @@ ; positions, and don't break rules of instruction domination and PHI nodes ; grouping at top of basic block. -; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %} diff --git a/llvm/test/CodeGen/SPIRV/phi-spvintrinsic-dominate.ll b/llvm/test/CodeGen/SPIRV/phi-spvintrinsic-dominate.ll index 471ab03ed89f6..45831ce97263d 100644 --- a/llvm/test/CodeGen/SPIRV/phi-spvintrinsic-dominate.ll +++ b/llvm/test/CodeGen/SPIRV/phi-spvintrinsic-dominate.ll @@ -3,7 +3,7 @@ ; positions, and don't break rules of instruction domination and PHI nodes ; grouping at top of basic block. -; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %} ; CHECK: OpFunction diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpConstantSampler.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpConstantSampler.ll index 7e0d13490fcf6..0169cc8b8fd81 100644 --- a/llvm/test/CodeGen/SPIRV/transcoding/OpConstantSampler.ll +++ b/llvm/test/CodeGen/SPIRV/transcoding/OpConstantSampler.ll @@ -12,8 +12,8 @@ ; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV -; CHECK-SPIRV: %[[#SamplerID0:]] = OpConstantSampler %[[#]] Repeat 1 Nearest -; CHECK-SPIRV: %[[#SamplerID1:]] = OpConstantSampler %[[#]] None 0 Nearest +; CHECK-SPIRV-DAG: %[[#SamplerID0:]] = OpConstantSampler %[[#]] Repeat 1 Nearest +; CHECK-SPIRV-DAG: %[[#SamplerID1:]] = OpConstantSampler %[[#]] None 0 Nearest ; CHECK-SPIRV: %[[#]] = OpSampledImage %[[#]] %[[#]] %[[#SamplerID0]] ; CHECK-SPIRV: %[[#]] = OpSampledImage %[[#]] %[[#]] %[[#SamplerID1]] diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpPhi_ArgumentsPlaceholders.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpPhi_ArgumentsPlaceholders.ll index ee5596ed38b1b..63b517c805494 100644 --- a/llvm/test/CodeGen/SPIRV/transcoding/OpPhi_ArgumentsPlaceholders.ll +++ b/llvm/test/CodeGen/SPIRV/transcoding/OpPhi_ArgumentsPlaceholders.ll @@ -14,7 +14,6 @@ ; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %} -; XFAIL: * %struct.Node = type { %struct.Node.0 addrspace(1)* } %struct.Node.0 = type opaque