text:
BGO - YVR
Find cheap flights from Bergen to Vancouver Airport
Bergen (BGO)
November Most popular time to fly (25% more expensive on average)
When to book flights from Bergen to Vancouver Intl
High season is considered to be October, November and December. The cheapest month to fly is October.
FAQs for booking Bergen to Vancouver Airport flights
How long does a flight from Bergen to Vancouver Airport take?
Which airlines provide the cheapest flights from Bergen to Vancouver Airport?
In the past 3 days, the cheapest round-trip tickets were found on Delta (C$ 1,090) and KLM (C$ 1,127)
How does KAYAK find such low prices on flights from Bergen to Vancouver Airport?
KAYAK is a travel search engine. That means we look across the web to find the best prices we can find for our users. With over 2 billion flight queries processed yearly, we are able to display a variety of prices and options on flights from Bergen to Vancouver Airport.
How does KAYAK's flight Price Forecast tool help me choose the right time to buy my flight ticket from Bergen to Vancouver Airport?
KAYAK's flight Price Forecast tool uses historical data to determine whether the price for a flight to Vancouver Airport from Bergen is likely to change within 7 days, so travellers know whether to wait or book now.
What is the Hacker Fare option on flights from Bergen to Vancouver Airport?
Hacker Fares allow you to combine one-way tickets in order to save you money over a traditional round-trip ticket. You could then fly to Vancouver Airport with an airline and back to Bergen with another airline.
What is KAYAK's "flexible dates" feature and why should I care when looking for a flight from Bergen to Vancouver Airport?
Sometimes travel dates aren't set in stone. If your preferred travel dates have some wiggle room, flexible dates will show you all the options when flying to Vancouver Airport from Bergen up to 3 days before/after your preferred dates. You can then pick the flights that suit you best.
Top airlines flying Bergen Flesland to Vancouver Intl
Cons: "connecting flight left without 1/6th of its passengers. Stuck at airport now because of Deltas laziness"
Cons: "Front right lav door hard to latch, headphones worked on one side only, gap in middle of lie-flat bed."
Cons: "Really felt happy on time touch down nice journey with delta"
Pros: "We left on time"
Cons: "The size of the plane is just so bad"
Cons: "It's time to update the snacks, bu thank you for serving more than just peanuts. I was very cold on the flight - unusual, but definitely very chilly."
Cons: "I'd prefer more a la carte food options rather than only boxes of stuff that include 3 things I don't want."
Cons: "Im paid for confort. But give a economic. Maybe mix with golairline."
Pros: "Nice smooth flight"
Pros: "The check in process was smooth and the flight crew were pleasant"
Cons: "some of the TSA crew were rude/seemed to be doing a lazy job with helping load items on the belt"
Cons: "Flight was delayed by an hour. No explanation given"
Pros: "Seats were horrible, we all booked together and a bunch of my group got bumped to a different flight."
Pros: "36 minute flight.."
Cons: "Not really much you can do"
Pros: "Cabin crew were very good. Very pleasant."
Cons: "Unpacking wet clothes from one of my bags. It must have been left out in the rain for some time. I filed a separate complaint with Delta."
Cons: "6 hours late. Unacceptable."
Cons: "We shared beverages The bathroom was barely big enough for a small person There isn't enough room per passenger seat"
Cons: "Over an hour delay before boarding due to supposedly bad weather. Because flight was overbooked they were offering $400 gift card to change to standby on another flight. If you didn't make that flight (evening), you'd be confirmed on a flight the following morning with one stop in Detroit (we booked a nonstop to Chicago). Uh, no thanks. Then to top it off, we've landed and been told that it will be at least an hour before we can deplane due to no availability at the gate (it's 1145 pm right now). All this plus their new policy of not allowing us to select our seats because we bought the cheapest tickets. Really Delta? You go ahead and cater to the rich and I'll choose to fly with another airline."
Cons: "Seat wouldn't redline."
Pros: "Boarding and staff were excellent. Plane was clean."
Cons: "I was unhappy with the seating arrangements. I could not upgrade my seats because I booked through a third party. If I'm willing to pay for my upgrade then it should be allowable. I don't like seating in the rear of the plane!"
Cons: "Haven't left yet!!!"
Pros: "Entertainment"
Cons: "Staff were a bit rude. The boarding process was slow as everyone rushed up when they announced the first zone to board, and obviously this was not policed. We didn't get our seats until we got to the gate because apparently we bought our tickets too soon to take off, which was three weeks. Also, staff claimed there wasn't enough bin space so asked people to check their bags. We saw people with two big bags get on board at the start, and then staff made everyone at the back of the line check their bags. But there was plenty of bin space before take off. And we were seated in the last row which can't recline."
Pros: "Avg flight"
Cons: "They changed my seat to a worse one without any explanation. I picked my seats on line for a reason and dont like them changed. Older MD series plane from AUS to ATL."
Pros: "Comfortable flight, ample leg room, and the chairs were pretty plush. Comfort+ is pretty nice"
Cons: "On my first flight they forgot to turn the wifi on. I have unlim data but obviously can't use while in air; no big though."
Pros: "it was great experience"
Pros: "Very friendly staff and the onboard meals were surprisingly good. Korean Air may quite possibly be my favorite airline."
Pros: "Delta is the best airline to use because they care about you as a customer. They will do everything they can to make your flight as enjoyable as possible. I would not recommend any other airline to use but DELTA !!"
Cons: "Nothing to input. All was great."
Pros: "I liked the in-flight service and the complimentary snacks and drinks despite the short trip."
Cons: "I did not like that there was not enough room for our 50L Osprey backpacks to be placed under the seats."
Cons: "Flight was completely full and I was seated next to someone who required TWO seat belt extenders! I was so uncomfortable, they were sitting on top of me, couldn't even put down the arm rest. The flight attendant said there was nothing they could do."
Pros: "There wasn't much to like. Just about everything was wrong. The plane was a newish 787, so it didn't feel old. Boarding went well because we complained about how tired we, at 70+, were because the flight was late and we'd been standing up; this resulted in us being boarded with some of the latish priority passengers."
Cons: "Everything, really. The plane was very crowded; small seats, little leg room. The meals were mediocre and the cabin staff were just barely the good side of unhelpful, officious and unfriendly The flight was inexplicably 2 hours or more late in excellent weather. No apologies given, the flight that was originally scheduled for 8 pm left close to 11 pm. While boarding the only light is a purplish ambient lighting that made it impossible to read anything, including the safety material, until the inflight entertainment was loaded up (the lights are only controlled through software-actuated virtual buttons on the screen). The inflight entertainment system is hard to use, too, designed by idiots for use by geniuses. But the very worst thing was the stress caused by Virgin Atlantic in just about guaranteeing that we would miss this flight. On our outbound voyage in January, VA, for reasons nobody knows, booked an ADDITIONAL leg from JHB to CPT on BA at 12:30 pm, even though we were already ON the earlier 9:30 BA flight we'd booked and paid for. Then, when we didn't show up for this spurious flight (because we were already in the air) we didn't book (BA swears they have evidence that VA made this booking), our return flight CPT to JBG three months later was cancelled WITHOUT OUR KNOWLEDGE. If I hadn't been interested in knowing, the day before the flight, if the return BA flight had a meal, I would have showed up at the CPT airport in April and discovered that I had no way to get to the VA flight in JHB! As it was I spent an entire day trying to get back on the flight I'd already paid for. I advise EVERYONE who uses VA to reconfirm flights over and over. There is still no explanation for this. I will never NEVER fly VA again. They are not to be trusted."
Pros: "Got an upgrade to Comfort + Delta is the best major airline in USA for sure"
Pros: "Good seat, easy on and off, everything went a little ahead of schedule and smooth"
Pros: "Boarding was efficient and the crew were nice."
Cons: "the seating is horrible. it was the tightest seating I've ever experienced."
Pros: "A flight was delayed due to weather conditions and we had to sit in the plane for almost an hour, BUT information sharing from the Capitan was sufficient and on-time. Very good job from pilots. Leg room in economy - I was positively surprised, very decent leg room! Thank you for providing it."
Cons: "I flew economy and all was good and appropriate to the level."
Pros: "Almost everything, especially the crew."
Cons: "Don't feel like anything should be better to be honest"
Pros: "The crews were pretty great!"
Cons: "The regulating of the temperature."
Cons: "Delay due to strike"
Cons: "Flight got cancelled"
Cons: "The KLM crew are always great serving and treating you. Well above many other airlines."
Pros: "Seats super comfy. Ended up with 3 seats to myself that formed a bed for the lap Uk to NZ. Very nice!"
Pros: "Nice staff and no delay"
Cons: "Instead of crisps maybe a bit of cheese or crackers"
Pros: "Our flight was delayed in Bejing, than we loosed the booked flight of KLM. When we arrived in Amsterdam, we get the recheked in flight."
Cons: "Doesn't"
Cons: "Dozens of high school students screaming and climbing onto seats, crew did not intervene."
Pros: "The earphones for out two seats only worked intermittently, but the Purser, Lee-Ann handled it professionally and pleasantly. That was the only disappointment in an otherwise pleasant flight"
Cons: "The earphones could have worked!"
Pros: "My seat at the window was great and the staff really friendly and courteous!"
Pros: "Once aboard the plane, all went well and I experienced excellent service from the cabin attendants."
Cons: "The flight was delayed (again!) for some 40 minutes and I was worried that I would miss my connection flight in Atlanata. Fortunately the pilot made up for the delay (probably costing the airline thousands in fuel). It seems these days that every KLM flight I take is delayed. This stretch goes back to 2015! Yet KLM prides itself as being punctual. Not the KLM that I have been flying!"
Cons: "Too much light in the cabin because of too many screens on. Should have a separate part of the cabin with screens off allowing one to sleep more easily."
Pros: "The flight AMS to MEX was smooth, very helpful personnel on board, we enjoyed a bit more space and the seat seemed a bit more comfortable."
Cons: "Besides the seat relative comfort, it did not recline much at all, i wondered what the extra money (at least $5 or $600) got us. The food, wine/ beer service was same as regular economy, the boarding took place at same time as economy, no drink before take-off if only sparkling water. And the plane was old generation 747 and the entertainment was same vintage: screen was not very bright and the selection of films was poor. No plug to charge electronics. We were disappointed with KLM when comparing with other airline companies offerings when you book in Premium Economy."
Pros: "Boarding agent extra effort to improve my seating!"
Cons: "Food amount less than expected."
Pros: "Nothing to mention"
Cons: "Crew was rude when I asked if there was a vegetarian option for the snack. I did request special meals for the trip. Even if they did not have a vegetarian option, they don't need to be rude!! Boarding was ridiculous. we were supposed to form a line and wait. Would have been a lot better if they boarded by seat numbers. Also they made me check in my fairly small and light carry on bag resulting in its contents arriving broken!"
Cons: "Nothing special"
Pros: "Snooth and efficiënt with a KLM service"
Cons: "KLM lost my luggage during the layover. My luggage didn't arrive even after the next flight to Prague. Customer service wouldn't give me any idea what flight my luggage would arrive on, nor would they tell me what time my luggage might be delivered to me."
Pros: "Travel on Crostian Airlines did not pappen. KLM flight to Munich was cancelled and I was rescheduled on Air Setbia to Belgrade, the Split."
Cons: "That it didn't happen."
Pros: "The cabin crew was so kind, efficient, and attentive. All meals and snacks were delicious."
Pros: "The aircraft felt clean and quite spacious (decent legroom). Cabin crew was friendly and everything went as expected. Bonus points for the Beemster cheese sandwich (I was totally disappointed when they served the food, but more than pleasantly surprised by the quality of the cheese - I even bought some afterwards, from the Albert Heijn just outside the security area)."
Cons: "Very odd queue separation at boarding. Passengers were divided in 5 lanes, depending on their seating area withing the plane (for a more efficient boarding, I presume) but, by the time we all got to the actual aircraft, we formed another queue in the boarding bridge so it didn't feel like any time was saved or anything."
Pros: "Overall everything was ok."
Cons: "Not that I cared at the time but having been asked for a rating on "entertainment" - there was none. Cheap and cheerful really. No extras over the likes of RyanAir."
Pros: "Friendly staff, good service and on time departure/arrival."
Pros: "Very friendly service!"
Pros: "Helpful and smiling cabin crew."
Pros: "Flight was lovely, crew were friendly and very helpful and food was delicious!! We travelled with assistance for mum and it was excellent and we were kept updated all through the flight."
Pros: "The flight was great."
Pros: "Flight was on time and quick and comfortable"
Cons: "Flight way delayed 3 hours. Staff gave no information and wouldn't help rebook us onto other flights. They gave us food vouchers 2 minutes before we finally boarded, so we couldn't use them. The food on the plane had spoiled so we were all starving on the flight, and we all missed our connections. Horrible experience and wouldn't fly with KLM again."
Cons: "Old airplane with not really comfy seats. No outlets for charging devices. Very old entertainment screen."
Cons: "Pet was left behind at vacation destination as pet's reservation (made and confirmed through KLM) was not found at check in. Waiting for Customer Care to help get pet home and take responsibility for situation and getting no response. Very dissapointed, considering law suit."
Pros: "Flight was efficient enough and staff were friendly."
Cons: "It was delayed quite a bit and more on-time updates would have been appeciated."
Pros: "Everything was good. The crew was very friendly and attentive. The plane was comfortable, with great entertainment on the personal screens. The food was delicious. Flight was on time and actually arrived early, but then we had to wait for a gate (not the airline's fault)."
Cons: "No complaints at all."
Pros: "Overall, my trip to Cardiff via Amsterdam was smooth and delightful. I've flown a few short trips this summer and I was pleasantly surprised to find KLM still offered complimentary snacks. What a refreshing change!"
Cons: "There was no entertainment which is why I assigned that category only one star. The boarding process in Amsterdam could have been a bit smoother. Announcements were no clear."
Pros: "The staff and crew"
Pros: "Short layover connecting from US flight and luggage transferred ok to destination. Food option not great but at least they didn't charge for it unlike some other airlines. No entertainment but to be expected on such a short flight."
Cons: "The crew on the Lagos Amsterdam route (in economy) are particularly unfriendly and brusque. This is my experience each time i fly this route in economy"
Pros: "Flight unpleasant. Ground staff in Marseiile great but gate crew didn't control carry on baggage and many of us could not use overhead bins because of passengers who stowed more than one and often oversized suitcases above, so we and many others had to place carry on suitcases under seat. Attendant on plane totally unhelpful and could have rearranged a few bags to make room but preferred to stay in back of plane and talk. To be fair, rest of flight was pleasant although late due in part to boarding issues."
Cons: "Carry on baggage issues and storage on plane. One aloof and unhelpful member of flight crew."
Pros: "Staff, service"
Pros: "I ended up getting home with less delay than originally predicted. I guess that's a good thing Also delta customer service was super polite and trying to help when I called"
Cons: "Delay again... seems to be pretty frequent on KLM flights at least on the ones I flew with in the past 4 years... this time it was 3hours wait due to a technical issue... no alternative flight option and we ended up getting a very old plane as a replacement. In addition people at info terminals are disorganized and not kind at all.."
Cons: "Flight delayed ... Myself and three other colleagues didn't have our luggage show up from KLM flight from Amsterdam to Brussels...even though all of our luggage was labeled "priority". Once in customer service line, we looked and saw that many of the other passengers on our flight also never received their luggage. We estimated that 20-25% of the people on that flight did not receive their luggage as they were in line with us for the same problem. Hard to understand how so many pieces of luggage could have been overlooked and not loaded on our flight. Obviously there is a huge gap in their quality system to ensure mistakes like this are prevented."
Cons: "I missed my flight because of MU"
Pros: "Except for my negative comment, a good flight."
Cons: "I paid extra for a window seat, but due to the poor alignment of the seats with the actual windows, I actually sat next to a wall! Nol much to see out of a wall. If KLM are going to charge extra for a window seat, then they should make sure there is a window there! If the seat had actually had a window it would have been an excellent flight."
Safety measures for airlines flying from Bergen Flesland to Vancouver Intl
Airlines flying from Bergen Flesland to Vancouver Intl have enacted additional safety measures and adjusted policies to better accommodate travellers. Policies vary by airline.
Daily cleaning, installation of cabin HEPA filters on flights from Bergen Flesland to Vancouver Intl
Masks required on board, masks provided on flights from Bergen Flesland to Vancouver Intl
Middle seats unavailable to book on flights from Bergen Flesland to Vancouver Intl
Testing for antibodies, testing for symptoms for flights from Bergen Flesland to Vancouver Intl
Waiving of change fees. Search flexible flights from Bergen Flesland to Vancouver Intl
Book cheap flights from Bergen to Vancouver Airport
YVR - BGO
Bergen - Vancouver Airport Flights
Bergen (BGO) Norway
Norway »
Search Vancouver Airport flights on KAYAK. Find cheap tickets to Vancouver Airport from Bergen. KAYAK searches hundreds of travel sites to help you find cheap airfare and book the flight that suits you best. With KAYAK you can also compare prices of plane tickets for last-minute flights to Vancouver Airport from Bergen.


