1. Trang chủ
  2. » Công Nghệ Thông Tin

Advanced backend optimization pdf

385 67 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 385
Dung lượng 4,57 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Other chaptersprovide the latest research results in well-known topics such asinstruction scheduling and its relationship with machine schedulingtheory, register need, software pipelinin

Trang 1

With chapters on phase ordering in optimizing compilation, registersaturation in instruction level parallelism, code size reduction forsoftware pipelining, memory hierarchy effects in instruction-levelparallelism, and rigorous statistical performance analysis, it coversmaterial not previously covered by books in the field Other chaptersprovide the latest research results in well-known topics such asinstruction scheduling and its relationship with machine schedulingtheory, register need, software pipelining and periodic registerallocation

As such, Advanced Backend Code Optimization is particularly

appropriate for researchers, professors and high-level Master’s students

in computer science, as well as computer science engineers

Sid Touati is currently Professor at University Nice Sophia Antipolis in

France His research interests include code optimization and analysis forhigh performance and embedded processors, compilation and codegeneration, parallelism, statistics and performance optimization His

research activities are conducted at the Institut National de Recherche

en Informatique et Automatisme (INRIA) as well as at the Centre National de Recherche Scientifique (CNRS).

Benoit Dupont de Dinechin is currently a Chief Technology Officer for

Kalray in France He was formerly a researcher and engineer at microelectronics in the field of backend code optimization in theadvanced compilation team He has a PhD in computer science, in thesubject area of instruction scheduling for instruction level parallelism,and a computer engineering diploma

ST-Advanced Backend Code Optimization

Sid Touati Benoit Dupont de Dinechin

COMPUTER ENGINEERING SERIES

Trang 3

I am proud to be their son.

– Sid TOUATI

Trang 4

Advanced Backend Code Optimization

Sid Touati Benoit Dupont de Dinechin

Trang 5

Apart from any fair dealing for the purposes of research or private study, or criticism or review, as permitted under the Copyright, Designs and Patents Act 1988, this publication may only be reproduced, stored or transmitted, in any form or by any means, with the prior permission in writing of the publishers,

or in the case of reprographic reproduction in accordance with the terms and licenses issued by the CLA Enquiries concerning reproduction outside these terms should be sent to the publishers at the undermentioned address:

Library of Congress Control Number: 2014935739

British Library Cataloguing-in-Publication Data

A CIP record for this book is available from the British Library

ISBN 978-1-84821-538-2

Printed and bound in Great Britain by CPI Group (UK) Ltd., Croydon, Surrey CR0 4YY

Trang 6

INTRODUCTION xiii

PART1 PROLOG: OPTIMIZINGCOMPILATION 1

CHAPTER1 ON THEDECIDABILITY OFPHASE ORDERING INOPTIMIZINGCOMPILATION 3

1.1 Introduction to the phase ordering problem 3

1.2 Background on phase ordering 5

1.2.1 Performance modeling and prediction 5

1.2.2 Some attempts in phase ordering 6

1.3 Toward a theoretical model for the phase ordering problem 7

1.3.1 Decidability results 8

1.3.2 Another formulation of the phase ordering problem 11

1.4 Examples of decidable simplified cases 12

1.4.1 Models with compilation costs 12

1.4.2 One-pass generative compilers 13

1.5 Compiler optimization parameter space exploration 16

1.5.1 Toward a theoretical model 17

1.5.2 Examples of simplified decidable cases 19

1.6 Conclusion on phase ordering in optimizing compilation 20

PART2 INSTRUCTIONSCHEDULING 23

CHAPTER2 INSTRUCTIONSCHEDULINGPROBLEMS ANDOVERVIEW 25 2.1 VLIW instruction scheduling problems 25

2.1.1 Instruction scheduling and register allocation in a code generator 25 2.1.2 The block and pipeline VLIW instruction scheduling problems 27

2.2 Software pipelining 29

2.2.1 Cyclic, periodic and pipeline scheduling problems 29

Trang 7

2.2.2 Modulo instruction scheduling problems and techniques 32

2.3 Instruction scheduling and register allocation 35

2.3.1 Register instruction scheduling problem solving approaches 35

CHAPTER3 APPLICATIONS OFMACHINESCHEDULING TO INSTRUCTIONSCHEDULING 39

3.1 Advances in machine scheduling 39

3.1.1 Parallel machine scheduling problems 39

3.1.2 Parallel machine scheduling extensions and relaxations 41

3.2 List scheduling algorithms 43

3.2.1 List scheduling algorithms and list scheduling priorities 43

3.2.2 The scheduling algorithm of Leung, Palem and Pnueli 45

3.3 Time-indexed scheduling problem formulations 47

3.3.1 The non-preemptive time-indexed RCPSP formulation 47

3.3.2 Time-indexed formulation for the modulo RPISP 48

CHAPTER4 INSTRUCTIONSCHEDULINGBEFORE REGISTERALLOCATION 51

4.1 Instruction scheduling for an ILP processor: case of a VLIW architecture 51

4.1.1 Minimum cumulative register lifetime modulo scheduling 51

4.1.2 Resource modeling in instruction scheduling problems 54

4.1.3 The modulo insertion scheduling theorems 56

4.1.4 Insertion scheduling in a backend compiler 58

4.1.5 Example of an industrial production compiler from STMicroelectronics 60

4.1.6 Time-indexed formulation of the modulo RCISP 64

4.2 Large neighborhood search for the resource-constrained modulo scheduling problem 67

4.3 Resource-constrained modulo scheduling problem 68

4.3.1 Resource-constrained cyclic scheduling problems 68

4.3.2 Resource-constrained modulo scheduling problem statement 69

4.3.3 Solving resource-constrained modulo scheduling problems 70

4.4 Time-indexed integer programming formulations 71

4.4.1 The non-preemptive time-indexed RCPSP formulation 71

4.4.2 The classic modulo scheduling integer programming formulation 72 4.4.3 A new time-indexed formulation for modulo scheduling 73

4.5 Large neighborhood search heuristic 74

4.5.1 Variables and constraints in time-indexed formulations 74

4.5.2 A large neighborhood search heuristic for modulo scheduling 74

4.5.3 Experimental results with a production compiler 75

4.6 Summary and conclusions 76

Trang 8

CHAPTER5 INSTRUCTIONSCHEDULINGAFTER

REGISTERALLOCATION 77

5.1 Introduction 77

5.2 Local instruction scheduling 79

5.2.1 Acyclic instruction scheduling 79

5.2.2 Scoreboard Scheduling principles 80

5.2.3 Scoreboard Scheduling implementation 82

5.3 Global instruction scheduling 84

5.3.1 Postpass inter-region scheduling 84

5.3.2 Inter-block Scoreboard Scheduling 86

5.3.3 Characterization of fixed points 87

5.4 Experimental results 87

5.5 Conclusions 89

CHAPTER6 DEALING INPRACTICE WITHMEMORY HIERARCHYEFFECTS ANDINSTRUCTIONLEVEL PARALLELISM 91

6.1 The problem of hardware memory disambiguation at runtime 92

6.1.1 Introduction 92

6.1.2 Related work 93

6.1.3 Experimental environment 94

6.1.4 Experimentation methodology 95

6.1.5 Precise experimental study of memory hierarchy performance 95

6.1.6 The effectiveness of load/store vectorization 100

