Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions llvm/include/llvm/Analysis/TargetTransformInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -810,9 +810,13 @@ class TargetTransformInfo {
LLVM_ABI AddressingModeKind
getPreferredAddressingMode(const Loop *L, ScalarEvolution *SE) const;

/// Return true if the target supports masked store.
/// Return true if the target supports masked store. A value of false for
/// IsMaskConstant indicates that the mask could either be variable or
/// constant. This is for targets that only support masked store with a
/// constant mask.
LLVM_ABI bool isLegalMaskedStore(Type *DataType, Align Alignment,
unsigned AddressSpace) const;
unsigned AddressSpace,
bool IsMaskConstant = false) const;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, if the purpose of the check is to check validity of X, we should pass X itself. Passing derived into instead of the actual object we're checking makes everyone do potentially unnecessary checks and limits what property of X we get to check. While a bool indicating contness of the masked store is sufficient for us here and now, it's not the best choice for a generic API that potentially needs to work for different architectures with different requirements.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd expect this to have a classification similar to the ShuffleKind queries

Copy link
Contributor Author

@dakersnar dakersnar Sep 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arsenm are you imagining an enum rather than a bool? Something like:

enum MaskType {
VariableOrConstantMask,
ConstantMask,
}

This is effectively the same as the bool approach but possibly a bit clearer. Like the bool approach, this would allow:

  • API use cases that do not know the constness of the mask to pass VariableOrConstantMask.
  • API use cases that can derive the constness of the mask will pass ConstantMask when applicable.
  • Targets that do not care about the constness of the mask will just ignore the parameter.
  • And architectures like NVPTX can only return true if the parameter is set to the more precise ConstantMask.

If this isn't what you had in mind, can you elaborate?

(edit: we could also add VariableMask as a third enum option if for some reason a target had special rules for that specific case)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, something like that

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

/// Return true if the target supports masked load.
LLVM_ABI bool isLegalMaskedLoad(Type *DataType, Align Alignment,
unsigned AddressSpace) const;
Expand Down
3 changes: 2 additions & 1 deletion llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,8 @@ class TargetTransformInfoImplBase {
}

virtual bool isLegalMaskedStore(Type *DataType, Align Alignment,
unsigned AddressSpace) const {
unsigned AddressSpace,
bool IsMaskConstant) const {
return false;
}

Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/Analysis/TargetTransformInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,8 +467,10 @@ TargetTransformInfo::getPreferredAddressingMode(const Loop *L,
}

bool TargetTransformInfo::isLegalMaskedStore(Type *DataType, Align Alignment,
unsigned AddressSpace) const {
return TTIImpl->isLegalMaskedStore(DataType, Alignment, AddressSpace);
unsigned AddressSpace,
bool IsMaskConstant) const {
return TTIImpl->isLegalMaskedStore(DataType, Alignment, AddressSpace,
IsMaskConstant);
}