text:
Platform for discussion 003
Can Artistic Practices Negotiate the Demands of Cultural Institutions, Public Space, and Civil Society?
Ibraaz Platform 003 Editorial: What Was Lost?2 May 2012
Archives, Museums and Collecting Practices in the Modern Arab World19 August 2012
Sonja Mejcher-Atassi and John Pedro Schwartz
In the Event of Fire13 July 2012
Precarious Images, the Aesthetics of Conflict, and the Future of an Anachronism
A Philosophical Banquet in the Country, staged by Dar al-Ma'mûn2 May 2012
Ali Benmakhlouf
Productive Contexts and Contemporary Restraints2 May 2012
The Practice of Contemporary Art in Algeria Today
Alice Planel
The Social Impulse2 May 2012
Politics, Media and Art after the Arab Uprisings
Fast Forward to the Past2 May 2012
Cultural Institutions, Urban Development, and Regional Cinema in the Gulf Today
Sheyma Buali
Occupying the Occupied2 May 2012
Perceptions of Occupation and Control in Cyprus
Başak Şenova
The Urban Observatory of Beirut2 May 2012
For a Polysemic Reading of Both City and Territory
Caecilia Pieri
view all essays
An Accidental Orientalist27 September 2012
Tom Bogaert in conversation with Anthony Downey
Absorbing Displacement27 September 2012
Bouchra Khalili in Conversation with Dorothea Schoene
Dorothea Schoene
An Architecture of Apprehension27 September 2012
Timo Nasseri in conversation with Laura Allsop
Laura Allsop
Auto-Connections26 July 2012
UBIK in conversation with Isabella Ellaheh Hughes
Isabella Ellaheh Hughes
Restaging Invisibilities26 July 2012
Fayçal Baghriche in conversation with Laura Allsop
The Noise of Cairo13 July 2012
Heiko Lange in conversation with Amira Gad
Geographic Gnomons13 July 2012
Ala Younis in conversation with Liane Al-Ghusain
Liane Al-Ghusain
In Lieu of Absence29 June 2012
Taysir Batniji in conversation with Silke Schmickl
Silke Schmickl
Nostalgia for the Future 29 May 2012
Ala Ebtekar in conversation with Sara Raza
Sara Raza
'If Walls Could Talk ...' 24 May 2012
Driss Ouadahi in conversation with Rachida Triki
Rachida Triki
Colourful Shadows and Reel Journeys2 May 2012
Tarzan and Arab in conversation with Laura Allsop
After the Storm2 May 2012
Michket Krifa in conversation with Wafa Gabsi
Wafa Gabsi
With Inside Outside2 May 2012
Nada Sehnaoui in conversation with Laura Allsop
Home Workspace2 May 2012
Christine Tohme in conversation with Anthony Downey
Migrations of Meaning2 May 2012
Lara Khaldi in conversation with Ghalya Saadawi
Ghalya Saadawi
The Shortest Length Between Two Points2 May 2012
Slavs and Tatars in conversation with Franz Thalmair
Franz Thalmair
Word Stress2 May 2012
Lawrence Abu Hamdan in conversation with Anthony Downey
What Was Lost2 May 2012
Joana Hadjithomas and Khalil Joreige in conversation with Nat Muller
The Jerusalem Show2 May 2012
Jack Persekian in conversation with Basak Senova
A Militant Cinema2 May 2012
Mohanad Yaqubi in conversation with Sheyma Buali
An Aesthetics of Expiration2 May 2012
Ziad Antar in Conversation with Anthony Downey
A project by Tom Bogaert for Ibraaz
Tom Bogaert
Culture In Defiance
Continuing Traditions of Satire, Art and the Struggle for Freedom in Syria
Map of Faith
A project by Yousef Moscatello
Yousef Moscatello
A project by Fayçal Baghriche
Untitled YouTube Stills
A Project by Anahita Razmi
Anahita Razmi
Transition, a photographic series by Myriam Abdelaziz
Myriam Abdelaziz
The Past Was Another Country
Two Projects by Sinisa Vlajkovic
Sinisa Vlajkovic
From Brute Ornament
Seher Shah's Recent Drawings
Seher Shah
D.M., The Arabian Gulf Chapter
Isak Berbic
On-longing
A Project by Saba Innab
Saba Innab
Bus Cemetery
A Project by Dictaphone Group
Dictaphone group
The Missing Link 3
A Mother's Tongue, On Ahmad Ghossein's film My Father is Still a Communist
Daniella Rose King
The two-year-old MASS Alexandria, founded by artist Wael Shawky in the working-class neighbourhood of Miami in east Alexandria, Egypt, aims to create a space for the production and dissemination of ideas and debates concerning contemporary visual culture. Apart from displaying and encouraging the consumption of art through exhibitions, it creates an open platform and a discursive space for encountering, (con)testing, and contributing to ideas in and around the practice of contemporary visual art and interdisciplinary studies. MASS Alexandria is a seven-month-long programme for artists in Egypt, which provides studio spaces and a study programme comprising discussions, workshops, seminars and reading groups delivered by visiting artists, curators and art educators based in Egypt and across the globe. Artists are invited to participate in the programme through an open call and as well as being provided with a studio space, take part in a study programme and receive mentoring by leading artists and curators. They also show their work in a group exhibition at the end of the programme. The discursive, open-ended and participatory programme is committed primarily to fostering critical engagement and creating a space for new ideas and approaches.
Hatem Imam
Rana Issa
When Umru' al-Qais stood by the traces of the tent of his beloved in the middle of the desert of Hijaz, he shed tears that became the key to Arab poetry. Until recently, no one could have guessed that those tents would one day be made of concrete. These days,...
Seher Shah, Artist
From Brute Ornament: Seher Shah's Recent Drawings
Saba Innab, Artist
On-longing: A Project by Saba Innab
Dictaphone Group is a collaboration between performance artist Tania El Khoury and urban researcher architect Abir Saksouk-Sasso, whose aim is to research specific urban spaces in Lebanon. Issues of public space and public amenities, or indeed the lack thereof in Beirut, come to the fore in Bus Cemetery, a sound-based...
Home Workspace, Beirut
Home Workspace: A Conversation Between Christine Tohme and Anthony Downey
Sinisa Vlajkovic, Photographer
The Past is Another Country: Two Projects by Sinisa Vlajkovic
Tessa Jackson OBE, Chief Executive, Iniva, London
There is no doubt that artists are addressing this question and its associated issues in their work, as anywhere in the world. However the region comprises so many different descriptions of civil society; the politics and economics of one country enable while those in another disable. Volatility can be a positive signal of change or a characteristic of uncertainty and ultimately stasis.
Cultural institutions, governmental and independent, have a responsibility to act as positive agents of activity and debate. How they play a strategic role is recognised both contemporaneously and of course with hindsight. Therefore, lacking in strategic purpose could be said to be a dereliction of duty. Yet to what purpose?
The best cultural institutions offer ways in which a particular society can know itself, look at itself and question or appreciate itself (often in relation to elsewhere). The MENA region has significant examples. Yet as there are disparities in capacity, there is disparity in terms of who some institutions and new initiatives are for. Who is benefitting? How are they contributing to society?
The MENA region, vast as it is, is no different to other parts of the world. Yet it has the opportunity to be different in how it responds.
Omar Berrada, Director of Library and Center for Literary Translation, Dar al-Ma'mûn, Marrakech
Dar al-Ma'mûn is a new arts centre and residency for artists and translators outside of Marrakech. The questions of public space and of civil society have been with us since the beginning, as we were trying to avoid creating a mere retreat for artists, a luxurious ivory tower for intellectuals in the middle of nowhere – precisely because the countryside is not 'nowhere'. We have neighbours, who were there before us – it's a quiet, though lively village, behind which lie more villages. A lot of the adults there are illiterate. Their children, though, go to school, to an elementary school in the village, and a middle school a few miles away.
As a budding institution, our impulse in order to 'bridge the gap' was to establish a children's library and a whole range of free educational projects: reading and writing workshops, literacy classes, a pre-school programme and film screenings. These initiatives have been fascinating and successful and enriching for all involved, but they have not veered much from the provider/receiver model.
Beral Madra, Director, BM Contemporary Art Center, Istanbul
Cultural institutions in Turkey are divided into those run by the state, local governments and private sectors; each have different culture policies and no significant collaborative policies. Contemporary art productions and practices are based in Istanbul and are dependent on private sector investments, rather than official funds. Compared to the EU culture system, the current relations between the producers (artists, art experts) and consumers (public, collectors) are still sporadic and unsustainable.
Political environments in most of the countries in the MENA are still authoritative and semi-democratic, in which art practices serve as activism or protest against human rights violations and restrictions of freedom of expression, among other things, albeit with limited influence in changing the convictions and attitudes of the public. Visual arts are almost the only channel through which creative people can convey their free and critical thinking to their societies and to the world. If the artists are represented in international exhibitions they have more prestige, confidence and power of persuasion in their local communities.
Wthin the neo-capitalist system, the monopoly of corporate culture is not to be avoided! Commercialisation of culture is growing rapidly and the market system norms and requirements force art practices to act accordingly. The distribution of visual production is manipulated by corporate institutions, foundations and art fair companies to their benefits. Yet, there is no other possibility of funding visual arts in the MENA region and even in Turkey, a country with a strong official modernist culture infrastructure and local government public culture institutions. In these regions, contemporary art infrastructures are still to be developed; the existing individual initiatives that practice and produce contemporary art are fragile and unsustainable. Art market prospects are still developing; galleries have financial difficulties to lift up the artists to international platforms.
'The young conservatives embrace the fundamental experience of aesthetic modernity – the disclosure of a de-centered subjectivity, freed from all constraints of rational cognition and purposiveness, from all imperatives of labour and utility – and in this way break out of the modern world. They transpose the spontaneous power of imagination, the experience of the self and affectivity into the remote and the archaic; and in Manichean fashion, they counter-pose to instrumental reason a principle only accessible via "evocation": be it the will to power or sovereignty, Being or the Dionysian power of the poetic'.
Shuruq Harb
A friend recently asked me, what would be my dream cultural/art space in Ramallah?
In the midst of rapid urban construction in Ramallah, my impulse is not to build another building but create what is lacking – an open public space. I feel this would be an artistic, political and cultural intervention against the current tides.
For the longest time, I have been complaining about the lack of properly equipped exhibition spaces in Palestine. And yes, I thought the lack of such a space was holding Palestinian art back, preventing artists from really communicating with the public. I longed for funding for Palestinian art that would be motivated by 'art for art's sake'.
The lack of this Super Duper Art Space has forced me to negotiate my work and role as an artist in society constantly. In Palestine, art has always been asked to visualise national identity, preserve cultural heritage, call for humane treatment, indicate civilisation, democratise society – and so on.
Shumon Basar, Director, Global Art Forum 6
Can or should or will? Everything is possible, while a lot less is likely. These to me are three discrete topics: the health of institutions; public space (itself a maligned, misused term, most of the time); and civil society. I think if artists – or curators, or any agent involved in the arts – had to take all of this on, I wouldn't blame them for conducting an endless Bed-In (with or without Yoko Ono. Or her authorisation). I'd have to plea for specificity in the question being asked. It is the only way to avoid (glib) overarching answers that at their worst mimic (glib) overarching art produced cynically and opportunistically In the Name of MENA. Has anyone opened an espionage agency called MENA yet? They should! Seriously, though (or, still): my honest answer is, 'I don't know', and I would be worried by – and deeply suspicious of – anyone that claimed they did know the answer to this riddle. With acuity like that, I would swiftly make such a bright spark head of MENA (covertly, of course) and solve some of the more pressing problems in the world. Like Bieber Fever. Or economic polarisation.
Khaled Alhamzah, Editor-in-Chief, Jordan Journal of the Arts
I will limit myself to tackling the situation from the point of view of the 'common ground', which is lost or has never been found. There is a wide gap between art practice on one side and the institutions on the other; the first doing the minimum in terms of...
Houcine Tlili, Writer, Tunis
Street art in Tunisia has appeared more and more since the early days of the 'revolution'. But this phenomenon was already there long before events took place. Certain activists – artists working in graphic and visual communication – invaded public spaces to express their grievances. They no longer wanted to express themselves on the walls of private or official galleries but definitively off the walls. Galleries are, in the eyes of these young people, linked to the world of economics, to the world of outdated capitalist exploitation.
The classic fine arts do not constitute an exclusive genre in themselves. New artistic practices have appeared. Their references are varied and their modes of expression are often improvised. Certain artists form groups, others act individually and informally. Some are revolutionary and want to bring art to the people by any means possible, even by provocation. Others are conservative and want to maintain a link with 'grand' art. The two approaches come together to make the street a space for art.
William Wells, Townhouse Gallery, Cairo
Since the 25th of January 2011, a traditional arts programming model has become functionally irrelevant in Egypt. In this context of conflict and change, diverse publics have asked to use Townhouse's spaces in ways that extend far beyond the scope of visual arts exhibitions. Consequently, over the past year, we have focused on initiating and supporting projects that respond to these calls for a critical space for reflection, discussion, and engagement with contemporary social issues.
We remain committed to our mandate of supporting local and regional contemporary arts, but have adopted a flexible, highly responsive curatorial programme that lets us respond to current events. In terms of exhibitions, this has meant opening our spaces to often participatory experiments that do not centre around art objects but rather invite discussion on topical issues – as with The Politics of Representation, an attempt to create a living archive of printed ephemera from Egypt's parliamentary elections that was housed in our first-floor gallery space. Townhouse has also launched initiatives like 'The Workshop Series', a programme of four nine-month long seminars that focus on human rights and social justice, while asking how arts and culture can positively engage in contemporary socio-political issues.
Sandra Teitge, Assistant Curator, 7th Berlin Biennale
News from the Arab World reaches western audiences on a daily basis. The various analogue and online formats of media – TV, radio, newspapers, and blogs – are extensively reporting on the events in this region. In Berlin, and certainly elsewhere in Europe, cultural institutions and festivals reacted very quickly to, and reported on developments by inviting artists from the MENA region to present their performances, films, and theatre pieces. Western cultural producers thus became allies of the revolutionaries.
The panel discussion 'Cairo: The City, the images, the archives' with Khalid Abdalla, Hala Galal, Maha Maamoun and Sarah Rifky, in the framework of the 62nd Berlinale Film Festival, provides just one example of the many festivals and events exploring such a topic. It revealed a diversity of reactions by cultural producers in Egypt and effectively contextualised the situation there. Khalid Abdalla, one of the co-founders of the alternative media collective Mosireen, presented the motivation and the main intention of the group and showed the most important work of the group so far, namely, The Diary of the Revolution, an impressive documentary of the events in Egypt filmed by its citizens.
Laura U. Marks
Yes, artistic practices can offer insights into those things – but need they? Many artists in the region deftly wield smart institutional critique without breaking a sweat. But why not pass that responsibility to the audiences for their work? I think the best way to develop civil society is not to demand that artists engage with civics but to support artists' experiments in all forms.
Of course this implies the need for a non-commercial culture or one in which commercial success is an option, not a criterion. Many institutions in the region are providing forums for experimentation, free inquiry, and spontaneous responses to events. Townhouse in Cairo, Zico House in Beirut, L'Appartement 22 in Rabat, and Traffic in Dubai are just a few that come to mind.
Charlotte Bank
One major obstacle for a diverse art scene in a country or region is the lack of artistic infrastructure with institutions that offer support for artistic research and the production of independent, non-market-related work. During the past decade, most countries in the MENA region have seen the establishment of independent, non-governmental institutions and a wide range of projects that have enabled local artists to pursue their artistic interests. Yet, much still remains to be done as some countries (such as Syria) still show a dramatic lack of such structures. And many institutions still depend largely on foreign funding from western partners who often follow agendas related to the foreign policy of their home countries. This again influences the thematic scope of the projects these institutions fund.
Larissa Sansour
As a politically engaged artist, I have to believe that artistic practices do have the potential to offer insights and negotiate anything from the demands of cultural institutions to politics and the ideals of civil society. Without such a belief, the entire foundation of what I do would be rattled. In each case, however, it is a tug-and-pull relation. It would, for instance, be naive to think that artistic practices themselves are not influenced by cultural institutions – either by being limited by them or acting in defiance of them. Artists are often driven by an urge to defy the restrictions, standards and politics of cultural institutions, and the resulting artistic gestures will eventually be submitted to a hopefully re-negotiated version of the institutions rebelled against, if you will.
Hanan Toukan
'What do we do when as artists we are invited to behave as liberal democratic [beings]? You have your own space, each has their own little house, we can all live together; does this not sound like the idea of a Lebanon of all the different mosaics and cohabitation - the cohabitation that failed us during the war?' (Ziad Abillama, Beirut, June 17, 2009)
In 1995, a young artist staged a disruption within what was already perceived as a disruption of young contemporary artists probing the notion of 'public' space in post-Civil War Beirut. For a group art show, participating artists were each allotted a space within a small park to exhibit their work by a newly formed, non-profit arts organisation. As part of his contribution to the show, the artist provoked his colleagues by handing out a questionnaire asking each if they would allow him to sequester 30 centimetres of each of their allocated spaces. The artist proposed that he would exhibit what he wanted in the space granted to him by his fellow participants as long as he complied with the agreement he made with them regarding the reallocation. His request was unanimously refused.
Ergin Çavuşoğlu, Artist
I am broadly interested in addressing the recontextualisation of cultural heritage in the MENA region by institutions, thus aligning it in the process with current developments in contemporary art at large. Artistic practices are frequently used to measure the economic and cultural growth of geographies. This is often achieved by...
Brian Kuan Wood, Editor, e-flux Journal
Artistic practices can offer many insights, but it is important to remember that when art's role is reduced to a tool for social development or economic prospects, it ceases to be art. Rather than provide a broad qualification of the use value of art in the world, it can be more interesting to consider how artistic practices must necessarily exceed and fall short of providing any direct contribution to civil society, whether political, democratic, economic, or whatever.
Barrak Alzaid
A recent project led by Walid Raad attempted to draw attention to, and improve the treatment of, migrant workers on Saadiyat Island by Guggenheim and its Abu Dhabi partner, the Tourism Development and Investment Company (TDIC). Tactics were initially conducted privately but when it was clear to those involved that changes were not being made, Raad, along with a slew of prominent artists from the Middle East and beyond launched a public letter calling for a boycott of the Guggenheim until the labour practices are resolved.
In this instance, political action cannot be divorced from artistic practice; by escalating the protest to the public domain, the project operates at the register of performance replete with public audience and set on an international stage. Although it is unclear what the effects will be and whether labour practices will shift sufficiently to satisfy the petitioners, the action opens up the potential for change, and creates an alternate avenue for showcasing art and art history.
Angela Harutyunyan
The question implies a view on artistic practice informed by a liberal framework of reception and interpretation: artistic practices are expected to politely negotiate within and with the larger sphere of culture; they are expected to expose, reveal, unmask, reform and finally find a place within various institutional configurations. The question proposes cultural politics wherein the formal, conceptual and sensorial impact of art works is reduced to being instrumentalised either for institutional critique or political contestation in the name of democracy and civil society. In its stead, I would like to reverse and paraphrase the question: 'Can cultural institutions, public spaces and various ideals of civil society negotiate the demands of artistic practices in the MENA region?'
How artistic practices define and negotiate public space is to me the most significant issue in the question posed, which I will begin to discuss in the context of Algiers. The site specific practice of Amina Menia testifies to both the richness of meaning and difficulties of execution endemic to...
Aaron Cezar, Director, Delfina Foundation
The MENA region is not short of attempts by cultural practitioners to interrogate, negotiate and redefine 'the public' (as manifested in the form of an institution, a public space, an audience, or the essentials of civil society). Some of most potent images of events over the last year in the Arab world have been those of graffiti artists/activists, cartoonists and caricaturists that have not only communicated demands and frustrations at the street level in the most immediate way, but have also caught the world's attention and transformed how the region is viewed. The forthcoming 4th Riwaq Biennale in Palestine and Tunisia's second Dream City project, run by artists and activists, also attempt to re-imagine possibilities about how society engages with politics and place. The list of examples goes on.
Myriam Abdelaziz, Photographer
Writing on the Walls: Transition, A Photographic Series by Myriam Abdelaziz
view all responses
What is a platform?
A platform is a space for speaking in public. It is an opportunity to express ideas and thoughts. It also suggests the formal declaration of a stance or position on any given subject.
Unique to Ibraaz is a 'platform', a question put to writers, thinkers and artists about an issue relevant to the MENA region. This platform is sent to respondents both within and beyond the MENA region and contributions will be archived every 12 months.
Ibraaz platforms
Where to Now? Shifting Regional Dynamics and Cultural Production in North Africa and the Middle East
What are the genealogies of performance art in North Africa and the Middle East?
How do we productively map the historical and contemporary relationships that exist between North Africa, the Middle East and the Global South?
What is the future of arts infrastructures and audiences across North Africa and the Middle East?
What role can the archive play in developing and sustaining a critical and culturally located art history?
How has a globalised cultural economy affected the production of contemporary visual culture in North Africa and the Middle East?
With the benefit of hindsight, what role does new media play in artistic practices, activism, and as an agent for social change in the Middle East and North Africa today?
What relationship does visual culture have to the world we live in?
What do we need to know about the MENA region today?
Banner image: Basel Abbas and Ruanne Abou Rahme, detail of The Zone, 2011, video installation, East Jerusalem, The Jerusalem Show 2011. Photograph by Issa Freij. Courtesy of Al-Ma'mal Foundation, Jerusalem.