6.1.7 Conclusion on hardware memory disambiguation mechanisms 103

6.2 Data preloading and prefetching 104

6.2.1 Introduction 104

6.2.2 Related work 105

6.2.3 Problems of optimizing cache effects at the instruction level 107

6.2.4 Target processor description 109

6.2.5 Our method of instruction-level code optimization 110

6.2.6 Experimental results 116

6.2.7 Conclusion on prefetching and preloading at instruction level 117

PART3 REGISTEROPTIMIZATION 119

CHAPTER7 THEREGISTERNEED OF AFIXED INSTRUCTIONSCHEDULE 121

7.1 Data dependence graph and processor model for register optimization 122

7.1.1 NUAL and UAL semantics 122

7.2 The acyclic register need 123

7.3 The periodic register need 125

Trang 9

7.3.1 Software pipelining, periodic scheduling and cyclic scheduling 125

7.3.2 The circular lifetime intervals 127

7.4 Computing the periodic register need 129

7.5 Some theoretical results on the periodic register need 132

7.5.1 Minimal periodic register need versus initiation interval 133

7.5.2 Computing the periodic register sufficiency 133

7.5.3 Stage scheduling under register constraints 134

7.6 Conclusion on the register requirement 139

CHAPTER8 THEREGISTERSATURATION 141

8.1 Motivations on the register saturation concept 141

8.2 Computing the acyclic register saturation 144

8.2.1 Characterizing the register saturation 146

8.2.2 Efficient algorithmic heuristic for register saturation computation 149 8.2.3 Experimental efficiency of Greedy-k 151

8.3 Computing the periodic register saturation 153

8.3.1 Basic integer linear variables 154

8.3.2 Integer linear constraints 154

8.3.3 Linear objective function 156

8.4 Conclusion on the register saturation 157

CHAPTER9 SPILLCODEREDUCTION 159

9.1 Introduction to register constraints in software pipelining 159

9.2 Related work in periodic register allocation 160

9.3 SIRA: schedule independant register allocation 162

9.3.1 Reuse graphs 162

9.3.2 DDG associated with reuse graph 164

9.3.3 Exact SIRA with integer linear programming 166

9.3.4 SIRA with fixed reuse edges 168

9.4 SIRALINA: an efficient polynomial heuristic for SIRA 169

9.4.1 Integer variables for the linear problem 170

9.4.2 Step 1: the scheduling problem 170

9.4.3 Step 2: the linear assignment problem 172

9.5 Experimental results with SIRA 173

9.6 Conclusion on spill code reduction 175

CHAPTER10 EXPLOITING THEREGISTERACCESS DELAYSBEFOREINSTRUCTIONSCHEDULING 177

10.1 Introduction 177

10.2 Problem description of DDG circuits with non-positive distances 179

10.3 Necessary and sufficient condition to avoid non-positive circuits 180

10.4 Application to the SIRA framework 182

Trang 10

10.4.1 Recall on SIRALINA heuristic 183

10.4.2 Step 1: the scheduling problem for a fixed II 183

10.4.3 Step 2: the linear assignment problem 184

10.4.4 Eliminating non-positive circuits in SIRALINA 184

10.4.5 Updating reuse distances 186

10.5 Experimental results on eliminating non-positive circuits 187

10.6 Conclusion on non-positive circuit elimination 188

CHAPTER11 LOOPUNROLLINGDEGREEMINIMIZATION FORPERIODICREGISTERALLOCATION 191

11.1 Introduction 191

11.2 Background 195

11.2.1 Loop unrolling after SWP with modulo variable expansion 196

11.2.2 Meeting graphs (MG) 197

11.2.3 SIRA, reuse graphs and loop unrolling 200

11.3 Problem description of unroll factor minimization for unscheduled loops 204

11.4 Algorithmic solution for unroll factor minimization: single register type 205

11.4.1 Fixed loop unrolling problem 206

11.4.2 Solution for the fixed loop unrolling problem 207

11.4.3 Solution for LCM-MIN problem 209

11.5 Unroll factor minimization in the presence of multiple register types 213

11.5.1 Search space for minimal kernel loop unrolling 217

11.5.2 Generalization of the fixed loop unrolling problem in the presence of multiple register types 218

11.5.3 Algorithmic solution for the loop unrolling minimization (LUM, problem 11.1) 219

11.6 Unroll factor reduction for already scheduled loops 221

11.6.1 Improving algorithm 11.4 (LCM-MIN) for the meeting graph framework 224

11.7 Experimental results 224

11.8 Related work 226

11.8.1 Rotating register files 226

11.8.2 Inserting move operations 227

11.8.3 Loop unrolling after software pipelining 228

11.8.4 Code generation for multidimensional loops 228

11.9 Conclusion on loop unroll degree minimization 228

Trang 11

PART4 EPILOG: PERFORMANCE, OPENPROBLEMS 231

THESPEEDUP-TESTPROTOCOL 23312.1 Code performance variation 23312.2 Background and notations 23612.3 Analyzing the statistical significance of the observed speedups 23912.3.1 The speedup of the observed average execution time 23912.3.2 The speedup of the observed median execution time, as well asindividual runs 24112.4 The Speedup-Test software 24412.5 Evaluating the proportion of accelerated benchmarks by a confidenceinterval 24612.6 Experiments and applications 24812.6.1 Comparing the performances of compiler optimization

levels 24912.6.2 Testing the performances of parallel executions of OpenMP

applications 25012.6.3 Comparing the efficiency of two compilers 25112.6.4 The impact of the Speedup-Test protocol over some observedspeedups 25312.7 Related work 25312.7.1 Observing execution times variability 25312.7.2 Program performance evaluation in presence of variability 25412.8 Discussion and conclusion on the Speedup-Test protocol 255

APPENDIX 4 EFFICIENCY OF NON-POSITIVE CIRCUITELIMINATION

IN THESIRA FRAMEWORK 293

APPENDIX5 LOOPUNROLLDEGREEMINIMIZATION:

EXPERIMENTALRESULTS 303

Trang 12

APPENDIX6 EXPERIMENTALEFFICIENCY OFSOFTWARE

DATAPRELOADING ANDPREFETCHING FOREMBEDDEDVLIW 315

APPENDIX7 APPENDIX OF THESPEEDUP-TESTPROTOCOL 319

BIBLIOGRAPHY 327

LISTS OFFIGURES, TABLES ANDALGORITHMS 345

INDEX 353

Trang 14

An open question that remains in computer science is how to define a program

of good quality At the semantic level, a good program is one that computes what isspecified formally (either in an exact way, or even without an exact result but at leastheading towards making a right decision) At the algorithmic level, a good program

is one that has a reduced spatial and temporal complexity This book does not tacklethese two levels of program quality abstraction We are interested in the aspects ofcode quality at the compilation level (after a coding and an implementation of analgorithm) When a program has been implemented, some quality can be quantifiedaccording to its efficiency, for instance By the term “efficiency”, we mean a programthat exploits the underlying hardware at its best, delivers the correct results as quickly

as possible, has a reasonable memory footprint and a moderate energy consumption.There are also some quality criteria that are not easy to define, for instance the clarity

of the code and its aptitude for being analyzed conveniently by automatic methods(worst-case execution time, data-flow dependence analysis, etc.)

