Commit Graph

164 Commits

Author SHA1 Message Date
Andrea Di Biagio
c19db3b1d5 [llvm-mca][BtVer2] teach how to identify false dependencies on partially written
registers.

The goal of this patch is to improve the throughput analysis in llvm-mca for the
case where instructions perform partial register writes.

On x86, partial register writes are quite difficult to model, mainly because
different processors tend to implement different register merging schemes in
hardware.

When the code contains partial register writes, the IPC (instructions per
cycles) estimated by llvm-mca tends to diverge quite significantly from the
observed IPC (using perf).

Modern AMD processors (at least, from Bulldozer onwards) don't rename partial
registers. Quoting Agner Fog's microarchitecture.pdf:
" The processor always keeps the different parts of an integer register together.
For example, AL and AH are not treated as independent by the out-of-order
execution mechanism. An instruction that writes to part of a register will
therefore have a false dependence on any previous write to the same register or
any part of it."

This patch is a first important step towards improving the analysis of partial
register updates. It changes the semantic of RegisterFile descriptors in
tablegen, and teaches llvm-mca how to identify false dependences in the presence
of partial register writes (for more details: see the new code comments in
include/Target/TargetSchedule.h - class RegisterFile).

This patch doesn't address the case where a write to a part of a register is
followed by a read from the whole register.  On Intel chips, high8 registers
(AH/BH/CH/DH)) can be stored in separate physical registers. However, a later
(dirty) read of the full register (example: AX/EAX) triggers a merge uOp, which
adds extra latency (and potentially affects the pipe usage).
This is a very interesting article on the subject with a very informative answer
from Peter Cordes:
https://stackoverflow.com/questions/45660139/how-exactly-do-partial-registers-on-haswell-skylake-perform-writing-al-seems-to

In future, the definition of RegisterFile can be extended with extra information
that may be used to identify delays caused by merge opcodes triggered by a dirty
read of a partial write.

Differential Revision: https://reviews.llvm.org/D49196

llvm-svn: 337123
2018-07-15 11:01:38 +00:00
Matt Davis
7599dd7f50 [llvm-mca] Turn InstructionTables into a Stage.
Summary:
This patch converts the InstructionTables class into a subclass of mca::Stage.  This change allows us to use the Stage's inherited Listeners for event notifications.  This also allows us to create a simple pipeline for viewing the InstructionTables report.

I have been working on a follow on patch that should cleanup addView in InstructionTables.  Right now, addView adds the view to both the Listener list and Views list.  The follow-on patch addresses the fact that we don't really need two lists in this case.  That change is not specific to just InstructionTables, so it will be a separate patch. 

Reviewers: andreadb, courbet, RKSimon

Reviewed By: andreadb

Subscribers: tschuett, gbedwell, llvm-commits

Differential Revision: https://reviews.llvm.org/D49329

llvm-svn: 337113
2018-07-14 23:52:50 +00:00
Matt Davis
4391ce3837 [llvm-mca] Remove unused InstRef formal from pre and post execute callbacks. NFC.
llvm-svn: 337077
2018-07-14 00:10:42 +00:00
Andrea Di Biagio
642e2e539c [llvm-mca] Improve a few debug prints. NFC
llvm-svn: 337003
2018-07-13 14:55:47 +00:00
Andrea Di Biagio
2c65d72a0f [llvm-mca] Simplify the Pipeline constructor. NFC
llvm-svn: 336984
2018-07-13 09:31:02 +00:00
Andrea Di Biagio
3af21f0841 [llvm-mca] Removed unused arguments from methods in class Pipeline. NFC
llvm-svn: 336983
2018-07-13 09:27:34 +00:00
Matt Davis
bcf4db053e [llvm-mca] Constify SourceMgr::hasNext. NFC.
llvm-svn: 336961
2018-07-12 23:19:30 +00:00
Matt Davis
3de6f07d48 [llvm-mca] Add cycleBegin/cycleEnd callbacks to mca::Stage.
Summary:
This patch  clears up some of the semantics within the Stage class.  Now, preExecute
can be called multiple times per simulated cycle.  Previously preExecute was
only called once per cycle, and postExecute could have been called multiple
times.

Now, cycleStart/cycleEnd are called only once per simulated cycle.
preExecute/postExecute can be called multiple times per cycle.  This
occurs because multiple execution events can occur during a single cycle.