redpajama_set_name: RedPajamaCommonCrawl


text:
Q: How do I visually stack multiple line graphs above each other in python? I was having trouble creating a plot I need which has multiple line graphs.
What I want is a way to graph each of these above the other (say one has a baseline of y=5 I want the next to have a baseline of y=10) and also each of these graphs must block the one above it.
So this will inevitably look like the cover to Joy Divisions Unknown Pleasures here:
           http://cococubed.asu.edu/images/unknown_pleasures/unknown_pleasures.jpg
Except inverted colors and I also would like an answer that utilizes python or numpy or matplotlib.

A: Here's one way. The key point is to use fill_between function and offset each plotted line with some margin (i*2 in this case). Also, plotting has to start from the top, hence the [::-1] in the arange slice.
t=linspace(-2*pi, 2*pi, 1000)
for i in arange(1, pi, 0.01)[::-1]:
    left = exp(-(t + (i - 1) * 2*pi)**2) * cos(t * i)**2 - 1
    right = exp(-(t - (i - 1) * 2*pi)**2) * cos(t * i)**2 - 1
    vertical_offset = i*2
    fill_between(t, vertical_offset + left + right, facecolor='white')

redpajama_set_name: RedPajamaStackExchange


text:
Q: Bulk update of specific columns (not all) in a table using python list of dictionaries I would like to perform bulk_update_mappings on a table using a python list of dictionaries that has selective columns as keys and its values.
Here is the table class and the python list of dict.
class KpcComputation(BASE):
    """KpcComputation model class"""
    __tablename__ = 'kpc_computation_v2'
    __table_args__ = {'useexisting': True}

    kc_rs_id = Column('kc_rs_id', Integer, ForeignKey("review_sentences_v2.rs_id"))
    kc_kpc_id = Column('kc_kpc_id', Integer, ForeignKey("kpc_v2.kpc_id"))
    kc_kpc_score = Column('kc_kpc_score', Float)
    kc_sentiment = Column('kc_sentiment', String)
    kc_sentiment_score = Column('kc_sentiment_score', Float)
    kc_last_updated_date_time = Column(
        DateTime,
        onupdate=datetime.datetime.now,
        default=datetime.datetime.now
    )
    __mapper_args__ = {
        'primary_key': [kc_rs_id, kc_kpc_id]}