Automatic code optimization, in general, focuses on two objectives that are notnecessarily antagonists: the computation speed and the memory footprint of the code.These are the two principal quality criteria approached in this book The computationspeed is the most popular objective, but it remains difficult to model precisely In fact,the execution time of a program is influenced by a complex combination of multiplefactors, a list of which (probably incomplete) is given below:

1) The underlying processor and machine architecture: instruction set architecture(ISA), explicit instruction-level parallelism (very long instruction word – VLIW),memory addressing modes, data size, input/output protocols, etc

parallelism (superscalar), branch prediction, memory hierarchy, speculative execution,pipelined execution, memory disambiguation mechanism, out-of-order execution,register renaming, etc

Trang 15

3) The technology: clock frequency, processor fabrication, silicon integration,transistor wide, components (chipset, DRAM and bus), etc.

4) Software implementation: syntactic constructs of the code, used data structures,program instructions’ order, way of programming, etc

5) The data input: the executed path of the code depends on the input data.6) The experimental environment: operating system configuration and version,activated system services, used compiler and optimization flags, workload of the testmachine, degradation of the hardware, temperature of the room, etc

7) The measure of the code performance: experimental methodology (codeloading and launching), rigor of the statistical analysis, etc

All the above factors are difficult to tackle in the same optimization process Therole of the compiler is to optimize a fraction of them only (software implementationand its interaction with the underlying hardware) For a long time, compilation hasbeen considered as one of the most active research topics in computer science Itsimportance is not only in the field of programming, code generation and optimization,but also in circuit synthesis, language translation, interpreters, etc We are all witness

of the high number of new languages and processor architectures It is not worthwhile

to create a compiler for each combination of language and processor The core of

a compiler is asked to be common to multiple combinations between programminglanguages and processor architectures In the past, compiler backends were specializedper architecture Nowadays, backends are trying to be increasingly general in order tosave the investment cost of developing a compiler

In universities and schools, classes that teach compilation theory define clearfrontiers between frontend and backend:

1) High-level code optimization: this is the set of code transformations applied

on an intermediate representation close to the high-level language Such intermediaterepresentation contains sophisticated syntax constructs (loops and controls) with richsemantics, as well as high-level data structures (arrays, containers, etc.) Analyzingand optimizing at this level of program abstraction tends to improve the performancemetrics that are not related to a specific processor architecture Examples includeinterprocedural and data dependence analysis, automatic parallelization, scalar andarray privatization, loop nest transformations, alias analysis, etc

2) Low-level code optimization: this is the set of code transformations applied

to an intermediate representation close to the final instruction set of the processor(assembly instructions, three address codes, Register Transfer Level (RTL), etc.).The performance metrics optimized at this level of program abstraction are generallyrelated to the processor architecture: number of generated instructions, code size,instruction scheduling, register need, register allocation, register assignment, cacheoptimization, instruction selection, addressing modes, etc

Trang 16

The practice is not very attractive It is not rare to have a code transformationimplemented at frontend optimizing for a backend objective: for instance, cacheoptimization at a loop nest can be done at frontend because the high-level programstructure (loops) has yet to be destroyed Inversely, it is possible to have a high-levelanalysis implemented at assembly or as binary code, such as data dependence andinterprocedural analysis Compilers are very complex pieces of software that aremaintained for a long period of time, and the frontiers between high and low levelscan sometimes be difficult to define formally Nevertheless, the notion of frontendand backend optimization is not fundamental It is a technical decomposition ofcompilation mainly for easing the development of the compiler software.

We are interested in backend code optimization mainly due to a personalinclination towards hardware/software frontiers Even this barrier starts to leak withthe development of reconfigurable and programmable architectures, where compilersare asked to generate a part of the instruction set In this book, we have tried to be asabstract as possible in order to have general results applicable to wide processorfamilies (superscalar, VLIW, Explicitly Parallel Instruction Computing (EPIC), etc.).When the micro-architectural features are too complex to model, we providetechnical solutions for practical situations

I.1 Inside this book

This book is the outcome of a long period of research activity in academia andindustry We write fundamental results in terms of lemmas, definitions, theorems andcorollaries, and in terms of algorithms and heuristics We also provide an appendixthat contains some experimental results For future reproducibility, we have releasedmost of our experimental results in terms of documented software and numerical data.Although we did not include all of our mature research results in this book, wethink that we have succeeded in summarizing most of our efforts on backend codeoptimization In the following, we briefly describe the organization of this book.Section I.3, on basic recalls on instruction-level parallelism (ILP) in processorarchitectures, starts with explaining the difference between superscalar and VLIWarchitectures ILP processor architectures are widely covered in other books, so thissection will be a brief summary

Part 1: introduction to optimizing compilation

Chapter 1 is entitled “On the Decidability of Phase Ordering in OptimizingCompilation”: we have had long and sometimes painful experiences with codeoptimization of large and complex applications The obtained speedups, in practice,

Trang 17

are not always satisfactory when using usual compilation flags When iterativecompilation started to become a new trend in our field, we asked ourselves whethersuch methodologies may outperform static compilation: static compilation isdesigned for all possible data inputs, while iterative compilation chooses a data inputand therefore, it seems to simplify the problem We studied the decidability of phaseordering from the theoretical point of view in the context of iterativecompilation.

Part 2: instruction scheduling

This part of the book covers instruction scheduling in ILP The chapters of this part(Chapters 2–6) use the same notations, which are different from the notations used

in the following part The reason why the formal notations in this part are slightlydifferent from the notations of Part 3 is that the instruction scheduling problems arestrongly related to the theory of machine scheduling In this area of research, there aresome common and usual notations that we use in this part but not in Part 3

Chapter 2, entitled “Instruction Scheduling Problems and Overview”, is areminder of scheduling problems for ILP, and their relationship with registeroptimization Special attention is given to cyclic scheduling problems because theyare of importance for optimizing the performance of loops

Chapter 3, entitled “Applications of Machine Scheduling to InstructionScheduling”, is an interesting chapter that discusses the relationship betweentheoretical scheduling problems and practical instruction scheduling problems.Indeed, although instruction scheduling is a mature discipline, its relationship withthe field of machine scheduling is often ignored In this chapter, we show how thetheory of machine scheduling can be applied to instruction scheduling

Chapter 4, entitled “Instruction Scheduling before Register Allocation”, provides

a formal method and a practical implementation for cyclic instruction schedulingunder resource constraints The presented scheduling method is still sensitive toregister pressure

Chapter 5, entitled “Instruction Scheduling after Register Allocation”, presents apostpass register allocation method After an instruction scheduling, register allocationmay introduce spill code and may require making some instruction rescheduling Thischapter presents a faster technique suitable for just-in-time compilation

Chapter 6, entitled “Dealing in Practice with Memory Hierarchy Effects andInstruction-Level Parallelism”, studies the complex micro-architectural features from

Trang 18

a practical point of view First, we highlight the problem with memorydisambiguation mechanisms in out-of-order processors This problem exists in most

of the micro-architectures and creates false dependences between independentinstructions during execution, limiting ILP Second, we show how to use insertinstructions for data preloading and prefetching in the context of embedded VLIW.Part 3: register optimization

This part of the book discusses register pressure in ILP, which can be readindependently from Part 2 In order to understand all the formal information andnotations of this part, we advise the readers not to neglect the formal model andnotations presented in section 7.1

