Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Neboat/strandpure #16

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
17 changes: 17 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ def BlocksSupported : LangOpt<"Blocks">;
def ObjCAutoRefCount : LangOpt<"ObjCAutoRefCount">;
def ObjCNonFragileRuntime : LangOpt<"ObjCNonFragileRuntime",
"LangOpts.ObjCRuntime.allowsClassStubs()">;
def Cilk : LangOpt<"Cilk", "LangOpts.getCilk() != LangOptions::Cilk_none">;

// Language option for CMSE extensions
def Cmse : LangOpt<"Cmse">;
Expand Down Expand Up @@ -3285,3 +3286,19 @@ def ObjCExternallyRetained : InheritableAttr {
let Subjects = SubjectList<[NonParmVar, Function, Block, ObjCMethod]>;
let Documentation = [ObjCExternallyRetainedDocs];
}

// Cilk attributes

// TODO: Add docs to these attributes

def Stealable : InheritableAttr {
let Spellings = [Clang<"stealable">];
let Subjects = SubjectList<[FunctionLike]>;
let Documentation = [StealableDocs];
}

def StrandPure : InheritableAttr {
let Spellings = [Clang<"strand_pure">];
let Subjects = SubjectList<[FunctionLike]>;
let Documentation = [StrandPureDocs];
}
18 changes: 17 additions & 1 deletion clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -4194,4 +4194,20 @@ be accessed on both device side and host side. It has external linkage and is
not initialized on device side. It has internal linkage and is initialized by
the initializer on host side.
}];
}
}

def StrandPureDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
The ``strand_pure`` attribute denotes that the function acts like a pure function
when called multiple times within the same strand.
}];
}

def StealableDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
The ``stealable`` attribute denotes that the function contains a continuation that
can be stolen by a work-stealing scheduler.
}];
}
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1846,6 +1846,8 @@ void CodeGenModule::ConstructAttributeList(
FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate);
if (TargetDecl->hasAttr<ConvergentAttr>())
FuncAttrs.addAttribute(llvm::Attribute::Convergent);
if (TargetDecl->hasAttr<StealableAttr>())
FuncAttrs.addAttribute(llvm::Attribute::Stealable);

if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
AddAttributesFromFunctionProtoType(
Expand All @@ -1867,6 +1869,10 @@ void CodeGenModule::ConstructAttributeList(
} else if (TargetDecl->hasAttr<NoAliasAttr>()) {
FuncAttrs.addAttribute(llvm::Attribute::ArgMemOnly);
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
} else if (TargetDecl->hasAttr<StrandPureAttr>()) {
FuncAttrs.addAttribute(llvm::Attribute::StrandPure);
FuncAttrs.addAttribute(llvm::Attribute::ReadOnly);
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
}
if (TargetDecl->hasAttr<RestrictAttr>())
RetAttrs.addAttribute(llvm::Attribute::NoAlias);
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,14 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
}
}

// Add Cilk attributes
if (D && (getLangOpts().getCilk() != LangOptions::Cilk_none)) {
if (D->getAttr<StrandPureAttr>())
Fn->setStrandPure();
if (D->getAttr<StealableAttr>())
Fn->addFnAttr(llvm::Attribute::Stealable);
}

// Add no-jump-tables value.
Fn->addFnAttr("no-jump-tables",
llvm::toStringRef(CGM.getCodeGenOpts().NoUseJumpTables));
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7341,6 +7341,14 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_MSAllocator:
handleMSAllocatorAttr(S, D, AL);
break;

// Cilk attributes
case ParsedAttr::AT_StrandPure:
handleSimpleAttribute<StrandPureAttr>(S, D, AL);
break;
case ParsedAttr::AT_Stealable:
handleSimpleAttribute<StealableAttr>(S, D, AL);
break;
}
}