dict_data = [{'kc_rs_id': 1194773, 'kc_sentiment': 'neutral', 'kc_sentiment_score': 2.0},
             {'kc_rs_id': 1194774, 'kc_sentiment': 'positive', 'kc_sentiment_score': 3.0},
             {'kc_rs_id': 1550643, 'kc_sentiment': 'negative', 'kc_sentiment_score': 1.0}]

The update operation has to happen only on kc_sentiment and kc_sentiment_score wherever the kc_rs_id matches between the table and the python list of dict. I tried the following method to update,
self.session.bulk_update_mappings(KpcComputation, dict_data)
self.session.commit()

My understanding is that the above statement will update the rows with new values wherever the kc_rs_id matches. But I feel I'm missing something.
I have tried finding ways to perform bulk update on specific columns but some answers suggested to use values for all the columns (filling columns that are not of insterest with some default values) which is not what I want. I'm new to SQLAlchemy so not able figure out how to exactly achieve this. Are there any better ways to do the same? Any suggestion is appreciated.


It is time to get your charity or community group involved and applying for the 2018 Z Energy Good in the Hood. Application is easy, just click here to apply on line.
Even better take a minute to watch the video and find out what it is all about.
Z Energy #GoodInTheHood is on again soon. Get your fav charity or community group involved for their share of $4k. Applications close 28th Feb. learn more by clicking play.
Tracey has been very busy!!!!
Tracey's been in the hood and reports it's all good. It's been a busy day for the team at Z Rutherford as they get ready for the 2018 Z Energy #GoodInTheHood. Applications end soon.
Good in the Hood is all about helping local groups doing good in our neighbourhoods. To see if your group is eligible to apply, you just answer three questions on the Z NZ website. If you're eligible, you'll be able to apply straight away.
Click here to begin your Good in the Hood Journey.
May 03 Welcome to this years Charities at Z Rutherford. Let's get Good in the Hood Nelson!
May is always exciting at the Bowater Motor Group Z Energy stations. It is a chance to facilitate giving back to local charity groups something all of them need to survive - cold hard cash!
This year we are pleased to announce the following charities that need your support to sort out what percentage of the $4,000 they will receive.
We got to meet this year's 2017 Z Rutherford Good in the Hood charities. Your token translates directly into funding dollars for these awesome groups so come down and support them. Big Brothers Big Sisters of Nelson, Victim Support New Zealand Nelson/Tasman, Child Cancer Foundation Nelson and our top of the south St John's.
Check out the rest of the articles in the section to find out more about the charities, how easy it is to vote, and what these charities are all about.
The 2017 Good in the Hood is on Nelson! Here's how to vote.
2017 funding is open. Get your charity involved!


text:
HomeReviewsReview: 2018 Porsche Panamera 4 Sport Turismo, Stuttgart's new eye candy
/ Dec 13, 2018 9:33 pm
/Porsche AGPorsche MalaysiaPorsche Panamera Sport TurismoSime Darby Auto Performance
Review: 2018 Porsche Panamera 4 Sport Turismo, Stuttgart's new eye candy
It's common knowledge that the 911 is one of very few sports cars you can drive to work with ease and come the weekends, it'll take any open day track day in its stride and still be able to drive you home after.
If the 911 is the sports car for all seasons, the new Panamera 4 Sport Turismo is the Porsche for all occasions. You might think the same about the Cayenne but lets be realistic, being an SUV and all it just wouldn't have the same dynamism of the 911 or the Panamera, when the sudden urge arises to swipe through the next long swooping bend.
But let's wind it back a little. When I first laid eyes on what could be the next four-door Porsche through images of the Porsche 989, I was horrified.
It looked as if it was performing an unnatural stretch – like a man doing a split – with both his hands pulled sideways and downwards. It's as uncomfortable to picture as it is to read.
Having already had to live with the existence of a high-rise Porsche, the Cayenne, the thought of diluting the Porsche brand further (which in MY MIND consists only of 911s) with yet another mass-appeal product just made me cringe.
I've seen what a four-door Ferrari 456 GT looks like on paper, what the Aston Martin Rapide looks like in person and more recently, a Lamborghini four-door concept all over the Internet – none of them looks as appealing as their two-door counterparts would.
But in 2009, it happened and just like everyone expected, it was like a stab in the eye with a crinkled fork, on fire. The second generation did the Panamera (Carrera + Panamericana) and ultimately Porsche name more justice with an even more pronounced fastback look but no matter how you do it, a 911 silhouette with four doors just doesn't work – visually, at least.
And that's why I think they've finally hit the bull's eye with the Sport Turismo. Now you can't see it as a stretched 911 anymore, it looks purpose-built; to stand on its own and project more individualism.
Objectively, it may still not be for everyone. You may still not like it, but you won't hate it. Me, I simply love how it looks. That burning fork is now replaced with a warm towel, gently placed on by a pair of delicate hands.
Arguably, it would look more proportionate with shorter rear overhangs, but it's got that chunky but approachable hatchback look that just doesn't try too hard to claim attention.
It gets better with closer examination of the details. Those 21-inch "Exclusive Design" wheels, a RM 23k option, are just to die for. Another must have item on the options list is that RM 16k quad-tailpipe Sport exhaust system that'll respond either with a gentle purr or a fierce growl, depending on how far you stretch your right feet to trigger the 2.9-litre biturbo V6 engine.
Even the 4-piece Porsche Dynamic Light System (PDLS) LED headlight system is an ornament on its own – there's an allure to it that just makes you want to take a closer look at its meticulous LED arrangement. Throw in a further RM 7,000 into the order sheet and you'll score yourself the LED Matrix PDLS pair.
But whatever you pick, please tick this particular "Special Colour" option with the lush Red hue; the Sport Turismo just turns heads everywhere it goes. It's like walking around with a big red "Ang Pow"; you can't not draw attention to yourself.
The "Porsche-ness" you seek is more apparent on the inside of the Sport Turismo, and behind the wheel, than from how it looks on the outside.
Let me try it to sum this up in the simplest way I can; it all just feels so right. Every twist of a knob, the push of a button, the resistance and the sound that it makes, justifies its RM 1 million price tag. This particular unit will cost you more, it's got every possible option on sale.
Whether it's a trim or a surface or a click, it all feels "tailor-made" but not for a specific individual but instead, "customised" for the masses, for every being privileged to ride in or own one to feel at home and at the centre of it all.
The gear lever console can be easily accustomed to but I suspect the more senior spectrum of Panamera owners will spend more time getting to know the 12-inch central command/infotainment system aptly named the Porsche Communication System, than it took them to assimilate with smartphones.
It also won't be easy, for the old and young for that matter, to get the exact adjustments of the electronically-controlled air con vents – you'll need the steady hands of a surgeon to get it just at the right position. In other words, you'll have to split your eyeballs in opposite directions.
At the back, the first thing you'd notice, if you've spent time in a Panamera is the increased head room from the Sport Turismo's "wagon" design. It doesn't feel like it was built to confine and induce claustrophobia in you, like the Panameras of old.
I absolutely love how the centre tunnel cascades to the back. The view ahead from the back allows you to appreciate the overall design inside the car; it's like an operating theater, draped in soft leather.
Behind the wheel, I like how easy the Sport Turismo was to drive. Its light but relatively communicative steering, taut pedals, enormously assuring brakes exudes harmony – a familiar trait of every Porsche driving experience.
Powerful it is not; not by any means. For the same price of a BMW M5 and Mercedes-Benz E63 S 4MATIC, it will be left for dust from the get-go with a 0 to 100 km/h time of just 5.3 seconds, armed with only 330 hp and 450Nm to pull its 1.9-tonne weight.
As much as it tries and to an extent succeeds to mask its weight, its belly still shows. The V6 engine really needs a good squeeze, to avoid feeling as if you were running with diving weights strapped on.
But work the revs hard enough through the flawless 8-speed PDK transmission, and you'd have a chubby kid that moves with the fluidity of a gymnast. The PDK gearbox is, in my opinion, simply the best transmission out there at the moment.
And as a long-distance, high speed cruiser, the Panamera Sport Turismo is right up there with the rest. It encloses you impeccably from the elements outside, making your mile-crunching journeys nearly effortless.
Considering the brief moment spent with the car, like literally for just a few hours, I must say it projected more strengths than weaknesses and its pros definitely out-shined any of its cons, if any at all.
And if it's down to the question of why you should get the Panamera Sport Turismo over the faster BMW or the rude Mercedes-Benz, I put this back to you; why would you bother with a Coach or Micheal Kors bag if you can get something with a Prada badge for the same money?
Tags:Porsche AGPorsche MalaysiaPorsche Panamera Sport TurismoSime Darby Auto Performance
Video: Compact Hatchback of Malaysia, Proton Iriz – #COM2018
Two more BMW i Charging stations in Ramada Plaza, Melaka