When stages are executed (Pipeline::runCycle), the postExecute hook will
be called only if all Stages return a success from their 'execute' callback.

Reviewers: andreadb, courbet, RKSimon

Reviewed By: andreadb

Subscribers: tschuett, gbedwell, llvm-commits

Differential Revision: https://reviews.llvm.org/D49250

llvm-svn: 336959
2018-07-12 22:59:53 +00:00
Matt Davis
9919114951 [llvm-mca] Simplify eventing by adding an onEvent templated method.
Summary:
This patch eliminates some redundancy in iterating across Listeners for the
Instruction and Stall HWEvents, by introducing a template onEvent routine.
This change was suggested by @courbet in https://reviews.llvm.org/D48576.  I
 hope that this patch addresses that suggestion appropriately.  I do like this
change better than what we had previously.


Reviewers: andreadb, courbet, RKSimon

Reviewed By: andreadb, courbet

Subscribers: javed.absar, tschuett, gbedwell, llvm-commits, courbet

Differential Revision: https://reviews.llvm.org/D48672

llvm-svn: 336916
2018-07-12 16:56:17 +00:00
Andrea Di Biagio
e2a4194fea [llvm-mca] Use a different character to flag instructions with side-effects in the Instruction Info View. NFC
This makes easier to identify changes in the instruction info flags.  It also
helps spotting potential regressions similar to the one recently introduced at
r336728.

Using the same character to mark MayLoad/MayStore/HasSideEffects is problematic
for llvm-lit. When pattern matching substrings, llvm-lit consumes tabs and
spaces. A change in position of the flag marker may not trigger a test failure.

This patch only changes the character used for flag `hasSideEffects`. The reason
why I didn't touch other flags is because I want to avoid spamming the mailing
because of the massive diff due to the numerous tests affected by this change.

In future, each instruction flag should be associated with a different character
in the Instruction Info View.

llvm-svn: 336797
2018-07-11 12:44:44 +00:00
Andrea Di Biagio
aaaf1382f8 [llvm-mca] report an error if the assembly sequence contains an unsupported instruction.
This is a short-term fix for PR38093.
For now, we llvm::report_fatal_error if the instruction builder finds an
unsupported instruction in the instruction stream.

We need to revisit this fix once we start addressing PR38101.
Essentially, we need a better framework for error handling.

llvm-svn: 336543
2018-07-09 12:30:55 +00:00
Matt Davis
7464e6c913 [llvm-mca] Add HardwareUnit and Context classes.
This patch moves the construction of the default backend from llvm-mca.cpp and
into mca::Context. The Context class is responsible for holding ownership of
the simulated hardware components. These components are subclasses of
HardwareUnit. Right now the HardwareUnit is pretty bare-bones, but eventually
we might want to add some common functionality across all hardware components,
such as isReady() or something similar.

I have a feeling this patch will probably need some updates, but it's a start.
One thing I am not particularly fond of is the rather large interface for
createDefaultPipeline. That convenience routine takes a rather large set of
inputs from the llvm-mca driver, where many of those inputs are generated via
command line options.

One item I think we might want to change is the separating of ownership of
hardware components (owned by the context) and the pipeline (which owns
Stages). In short, a Pipeline owns Stages, a Context (currently) owns hardware.
The Pipeline's Stages make use of the components, and thus there is a lifetime
dependency generated. The components must outlive the pipeline. We could solve
this by having the Context also own the Pipeline, and not return a
unique_ptr<Pipeline>. Now that I think about it, I like that idea more.

Differential Revision: https://reviews.llvm.org/D48691

llvm-svn: 336456
2018-07-06 18:03:14 +00:00
Andrea Di Biagio
f4b2508e93 [llvm-mca] A write latency cannot be a negative value. NFC
llvm-svn: 336437
2018-07-06 13:46:10 +00:00
Andrea Di Biagio
46e908a592 [llvm-mca] improve the instruction issue logic implemented by the Scheduler.
This patch modifies the Scheduler heuristic used to select the next instruction
to issue to the pipelines.