Chapter 7, entitled “The Register Need of a Fixed Instruction Schedule”, deals withregister allocation This is a wide research topic, where multiple distinct problemscoexist, some notions are similarly named but do not have the same mathematicaldefinition Typically, the notion of the register need may have distinct significations

We formally define this quantity in two contexts: the context of acyclic scheduling(basic block and superblock) and the context of cyclic scheduling (software pipelining

of a loop) While the acyclic register need is a well-understood notion, we provide newformal knowledge on the register need in cyclic scheduling

Chapter 8 is entitled “The Register Saturation”: our approach here for tacklingregister constraints is radically different from the usual point of view in registerallocation Indeed, we study the problem of register need maximization, notminimization We explain the differences between the two problems and provide anefficient greedy heuristic Register maximization allows us to decouple registerconstraints from instruction scheduling: if we detect that the maximal register need isbelow the processor capacity, we can neglect register constraints

Chapter 9, entitled “Spill Code Reduction”, mainly discusses scheduleindependent register allocation (SIRA) framework: this approach handles registerconstraints before instruction scheduling by adding edges to the data dependencegraph (DDG) It guarantees the absence of spilling for all valid instruction schedules.This approach takes care not to alter the ILP if possible We present the theoreticalgraph approach, called SIRA, and we show its applications in multiple contexts:multiple register file architectures, rotating register files and buffers We presentSIRALINA, an efficient and effective heuristic that allows satisfactory spill codereduction in practice while saving the ILP

Chapter 10, entitled “Exploiting the Register Access Delays before InstructionScheduling”, discusses a certain problem and provides a solution: until now, the

Trang 19

literature has not formally tackled one of the real problems that arises when registeroptimization is handled before instruction scheduling Indeed, when the processorhas explicit register access delays (such as in VLIW, explicitly parallel instructioncomputing (EPIC) and digital signal processing (DSP)), bounding or minimizing theregister requirement before fixing an instruction schedule may create a deadlock intheory when resource constraints are considered afterward The nature of thisproblem and a solution in the context of SIRA are the main subject of this chapter.Chapter 11 is entitled “Loop Unrolling Degree Minimization for PeriodicRegister Allocation”: the SIRA framework proves to be an interesting relationshipbetween the number of allocated registers in a loop, the critical circuit of the DDGand the loop unrolling factor For the purpose of code size compaction, we show howcan we minimize the unrolling degree with the guarantee of neither generating spillcode nor altering the ILP The problem is based on the minimization of a leastcommon multiple, using the set of remaining registers.

Part 4: Epilog

Chapter 12, entitled “Statistical Performance Analysis: The Speedup-TestProtocol”, tends to improve the reproducibility of the experimental results in ourcommunity We tackle the problem of code performance variation in practicalobservations We describe the protocol called the Speedup-Test; it uses well-knownstatistical tests to declare, with a proved risk level, whether an average or a medianexecution time has been improved or not We clearly explain what the hypothesesthat must be checked for each statistical test are

Finally, the Conclusion describes some open problems in optimizing compilation

in general These open problems are known but do not yet have satisfactory solutions

in the literature Here, we conclude with a general summary

I.2 Other contributors

This book is the outcome of long-term fundamental, experimental and technicalresearch using graph theory, scheduling theory, linear programming, complexitytheory, compilation, etc We had great pleasure and honor collaborating with manytalented people with high-quality backgrounds in computer science, computerengineering and mathematics Table I.1 provides a list of collaborators for eachchapter, whom we would like to thank very much

Trang 20

Chapter Contributor Nature of the contribution

problems

performance analysis of memory disambiguationmechanisms

performance analysis of instruction schedulingunder cache effects on VLIW processors

SIRA framework, PhD direction

implementation

experiments

industrial compiler for VLIW processors,experiments and performance analysis

circuits in data dependence graphs

and experiments

experiments

VLIW processors

variabilityTable I.1 Other contributors to the results presented in this book

I.3 Basics on instruction-level parallelism processor architectures

Today’s microprocessors are the powerful descendants of the Von Neumanncomputer [SIL 99] Although various computer architectures have been considerablychanged and rapidly developed over the last 20 years, the basic principles in VonNeumann computational model are still the foundation of today’s most widely usedcomputer architectures as well as high-level programming languages The VonNeumann computational model was proposed by Von Neumann and his colleagues in

Trang 21

1946; its key characteristics result from the multiple assignments of variables andfrom the control-driven execution.

While the sequential operating principles of the Von Neumann architecture arestill the basis for today’s most used instruction sets, its internal structure, calledmicro-architecture, has been changed considerably The main goal of the VonNeumann machine model was to minimize the hardware structure, while today’sdesigns are mainly oriented toward maximizing the performance For this last reason,machines have been designed to be able to execute multiple tasks simultaneously.Architectures, compilers and operating systems have been striving for more than twodecades to extract and utilize as much parallelism as possible in order to boost theperformance

Parallelism can be exploited by a machine at multiple levels:

1) Fine-grain parallelism This is the parallelism available at instruction level (or,say, at machine-language level) by means of executing instructions simultaneously.ILP can be achieved by architectures that are capable of parallel instructionexecution Such architectures are called instruction-level parallel architectures, i.e.ILP architectures

2) Medium-grain parallelism This is the parallelism available at thread level Athread (lightweight process) is a sequence of instructions that may share a commonregister file, a heap and a stack Multiple threads can be executed concurrently

or in parallel The hardware implementation of thread-level parallelism is calledmultithreaded processor or simultaneous multithreaded processor

3) Coarse-grain parallelism This is the parallelism available at process, task,program or user level The hardware implementation of such parallelism is calledmultiprocessor machine or multiprocessor chips The latter may integrate multipleprocessors into a single chip, also called multi-core or many core processors

The discussion about coarse- or medium-grain parallel architectures is outside thescope of this book In this introduction, we provide a brief analysis of ILParchitectures, which principally include static issue processors (e.g VLIW, EPIC andTransport Triggered Architectures (TTAs)) and dynamic issue processors(superscalar)

Pipelined processors overlap the execution of multiple instructions simultaneously,but issue only one instruction at every clock cycle (see Figure I.1) The principalmotivation of multiple issue processors was to break away from the limitation onthe single issue of pipelined processors, and to provide the facility to execute morethan one instruction in one clock cycle The substantial difference from pipelinedprocessors is that multiple issue processors replicate functional units (FUs) in order todeal with instructions in parallel, such as parallel instruction fetch, decode, executionand write back However, the constraints in multiple issue processors are the same as

Trang 22

in pipelined processors, that is the dependences between instructions have to be takeninto account when multiple instructions are issued and executed in parallel Therefore,the following questions arise:

– How to detect dependences between instructions?

– How to express instructions in parallel execution?

The answers to these two questions gave rise to the significant differences betweentwo classes of multiple issue processors: static issue processors and dynamic issueprocessors In the following sections, we describe the characteristics of these two kinds

of multiple issue processors

Figure I.1 Pipelined vs simultaneous execution

I.3.1 Processors with dynamic instruction issue

The hardware micro-architectural mechanism designed to increase the number ofexecuted instructions per clock cycle is called superscalar execution The goal of asuperscalar processor is to dynamically (at runtime) issue multiple independentoperations in parallel (Figure I.2), even though the hardware receives a sequentialinstruction stream Consequently, the program is written as if it were to be executed