text:
//===--- LoopRegionAnalysis.cpp -------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sil-loop-region-analysis"
#include "swift/SILAnalysis/LoopRegionAnalysis.h"
#include "swift/Basic/Range.h"
#include "llvm/Support/DOTGraphTraits.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/GraphWriter.h"

using namespace swift;

//===----------------------------------------------------------------------===//
//                                 LoopRegion
//===----------------------------------------------------------------------===//

LoopRegion::~LoopRegion() {
  // Blocks do not have subregion data, so everything should just clean up via
  // RAII.
  if (isBlock())
    return;

  // Otherwise, we need to cleanup subregion data.
  getSubregionData().~SubregionData();
}

LoopRegion::BlockTy *LoopRegion::getBlock() const {
  return Ptr.get<BlockTy *>();
}

LoopRegion::LoopTy *LoopRegion::getLoop() const {
  return Ptr.get<LoopTy *>();
}

LoopRegion::FunctionTy *LoopRegion::getFunction() const {
  return Ptr.get<FunctionTy *>();
}

void LoopRegion::dump() const {
  print(llvm::outs());
  llvm::outs() << "\n";
}

void LoopRegion::dumpName() const {
  printName(llvm::outs());
  llvm::outs() << "\n";
}

void LoopRegion::printName(llvm::raw_ostream &os) const {
  if (isBlock()) {
    os << "BB" << getID();
    return;
  }
  if (isLoop()) {
    os << "Loop" << getID();
    return;
  }
  assert(isFunction());
  os << "Function" << getID();
  return;
}

void LoopRegion::print(llvm::raw_ostream &os, bool isShort) const {
  os << "(region id:" << ID;
  if (isShort) {
    os << ")";
    return;
  }
  os << " kind:";
  if (isBlock()) {
    os << "bb  ";
  } else if (isLoop()) {
    os << "loop";
  } else if (isFunction()) {
    os << "func";
  } else {
    llvm_unreachable("Unknown region type");
  }

  os << " ucfh:" << (IsUnknownControlFlowEdgeHead? "true " : "false")
     << " ucft:" << (IsUnknownControlFlowEdgeTail? "true " : "false");
}

llvm::raw_ostream &llvm::operator<<(llvm::raw_ostream &os, LoopRegion &LR) {
  LR.print(os);
  return os;
}

LoopRegion::SuccRange LoopRegion::getSuccs() const {
  auto Range = InnerSuccRange(Succs.begin(), Succs.end());
  return SuccRange(Range, SuccessorID::ToLiveSucc());
}

LoopRegion::LocalSuccRange LoopRegion::getLocalSuccs() const {
  auto Range = InnerSuccRange(Succs.begin(), Succs.end());
  return LocalSuccRange(Range, SuccessorID::ToLiveLocalSucc());
}

LoopRegion::NonLocalSuccRange LoopRegion::getNonLocalSuccs() const {
  auto Range = InnerSuccRange(Succs.begin(), Succs.end());
  return NonLocalSuccRange(Range, SuccessorID::ToLiveNonLocalSucc());
}

/// Replace OldSuccID by NewSuccID, just deleting OldSuccID if what NewSuccID
/// is already in the list.
void LoopRegion::replaceSucc(SuccessorID OldSucc, SuccessorID NewSucc) {
  DEBUG(llvm::dbgs() << "                Replacing " << OldSucc << " with "
                     << NewSucc << "\n");
  Succs.replace(OldSucc, NewSucc);
}

llvm::raw_ostream &llvm::operator<<(llvm::raw_ostream &os,
                                    LoopRegion::SuccessorID &S) {
  return os << "(succ id:" << S.ID
            << " nonlocal:" << (S.IsNonLocal ? "true" : "false") << ")";
}

//===----------------------------------------------------------------------===//
//                           LoopRegionFunctionInfo
//===----------------------------------------------------------------------===//

LoopRegionFunctionInfo::LoopRegionFunctionInfo(FunctionTy *F,
                                               PostOrderFunctionInfo *PI,
                                               LoopInfoTy *LI)
    : F(F), Allocator(), BBToIDMap(), LoopToIDMap(),