The motivating example is test X86/BtVer2/add-sequence.s, for which llvm-mca
wrongly reported an estimated IPC of 1.50. According to perf, the actual IPC for
that test should have been ~2.00.
It turns out that an IPC of 2.00 for test add-sequence.s cannot possibly be
predicted by a Scheduler that only prioritizes instructions based on their
"age". A similar issue also affected test X86/BtVer2/dependent-pmuld-paddd.s,
for which llvm-mca wrongly estimated an IPC of 0.84 instead of an IPC of 1.00.

Instructions in the ReadyQueue are now ranked based on two factors:
 - The "age" of an instruction.
 - The number of unique users of writes associated with an instruction.

The new logic still prioritizes older instructions over younger instructions to
minimize the pressure on the reorder buffer. However, the number of users of an
instruction now also affects the overall rank. This potentially increases the
ability of the Scheduler to extract instruction level parallelism.  This patch
fixes the problem with the wrong IPC reported for test add-sequence.s and test
dependent-pmuld-paddd.s.

llvm-svn: 336420
2018-07-06 08:08:30 +00:00
Andrea Di Biagio
c51f4304c7 [llvm-mca] Fix RegisterFile debug prints. NFC
llvm-svn: 336367
2018-07-05 16:13:49 +00:00
Andrea Di Biagio
9758b05b3b [llvm-mca] Clear the content of map VariantDescriptors in InstrBuilder before we start analyzing a new CodeBlock. NFCI.
Different CodeBlocks don't overlap. The same MCInst cannot appear in more than
one code block because all blocks are instantiated before the simulation is run.

We should always clear the content of map VariantDescriptors before every
simulation, since VariantDescriptors cannot possibly store useful information
for the next blocks. It is also "safer" to clear its content because `MCInst*`
is used as the key type for map VariantDescriptors.

llvm-svn: 336142
2018-07-02 20:39:57 +00:00
Francis Visoiu Mistrih
bb4cf24f14 [MC] Error on a .zerofill directive in a non-virtual section
On darwin, all virtual sections have zerofill type, and having a
.zerofill directive in a non-virtual section is not allowed. Instead of
asserting, show a nicer error.

In order to use the equivalent of .zerofill in a non-virtual section,
the usage of .zero of .space is required.

This patch replaces the assert with an error.

Differential Revision: https://reviews.llvm.org/D48517

llvm-svn: 336127
2018-07-02 17:29:43 +00:00
Andrea Di Biagio
a5b30c5c97 [llvm-mca] Remove field HasReadAdvanceEntries from class ReadDescriptor.
This simplifies the logic that updates RAW dependencies in the DispatchStage.
There is no advantage in storing that flag in the ReadDescriptor; we should
simply rely on the call to `STI.getReadAdvanceCycles()` to obtain the
ReadAdvance cycles. If there are no read-advance entries, then method
`getReadAdvanceCycles()` quickly returns 0.

No functional change intended.

llvm-svn: 335977
2018-06-29 14:24:46 +00:00
Matt Davis
50390608b5 [llvm-mca] Delete Pipeline's copy ctor and assignement operator.
Prevent copying of the Pipeline.

llvm-svn: 335885
2018-06-28 17:33:24 +00:00
Andrea Di Biagio
e6cf14997b [llvm-mca] Use a WriteRef to describe register writes in class RegisterFile.
This patch introduces a new class named WriteRef. A WriteRef is used by the
RegisterFile to keep track of register definitions. Internally it wraps a
WriteState, as well as the source index of the defining instruction.

This patch allows the tool to propagate additional information to support future
analysis on data dependencies.

llvm-svn: 335867
2018-06-28 15:50:26 +00:00
Andrea Di Biagio
1a03456a00 [llvm-mca] Refactor method RegisterFile::collectWrites(). NFCI
Rather than calling std::find in a loop, just sort the vector and remove
duplicate entries at the end of the function.

Also, move the debug print at the end of the function, and query the
MCRegisterInfo to print register names rather than physreg IDs.

No functional change intended.

llvm-svn: 335837
2018-06-28 11:20:14 +00:00
Matt Davis
92f0c6b4ce [llvm-mca] Register listeners with stages; remove Pipeline dependency from Stage.
Summary:
This patch removes a few callbacks from Pipeline.  It comes at the cost of
registering Listeners with all Stages.  Not all stages need listeners or issue
callbacks, this registration is a bit redundant.  However, as we build-out the
API, this redundancy can disappear.

The main purpose here is to move callback code from the Pipeline and into the
stages that actually issue those callbacks. This removes the back-pointer to
the Pipeline that was put into a few Stage subclasses.