Expand Down
5 changes: 3 additions & 2 deletions clang/test/CodeGenCXX/auto-var-init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1042,8 +1042,9 @@ TEST_UNINIT(intptr4, int*[4]);
// CHECK: %uninit = alloca [4 x i32*], align
// CHECK-NEXT: call void @{{.*}}used{{.*}}%uninit)
// PATTERN-O1-LABEL: @test_intptr4_uninit()
// PATTERN-O1: %1 = bitcast [4 x i32*]* %uninit to i8*
// PATTERN-O1-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull align 16 %1, i8 -86, i64 32, i1 false)
// PATTERN-O1: %0 = bitcast [4 x i32*]* %uninit to i8*
// PATTERN-O1-NEXT: call void @llvm.lifetime.start.p0i8(i64 32, i8* nonnull %0)
// PATTERN-O1-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull align 16 %0, i8 -86, i64 32, i1 false)
// ZERO-LABEL: @test_intptr4_uninit()
// ZERO: call void @llvm.memset{{.*}}, i8 0,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@
// CHECK-NEXT: Section (SubjectMatchRule_function, SubjectMatchRule_variable_is_global, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property)
// CHECK-NEXT: SetTypestate (SubjectMatchRule_function_is_member)
// CHECK-NEXT: SpeculativeLoadHardening (SubjectMatchRule_function, SubjectMatchRule_objc_method)
// CHECK-NEXT: Stealable (SubjectMatchRule_hasType_functionType)
// CHECK-NEXT: StrandPure (SubjectMatchRule_hasType_functionType)
// CHECK-NEXT: SwiftContext (SubjectMatchRule_variable_is_parameter)
// CHECK-NEXT: SwiftErrorResult (SubjectMatchRule_variable_is_parameter)
// CHECK-NEXT: SwiftIndirectResult (SubjectMatchRule_variable_is_parameter)
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/Bitcode/LLVMBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,7 @@ enum AttributeKindCodes {
ATTR_KIND_SANITIZE_MEMTAG = 64,
ATTR_KIND_SANITIZE_CILK = 65,
ATTR_KIND_STEALABLE = 66,
ATTR_KIND_STRAND_PURE = 67,
};