bool TargetTransformInfo::isLegalMaskedLoad(Type *DataType, Align Alignment,
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/AArch64/AArch64TargetTransformInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,8 @@ class AArch64TTIImpl final : public BasicTTIImplBase<AArch64TTIImpl> {
}

bool isLegalMaskedStore(Type *DataType, Align Alignment,
unsigned /*AddressSpace*/) const override {
unsigned /*AddressSpace*/,
bool /*IsMaskConstant*/) const override {
return isLegalMaskedLoadStore(DataType, Alignment);
}

Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Target/ARM/ARMTargetTransformInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@ class ARMTTIImpl final : public BasicTTIImplBase<ARMTTIImpl> {
bool isLegalMaskedLoad(Type *DataTy, Align Alignment,
unsigned AddressSpace) const override;

bool isLegalMaskedStore(Type *DataTy, Align Alignment,
unsigned AddressSpace) const override {
bool isLegalMaskedStore(Type *DataTy, Align Alignment, unsigned AddressSpace,
bool /*IsMaskConstant*/) const override {
return isLegalMaskedLoad(DataTy, Alignment, AddressSpace);
}

Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/Hexagon/HexagonTargetTransformInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,8 @@ InstructionCost HexagonTTIImpl::getVectorInstrCost(unsigned Opcode, Type *Val,
}

bool HexagonTTIImpl::isLegalMaskedStore(Type *DataType, Align /*Alignment*/,
unsigned /*AddressSpace*/) const {
unsigned /*AddressSpace*/,
bool /*IsMaskConstant*/) const {
// This function is called from scalarize-masked-mem-intrin, which runs
// in pre-isel. Use ST directly instead of calling isHVXVectorType.
return HexagonMaskedVMem && ST.isTypeForHVX(DataType);
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/Hexagon/HexagonTargetTransformInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@ class HexagonTTIImpl final : public BasicTTIImplBase<HexagonTTIImpl> {
}

bool isLegalMaskedStore(Type *DataType, Align Alignment,
unsigned AddressSpace) const override;
unsigned AddressSpace,
bool IsMaskConstant) const override;
bool isLegalMaskedLoad(Type *DataType, Align Alignment,
unsigned AddressSpace) const override;

Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXInstPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,16 @@ void NVPTXInstPrinter::printMemOperand(const MCInst *MI, int OpNum,
}
}

void NVPTXInstPrinter::printRegisterOrSinkSymbol(const MCInst *MI, int OpNum,
raw_ostream &O,
const char *Modifier) {
const MCOperand &Op = MI->getOperand(OpNum);
if (Op.isReg() && Op.getReg() == MCRegister::NoRegister)
O << "_";
else
printOperand(MI, OpNum, O);
}

void NVPTXInstPrinter::printHexu32imm(const MCInst *MI, int OpNum,
raw_ostream &O) {
int64_t Imm = MI->getOperand(OpNum).getImm();
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXInstPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ class NVPTXInstPrinter : public MCInstPrinter {
StringRef Modifier = {});
void printMemOperand(const MCInst *MI, int OpNum, raw_ostream &O,
StringRef Modifier = {});
void printRegisterOrSinkSymbol(const MCInst *MI, int OpNum, raw_ostream &O,
const char *Modifier = nullptr);
void printHexu32imm(const MCInst *MI, int OpNum, raw_ostream &O);
void printProtoIdent(const MCInst *MI, int OpNum, raw_ostream &O);
void printPrmtMode(const MCInst *MI, int OpNum, raw_ostream &O);
Expand Down
89 changes: 88 additions & 1 deletion llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,7 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM,
setOperationAction({ISD::LOAD, ISD::STORE}, {MVT::i128, MVT::f128}, Custom);
for (MVT VT : MVT::fixedlen_vector_valuetypes())
if (!isTypeLegal(VT) && VT.getStoreSizeInBits() <= 256)
setOperationAction({ISD::STORE, ISD::LOAD}, VT, Custom);
setOperationAction({ISD::STORE, ISD::LOAD, ISD::MSTORE}, VT, Custom);

// Custom legalization for LDU intrinsics.
// TODO: The logic to lower these is not very robust and we should rewrite it.
Expand Down Expand Up @@ -2869,6 +2869,87 @@ static SDValue lowerSELECT(SDValue Op, SelectionDAG &DAG) {
return Or;
}

static SDValue lowerMSTORE(SDValue Op, SelectionDAG &DAG) {
SDNode *N = Op.getNode();

SDValue Chain = N->getOperand(0);
SDValue Val = N->getOperand(1);
SDValue BasePtr = N->getOperand(2);
SDValue Offset = N->getOperand(3);
SDValue Mask = N->getOperand(4);

SDLoc DL(N);
EVT ValVT = Val.getValueType();
MemSDNode *MemSD = cast<MemSDNode>(N);
assert(ValVT.isVector() && "Masked vector store must have vector type");
assert(MemSD->getAlign() >= DAG.getEVTAlign(ValVT) &&
"Unexpected alignment for masked store");

unsigned Opcode = 0;
switch (ValVT.getSimpleVT().SimpleTy) {
default:
llvm_unreachable("Unexpected masked vector store type");
case MVT::v4i64:
case MVT::v4f64: {
Opcode = NVPTXISD::StoreV4;
break;
}
case MVT::v8i32:
case MVT::v8f32: {
Opcode = NVPTXISD::StoreV8;
break;
}
}

SmallVector<SDValue, 8> Ops;

// Construct the new SDNode. First operand is the chain.
Ops.push_back(Chain);

// The next N operands are the values to store. Encode the mask into the
// values using the sentinel register 0 to represent a masked-off element.
assert(Mask.getValueType().isVector() &&
Mask.getValueType().getVectorElementType() == MVT::i1 &&
"Mask must be a vector of i1");
assert(Mask.getOpcode() == ISD::BUILD_VECTOR &&
"Mask expected to be a BUILD_VECTOR");
assert(Mask.getValueType().getVectorNumElements() ==
ValVT.getVectorNumElements() &&
"Mask size must be the same as the vector size");
for (unsigned I : llvm::seq(ValVT.getVectorNumElements())) {
assert(isa<ConstantSDNode>(Mask.getOperand(I)) &&
"Mask elements must be constants");
if (Mask->getConstantOperandVal(I) == 0) {
// Append a sentinel register 0 to the Ops vector to represent a masked
// off element, this will be handled in tablegen
Ops.push_back(DAG.getRegister(MCRegister::NoRegister,
ValVT.getVectorElementType()));
} else {
// Extract the element from the vector to store
SDValue ExtVal =
DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, ValVT.getVectorElementType(),
Val, DAG.getIntPtrConstant(I, DL));
Ops.push_back(ExtVal);
}
}

// Next, the pointer operand.
Ops.push_back(BasePtr);

// Finally, the offset operand. We expect this to always be undef, and it will
// be ignored in lowering, but to mirror the handling of the other vector
// store instructions we include it in the new SDNode.
assert(Offset.getOpcode() == ISD::UNDEF &&
"Offset operand expected to be undef");
Ops.push_back(Offset);

SDValue NewSt =
DAG.getMemIntrinsicNode(Opcode, DL, DAG.getVTList(MVT::Other), Ops,
MemSD->getMemoryVT(), MemSD->getMemOperand());

return NewSt;
}

SDValue
NVPTXTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
switch (Op.getOpcode()) {
Expand Down Expand Up @@ -2905,6 +2986,12 @@ NVPTXTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
return LowerVECREDUCE(Op, DAG);
case ISD::STORE:
return LowerSTORE(Op, DAG);
case ISD::MSTORE: {
assert(STI.has256BitVectorLoadStore(
cast<MemSDNode>(Op.getNode())->getAddressSpace()) &&
"Masked store vector not supported on subtarget.");
return lowerMSTORE(Op, DAG);
}
case ISD::LOAD:
return LowerLOAD(Op, DAG);
case ISD::SHL_PARTS:
Expand Down
10 changes: 7 additions & 3 deletions llvm/lib/Target/NVPTX/NVPTXInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -1500,6 +1500,10 @@ def ADDR : Operand<pAny> {
let MIOperandInfo = (ops ADDR_base, i32imm);
}

def RegOrSink : Operand<Any> {
let PrintMethod = "printRegisterOrSinkSymbol";
}

def AtomicCode : Operand<i32> {
let PrintMethod = "printAtomicCode";
}
Expand Down Expand Up @@ -1806,16 +1810,16 @@ multiclass ST_VEC<DAGOperand O, bit support_v8 = false> {
"\t[$addr], {{$src1, $src2}};">;
def _v4 : NVPTXInst<
(outs),
(ins O:$src1, O:$src2, O:$src3, O:$src4,
(ins RegOrSink:$src1, RegOrSink:$src2, RegOrSink:$src3, RegOrSink:$src4,
AtomicCode:$sem, AtomicCode:$scope, AtomicCode:$addsp, i32imm:$fromWidth,
ADDR:$addr),
"st${sem:sem}${scope:scope}${addsp:addsp}.v4.b$fromWidth "
"\t[$addr], {{$src1, $src2, $src3, $src4}};">;
if support_v8 then
def _v8 : NVPTXInst<
(outs),
(ins O:$src1, O:$src2, O:$src3, O:$src4,
O:$src5, O:$src6, O:$src7, O:$src8,
(ins RegOrSink:$src1, RegOrSink:$src2, RegOrSink:$src3, RegOrSink:$src4,
RegOrSink:$src5, RegOrSink:$src6, RegOrSink:$src7, RegOrSink:$src8,
AtomicCode:$sem, AtomicCode:$scope, AtomicCode:$addsp, i32imm:$fromWidth,
ADDR:$addr),
"st${sem:sem}${scope:scope}${addsp:addsp}.v8.b$fromWidth "
Expand Down
27 changes: 27 additions & 0 deletions llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,33 @@ Value *NVPTXTTIImpl::rewriteIntrinsicWithAddressSpace(IntrinsicInst *II,
return nullptr;
}

bool NVPTXTTIImpl::isLegalMaskedStore(Type *DataTy, Align Alignment,
unsigned AddrSpace,
bool IsMaskConstant) const {

if (!IsMaskConstant)
return false;

// We currently only support this feature for 256-bit vectors, so the
// alignment must be at least 32
if (Alignment < 32)
return false;

if (!ST->has256BitVectorLoadStore(AddrSpace))
return false;

auto *VTy = dyn_cast<FixedVectorType>(DataTy);
if (!VTy)
return false;

auto *ScalarTy = VTy->getScalarType();
if ((ScalarTy->getScalarSizeInBits() == 32 && VTy->getNumElements() == 8) ||
(ScalarTy->getScalarSizeInBits() == 64 && VTy->getNumElements() == 4))
return true;

return false;
}

unsigned NVPTXTTIImpl::getLoadStoreVecRegBitWidth(unsigned AddrSpace) const {
// 256 bit loads/stores are currently only supported for global address space
if (ST->has256BitVectorLoadStore(AddrSpace))
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ class NVPTXTTIImpl final : public BasicTTIImplBase<NVPTXTTIImpl> {
bool collectFlatAddressOperands(SmallVectorImpl<int> &OpIndexes,
Intrinsic::ID IID) const override;

bool isLegalMaskedStore(Type *DataType, Align Alignment, unsigned AddrSpace,
bool IsMaskConstant) const override;

unsigned getLoadStoreVecRegBitWidth(unsigned AddrSpace) const override;

Value *rewriteIntrinsicWithAddressSpace(IntrinsicInst *II, Value *OldV,
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,8 @@ class RISCVTTIImpl final : public BasicTTIImplBase<RISCVTTIImpl> {
return isLegalMaskedLoadStore(DataType, Alignment);
}
bool isLegalMaskedStore(Type *DataType, Align Alignment,
unsigned /*AddressSpace*/) const override {
unsigned /*AddressSpace*/,
bool /*IsMaskConstant*/) const override {
return isLegalMaskedLoadStore(DataType, Alignment);
}

Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/VE/VETargetTransformInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ class VETTIImpl final : public BasicTTIImplBase<VETTIImpl> {
return isVectorLaneType(*getLaneType(DataType));
}
bool isLegalMaskedStore(Type *DataType, Align Alignment,
unsigned /*AddressSpace*/) const override {
unsigned /*AddressSpace*/,
bool /*IsMaskConstant*/) const override {
return isVectorLaneType(*getLaneType(DataType));
}
bool isLegalMaskedGather(Type *DataType, Align Alignment) const override {
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/X86/X86TargetTransformInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6330,7 +6330,8 @@ bool X86TTIImpl::isLegalMaskedLoad(Type *DataTy, Align Alignment,
}

bool X86TTIImpl::isLegalMaskedStore(Type *DataTy, Align Alignment,
unsigned AddressSpace) const {
unsigned AddressSpace,
bool IsMaskConstant) const {
Type *ScalarTy = DataTy->getScalarType();

// The backend can't handle a single element vector w/o CFCMOV.
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/X86/X86TargetTransformInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,8 @@ class X86TTIImpl final : public BasicTTIImplBase<X86TTIImpl> {
bool isLegalMaskedLoad(Type *DataType, Align Alignment,
unsigned AddressSpace) const override;
bool isLegalMaskedStore(Type *DataType, Align Alignment,
unsigned AddressSpace) const override;
unsigned AddressSpace,
bool IsMaskConstant = false) const override;
bool isLegalNTLoad(Type *DataType, Align Alignment) const override;
bool isLegalNTStore(Type *DataType, Align Alignment) const override;
bool isLegalBroadcastLoad(Type *ElementTy,
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Transforms/Scalar/ScalarizeMaskedMemIntrin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1137,7 +1137,8 @@ static bool optimizeCallInst(CallInst *CI, bool &ModifiedDT,
CI->getArgOperand(0)->getType(),
cast<ConstantInt>(CI->getArgOperand(2))->getAlignValue(),
cast<PointerType>(CI->getArgOperand(1)->getType())
->getAddressSpace()))
->getAddressSpace(),
isConstantIntVector(CI->getArgOperand(3))))
return false;
scalarizeMaskedStore(DL, HasBranchDivergence, CI, DTU, ModifiedDT);
return true;
Expand Down
56 changes: 56 additions & 0 deletions llvm/test/CodeGen/NVPTX/masked-store-variable-mask.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
; RUN: llc < %s -march=nvptx64 -mcpu=sm_100 -mattr=+ptx88 | FileCheck %s -check-prefixes=CHECK
; RUN: %if ptxas %{ llc < %s -march=nvptx64 -mcpu=sm_100 -mattr=+ptx88 | %ptxas-verify -arch=sm_100 %}

; Confirm that a masked store with a variable mask is scalarized before lowering

define void @global_variable_mask(ptr addrspace(1) %a, ptr addrspace(1) %b, <4 x i1> %mask) {
; CHECK-LABEL: global_variable_mask(
; CHECK: {
; CHECK-NEXT: .reg .pred %p<9>;
; CHECK-NEXT: .reg .b16 %rs<9>;
; CHECK-NEXT: .reg .b64 %rd<7>;
; CHECK-EMPTY:
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: ld.param.b8 %rs1, [global_variable_mask_param_2+3];
; CHECK-NEXT: ld.param.b8 %rs3, [global_variable_mask_param_2+2];
; CHECK-NEXT: and.b16 %rs4, %rs3, 1;
; CHECK-NEXT: ld.param.b8 %rs5, [global_variable_mask_param_2+1];
; CHECK-NEXT: and.b16 %rs6, %rs5, 1;
; CHECK-NEXT: setp.ne.b16 %p2, %rs6, 0;
; CHECK-NEXT: ld.param.b8 %rs7, [global_variable_mask_param_2];
; CHECK-NEXT: and.b16 %rs8, %rs7, 1;
; CHECK-NEXT: setp.ne.b16 %p1, %rs8, 0;
; CHECK-NEXT: ld.param.b64 %rd5, [global_variable_mask_param_1];
; CHECK-NEXT: ld.param.b64 %rd6, [global_variable_mask_param_0];
; CHECK-NEXT: ld.global.v4.b64 {%rd1, %rd2, %rd3, %rd4}, [%rd6];
; CHECK-NEXT: not.pred %p5, %p1;
; CHECK-NEXT: @%p5 bra $L__BB0_2;
; CHECK-NEXT: // %bb.1: // %cond.store
; CHECK-NEXT: st.global.b64 [%rd5], %rd1;
; CHECK-NEXT: $L__BB0_2: // %else
; CHECK-NEXT: and.b16 %rs2, %rs1, 1;
; CHECK-NEXT: setp.ne.b16 %p3, %rs4, 0;
; CHECK-NEXT: not.pred %p6, %p2;
; CHECK-NEXT: @%p6 bra $L__BB0_4;
; CHECK-NEXT: // %bb.3: // %cond.store1
; CHECK-NEXT: st.global.b64 [%rd5+8], %rd2;
; CHECK-NEXT: $L__BB0_4: // %else2
; CHECK-NEXT: setp.ne.b16 %p4, %rs2, 0;
; CHECK-NEXT: not.pred %p7, %p3;
; CHECK-NEXT: @%p7 bra $L__BB0_6;
; CHECK-NEXT: // %bb.5: // %cond.store3
; CHECK-NEXT: st.global.b64 [%rd5+16], %rd3;
; CHECK-NEXT: $L__BB0_6: // %else4
; CHECK-NEXT: not.pred %p8, %p4;
; CHECK-NEXT: @%p8 bra $L__BB0_8;
; CHECK-NEXT: // %bb.7: // %cond.store5
; CHECK-NEXT: st.global.b64 [%rd5+24], %rd4;
; CHECK-NEXT: $L__BB0_8: // %else6
; CHECK-NEXT: ret;
%a.load = load <4 x i64>, ptr addrspace(1) %a
tail call void @llvm.masked.store.v4i64.p1(<4 x i64> %a.load, ptr addrspace(1) %b, i32 32, <4 x i1> %mask)
ret void
}

declare void @llvm.masked.store.v4i64.p1(<4 x i64>, ptr addrspace(1), i32, <4 x i1>)
Loading
Loading