Reviewers: andreadb, courbet, RKSimon

Reviewed By: andreadb, courbet

Subscribers: tschuett, gbedwell, llvm-commits

Differential Revision: https://reviews.llvm.org/D48576

llvm-svn: 335748
2018-06-27 16:09:33 +00:00
Andrea Di Biagio
bb10807000 [llvm-mca] Avoid calling method update() on instructions that are already in the IS_READY state. NFCI
When promoting instructions from the wait queue to the ready queue, we should
check if an instruction has already reached the IS_READY state before
calling method update().

llvm-svn: 335722
2018-06-27 11:17:07 +00:00
Matt Davis
7c9f26f009 [llvm-mca] Add a comment to Stage::execute and fix a spelling error. NFC.
llvm-svn: 335697
2018-06-27 00:54:11 +00:00
Andrea Di Biagio
95b54979b5 [llvm-mca] Removed wrong NDEBUG guards introduced by my last commit.
This partially reverts r335589.

llvm-svn: 335592
2018-06-26 11:00:21 +00:00
Andrea Di Biagio
a58b32e07f [llvm-mca] Remove unused header files and correctly guard some include headers under NDEBUG. NFC
llvm-svn: 335589
2018-06-26 10:44:12 +00:00
Matt Davis
12a71b7b2e [llvm-mca] Rename Backend to Pipeline. NFC.
Summary:
This change renames the Backend and BackendPrinter to Pipeline and PipelinePrinter respectively. 
Variables and comments have also been updated to reflect this change.

The reason for this rename, is to be slightly more correct about what MCA is modeling.  MCA models a Pipeline, which implies some logical sequence of stages. 

Reviewers: andreadb, courbet, RKSimon

Reviewed By: andreadb, courbet

Subscribers: mgorny, javed.absar, tschuett, gbedwell, llvm-commits

Differential Revision: https://reviews.llvm.org/D48496

llvm-svn: 335496
2018-06-25 16:53:00 +00:00
Matt Davis
e6c725e139 [llvm-mca] Remove unnecessary include and forward decl in RCU. NFC.
The DispatchUnit is no longer a dependency of RCU, so this patch removes a
stale include and forward decl.  This patch also cleans up some comments.

llvm-svn: 335392
2018-06-22 21:35:26 +00:00
Andrea Di Biagio
fa489a9fd0 [llvm-mca] Remove redundant call. NFC
llvm-svn: 335368
2018-06-22 17:03:40 +00:00
Andrea Di Biagio
6a1ca757a7 [llvm-mca] Set the operand ID for implicit register reads/writes. NFC
Also, move the definition of InstRef at the end of Instruction.h to avoid a
forward declaration.

llvm-svn: 335363
2018-06-22 16:37:05 +00:00
Matt Davis
85ee56f371 [llvm-mca] Introduce a sequential container of Stages
Summary:
Remove explicit stages and introduce a list of stages.

A pipeline should be composed of an arbitrary list of stages, and not any
 predefined list of stages in the Backend.  The Backend should not know of any
 particular stage, rather it should only be concerned that it has a list of
 stages, and that those stages will fulfill the contract of what it means to be
 a Stage (namely pre/post/execute a given instruction).

For now, we leave the original set of stages defined in the Backend ctor;
however, I imagine these will be moved out at a later time.

This patch makes an adjustment to the semantics of Stage::isReady.
Specifically, what the Backend really needs to know is if a Stage has
unfinished work.  With that said, it is more appropriately renamed
Stage::hasWorkToComplete().  This change will clean up the check in
Backend::run(), allowing us to query each stage to see if there is unfinished
work, regardless of what subclass a stage might be.  I feel that this change
simplifies the semantics too, but that's a subjective statement.

Given how RetireStage and ExecuteStage handle data in their preExecute(), I've
had to change the order of Retire and Execute in our stage list.  Retire must
complete any of its preExecute actions before ExecuteStage's preExecute can
take control.  This is mainly because both stages utilize the RCU.  In the
meantime, I want to see if I can adjust that or remove that coupling.

Reviewers: andreadb, RKSimon, courbet

Reviewed By: andreadb

Subscribers: tschuett, gbedwell, llvm-commits

Differential Revision: https://reviews.llvm.org/D46907