by a sequential processor, but the underlying execution is parallel

Trang 23

4 5

Figure I.2 Superscalar execution

Again, there are two micro-architectural mechanisms of superscalar processors:in-order execution and out-of-order (OoO) processors A processor with an in-orderissue sends the instructions to be executed in the same order as they appear in theprogram That is, if instruction a appears before b, then instruction b may in the bestcase be executed in parallel with a but not before However, an OoO processor candynamically change the execution order if operations are independent This powerfulmechanism enables us to pursue the computation in the presence of long delayoperations or unexpected events such as cache misses However, because of thehardware complexity of dynamic independence testing, the window size where theprocessor can dynamically reschedule operations is limited

Compared with VLIW architectures, as we will soon see, superscalar processorsachieve a certain degree of parallel execution at the cost of increased hardwarecomplexity A VLIW processor outperforms a superscalar processor in terms ofhardware complexity, cost and power consumption However, the advantages of asuperscalar processor over a VLIW processor are multiple:

1) Varying numbers of instructions per clock cycle: since the hardware determinesthe number of instructions issued per clock cycle, the compiler does not need to layout instructions to match the maximum issue bandwidth Accordingly, there is lessimpact on code density than for a VLIW processor

2) Binary code compatibility: the binary code generated for a scalar (sequential)processor can also be executed in a superscalar processor with the same ISA, and viceversa This means that the code can migrate between successive implementations even

Trang 24

with different numbers of issues and different execution times of FUs Superscalarprocessors constitute a micro-architectural evolution, not an architectural one.3) Different execution scenarios: superscalar processors dynamically schedule theoperations in parallel Then, there may be more than one parallel execution scenario(dynamic schedule) because of the dynamic events However, VLIW processorsalways execute the same ILP schedule computed at compile time.

For the purpose of issuing multiple instructions per clock cycle, superscalarprocessing generally consists of a number of subtasks, such as parallel decoding,superscalar instruction issue and parallel instruction execution, preserving thesequential consistency of execution and exception processing These tasks areexecuted by a powerful hardware pipeline (see Figure I.3 for a simple example).Below, we illustrate the basic functions of these pipelined steps

Decode Fetch

Figure I.3 Simple superscalar pipelined steps

Fetch pipeline step A high-performance micro-processor usually contains twoseparate on-chip caches: the Instruction-cache (Icache) and Data-cache the (Dcache).This is because the Icache is less complicated to handle: it is read-only and is notsubject to cache coherence in contrast to the Dcache The main problem ofinstruction fetching is control transfers performed by procedural calls, branch, returnand interrupt instructions The sequential stream of instructions is disturbed andhence the CPU may stall This is why some architectural improvements must beadded if we expect a full utilization of ILP Such features include instructionprefetching, branch prediction and speculative execution

Decode pipeline step Decoding multiple instructions in a superscalar processor is

a much more complex task than in a scalar one, which only decodes a singleinstruction at each clock cycle Since there are multiple FUs in a superscalarprocessor, the number of issued instructions in a clock cycle is much greater than that

in a scalar case Consequently, it becomes more complex for a superscalar processor

Trang 25

to detect the dependences among the instructions currently in execution and to findout the instructions for the next issue Superscalar processors often take two or threemore pipeline cycles to decode and issue instructions An increasingly used method

to overcome the problem is predecoding: a partial decoding is performed beforeeffective decoding, while instructions are loaded into the instruction cache

Rename pipeline step The aim of register renaming is to dynamically remove falsedependences (anti- and output ones) by the hardware This is done by associatingspecific rename registers with the ISA registers specified by the program The renameregisters cannot be accessed directly by the compiler or the user

Issue and dispatch pipeline step The notion of instruction window comprises allthe waiting instructions between the decode (rename) and execute stage of thepipeline Instructions in this reorder buffer are free from control and falsedependences Thus, only data dependence and resource conflicts remain to be dealtwith The former are checked during this stage An operation is issued to the FUreservation buffer whether all operations on which it depends have been completed.This issue can be done statically (in-order) or dynamically (OoO) depending on theprocessor [PAT 94]

Execute pipeline step Instructions inside the FU reservation buffer are free fromdata dependences Only resource conflicts have to be solved When a resource is freed,the instruction that needs it is initiated to execute After one or more clock cycles (thelatency depends on the FU type), it completes and therefore is ready for the nextpipeline stage The results are ready for any forwarding This latter technique, alsocalled bypassing, enables other dependent instructions to be issued before committingthe results

Commit and write back pipeline step After completion, instructions are committedin-order and in parallel to guarantee the sequential consistency of the Von Neumannexecution model This means that if no interruptions or exceptions have been emitted,results of executions are written back from rename registers to architectural registers

If any exception occurs, the instructions results are canceled (without committing theresult)

We should know that current superscalar processors have more than five pipelinesteps, the manual of every architecture can provide useful information about it.I.3.2 Processors with static instruction issue

These processors take advantage of the static ILP of the program and executeoperations in parallel (see Figure I.1(b)) This kind of architecture asks programs toprovide information about operations that are independent of each other Thecompiler identifies the parallelism in the program and communicates it to the

Trang 26

hardware by specifying independence information between operations Thisinformation is directly used by the hardware, since it knows with no further checkingwhich operations can be executed in the same processor clock cycle Paralleloperations are packed by the compiler into instructions Then, the hardware has tofetch, decode and execute them as they are.

We classify static issue processors into three main families: VLIW, TTA and EPICprocessors The following sections define their characteristics

I.3.2.1 VLIW processors

VLIW architectures [FIS 05] use a long instruction word that usually contains afixed number of operations (corresponding to RISC instructions) The operations in

a VLIW instruction must be independent of each other so that they can be fetched,decoded, issued and executed simultaneously (see Figure I.4)

Registers Write

Registers Access Instruction Fetch

Figure I.4 VLIW processors

The key features of a VLIW processor are the following [SIL 99]:

– VLIW relies on a sequential stream of very long instruction words

– Each instruction consists of multiple independent operations that can be issuedand executed in one clock cycle In general, the number of operations in an instruction

is fixed

Trang 27

– VLIW instructions are statically built by the compiler, i.e the compiler dealswith dependences and encodes parallelism in long instructions.

– The compiler must be aware of the hardware characteristics of the processor andmemory

– A central controller issues one VLIW instruction per cycle

– A global shared register file connects the multiple FUs

In a VLIW processor, unlike in superscalar processors, the compiler takes fullresponsibility for building VLIW instructions In other words, the compiler has todetect and remove dependences and create the packages of independent operationsthat can be issued and executed in parallel Furthermore, VLIW processors exposearchitecturally visible latencies to the compiler The latter must take into account theselatencies to generate valid codes

The limitations of VLIW architectures arise in the following ways

First, the full responsibility of the complex task for exploiting and extractingparallelism is delegated to the compiler The compiler has to be aware of manydetails about VLIW architectures, such as the number and type of the availableexecution units, their latencies and replication numbers (number of same FUs),memory load-use delay and so on Although VLIW architectures have less hardwarecomplexity, powerful optimizing and parallelizing compiler techniques are required

to effectively achieve high performance As a result, it is questionable whether thereduced complexity of VLIW architectures can really be utilized by the compiler,since the design and implementation of the latter are generally much more expensivethan expected