#ifndef NDEBUG
      IDToRegionMap(PI->size()), AllBBRegionsCreated(false) {
#else
      IDToRegionMap(PI->size()) {
#endif
  if (F->isExternalDeclaration())
    return;
  DEBUG(llvm::dbgs() << "**** LOOP REGION FUNCTION INFO ****\n");
  DEBUG(llvm::dbgs() << "Analyzing function: " << F->getName() << "\n");
  initializeBlockRegions(PI, LI);
  initializeLoopRegions(LI);
  initializeFunctionRegion(LI->getTopLevelLoops());
#ifndef NDEBUG
  verify();
#endif
}

LoopRegionFunctionInfo::~LoopRegionFunctionInfo() {
  for (auto *R : IDToRegionMap) {
    R->~RegionTy();
  }
  IDToRegionMap.clear();
}

void LoopRegionFunctionInfo::verify() {
#ifndef NDEBUG
  llvm::SmallVector<unsigned, 8> UniquePredList;
  llvm::SmallVector<LoopRegion::SuccessorID, 8> UniqueSuccList;
  for (auto *R : IDToRegionMap) {
    // Make sure that our region has a pred list without duplicates. We do not
    // care if the predecessor list is sorted, just that it is unique.
    {
      UniquePredList.clear();
      std::copy(R->Preds.begin(), R->Preds.end(), std::back_inserter(UniquePredList));
      std::sort(UniquePredList.begin(), UniquePredList.end());
      auto End = UniquePredList.end();
      assert(End == std::unique(UniquePredList.begin(), UniquePredList.end()) &&
             "Expected UniquePredList to not have any duplicate elements");
    }

    // If this node does not have a parent, it should have no non-local
    // successors.
    if (!R->ParentID.hasValue()) {
      auto NLSuccs = R->getNonLocalSuccs();
      assert(NLSuccs.begin() == NLSuccs.end() &&
             "Can not have non local "
             "successors without a parent node");
      continue;
    }

    // If this node /does/ have a parent, make sure that all non-local
    // successors point to a successor in the parent and match whether or not it
    // is dead.
    auto *ParentRegion = getRegion(*R->ParentID);
    unsigned NumParentSuccs = ParentRegion->succ_size();
    for (LoopRegion::SuccessorID ID : R->getSuccs()) {
      // Skip local successors. We are not verifying anything here.
      if (!ID.IsNonLocal)
        continue;
      assert(ID.ID < NumParentSuccs && "Non local successor pointing off the "
                                       "parent node successor list?!");
      // Since we are not dead, make sure our parent is not dead.
      assert(ParentRegion->Succs[ID.ID].hasValue() &&
             "non-local successor edge sources should have the same liveness "
             "properties as non-local successor edge targets");
      // Make sure that we can look up the local region corresponding to this
      // region's successor.
      auto *OtherR = getRegionForNonLocalSuccessor(R, ID.ID);
      (void)OtherR;

      // If R and OtherR are blocks, then OtherR should be a successor of the
      // real block.
      if (R->isBlock() && OtherR->isBlock())
        assert(R->getBlock()->isSuccessor(OtherR->getBlock()) &&
               "Expected either R was not a block or OtherR was a CFG level "
               "successor of R.");
    }
  }
#endif
}

//===---
// Region Creation Functions
//

LoopRegionFunctionInfo::RegionTy *
LoopRegionFunctionInfo::getRegion(BlockTy *BB) const {
  assert(AllBBRegionsCreated && "All BB Regions have not been created yet?!");
  // Check if we have allocated a region for this BB. If so, just return it.
  auto Iter = BBToIDMap.find(BB);
  if (Iter != BBToIDMap.end()) {
    return IDToRegionMap[Iter->second];
  }
  llvm_unreachable("Unknown BB?!");
}

LoopRegionFunctionInfo::RegionTy *
LoopRegionFunctionInfo::getRegion(FunctionTy *F) const {
  if (FunctionRegionID.hasValue()) {
    return IDToRegionMap[FunctionRegionID.getValue()];
  }

  auto &Self = const_cast<LoopRegionFunctionInfo &>(*this);
  unsigned Idx = IDToRegionMap.size();
  unsigned NumBytes = sizeof(RegionTy) + sizeof(LoopRegion::SubregionData);
  void *Memory = Self.Allocator.Allocate(NumBytes, alignof(RegionTy));
  auto *R = new (Memory) RegionTy(F, Idx);
  new ((void *)&R[1]) LoopRegion::SubregionData();
  Self.IDToRegionMap.push_back(R);
  Self.FunctionRegionID = Idx;
  return R;
}

LoopRegionFunctionInfo::RegionTy *
LoopRegionFunctionInfo::getRegion(LoopTy *Loop) const {
  auto Iter = LoopToIDMap.find(Loop);
  if (Iter != LoopToIDMap.end()) {
    return IDToRegionMap[Iter->second];
  }

  auto &Self = const_cast<LoopRegionFunctionInfo &>(*this);
  unsigned Idx = IDToRegionMap.size();
  unsigned NumBytes = sizeof(RegionTy) + sizeof(LoopRegion::SubregionData);
  void *Memory = Self.Allocator.Allocate(NumBytes, alignof(RegionTy));
  auto *R = new (Memory) RegionTy(Loop, Idx);
  new ((void *)&R[1]) LoopRegion::SubregionData();
  Self.IDToRegionMap.push_back(R);
  Self.LoopToIDMap[Loop] = Idx;
  return R;
}

LoopRegionFunctionInfo::RegionTy *
LoopRegionFunctionInfo::createRegion(BlockTy *BB, unsigned RPONum) {
  assert(!AllBBRegionsCreated && "All BB Regions have been created?!");
  // Check if we have allocated a region for this BB. If so, just return it.
  auto Iter = BBToIDMap.find(BB);
  if (Iter != BBToIDMap.end()) {
    return IDToRegionMap[Iter->second];
  }

  unsigned Idx = RPONum;
  auto *R = new (Allocator) RegionTy(BB, RPONum);
  IDToRegionMap[RPONum] = R;
  BBToIDMap[BB] = Idx;
  return R;
}

//===---
// Block Region Initialization
//

void LoopRegionFunctionInfo::initializeBlockRegionSuccessors(
    BlockTy *BB, RegionTy *BBRegion, PostOrderFunctionInfo *PI) {
  for (auto &SuccIter : BB->getSuccessors()) {
    unsigned SuccRPOIndex = *PI->getRPONumber(SuccIter.getBB());
    auto *SuccRegion = createRegion(SuccIter.getBB(), SuccRPOIndex);
    BBRegion->addSucc(SuccRegion);
    SuccRegion->addPred(BBRegion);
    DEBUG(llvm::dbgs() << "    Succ: ";
          SuccIter.getBB()->printAsOperand(llvm::dbgs());
          llvm::dbgs() << " RPONum: " << SuccRPOIndex << "\n");
  }
}

void LoopRegionFunctionInfo::markIrreducibleLoopPredecessorsOfNonLoopHeader(
    BlockTy *NonHeaderBB, RegionTy *NonHeaderBBRegion,
    PostOrderFunctionInfo *PI) {
  for (BlockTy *Pred : NonHeaderBB->getPreds()) {
    // If we do not have an RPO number for a predecessor, it is because the
    // predecessor is unreachable and a pass did not clean up after
    // itself. Just ignore it, it will be cleaned up by simplify-cfg.
    auto PredRPONumber = PI->getRPONumber(Pred);
    if (!PredRPONumber || *PredRPONumber < NonHeaderBBRegion->getRPONumber())
      continue;

    auto *PredRegion = createRegion(Pred, *PredRPONumber);
    DEBUG(llvm::dbgs() << "    Backedge: ";
          Pred->printAsOperand(llvm::dbgs());
          llvm::dbgs() << " " << PredRegion->getID() << "\n");

    // We mark the head/tail as unknown control flow regions since in CFGs like
    // the following:
    //
    //         /------\
    //         v      |
    // BB0 -> BB1 -> BB2 -> BB4
    //  |             |^
    //  |             v|
    //  \----------> BB3
    //
    // We need to ensure that the edge from BB0 -> BB3 does not propagate any
    // dataflow state into the irreducible loop even if the back edge we see is
    // from BB3 -> BB2.
    NonHeaderBBRegion->IsUnknownControlFlowEdgeHead = true;
    NonHeaderBBRegion->IsUnknownControlFlowEdgeTail = true;
    PredRegion->IsUnknownControlFlowEdgeHead = true;
    PredRegion->IsUnknownControlFlowEdgeTail = true;
  }
  DEBUG(llvm::dbgs() << "\n");
}

void
LoopRegionFunctionInfo::
markMultipleLoopLatchLoopBackEdges(RegionTy *LoopHeaderRegion, LoopTy *Loop,
                                   PostOrderFunctionInfo *PI) {
  llvm::SmallVector<BlockTy *, 4> Latches;
  Loop->getLoopLatches(Latches);
  assert(Latches.size() > 1 &&
         "Assumed that this loop had multiple loop latches");

  LoopHeaderRegion->IsUnknownControlFlowEdgeHead = true;
  for (auto *LatchBB : Latches) {
    auto *LatchBBRegion = createRegion(LatchBB, *PI->getRPONumber(LatchBB));
    LatchBBRegion->IsUnknownControlFlowEdgeTail = true;
  }
}

void LoopRegionFunctionInfo::initializeBlockRegions(PostOrderFunctionInfo *PI,
                                                    LoopInfoTy *LI) {
  DEBUG(llvm::dbgs() << "Visting BB Regions:\n");

  // Initialize regions for each BB and associate RPO numbers with each BB.
  //
  // We use the RPO number of a BB as its Index in our data structures.
  for (auto P : PI->getEnumeratedReversePostOrder()) {
    BlockTy *BB = P.first;
    unsigned RPOIndex = P.second;
    auto *BBRegion = createRegion(BB, RPOIndex);
    assert(BBRegion && "Create region fail to create a BB?");
    assert(*PI->getRPONumber(BB) == RPOIndex &&
           "Enumerated Reverse Post Order out of sync with RPO number");

    DEBUG(llvm::dbgs() << "Visiting BB: "; BB->printAsOperand(llvm::dbgs());
          llvm::dbgs() << " RPO: " << RPOIndex << "\n");

    // Wire up this BB as an "initial predecessor" of all of its successors
    // and make each of its successors a successor for the region.
    initializeBlockRegionSuccessors(BB, BBRegion, PI);

    // Then try to lookup the innermost loop that BB belongs to. If we get back
    // a nullptr, then we know that the BB belongs to the function region and is
    // also not a loop header.
    auto *Loop = LI->getLoopFor(BB);
    auto *ParentRegion = Loop? getRegion(Loop) : getRegion(F);

    // Add BBRegion to the ParentRegion.
    ParentRegion->addBlockSubregion(BBRegion);

    // Determine if this basic block is part of an irreducible loop by looking
    // at all blocks that are:
    //
    // 1. Not in any loop identified by loop info.
    // 2. Or are part of an identified loop but are not a loop header.
    //
    // In such a case, check if any predecessors have a smaller PO number. If so
    // then we know that both this BB and the predecessor are boundaries of a
    // loop that is not understood by SILLoopInfo. Mark them as unknown control
    // flow boundaries. Then add the BB as a subregion to its parent region.
    DEBUG(llvm::dbgs() << "Checking Preds for Back Edges\n");
    if (!Loop || !LI->isLoopHeader(BB)) {
      markIrreducibleLoopPredecessorsOfNonLoopHeader(BB, BBRegion, PI);
      continue;
    }
    assert(Loop && "Should have a non-null Loop at this point");
    assert(ParentRegion && "Expected a non-null LoopRegion");

    // Now we know that the block is in a loop and is a loop header. Check if
    // this loop has multiple latches. If so, mark the latch head/tail blocks as
    // head/tail unknown cfg boundaries.
    //
    // We rely on Loop canonicalization to separate such loops into separate
    // nested loops.
    ParentRegion->getSubregionData().RPONumOfHeaderBlock = RPOIndex;

    // If we have one loop latch, continue.
    if (Loop->getLoopLatch()) {
      DEBUG(llvm::dbgs() << "\n");
      continue;
    }

    // Otherwise, mark each of the loop latches as irreducible control flow edge
    // tails so we are conservative around them.
    markMultipleLoopLatchLoopBackEdges(BBRegion, Loop, PI);
    DEBUG(llvm::dbgs() << "\n");
  }

#ifndef NDEBUG
  AllBBRegionsCreated = true;
#endif
}

//===---
// Loop and Function Region Initialization
//

void LoopRegionFunctionInfo::initializeLoopRegions(LoopInfoTy *LI) {
  // Now visit the loop nest in a DFS.
  llvm::SmallVector<LoopTy *, 16> LoopWorklist(LI->begin(), LI->end());
  llvm::SmallPtrSet<LoopTy *, 16> VisitedLoops;

  while (LoopWorklist.size()) {
    LoopTy *L = LoopWorklist.back();
    auto *LRegion = getRegion(L);

    // If we have not visited this loop yet and it has subloops, add its
    // subloops to the worklist and continue.
    auto SubLoops = L->getSubLoopRange();
    if (VisitedLoops.insert(L).second && SubLoops.begin() != SubLoops.end()) {
      for (auto *SubLoop : SubLoops) {
        LoopWorklist.push_back(SubLoop);
      }
      continue;
    }
    LoopWorklist.pop_back();

    // Otherwise, process this loop. We have already visited all of its
    // potential children loops.
    initializeLoopFunctionRegion(LRegion, SubLoops);
  }
}

/// For each predecessor of the header of the loop:
///
/// 1. If the predecessor is not in the loop, make the predecessor a predecessor
/// of the loop instead of the header.
///
/// 2. If the predecessor *is* in the loop it must be the tail of a backedge. We
/// remove these back edges and instead represent them as unknown control flow
/// edges. This is because we rely on loop canonicalization to canonicalize
/// multiple backedge loops into separate loops.
LoopRegionFunctionInfo::RegionTy *
LoopRegionFunctionInfo::
rewriteLoopHeaderPredecessors(LoopTy *SubLoop, RegionTy *SubLoopRegion) {
  auto *SubLoopHeaderRegion = getRegion(SubLoop->getHeader());
  assert(SubLoopHeaderRegion->isBlock() && "A header must always be a block");

  DEBUG(llvm::dbgs()
        << "        Header: " << SubLoopHeaderRegion->getID() << "\n"
        << "        Rewiring Header Predecessors to be Loop Preds.\n");

  if (SubLoopHeaderRegion->IsUnknownControlFlowEdgeHead)
    SubLoopRegion->IsUnknownControlFlowEdgeHead = true;

  for (unsigned PredID : SubLoopHeaderRegion->Preds) {
    auto *PredRegion = getRegion(PredID);

    DEBUG(llvm::dbgs() << "            " << PredRegion->getID() << "\n");
    if (!SubLoopRegion->containsSubregion(PredRegion)) {
      DEBUG(llvm::dbgs() << "            Not in loop... Replacing...\n");
      // This is always a local edge since non-local edges can only have loops
      // as heads. Since the head of our edge is SubLoopHeaderRegion, this must
      // be local.
      PredRegion->replaceSucc(LoopRegion::SuccessorID(SubLoopHeaderRegion->ID,
                                                      /*IsNonLocal*/ false),
                              LoopRegion::SuccessorID(SubLoopRegion->ID,
                                                      /*IsNonLocal*/ false));
      propagateLivenessDownNonLocalSuccessorEdges(PredRegion);
      SubLoopRegion->addPred(PredRegion);
      continue;
    }

    DEBUG(llvm::dbgs() << "            Is in loop... Erasing...\n");
    // We are abusing the fact that a block can only be a local successor.
    PredRegion->removeLocalSucc(SubLoopHeaderRegion->getID());
    propagateLivenessDownNonLocalSuccessorEdges(PredRegion);
  }
  SubLoopHeaderRegion->Preds.clear();

  return SubLoopHeaderRegion;
}

static void
getExitingRegions(LoopRegionFunctionInfo *LRFI,
                  SILLoop *Loop,
                  LoopRegion *LRegion,
                  llvm::SmallVectorImpl<LoopRegion *> &ExitingRegions) {
  llvm::SmallVector<SILBasicBlock *, 8> ExitingBlocks;
  Loop->getExitingBlocks(ExitingBlocks);

  // Determine the outer most region that contains the exiting block that is not
  // this subloop's region. That is the *true* exiting region.
  for (auto *BB : ExitingBlocks) {
    auto *Region = LRFI->getRegion(BB);
    unsigned RegionParentID = Region->getParentID();
    while (RegionParentID != LRegion->getID()) {
      Region = LRFI->getRegion(RegionParentID);
      RegionParentID = Region->getParentID();
    }
    ExitingRegions.push_back(Region);
  }

  // We can have a loop subregion that has multiple exiting edges from the
  // current loop. We do not want to visit that loop subregion multiple
  // times. So we unique the exiting region list.
  sortUnique(ExitingRegions);
}

/// For each exiting block:
///
/// 1. Make any successors outside of the loop successors of the loop instead
/// of the exiting block.
///
/// 2. Any successors that are inside the loop but are not back edges are
/// left alone.
///
/// 3. Any successors that are inside the loop but are the head of a backedge
/// have the edge removed. This is computed by the successor having a greater
/// post order number than the exit.
///
/// *NOTE* We have to be careful here since exiting blocks may include BBs
/// that have been subsumed into a subloop already. Also to determine back
/// edges, we need to compare post order numbers potentially of loop headers,
/// not the loops themselves.
void
LoopRegionFunctionInfo::
rewriteLoopExitingBlockSuccessors(LoopTy *Loop, RegionTy *LRegion) {
  llvm::SmallVector<RegionTy *, 8> ExitingRegions;
  getExitingRegions(this, Loop, LRegion, ExitingRegions);

  DEBUG(llvm::dbgs() << "    Visiting Exit Blocks...\n");
  for (auto *ExitingRegion : ExitingRegions) {
    DEBUG(llvm::dbgs() << "        Exiting Region: "
          << ExitingRegion->getID() << "\n");
    for (auto SuccID : ExitingRegion->getSuccs()) {
      DEBUG(llvm::dbgs() << "            Succ: " << SuccID.ID
                         << ". IsNonLocal: "
                         << (SuccID.IsNonLocal ? "true" : "false") << "\n");

      auto *SuccRegion = getRegion(SuccID.ID);
      if (!LRegion->containsSubregion(SuccRegion)) {
        DEBUG(llvm::dbgs() << "            Is not a subregion, replacing.\n");
        SuccRegion->replacePred(ExitingRegion->ID, LRegion->ID);
        if (ExitingRegion->IsUnknownControlFlowEdgeTail)
          LRegion->IsUnknownControlFlowEdgeTail = true;
        // If the successor region is already in this LRegion this returns that
        // regions index. Otherwise it returns a new index.
        unsigned Index = LRegion->addSucc(SuccRegion);
        ExitingRegion->replaceSucc(SuccID,
                                   LoopRegion::SuccessorID(Index, true));
        propagateLivenessDownNonLocalSuccessorEdges(ExitingRegion);
        continue;
      }

      // If the rpo number of the successor is less than the RPO number of the
      // BB, then we know that it is not a backedge.
      if (SuccRegion->getRPONumber() > ExitingRegion->getRPONumber()) {
        DEBUG(llvm::dbgs() << "            Is a subregion, but not a "
              "backedge, not removing.\n");
        continue;
      }
      DEBUG(llvm::dbgs() << "            Is a subregion and a backedge, "
            "removing.\n");
      auto Iter =
        std::remove(SuccRegion->Preds.begin(), SuccRegion->Preds.end(),
                    ExitingRegion->getID());
      SuccRegion->Preds.erase(Iter);
    }
  }
}

/// The high level algorithm is that via the loop info we already know for
/// each subloop:
///
/// 1. predecessors.
/// 2. header.
/// 3. exiting blocks.
/// 4. successor blocks.
///
/// This means that we can simply fix up those BB regions.
///
/// *NOTE* We do not touch the successors/predecessors of the current loop. We
/// leave those connections in place for our parent loop to fix up. In the case
/// we are the function level loop, these will of course be empty anyways.
void
LoopRegionFunctionInfo::
initializeLoopFunctionRegion(RegionTy *ParentRegion,
                             iterator_range<LoopInfoTy::iterator> SubLoops) {

  DEBUG(llvm::dbgs() << "Initializing Loop Region " << ParentRegion->getID()
        << "\n");
  // For each subloop...
  for (auto *SubLoop : SubLoops) {
    // Grab the region associated with the subloop...
    auto *SubLoopRegion = getRegion(SubLoop);

    DEBUG(llvm::dbgs() << "    Visiting Subloop: " << SubLoopRegion->getID()
          << "\n");

    // First rewrite predecessors of the loop header to point at the loop.
    auto *SubLoopHeaderRegion = rewriteLoopHeaderPredecessors(SubLoop,
                                                              SubLoopRegion);

    // Then rewrite successors of all exits.
    rewriteLoopExitingBlockSuccessors(SubLoop, SubLoopRegion);

    // Add the subloop region to the subregion data.
    ParentRegion->addLoopSubregion(SubLoopRegion, SubLoopHeaderRegion);
  }

  // Now that we have finished processing this loop, sort its subregions so that
  // they are now in RPO order. This works because each BB's ID is its RPO
  // number and we represent loops by the RPO number of their preheader (with a
  // flag in the first bit to say to look in the subloop array for the *real* ID
  // of the loop).
  //
  // TODO: Is this necessary? We visit BBs in RPO order. This means that we
  // should always add BBs in RPO order to subregion lists, no? For now I am
  // going to sort just to be careful while bringing this up.
  ParentRegion->getSubregionData().sortSubregions();
}

void LoopRegionFunctionInfo::
initializeFunctionRegion(iterator_range<LoopInfoTy::iterator> SubLoops) {
  // We have already processed all of our subloops, so everything there has
  // already been properly setup.
  initializeLoopFunctionRegion(getRegion(F), SubLoops);
}

/// Recursively visit all the descendents of Parent. If there is a non-local
/// successor edge path that points to a dead edge in Parent, mark the
/// descendent non-local successor edge as dead.
void LoopRegionFunctionInfo::
propagateLivenessDownNonLocalSuccessorEdges(LoopRegion *Parent) {
  llvm::SmallVector<LoopRegion *, 4> Worklist;
  Worklist.push_back(Parent);

  while (Worklist.size()) {
    LoopRegion *R = Worklist.pop_back_val();
    for (unsigned SubregionID : R->getSubregions()) {
      LoopRegion *Subregion = getRegion(SubregionID);
      bool ShouldVisit = false;
      for (auto &SuccID : Subregion->Succs) {
        // If the successor is already dead, skip it. We should have visited all
        // its children when we marked it as dead.
        if (!SuccID)
          continue;

        // We do not care about local IDs, we only process non-local IDs.
        if (!SuccID->IsNonLocal)
          continue;

        // Finally if the non-local successor edge points to a parent successor
        // that is not dead continue.
        if (R->Succs[SuccID->ID].hasValue())
          continue;

        // Ok, we found a target! Mark is as dead and make sure that we visit
        // the subregion's children.
        ShouldVisit = true;

        // This is safe to do since when erasing in a BlotSetVector, we do not
        // invalidate the iterators.
        Subregion->Succs.erase(*SuccID);
      }

      if (ShouldVisit)
        Worklist.push_back(Subregion);
    }
  }
}

LoopRegionFunctionInfo::RegionTy *
LoopRegionFunctionInfo::
getRegionForNonLocalSuccessor(const LoopRegion *Child, unsigned SuccID) const {
  const LoopRegion *Iter = Child;
  LoopRegion::SuccessorID Succ = {0, 0};

  do {
    Iter = getRegion(Iter->getParentID());
    Succ = Iter->Succs[SuccID].getValue();
    SuccID = Succ.ID;
  } while (Succ.IsNonLocal);

  return getRegion(SuccID);
}

void LoopRegionFunctionInfo::dump() const {
  print(llvm::outs());
  llvm::outs() << "\n";
}

void LoopRegionFunctionInfo::print(raw_ostream &os) const {
  // Print out the information for each loop.
  std::vector<std::pair<LoopRegion *, LoopRegion *>> RegionWorklist;

  // Initialize the worklist with the function level region.
  RegionWorklist.push_back({nullptr, getRegion(F)});

  // Vectors that we use to sort our local successor/predecessor indices to make
  // our output deterministic.
  llvm::SmallVector<unsigned, 4> SortedPreds;
  llvm::SmallVector<unsigned, 4> SortedSuccs;

  // Then go to town...
  while (RegionWorklist.size()) {
    LoopRegion *Parent, *R;
    std::tie(Parent, R) = RegionWorklist.back();
    RegionWorklist.pop_back();

    os << *R;

    // If we have a parent, print out its id. This is not strictly necessary,
    // but it makes it easier to read the output from a dump.
    if (Parent)
      os << " parent:" << Parent->getID();
    os << "\n";

    // Print predecessors.
    SortedPreds.clear();
    for (unsigned Pred : R->Preds)
      SortedPreds.push_back(Pred);
    std::sort(SortedPreds.begin(), SortedPreds.end());
    os << "    (preds";
    for (unsigned SID : SortedPreds) {
      os << "\n        ";
      LoopRegion *PredRegion = getRegion(SID);
      PredRegion->print(os, true);
    }
    os << ")\n";

    os << "    (succs";

    // To make our output deterministic, we sort local successor indices.
    SortedSuccs.clear();
    auto LSuccRange = R->getLocalSuccs();
    std::copy(LSuccRange.begin(), LSuccRange.end(),
              std::back_inserter(SortedSuccs));
    std::sort(SortedSuccs.begin(), SortedSuccs.end());
    for (unsigned SID : SortedSuccs) {
      os << "\n        ";
      LoopRegion *SuccRegion = getRegion(SID);
      SuccRegion->print(os, true);
    }
    os << ")\n";

    os << "    (subregs";
    if (!R->isBlock()) {
      // Go through the subregions.
      for (unsigned SID : R->getSubregions()) {
        os << "\n        ";
        LoopRegion *Subregion = getRegion(SID);
        Subregion->print(os, true);
        RegionWorklist.push_back({R, Subregion});
      }
    }
    os << ")\n";

    SortedSuccs.clear();
    auto NonLSuccs = R->getNonLocalSuccs();
    std::copy(NonLSuccs.begin(), NonLSuccs.end(),
              std::back_inserter(SortedSuccs));
    std::sort(SortedSuccs.begin(), SortedSuccs.end());
    os << "    (non-local-succs";
    for (unsigned I : SortedSuccs) {
      os << "\n        (parentindex:" << I << ")";
    }
    os << "))\n";
  }
}

//===----------------------------------------------------------------------===//
//                              Graphing Support
//===----------------------------------------------------------------------===//

#ifndef NDEBUG

/// A lot of the code below is unfortunate and due to the inflexibility of
/// GraphUtils. But you gotta do what you gotta do.
namespace {

struct LoopRegionWrapper;

struct LoopRegionFunctionInfoGrapherWrapper {
  LoopRegionFunctionInfo *FuncInfo;
  std::vector<LoopRegionWrapper> Data;
};

struct alledge_iterator;

struct LoopRegionWrapper {
  LoopRegionFunctionInfoGrapherWrapper &FuncInfo;
  LoopRegion *Region;

  LoopRegionWrapper *getParent() const {
    unsigned ParentIndex = Region->getParentID();
    return &FuncInfo.Data[ParentIndex];
  }

  alledge_iterator begin();
  alledge_iterator end();
};

/// An iterator on Regions that first iterates over subregions and then over
/// successors.
struct alledge_iterator
    : std::iterator<std::forward_iterator_tag, LoopRegionWrapper> {
  LoopRegionWrapper *Wrapper;
  LoopRegion::subregion_iterator SubregionIter;
  LoopRegion::const_succ_iterator SuccIter;

  alledge_iterator(LoopRegionWrapper *w,
                   swift::LoopRegion::subregion_iterator subregioniter,
                   LoopRegion::const_succ_iterator succiter)
      : Wrapper(w), SubregionIter(subregioniter), SuccIter(succiter) {

    // Prime the successor iterator so that we skip over any initial dead
    // successor edges.
    //
    // TODO: Refactor this to use a FilterRange.
    for (auto SuccEnd = Wrapper->Region->succ_end();
         !SuccIter->hasValue() && SuccIter != SuccEnd; ++SuccIter) {
    }
  }

  bool isSubregion() const {
    return SubregionIter != Wrapper->Region->subregion_end();
  }

  bool isNonLocalEdge() const {
    if (isSubregion())
      return false;
    return SuccIter->getValue().IsNonLocal;
  }

  Optional<unsigned> getSuccIndex() const {
    if (isSubregion())
      return None;
    // Since we have a bidirectional iterator, this will perform increments
    // until we get to SuccIter. This is the behavior we want so that we ensure
    // that we skip over any dead successor edges. We are just performing
    // graphing, so performance is not a concern.
    return std::distance(Wrapper->Region->succ_begin(), SuccIter);
  }

  LoopRegionWrapper *operator*() const {
    if (SubregionIter != Wrapper->Region->subregion_end()) {
      return &Wrapper->FuncInfo.Data[*SubregionIter];
    }
    // If we have a non-local id, just return the parent region's data.
    if ((*SuccIter)->IsNonLocal)
      return &Wrapper->FuncInfo.Data[Wrapper->Region->getParentID()];
    // Otherwise return the data associated with this successor.
    return &Wrapper->FuncInfo.Data[(*SuccIter)->ID];
  }

  alledge_iterator &operator++() {
    if (SubregionIter != Wrapper->Region->subregion_end()) {
      SubregionIter++;
    } else {
      // Make sure that we skip past any dead successors.
      auto End = Wrapper->Region->succ_end();
      do {
        SuccIter++;
      } while (!SuccIter->hasValue() && SuccIter != End);
    }
    return *this;
  }
  alledge_iterator operator++(int) {
    if (SubregionIter != Wrapper->Region->subregion_end()) {
      return alledge_iterator{Wrapper, SubregionIter++, SuccIter};
    }
    auto NewIter = *this;
    ++NewIter;
    return NewIter;
  }
  bool operator==(alledge_iterator rhs) {
    if (Wrapper->Region != rhs.Wrapper->Region)
      return false;
    if (SubregionIter != rhs.SubregionIter)
      return false;
    if (SuccIter != rhs.SuccIter)
      return false;
    return true;
  }
  bool operator!=(alledge_iterator rhs) { return !(*this == rhs); }
};

} // end anonymous namespace

alledge_iterator LoopRegionWrapper::begin() {
  return alledge_iterator(this, Region->subregion_begin(),
                          Region->succ_begin());
}

alledge_iterator LoopRegionWrapper::end() {
  return alledge_iterator(this, Region->subregion_end(), Region->succ_end());
}

namespace llvm {
template <> struct GraphTraits<LoopRegionWrapper> {
  using NodeType = LoopRegionWrapper;
  using ChildIteratorType = alledge_iterator;

  static NodeType *getEntryNode(NodeType *BB) { return BB; }

  static ChildIteratorType child_begin(NodeType *N) { return N->begin(); }
  static ChildIteratorType child_end(NodeType *N) { return N->end(); }
};

template <>
struct GraphTraits<LoopRegionFunctionInfoGrapherWrapper *>
    : public GraphTraits<LoopRegionWrapper> {
  using GraphType = LoopRegionFunctionInfoGrapherWrapper;

  static NodeType *getEntryNode(GraphType *F) { return &F->Data[0]; }

  using nodes_iterator = std::vector<LoopRegionWrapper>::iterator;

  static nodes_iterator nodes_begin(GraphType *F) { return F->Data.begin(); }
  static nodes_iterator nodes_end(GraphType *F) { return F->Data.end(); }
  static unsigned size(GraphType *F) { return F->Data.size(); }
};

} // end namespace llvm

static llvm::cl::opt<unsigned>
    MaxColumns("view-loop-regions-max-columns", llvm::cl::init(80),
               llvm::cl::desc("Maximum width of a printed node"));

namespace {
enum class LongLineBehavior { None, Truncate, Wrap };
} // end anonymous namespace
static llvm::cl::opt<LongLineBehavior> LLBehavior(
    "view-loop-regions-long-line-behavior",
    llvm::cl::init(LongLineBehavior::Truncate),
    llvm::cl::desc("Behavior when line width is greater than the "
                   "value provided my -view-loop-regions-max-columns "
                   "option"),
    llvm::cl::values(
        clEnumValN(LongLineBehavior::None, "none", "Print everything"),
        clEnumValN(LongLineBehavior::Truncate, "truncate",
                   "Truncate long lines"),
        clEnumValN(LongLineBehavior::Wrap, "wrap", "Wrap long lines"),
        clEnumValEnd));

static llvm::cl::opt<bool> RemoveUseListComments(
    "view-loop-regions-remove-use-list-comments", llvm::cl::init(false),
    llvm::cl::desc("Should use list comments be removed"));

namespace llvm {
template <>
struct DOTGraphTraits<LoopRegionFunctionInfoGrapherWrapper *>
    : public DefaultDOTGraphTraits {

  DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}

  static std::string
  getGraphName(const LoopRegionFunctionInfoGrapherWrapper *F) {
    return "Loop Regions for '" + F->FuncInfo->getFunction()->getName().str() +
           "' function";
  }

  static std::string
  getSimpleNodeLabel(LoopRegionWrapper *Node,
                     const LoopRegionFunctionInfoGrapherWrapper *F) {
    std::string OutStr;
    raw_string_ostream OSS(OutStr);
    Node->Region->printName(OSS);
    return OSS.str();
  }

  static std::string
  getCompleteNodeLabel(LoopRegionWrapper *Node,
                       const LoopRegionFunctionInfoGrapherWrapper *F) {
    std::string Tmp0;
    raw_string_ostream OSS(Tmp0);
    Node->Region->printName(OSS);
    if (Node->Region->isUnknownControlFlowEdgeHead())
      OSS << " Unknown CF Head";
    if (Node->Region->isUnknownControlFlowEdgeTail())
      OSS << " Unknown CF Tail";
    if (!Node->Region->isBlock())
      return OSS.str();
    OSS << "\n";
    std::string Tmp1;
    raw_string_ostream OSS2(Tmp1);
    OSS2 << *Node->Region->getBlock();
    std::string OutStr = OSS2.str();
    if (OutStr[0] == '\n')
      OutStr.erase(OutStr.begin());

    // Process string output to make it nicer...
    unsigned ColNum = 0;
    unsigned LastSpace = 0;
    for (unsigned i = 0; i != OutStr.length(); ++i) {
      if (OutStr[i] == '\n') { // Left justify
        OutStr[i] = '\\';
        OutStr.insert(OutStr.begin() + i + 1, 'l');
        ColNum = 0;
        LastSpace = 0;
      } else if (RemoveUseListComments && OutStr[i] == '/' &&
                 i != (OutStr.size() - 1) && OutStr[i + 1] == '/') {
        unsigned Idx = OutStr.find('\n', i + 1); // Find end of line
        OutStr.erase(OutStr.begin() + i, OutStr.begin() + Idx);
        --i;

      } else if (ColNum == MaxColumns) { // Handle long lines.

        if (LLBehavior == LongLineBehavior::Wrap) {
          if (!LastSpace)
            LastSpace = i;
          OutStr.insert(LastSpace, "\\l...");
          ColNum = i - LastSpace;
          LastSpace = 0;
          i += 3; // The loop will advance 'i' again.
        } else if (LLBehavior == LongLineBehavior::Truncate) {
          unsigned Idx = OutStr.find('\n', i + 1); // Find end of line
          OutStr.erase(OutStr.begin() + i, OutStr.begin() + Idx);
          --i;
        }

        // Else keep trying to find a space.
      } else
        ++ColNum;
      if (OutStr[i] == ' ')
        LastSpace = i;
    }

    return OSS.str() + OutStr;
  }

  std::string getNodeLabel(LoopRegionWrapper *Node,
                           const LoopRegionFunctionInfoGrapherWrapper *Graph) {
    if (isSimple())
      return getSimpleNodeLabel(Node, Graph);
    else
      return getCompleteNodeLabel(Node, Graph);
  }

  static bool hasEdgeDestLabels() { return true; }

  static unsigned numEdgeDestLabels(LoopRegionWrapper *Node) {
    return std::distance(Node->begin(), Node->end());
  }

  static std::string getEdgeDestLabel(LoopRegionWrapper *Node, unsigned i) {
    alledge_iterator Iter = Node->begin();
    std::advance(Iter, i);
    return getEdgeSourceLabel(Node, Iter);
  }

  static std::string getEdgeSourceLabel(LoopRegionWrapper *Node,
                                        alledge_iterator I) {
    if (I.isNonLocalEdge())
      return "NLSuc";
    if (I.isSubregion())
      return "Sub";
    return "LSuc";
  }

  /// If you want to override the dot attributes printed for a particular
  /// edge, override this method.
  static std::string
  getEdgeAttributes(const LoopRegionWrapper *Node, alledge_iterator EI,
                    const LoopRegionFunctionInfoGrapherWrapper *Graph) {
    if (EI.isSubregion())
      return "color=red";
    if (EI.isNonLocalEdge())
      return "color=blue";
    return "";
  }

  static bool edgeTargetsEdgeSource(const LoopRegionWrapper *Node,
                                    alledge_iterator I) {
    return I.isNonLocalEdge();
  }

  /// If edgeTargetsEdgeSource returns true, this method is called to determine
  /// which outgoing edge of Node is the target of this edge.
  ///
  /// Currently this can only happen given a non-local edge in which case we
  /// want the non-local edge to point at its parent's successor edge.
  static alledge_iterator getEdgeTarget(LoopRegionWrapper *Node,
                                        alledge_iterator I) {
    assert(I.isNonLocalEdge() && "This should only be called given a non "
                                 "local edge");
    auto *ParentRegion = Node->getParent();
    auto SuccIter = ParentRegion->Region->succ_begin();
    std::advance(SuccIter, (*I.SuccIter)->ID);
    return alledge_iterator(ParentRegion, ParentRegion->Region->subregion_end(),
                            SuccIter);
  }
};
} // end llvm namespace