llvm-svn: 335361
2018-06-22 16:17:26 +00:00
Andrea Di Biagio
371b1bd7b2 [llvm-mca] Updates comment in code, and remove some stale comments. NFC
Also, rename fields `TotalMappings` and `NumUsedMappings` in struct
RegisterMappingTracker into `NumPhysRegs` and `NumUsedPhysRegs`.

llvm-svn: 335219
2018-06-21 12:14:49 +00:00
Andrea Di Biagio
17e1fccadc [llvm-mca] use APint::operator[] to obtain the bit value. NFC
llvm-svn: 335131
2018-06-20 14:30:17 +00:00
Andrea Di Biagio
4893e095df [llvm-mca][X86] Teach how to identify register writes that implicitly clear the upper portion of a super-register.
This patch teaches llvm-mca how to identify register writes that implicitly zero
the upper portion of a super-register.

On X86-64, a general purpose register is implemented in hardware as a 64-bit
register. Quoting the Intel 64 Software Developer's Manual: "an update to the
lower 32 bits of a 64 bit integer register is architecturally defined to zero
extend the upper 32 bits".  Also, a write to an XMM register performed by an AVX
instruction implicitly zeroes the upper 128 bits of the aliasing YMM register.

This patch adds a new method named clearsSuperRegisters to the MCInstrAnalysis
interface to help identify instructions that implicitly clear the upper portion
of a super-register.  The rest of the patch teaches llvm-mca how to use that new
method to obtain the information, and update the register dependencies
accordingly.

I compared the kernels from tests clear-super-register-1.s and
clear-super-register-2.s against the output from perf on btver2.  Previously
there was a large discrepancy between the estimated IPC and the measured IPC.
Now the differences are mostly in the noise.

Differential Revision: https://reviews.llvm.org/D48225

llvm-svn: 335113
2018-06-20 10:08:11 +00:00
Matt Davis
8c00f4b3c2 [llvm-mca] Cleanup the header syntax line. Fix a comment. NFC.
This patch removes a few dashes from the header comment to make room for the syntax line.

llvm-svn: 334986
2018-06-18 21:38:38 +00:00
Andrea Di Biagio
f6e62b21be [llvm-mca] Use an ordered map to collect hardware statistics. NFC.
Histogram entries are now ordered by key.  This should improves their
readability when statistics are printed.

llvm-svn: 334961
2018-06-18 17:04:56 +00:00
Roman Lebedev
4ec9cfed2e [MCA] Add -summary-view option
Summary:
While that is indeed a quite interesting summary stat,
there are cases where it does not really add anything
other than consuming extra lines.

Declutters the output of D48190.

Reviewers: RKSimon, andreadb, courbet, craig.topper

Reviewed By: andreadb

Subscribers: javed.absar, gbedwell, llvm-commits

Differential Revision: https://reviews.llvm.org/D48209

llvm-svn: 334833
2018-06-15 14:01:43 +00:00
Matt Davis
e567892d10 [llvm-mca] Clean up the header comment. NFC.
This change removes a few dashes to make room for the header syntax string.

llvm-svn: 334770
2018-06-14 20:58:54 +00:00
Matt Davis
0594746649 [llvm-mca] Introduce the ExecuteStage (was originally the Scheduler class).
Summary: This patch transforms the Scheduler class into the ExecuteStage.  Most of the logic remains.  

Reviewers: andreadb, RKSimon, courbet

Reviewed By: andreadb

Subscribers: mgorny, javed.absar, tschuett, gbedwell, llvm-commits

Differential Revision: https://reviews.llvm.org/D47246

llvm-svn: 334679
2018-06-14 01:20:18 +00:00
Andrea Di Biagio
7cc34df875 [llvm-mca] Fixed a bug in the logic that checks if a memory operation is ready to execute.
Fixes PR37790.

In some (very rare) cases, the LSUnit (Load/Store unit) was wrongly marking a
load (or store) as "ready to execute" effectively bypassing older memory barrier
instructions.

To reproduce this bug, the memory barrier must be the first instruction in the
input assembly sequence, and it doesn't have to perform any register writes.

llvm-svn: 334633
2018-06-13 18:30:14 +00:00
Andrea Di Biagio
b297f1e738 Revert: [llvm-mca] Flush the output stream before we start the analysis of a new code region. NFC
Not sure why, but it breaks buildbot clang-cmake-armv8-full.
It causes a failure in TEST 'Xray-armhf-linux :: TestCases/Posix/profiling-single-threaded.cc'.