Second, the binary code generated by a VLIW compiler is sensitive to the VLIWarchitecture This means that the code cannot migrate within a generation ofprocessors, even though these processors are compatible in the conventional sense.The problem is that different versions of the code are required for differenttechnology-dependent parameters, such as the latencies and the repetition rates of theFUs This sensitivity of the compiler restricts the use of the same compiler forsubsequent models of a VLIW line This is the most significant drawback of VLIWarchitectures

Third, the length of a VLIW is usually fixed Each instruction word provides afield for each available execution unit Due to the lack of sufficient independentoperations, only some of the fields may actually be used while other fields have to befilled by no-ops This results in increased code size, and wasted memory space andmemory bandwidth In order to overcome this problem, some VLIW architecturesuse a compressed code format that allows the removal of the no-ops

Trang 28

Finally, the performance of a VLIW processor is very sensitive to unexpecteddynamic events, such as cache misses, page faults and interrupts All these eventsmake the processor stall from its ILP execution For instance, if a load operation hasbeen assumed by the compiler as hitting the cache, and this unfortunately happensnot to be the case during dynamic execution, the entire processor stalls until thesatisfaction of the cache request.

I.3.2.2 Transport triggered architectures

TTAs resemble VLIW architectures: both exploit ILP at compile time [JAN 01].However, there are some significant architectural differences Unlike VLIW, TTAs

do not require that each FU has its own private connection to the register file InTTAs, FUs are connected to registers by an interconnection network (see Figure I.5).This design allows us to reduce the register file ports bottleneck It also reduces thecomplexity of the bypassing network since data forwarding is programmed explicitly.However, programming TTAs is different from the classical RISC programmingstyle Traditional architectures are programmed by specifying operations Datatransports between FUs and register files are implicitly triggered by executing theoperations TTAs are programmed by specifying the data transports; as a side effect,operations are executed In other words, data movements are made explicit by theprogram, and executing operations is implicitly done by the processor Indeed, TTA

is similar to data-flow processors except that instruction scheduling is done statically

Register File

Interconnection network

Figure I.5 Block diagram of a TTA

I.3.2.3 EPIC/IA64 processors

EPIC [SCH 00] technology was introduced to the IA64 architecture and compileroptimizations [KNI 99] in order to deliver explicit parallelism, massive resources andinherent scalability It is, in a way, a mix between VLIW and superscalar programmingstyles On the one hand, EPIC, like VLIW, allows the compiler to statically specifyindependent instructions On the other hand, EPIC is like superscalar in the sense thatthe code semantics may be sequential, while guaranteeing the binary compatibilitybetween different IA64 implementations

Trang 29

The philosophy behind EPIC is much more about scalability OoO processors gettheir issue unit saturated because of the architectural complexity EPIC incorporatesthe combination of speculation, predication (guarded execution) and explicitparallelism to increase the performance by reducing the number of branches andbranch mispredicts, and by reducing the effects of memory-to-processor latency.The key features of the EPIC technology are:

– static speculative execution of memory load operations, i.e loading data frommemory is allowed for issue before knowing whether it is required or not, and thusreducing the effects of memory latency;

– a fully predicated (guarded) instruction set that allows us to remove branches

so as to minimize the impact of branch mispredicts Both speculative loads andpredicated instructions aim to make it possible to handle static uncertainties (whatcompilers cannot determine or assert);

– specifying ILP explicitly in the machine code, i.e the parallelism is encodeddirectly into the instructions as in a VLIW architecture;

– more registers: the IA-64 instruction set specifies 128 64-bit general-purposeregisters, 128 80-bit floating-point registers and 64 1-bit predicate registers;

– an inherently scalable instruction set, i.e the ability to scale to a larger number

of FUs But this point remains debatable

Finally, we must note that VLIW and superscalar processors suffer from thehardware complexity of register ports The number of register ports depends on aquadratic function of the number of FUs Thus, both architectures do not scale verywell since increasing the ILP degree (i.e the number of FUs) results in creating abottleneck on register ports Consequently, the time required to access registersincreases An architectural alternative to this limitation is clustered-processors[FER 98] Clustered architectures group FU into clusters Each cluster has its ownprivate register file: registers inside a cluster are strictly accessed by the FUsbelonging the this cluster If an FU needs a result from a remote register file (fromanother cluster), an intercluster communication (move operation) must be performed.Then, clustered architectures offer better scalability than VLIW and superscalarprocessors since the additional clusters do not require new register ports (given afixed number of FUs per cluster) However, inserting move operations into theprogram may decrease the performance since more operations must be executed.Furthermore, the communication network between clusters may become a newsource of bottleneck

To take full advantage of ILP architectures, compiler techniques have beencontinuously improved since the 1980s [RAU 93b, FIS 05] This book presentsadvanced methods regarding instruction scheduling and register optimization

Trang 30

OB=B7) DU:>:_:?7 B>D:= U:B?

Trang 32

1 C*  ,,/,CK 3$ *> = =,1) ,1

5C,0,L,1) 305,/C,31

 = ,1C = >C  ,1 C* 305FC,1) $=31C, = =3F1 1 >> 1C,/ :F >C,31 3FC 305,/ =

31>C=FC,31 *H,1)  5=3)=0  1  > C  3$ 131+5=0 C=, 305,/ = 35C,0,LC,31 03F/ > 6/>3 //  5*> >7 ,> ,C 53>>,/ C3 %1  > :F 1 % 3$ C* > 5*> > >F* C*C C*

%)F= 3FC *3I C3 305FC C*  >C 5=0 C = H/F > $3= // 5=3)=0 C=1>$3=0C,31> I* 1 C*

305,/C,31 > :F 1 ,> ),H 18  />3 5=3H C*C C*,> ) 1 =/ 5=3/ 0 ,> F1 ,/ 1 I 5=3H, >30 >,05/,%   ,/ ,1>C1 >8