enum ComdatSelectionKindCodes {
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/IR/Attributes.td
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ def StackProtectReq : EnumAttr<"sspreq">;
/// Strong Stack protection.
def StackProtectStrong : EnumAttr<"sspstrong">;

/// Multiple calls to this function in a strand return the same result.
def StrandPure : EnumAttr<"strand_pure">;

/// Function was called in a scope requiring strict floating point semantics.
def StrictFP : EnumAttr<"strictfp">;

Expand Down
8 changes: 8 additions & 0 deletions llvm/include/llvm/IR/Function.h
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,14 @@ class Function : public GlobalObject, public ilist_node<Function> {
addFnAttr(Attribute::Speculatable);
}

/// Determine if the call is pure within a strand.
bool isStrandPure() const {
return hasFnAttribute(Attribute::StrandPure);
}
void setStrandPure() {
addFnAttr(Attribute::StrandPure);
}

/// Determine if the call might deallocate memory.
bool doesNotFreeMemory() const {
return onlyReadsMemory() || hasFnAttribute(Attribute::NoFree);
Expand Down
9 changes: 9 additions & 0 deletions llvm/include/llvm/IR/InstrTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1700,6 +1700,15 @@ class CallBase : public Instruction {
removeAttribute(AttributeList::FunctionIndex, Attribute::Convergent);
}

/// Determine if the call or invoke is strand-pure.
bool isStrandPure() const { return hasFnAttr(Attribute::StrandPure); }
void setStrandPure() {
addAttribute(AttributeList::FunctionIndex, Attribute::StrandPure);
}
void setNotStrandPure() {
removeAttribute(AttributeList::FunctionIndex, Attribute::StrandPure);
}

/// Determine if the call returns a structure through first
/// pointer argument.
bool hasStructRetAttr() const {
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Analysis/AliasSetTracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ void AliasSetTracker::add(Instruction *I) {

// Handle all calls with known mod/ref sets genericall
if (auto *Call = dyn_cast<CallBase>(I))
if (Call->onlyAccessesArgMemory()) {
if (Call->onlyAccessesArgMemory() || Call->isStrandPure()) {
auto getAccessFromModRef = [](ModRefInfo MRI) {
if (isRefSet(MRI) && isModSet(MRI))
return AliasSet::ModRefAccess;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/AsmParser/LLLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(sanitize_memory);
KEYWORD(speculative_load_hardening);
KEYWORD(stealable);
KEYWORD(strand_pure);
KEYWORD(swifterror);
KEYWORD(swiftself);
KEYWORD(uwtable);
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1323,6 +1323,9 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
B.addAttribute(Attribute::SpeculativeLoadHardening);
break;
case lltok::kw_stealable: B.addAttribute(Attribute::Stealable); break;
case lltok::kw_strand_pure:
B.addAttribute(Attribute::StrandPure);
break;
case lltok::kw_strictfp: B.addAttribute(Attribute::StrictFP); break;
case lltok::kw_uwtable: B.addAttribute(Attribute::UWTable); break;
case lltok::kw_willreturn: B.addAttribute(Attribute::WillReturn); break;
Expand Down Expand Up @@ -1684,6 +1687,7 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) {
case lltok::kw_safestack:
case lltok::kw_shadowcallstack:
case lltok::kw_stealable:
case lltok::kw_strand_pure:
case lltok::kw_strictfp:
case lltok::kw_uwtable:
HaveError |= Error(Lex.getLoc(), "invalid use of function-only attribute");
Expand Down Expand Up @@ -1785,6 +1789,7 @@ bool LLParser::ParseOptionalReturnAttrs(AttrBuilder &B) {
case lltok::kw_safestack:
case lltok::kw_shadowcallstack:
case lltok::kw_stealable:
case lltok::kw_strand_pure:
case lltok::kw_strictfp:
case lltok::kw_uwtable:
HaveError |= Error(Lex.getLoc(), "invalid use of function-only attribute");
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/AsmParser/LLToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ enum Kind {
kw_sanitize_memory,
kw_speculative_load_hardening,
kw_stealable,
kw_strand_pure,
kw_strictfp,
kw_swifterror,
kw_swiftself,
Expand Down
8 changes: 7 additions & 1 deletion llvm/lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1305,6 +1305,9 @@ static uint64_t getRawAttributeMask(Attribute::AttrKind Val) {
case Attribute::Stealable:
llvm_unreachable("stealable attribute not supported in raw format");
break;
case Attribute::StrandPure:
llvm_unreachable("strand_pure attribute not supported in raw format");
break;
}
llvm_unreachable("Unsupported attribute type");
}
Expand All @@ -1321,7 +1324,8 @@ static void addRawAttributeValue(AttrBuilder &B, uint64_t Val) {
I == Attribute::AllocSize ||
I == Attribute::NoSync ||
I == Attribute::SanitizeCilk ||
I == Attribute::Stealable)
I == Attribute::Stealable ||
I == Attribute::StrandPure)
continue;
if (uint64_t A = (Val & getRawAttributeMask(I))) {
if (I == Attribute::Alignment)
Expand Down Expand Up @@ -1520,6 +1524,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::ShadowCallStack;
case bitc::ATTR_KIND_STEALABLE:
return Attribute::Stealable;
case bitc::ATTR_KIND_STRAND_PURE:
return Attribute::StrandPure;
case bitc::ATTR_KIND_STRICT_FP:
return Attribute::StrictFP;
case bitc::ATTR_KIND_STRUCT_RET:
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_SHADOWCALLSTACK;
case Attribute::Stealable:
return bitc::ATTR_KIND_STEALABLE;
case Attribute::StrandPure:
return bitc::ATTR_KIND_STRAND_PURE;
case Attribute::StrictFP:
return bitc::ATTR_KIND_STRICT_FP;
case Attribute::StructRet:
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/IR/Attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
return "shadowcallstack";
if (hasAttribute(Attribute::Stealable))
return "stealable";
if (hasAttribute(Attribute::StrandPure))
return "strand_pure";
if (hasAttribute(Attribute::StrictFP))
return "strictfp";
if (hasAttribute(Attribute::StructRet))
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/IR/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1537,6 +1537,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) {
case Attribute::SpeculativeLoadHardening:
case Attribute::Speculatable:
case Attribute::Stealable:
case Attribute::StrandPure:
case Attribute::StrictFP:
return true;
default:
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Passes/PassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,8 @@ ModulePassManager PassBuilder::buildModuleOptimizationPipeline(
convertSwitchToLookupTable(true).
needCanonicalLoops(false).
sinkCommonInsts(true)));
// Rerun EarlyCSE for further cleanup after the sinking transformation.
OptimizePM.addPass(EarlyCSEPass(true /* Enable mem-ssa. */));

// Optimize parallel scalar instruction chains into SIMD instructions.
if (PTO.SLPVectorization)
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ static Attribute::AttrKind parseAttrKind(StringRef Kind) {
.Case("sspreq", Attribute::StackProtectReq)
.Case("sspstrong", Attribute::StackProtectStrong)
.Case("stealable", Attribute::Stealable)
.Case("strand_pure", Attribute::StrandPure)
.Case("strictfp", Attribute::StrictFP)
.Case("uwtable", Attribute::UWTable)
.Default(Attribute::None);
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Transforms/IPO/PassManagerBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,8 @@ void PassManagerBuilder::populateModulePassManager(
// before SLP vectorization.
MPM.add(createTaskSimplifyPass());
MPM.add(createCFGSimplificationPass(1, true, true, false, true));
// Rerun EarlyCSE for further cleanup after the sinking transformation.
MPM.add(createEarlyCSEPass(true /* Enable mem-ssa. */));

if (SLPVectorize) {
MPM.add(createSLPVectorizerPass()); // Vectorize parallel scalar chains.
Expand Down
11 changes: 10 additions & 1 deletion llvm/lib/Transforms/Scalar/LICM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1150,7 +1150,8 @@ bool llvm::canSinkOrHoistInst(Instruction &I, AAResults *AA, DominatorTree *DT,
// A readonly argmemonly function only reads from memory pointed to by
// it's arguments with arbitrary offsets. If we can prove there are no
// writes to this memory in the loop, we can hoist or sink.
if (AliasAnalysis::onlyAccessesArgPointees(Behavior)) {
if (AliasAnalysis::onlyAccessesArgPointees(Behavior) ||
CI->isStrandPure()) {
// TODO: expand to writeable arguments
for (Value *Op : CI->arg_operands())
if (Op->getType()->isPointerTy()) {
Expand Down Expand Up @@ -1705,6 +1706,14 @@ static bool isSafeToExecuteUnconditionally(Instruction &Inst,
if (isSafeToSpeculativelyExecute(&Inst, CtxI, DT))
return true;

if (CtxI)
if (const CallBase *CB = dyn_cast<CallBase>(&Inst)) {
const Function *Callee = CB->getCalledFunction();
if (Callee && Callee->isStrandPure())
return (TI->getSpindleFor(Inst.getParent()) ==
TI->getSpindleFor(CtxI->getParent()));
}

bool GuaranteedToExecute =
SafetyInfo->isGuaranteedToExecute(Inst, DT, TI, CurLoop);

Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Transforms/Utils/CodeExtractor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
case Attribute::NoCfCheck:
case Attribute::SanitizeCilk:
case Attribute::Stealable:
case Attribute::StrandPure:
break;
}

Expand Down
1 change: 1 addition & 0 deletions llvm/test/Other/new-pm-defaults.ll
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@
; CHECK-O-NEXT: Running pass: InstCombinePass
; CHECK-O-NEXT: Running pass: TaskSimplifyPass
; CHECK-O-NEXT: Running pass: SimplifyCFGPass
; CHECK-O-NEXT: Running pass: EarlyCSEPass
; CHECK-O-NEXT: Running pass: InstCombinePass
; CHECK-O-NEXT: Running pass: LoopUnrollPass
; CHECK-O-NEXT: Running pass: WarnMissedTransformationsPass
Expand Down
1 change: 1 addition & 0 deletions llvm/test/Other/new-pm-thinlto-defaults.ll
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@
; CHECK-POSTLINK-O-NEXT: Running pass: InstCombinePass
; CHECK-POSTLINK-O-NEXT: Running pass: TaskSimplifyPass
; CHECK-POSTLINK-O-NEXT: Running pass: SimplifyCFGPass
; CHECK-POSTLINK-O-NEXT: Running pass: EarlyCSEPass
; CHECK-POSTLINK-O-NEXT: Running pass: InstCombinePass
; CHECK-POSTLINK-O-NEXT: Running pass: LoopUnrollPass
; CHECK-POSTLINK-O-NEXT: Running pass: WarnMissedTransformationsPass
Expand Down
4 changes: 4 additions & 0 deletions llvm/test/Other/opt-O2-pipeline.ll
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,10 @@
; CHECK-NEXT: Simplify Tapir tasks
; CHECK-NEXT: Simplify the CFG
; CHECK-NEXT: Dominator Tree Construction
; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
; CHECK-NEXT: Function Alias Analysis Results
; CHECK-NEXT: Memory SSA
; CHECK-NEXT: Early CSE w/ MemorySSA
; CHECK-NEXT: Natural Loop Information
; CHECK-NEXT: Scalar Evolution Analysis
; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
Expand Down
4 changes: 4 additions & 0 deletions llvm/test/Other/opt-O3-pipeline.ll
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,10 @@
; CHECK-NEXT: Simplify Tapir tasks
; CHECK-NEXT: Simplify the CFG
; CHECK-NEXT: Dominator Tree Construction
; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
; CHECK-NEXT: Function Alias Analysis Results
; CHECK-NEXT: Memory SSA
; CHECK-NEXT: Early CSE w/ MemorySSA
; CHECK-NEXT: Natural Loop Information
; CHECK-NEXT: Scalar Evolution Analysis
; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
Expand Down
4 changes: 4 additions & 0 deletions llvm/test/Other/opt-Os-pipeline.ll
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,10 @@
; CHECK-NEXT: Simplify Tapir tasks
; CHECK-NEXT: Simplify the CFG
; CHECK-NEXT: Dominator Tree Construction
; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
; CHECK-NEXT: Function Alias Analysis Results
; CHECK-NEXT: Memory SSA
; CHECK-NEXT: Early CSE w/ MemorySSA
; CHECK-NEXT: Natural Loop Information
; CHECK-NEXT: Scalar Evolution Analysis
; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/Transforms/LoopVectorize/X86/metadata-enable.ll
Original file line number Diff line number Diff line change
Expand Up @@ -1856,7 +1856,7 @@ define i32 @disabled(i32* noalias nocapture %a, i32* noalias nocapture readonly
; O3DEFAULT-NEXT: [[TMP48:%.*]] = add nsw <4 x i32> [[TMP47]], [[TMP3]]
; O3DEFAULT-NEXT: [[TMP49:%.*]] = bitcast i32* [[ARRAYIDX2_44]] to <4 x i32>*
; O3DEFAULT-NEXT: store <4 x i32> [[TMP48]], <4 x i32>* [[TMP49]], align 4
; O3DEFAULT-NEXT: [[TMP50:%.*]] = load i32, i32* [[A]], align 4
; O3DEFAULT-NEXT: [[TMP50:%.*]] = extractelement <4 x i32> [[TMP4]], i32 0
; O3DEFAULT-NEXT: ret i32 [[TMP50]]
;
; Os-LABEL: @disabled(
Expand Down
Loading