llvm-svn: 334617
2018-06-13 16:33:52 +00:00
Andrea Di Biagio
24185018fb [llvm-mca] Flush the output stream before we start the analysis of a new code region. NFC
llvm-svn: 334610
2018-06-13 15:43:56 +00:00
Andrea Di Biagio
0fae23f1ce [llvm-mca] Correctly update the CyclesLeft of a register read in the presence of partial register updates.
This patch fixe the logic in ReadState::cycleEvent(). That method was not
correctly updating field `TotalCycles`.

Added extra code comments in class ReadState to better describe each field.

llvm-svn: 334028
2018-06-05 17:12:02 +00:00
Andrea Di Biagio
8b4cab0d54 [RFC][patch 3/3] Add support for variant scheduling classes in llvm-mca.
This patch is the last of a sequence of three patches related to LLVM-dev RFC
"MC support for variant scheduling classes".
http://lists.llvm.org/pipermail/llvm-dev/2018-May/123181.html

This fixes PR36672.

The main goal of this patch is to teach llvm-mca how to solve variant scheduling
classes.  This patch does that, plus it adds new variant scheduling classes to
the BtVer2 scheduling model to identify so-called zero-idioms (i.e. so-called
dependency breaking instructions that are known to generate zero, and that are
optimized out in hardware at register renaming stage).

Without the BtVer2 change, this patch would not have had any meaningful tests.
This patch is effectively the union of two changes:
 1) a change that teaches llvm-mca how to resolve variant scheduling classes.
 2) a change to the BtVer2 scheduling model that allows us to special-case
    packed XOR zero-idioms (this partially fixes PR36671).

Differential Revision: https://reviews.llvm.org/D47374 

llvm-svn: 333909
2018-06-04 15:43:09 +00:00
Andrea Di Biagio
9cf08c77bf [llvm-mca] Track cycles contributed by resources that are in a 'Super' relationship.
This is required if we want to correctly match the behavior of method
SubtargetEmitter::ExpandProcResource() in Tablegen. When computing the set of
"consumed" processor resources and resource cycles, the logic in
ExpandProcResource() doesn't update the number of resource cycles contributed by
a "Super" resource to a group.  We need to take this into account when a model
declares a processor resource which is part of a 'processor resource group', and
it is also used as the "Super" of other resources.

llvm-svn: 333892
2018-06-04 12:23:07 +00:00
Andrea Di Biagio
0110f33d56 [llvm-mca] Move the logic that computes the block throughput into Support.h. NFC
This will allow us to share the logic that computes the block throughput with
other views.

llvm-svn: 333755
2018-06-01 14:35:21 +00:00
Andrea Di Biagio
93f3fc5db3 [llvm-mca] Fixed a problem caused by an invalid use of a processor resource mask in the Scheduler.
The lambda functions used by method ResourceManager::mustIssueImmediately() was
incorrectly truncating masks of buffered processor resources to 32-bit quantities.
The invalid mask values were then used to access a map of processor
resource descriptors.

Fixes PR37643.

llvm-svn: 333692
2018-05-31 20:27:46 +00:00
Matt Davis
d559fd8c73 [llvm-mca] Update the header's guard name. NFC.
This patch also places a comment at the end of the header guard.

llvm-svn: 333297
2018-05-25 18:45:43 +00:00
Matt Davis
3be2788247 [llvm-mca] Update DispatchStage header comment. NFC.
Updated the comment to be a wee bit more descriptive.

llvm-svn: 333296
2018-05-25 18:31:28 +00:00
Matt Davis
61885d41df [llvm-mca] Add the RetireStage.
Summary:
This class maintains the same logic as the original RetireControlUnit.

This is just an intermediate patch to make the RCU a Stage.  Future patches will remove the dependency on the DispatchStage, and then more properly populate the pre/execute/post Stage interface.  

Reviewers: andreadb, RKSimon, courbet

Reviewed By: andreadb, courbet

Subscribers: javed.absar, mgorny, tschuett, gbedwell, llvm-commits

Differential Revision: https://reviews.llvm.org/D47244

llvm-svn: 333292
2018-05-25 18:00:25 +00:00