(8\:,7,=P8B8? !E 1; P8B\,+ & @C' U8 U U8,O, O, =BBDP \:U8 (B?+:U:B? = ;X>DP2BO \8:(8 ?B P,> ?U:( ==^ ,JX:[ =,?U U:>,9BDU:> = DOB7O > ,]:PUP B? D O ==,=

> (8:?,P* ,[,? \:U8 PD,(X= U:[, ,],(XU:B?CH BO, DO,(:P,=^* U8,^ P8B\,+ \8^ :U :P

C ?+,,+* U8, (:U,+ D D,O +B,P ?BU (B?U :? 2BO> = +,U :=,+ DOBB2* #XU D,OPX P:[, O, PB?:?7H

Trang 33

:>DBPP:#=, UB \O:U, DOB7O > U8 U :P U8, 2 PU,PU 2BO ?^ :?DXU + U H 8:P :P #,( XP,U8, DO,P,?(, B2 (B?+:U:B? = ;X>DP > <,P U8, DOB7O > ,],(XU:B? D U8P +,D,?+,?U B?U8, :?DXU + U Q PB :U :P ?BU 7X O ?U,,+ U8 U DOB7O > P8B\? 2 PU,O 2BO (B?P:+,O,+:?DXU + U P,U E:H,H 2BO 7:[,? ,],(XU:B? D U8F O,> :?P U8, 2 PU,PU 2BO == DBPP:#=, :?DXU+ U H XOU8,O>BO,* (8\:,7,=P8B8? !E 1; (B?[:?(,+ XP U8 U 68E.21 (B+,P 2BO =BBDP

\:U8 #O ?(8,P E\:U8 O#:UO O^ :?DXU + U F O,JX:O, U8, #:=:U^ UB ,]DO,PP ?+ ,],(XU, DOB7O > \:U8 ? X?#BX?+,+ PD,(X= U:[, \:?+B\H :?(, ?^ O, = PD,(X= U:[, 2, UXO, :P

=:>:U,+ :? DO (U:(,W* :U :P 286@@.1! UB \O:U, ? BDU:> = (B+, 2BO PB>, =BBDP \:U8

#O ?(8,P B? O, = > (8:?,PH

? BXO O,PX=U* \, +,3?, U8, DOB7O > BDU:> =:U^ ((BO+:?7 UB U8, :?DXU + U H B* \,

P ^ U8 U DOB7O >  :P BDU:> = :2 U8,O, :P ?BU ?BU8,O ,JX:[ =,?U DOB7O >  2 PU,OU8 ?  (B?P:+,O:?7 U8, P >, :?DXU + U H 2 (BXOP,* U8, BDU:> = DOB7O >  O,= U,+

UB U8, (B?P:+,O,+ :?DXU + U >XPU PU:== ,],(XU, (BOO,(U=^ 2BO ?^ BU8,O :?DXU + U * #XU

?BU ?,(,PP O:=^ :? U8, 2 PU,PU PD,,+ B2 ,],(XU:B?H ? BU8,O \BO+P* \, +B ?BU UO^ UB #X:=+,23(:,?U PD,(: =:_,+ DOB7O >P* :H,H \, P8BX=+ ?BU 7,?,O U, DOB7O >P U8 U ,],(XU, B?=^2BO (,OU :? :?DXU + U P,UH U8,O\:P,* P:>D=, DOB7O > U8 U B?=^ DO:?UP U8, O,PX=UP

\BX=+ #, PX23(:,?U 2BO 3],+ :?DXU + U H

:U8 U8:P ?BU:B? B2 BDU:> =:U^* \, ( ? P< U8, 7,?,O = JX,PU:B?) 8B\ ( ? \, #X:=+ (B>D:=,O U8 U 7,?,O U,P ? BDU:> = DOB7O > 7:[,? ? :?DXU + U P,UK X(8 JX,PU:B?:P [,O^ +:23(X=U UB ?P\,O* P:?(, X?U:= ?B\ \, 8 [, ?BU #,,? #=, UB ,?X>,O U, ==U8, DBPP:#=, XUB> U:( DOB7O > O,\O:U:?7 >,U8B+P :? (B>D:= U:B? EPB>, O, DO,P,?U:? U8, =:U,O UXO,Q BU8,OP 8 [, UB #, P,U XD :? U8, 2XUXO,FH B* \, 3OPU ++O,PP :? U8:P(8 DU,O ?BU8,O P:>:= O JX,PU:B?) 7:[,? 3?:U, P,U B2 (B>D:=,O BDU:>:_ U:B? >B+X=,P

* 8B\ ( ? \, #X:=+ ? XUB> U:( >,U8B+ UB (B>#:?, U8,> :? 3?:U, P,JX,?(,U8 U DOB+X(,P ? BDU:> = DOB7O >K ^ (B>D:=,O BDU:>:_ U:B? >B+X=,* \, >, ? DOB7O > UO ?P2BO> U:B? U8 U O,\O:U,P U8, BO:7:? = (B+,H ?=,PP U8,^ O, ,?( DPX= U,+:?P:+, (B+, BDU:>:_ U:B? >B+X=,P* \, ,](=X+, DOB7O > ? =^P:P D PP,P P:?(, U8,^ +B

?BU >B+:2^ U8, (B+,H

8:P (8 DU,O DOB[:+,P 2BO> =:P> 2BO PB>, 7,?,O = JX,PU:B?P #BXU D8 P,BO+,O:?7H XO 2BO> = \O:U:?7 ==B\P XP UB 7:[, DO,=:>:? O^ ?P\,OP 2OB> U8,(B>DXU,O P(:,?(, D,OPD,(U:[, #BXU +,(:+ #:=:U^ E\8 U \, ( ? O, ==^ +B #^ XUB> U:((B>DXU U:B?F ?+ X?+,(:+ #:=:U^ E\8 U \, ( ? ?,[,O +B #^ XUB> U:( (B>DXU U:B?FH

, \:== P8B\ U8 U BXO ?P\,OP O, PUOB?7=^ (BOO,= U,+ UB U8, ? UXO, B2 U8, >B+,=PE2X?(U:B?PF XP,+ UB DO,+:(U BO ,[ =X U, U8, DOB7O >NP D,O2BO> ?(,PH BU, U8 U \, O,

?BU :?U,O,PU,+ :? U8, ,23(:,?(^ PD,(UP B2 (B>D:= U:B? ?+ (B+, BDU:>:_ U:B?) \,

<?B\ U8 U >BPU B2 U8, (B+, BDU:>:_ U:B? DOB#=,>P O, :?8,O,?U=^ 9(B>D=,U,H

B?P,JX,?U=^* U8, DOBDBP,+ =7BO:U8>P :? U8:P (8 DU,O O, ?BU ?,(,PP O:=^ ,23(:,?U* ?+ O, \O:UU,? 2BO U8, DXODBP, B2 +,>B?PUO U:?7 U8, +,(:+ #:=:U^ B2 PB>, DOB#=,>PH

W 2 U8, PD,(X= U:B? :P PU U:(* U8, (B+, P:_, :P 3?:U,H 2 U8, PD,(X= U:B? :P > +, +^? >:( ==^* U8,

8 O+\ O, PD,(X= U:[, \:?+B\ :P #BX?+,+H

Trang 34

OBDBP:?7 ,23(:,?U =7BO:U8>P 2BO +,(:+ #=, DOB#=,>P :P ?BU8,O O,P, O(8 PD,(UBXUP:+, U8, (XOO,?U P(BD,H

8:P (8 DU,O :P BO7 ?:_,+ P 2B==B\PH ,(U:B? CHW 7:[,P #O:,2 B[,O[:,\ #BXUPB>, D8 P, BO+,O:?7 PUX+:,P :? U8, =:U,O UXO,* P \,== P PB>, D,O2BO> ?(, DO,+:(U:B?

>B+,=:?7PH ,(U:B? CHV +,3?,P 2BO> = >B+,= 2BO U8, D8 P, BO+,O:?7 DOB#=,> U8 U ==B\P XP UB DOB[, PB>, ?,7 U:[, +,(:+ #:=:U^ O,PX=UPH ,]U* :? P,(U:B? CH6* \, P8B\PB>, 7,?,O = BDU:>:_:?7 (B>D:= U:B? P(8,>, :? \8:(8 U8, D8 P, BO+,O:?7 DOB#=,>

#,(B>,P +,(:+ #=,H ,(U:B? CH4 ,]D=BO,P U8, DOB#=,> B2 UX?:?7 BDU:>:_:?7(B>D:= U:B? D O >,U,OP \:U8 (B>D:= U:B? P,JX,?(,H :? ==^* P,(U:B? CHS (B?(=X+,PU8, (8 DU,OH

59B9 /+<4C2" 42 6,=$ 4<"$<.2+

8, DOB#=,> B2 D8 P, BO+,O:?7 :? BDU:>:_:?7 (B>D:= U:B? :P (BXD=,+ \:U8 U8,DOB#=,> B2 D,O2BO> ?(, >B+,=:?7* P:?(, D,O2BO> ?(, DO,+:(U:B?T,PU:> U:B? > ^7X:+, U8, P, O(8 DOB(,PPH 8, U\B P,(U:B?P U8 U 2B==B\ DO,P,?U JX:(< B[,O[:,\ B2O,= U,+ \BO<H

59B959 /(/&' &(%"' ' */"2"('

OB7O > D,O2BO> ?(, >B+,=:?7 ?+ ,PU:> U:B? B? (,OU :? > (8:?, :P ? B=+ ?+ EPU:==F :>DBOU ?U O,P, O(8 UBD:( :>:?7 UB 7X:+, (B+, BDU:>:_ U:B?H 8, P:>D=,PUD,O2BO> ?(, DO,+:(U:B? 2BO>X= :P U8, =:?, O 2X?(U:B? U8 U (B>DXU,P U8, ,],(XU:B?U:>, B2 P,JX,?U: = DOB7O > B? P:>D=, B? ,X> ?? > (8:?,) :U :P P:>D=^ =:?, O 2X?(U:B? B2 U8, ?X>#,O B2 ,],(XU,+ :?PUOX(U:B?PH :U8 U8, :?UOB+X(U:B? B2

>,>BO^ 8:,O O(8^* D O ==,=:P> U > ?^ =,[,= E:?PUOX(U:B?P* U8O, +P ?+ DOB(,PPF*

#O ?(8 DO,+:(U:B? ?+ PD,(X= U:B?* >X=U:9(BO,P* D,O2BO> ?(, DO,+:(U:B? #,(B>,P >BO,(B>D=,] U8 ? P:>D=, =:?, O 2BO>X= H 8, ,] (U @,8! BO U8, ? UXO, B2 PX(8 2X?(U:B? ?+ U8, D O >,U,OP U8 U :U :?[B=[,P 8 [, #,,? U\B X?<?B\? DOB#=,>P X?U:=

?B\H B\,[,O* U8,O, ,]:PU PB>, OU:(=,P U8 U UO^ UB +,3?, DDOB]:> U,+ D,O2BO> ?(,DO,+:(U:B? 2X?(U:B?P)

/ EE.@E.1 1.3!? ?!+?!@@.63 26 !1@) U8, D O >,U,OP :?[B=[,+ :? U8, =:?, OO,7O,PP:B? O, XPX ==^ (8BP,? #^ U8, XU8BOPH  ?^ DOB7O > ,],(XU:B?P BO P:>X= U:B?U8OBX78 >X=U:D=, + U P,UP > <, :U DBPP:#=, UB #X:=+ PU U:PU:(P U8 U (B>DXU, U8,(B,23(:,?UP B2 U8, >B+,= & @V*  `V'H

/ EE. 1+6?.E,2. 26 !1@) XPX ==^* PX(8 >B+,=P O, =7BO:U8>:( ? =^P:P

>,U8B+P U8 U UO^ UB DO,+:(U DOB7O > D,O2BO> ?(, & *  @V*  @6(*

  @W'H BO :?PU ?(,* U8, =7BO:U8> (BX?UP U8, :?PUOX(U:B?P B2 (,OU :? U^D,* BO > <,P 7X,PP B2 U8, =B( = :?PUOX(U:B? P(8,+X=,* BO ? =^_,P + U +,D,?+,?(,P UB DO,+:(U U8,

=B?7,PU ,],(XU:B? D U8* ,U(H

Trang 35

/ 628?.@63 26 !1@) :?PU, + B2 DO,+:(U:?7 DO,(:P, D,O2BO> ?(, >,UO:(* PB>,PUX+:,P DOB[:+, >B+,=P U8 U (B>D O, U\B (B+, [,OP:B?P ?+ UO^ UB DO,+:(U U8, 2 PU,PUB?, & @W*  `4'H

2 (BXOP,* U8, #,PU ?+ U8, >BPU ((XO U, D,O2BO> ?(, DO,+:(U:B? :P U8, U O7,U O(8:U,(UXO,* P:?(, :U ,],(XU,P U8, DOB7O >* ?+ 8,?(, \, ( ? +:O,(U=^ >, PXO, U8,D,O2BO> ?(,H 8:P :P \8 U :P XPX ==^ XP,+ :? :U,O U:[, (B>D:= U:B? ?+ =:#O O^7,?,O U:B?* 2BO :?PU ?(,H

8, > :? DOB#=,> \:U8 D,O2BO> ?(, DO,+:(U:B? >B+,=P :P U8,:O DU:UX+, 2BO

#,( XP, :U D=BUP @.2.1? (XO[, (B>D O,+ UB U8, O, = D=BU E DOBB2 #^ ,^,P1FH ?+,,+*U8:P U^D, B2 ,]D,O:>,?U = [ =:+ U:B? :P ?BU (BOO,(U 2OB> U8, PU U:PU:( = P(:,?(, U8,BO^DB:?U B2 [:,\* ?+ U8,O, ,]:PU 2BO> = PU U:PU:( = >,U8B+P U8 U (8,(< \8,U8,O >B+,=3UP U8, O, =:U^H ?U:= ?B\* \, 8 [, ?BU 2BX?+ ?^ PUX+^ U8 U [ =:+ U,P DOB7O >D,O2BO> ?(, DO,+:(U:B? >B+,= XP:?7 PX(8 2BO> = PU U:PU:( = >,U8B+PH

59B9B9 (& 22&*20 "' * 0 (//"'

:?+:?7 U8, #,PU BO+,O :? BDU:>:_:?7 (B>D:= U:B? :P ? B=+ ?+ +:23(X=U DOB#=,>H

8, >BPU (B>>B? ( P, :P U8, +,D,?+,?(, #,U\,,? O,7:PU,O ==B( U:B? ?+ :?PUOX(U:B?P(8,+X=:?7 :? :?PUOX(U:B? =,[,= D O ==,=:P> DOB(,PPBOP P P8B\? :? &  @W'H  ?^BU8,O ( P,P B2 :?U,O9D8 P, +,D,?+,?(,P ,]:PU* #XU :U :P 8 O+ UB ? =^_, == U8, DBPP:#=,:?U,O (U:B?P & @R'H

=:(< ?+ BBD,O :? & @4' DO,P,?U 2BO> = >,U8B+ U8 U (B>#:?,P U\B (B>D:=,O

>B+X=,P UB #X:=+ @H8!?9>B+X=, U8 U DOB+X(,P #,UU,O E2 PU,OF DOB7O >P U8 ? :2 \, DD=^ , (8 >B+X=, P,D O U,=^H B\,[,O* U8,^ +B ?BU PX((,,+ :? 7,?,O =:_:?7 U8,:O2O >,\BO< B2 >B+X=, (B>#:? U:B?* P:?(, U8,^ DOB[, :U 2BO B?=^ U\B PD,(: = ( P,P*

\8:(8 O, (B?PU ?U DOBD 7 U:B? ?+ +, + (B+, ,=:>:? U:B?H

Ngày đăng: 21/03/2019, 09:38

TỪ KHÓA LIÊN QUAN