static llvm::cl::opt<std::string> TargetFunction(
    "view-loop-regions-only-for-function", llvm::cl::init(""),
    llvm::cl::desc("Only print out the loop regions for this function"));
#endif

void LoopRegionFunctionInfo::viewLoopRegions() const {
// This is a no-op when asserts are disabled.
#ifndef NDEBUG
  // If we have a target function, only print that function out.
  if (!TargetFunction.empty() && !(F->getName().str() == TargetFunction))
    return;
  LoopRegionFunctionInfoGrapherWrapper Wrapper;
  Wrapper.FuncInfo = const_cast<LoopRegionFunctionInfo *>(this);
  for (auto *R : IDToRegionMap) {
    Wrapper.Data.push_back({Wrapper, R});
  }
  llvm::ViewGraph(&Wrapper, "loop region function info" + F->getName().str());
#endif
}

//===----------------------------------------------------------------------===//
//                             LoopRegionAnalysis
//===----------------------------------------------------------------------===//

void LoopRegionAnalysis::initialize(SILPassManager *PM) {
  SLA = PM->getAnalysis<SILLoopAnalysis>();
  POA = PM->getAnalysis<PostOrderAnalysis>();
}

//===----------------------------------------------------------------------===//
//                              Main Entry Point
//===----------------------------------------------------------------------===//

SILAnalysis *swift::createLoopRegionAnalysis(SILModule *M) {
  return new LoopRegionAnalysis(M);
}

redpajama_set_name: RedPajamaGithub