LLVM marka laga eego dhinaca Go

Samaynta iskudubaridku waa hawl aad u adag. Laakiin, nasiib wanaag, horumarinta mashaariicda sida LLVM, xallinta dhibaatadan si weyn ayaa loo fududeeyay, taas oo u oggolaanaysa xitaa hal barnaamij-sameeyaha inuu abuuro luqad cusub oo ku dhow waxqabadka C. La shaqeynta LLVM waa mid adag iyadoo xaqiiqda ah in tani ay tahay mid adag. nidaamka waxaa lagu matalaa tiro aad u badan oo kood ah, oo ku qalabaysan dukumeenti yar. Haddaba si loo saxo khaladkaas, qoraaga qoraalkan oo tarjumaaddiisa aan maanta daabacnay, waxa uu soo bandhigayaa tusaalayaal kood ku qoran Go oo muujinaya sidii markii hore loo turjumay. Tag SSA, ka dibna gudaha LLVM IR adoo isticmaalaya isku-duwaha yarGO. Koodhka Go SSA iyo LLVM IR ayaa waxyar la tafatiray si meesha looga saaro waxyaabaha aan khusayn sharraxaadaha halkan lagu bixiyo, si sharraxaaddu u noqoto mid la fahmi karo.

LLVM marka laga eego dhinaca Go

Tusaalaha koowaad

Shaqada ugu horeysa ee aan halkan ku eegi doono waa hab fudud oo lagu daro tirooyinka:

func myAdd(a, b int) int{
    return a + b
}

Shaqadani waa mid aad u fudud, iyo, laga yaabee, ma jiraan wax ka fudud. Waxay u turjumaysaa summada soo socota ee Go SSA:

func myAdd(a int, b int) int:
entry:
    t0 = a + b                                                    int
    return t0

Marka la eego aragtidan, tilmaamayaasha nooca xogta ayaa la dhigayaa dhinaca midig waxaana la iska indho tiri karaa inta badan kiisaska.

Tusaalahan yar ayaa horeba kuu ogolaanaya inaad aragto nuxurka hal dhinac oo SSA ah. Magac ahaan, marka koodhka loo beddelo foomka SSA, tibaax kasta waxa loo qaybiyaa qaybaha hoose ee ugu badan ee uu ka kooban yahay. Xaaladeena, amarka return a + b, dhab ahaantii, waxay u taagan tahay laba hawlgal: ku darista laba tiro iyo soo celinta natiijada.

Intaa waxaa dheer, halkan waxaad ku arki kartaa blocks aasaasiga ah ee barnaamijka, in code this waxaa jira hal block oo kaliya - block gelitaanka. Waxaan ka hadli doonaa wax badan oo ku saabsan blocks hoos.

Koodhka Go SSA wuxuu si fudud ugu beddelaa LLVM IR:

define i64 @myAdd(i64 %a, i64 %b) {
entry:
  %0 = add i64 %a, %b
  ret i64 %0
}

Waxa aad ogaan karto in inkasta oo qaabab kala duwan oo isku dhafan loo isticmaalo halkan, qaab dhismeedka shaqadu asal ahaan waxba kama beddelin. Koodhka LLVM IR wuxuu ka yara xoog badan yahay Go SSA code, oo la mid ah C. Halkan, ku dhawaaqida shaqada, marka hore waxaa jira sharraxaad nooca xogta ay soo celinayso, nooca doodda ayaa lagu tilmaamay ka hor magaca doodda. Intaa waxaa dheer, si loo fududeeyo falanqaynta IR, magacyada hay'adaha caalamiga ah ayaa ka horreeya calaamadda @, iyo ka hor magacyada maxalliga ah waxaa jira calaamad % (shaqo sidoo kale waxaa loo tixgeliyaa hay'ad caalami ah).

Hal shay oo la xuso oo ku saabsan xeerkan ayaa ah go'aanka matalaadda nooca Go int, kaas oo loo matali karo 32-bit ama 64-bit qiimaha, taas oo ku xidhan isku-dubaridiyaha iyo bartilmaameedka isku-darka, waa la aqbalayaa marka LLVM ay soo saarto koodhka IR. Tani waa mid ka mid ah sababaha badan ee LLVM IR code uusan ahayn, sida ay dad badani qabaan, madal madax bannaan. Koodhkan oo kale, oo loo sameeyay hal madal, si fudud looma qaadi karo oo madal kale looma diyaarin karo (ilaa aad ku habboon tahay xallinta dhibaatadan mooyaane. oo leh daryeel xad -dhaaf ah).

Qodob kale oo xiiso leh oo mudan in la xuso waa nooca i64 ma aha tiro saxeexan: waa dhexdhexaad marka la eego calaamadda lambarka. Iyadoo ku xiran tilmaanta, waxay matali kartaa nambarada saxiixa iyo kuwa aan saxiixin labadaba. Marka laga hadlayo matalaadda hawlgalka dheeriga ah, tani maahan arrin, sidaas darteed ma jirto wax farqi ah oo ku saabsan la shaqeynta lambarrada saxiixa ama aan la saxiixin. Halkan waxaan jeclaan lahaa in aan ku ogaado in luqadda C, buuxdhaafka doorsoomayaasha saxeexan ay keenayso dabeecad aan la qeexin, marka Clang frontend wuxuu ku darayaa calanka hawlgalka nsw (ma jiro duub saxeexan), taas oo u sheegaysa LLVM inay u qaadan karto in isku-darka aanu waligeed buux dhaafin.

Tani waxay muhiim u noqon kartaa hagaajinta qaarkood. Tusaale ahaan, ku darida laba qiime i16 madal 32-bit ah (oo leh diiwaan 32-bit ah) waxay u baahan tahay, ka dib marka lagu daro, hawlgalka ballaarinta calaamad si ay ugu sii jirto tirada i16. Sababtaas awgeed, inta badan aad bay u fiican tahay in la sameeyo hawlgallo isku dhafan oo ku salaysan cabbirrada diiwaanka mashiinka.

Waxa ku xigi doona koodhkan IR-ka dan gaar ah nooguma jirto hadda. Koodhka waa la hagaajiyay (laakiin marka la eego tusaale fudud oo annaga oo kale ah, waxba lama hagaajiyo) ka dibna loo beddelo koodka mashiinka.

Tusaalaha labaad

Tusaalaha xiga ee aan eegi doono waxa uu noqon doonaa mid ka sii dhib badan. Magac ahaan, waxaanu ka hadlaynaa hawl soo koobaysa tiro tirooyin ah:

func sum(numbers []int) int {
    n := 0
    for i := 0; i < len(numbers); i++ {
        n += numbers[i]
    }
    return n
}

Koodhkani wuxuu u rogaa summada Go SSA ee soo socota:

func sum(numbers []int) int:
entry:
    jump for.loop
for.loop:
    t0 = phi [entry: 0:int, for.body: t6] #n                       int
    t1 = phi [entry: 0:int, for.body: t7] #i                       int
    t2 = len(numbers)                                              int
    t3 = t1 < t2                                                  bool
    if t3 goto for.body else for.done
for.body:
    t4 = &numbers[t1]                                             *int
    t5 = *t4                                                       int
    t6 = t0 + t5                                                   int
    t7 = t1 + 1:int                                                int
    jump for.loop
for.done:
    return t0

Halkan waxa aad horeba ugu arki kartaa dhismayaal badan oo caadi ah oo lagu matalo koodka foomka SSA. Waxaa laga yaabaa in qaabka ugu cad ee koodhkani yahay xaqiiqda ah in aysan jirin amarada xakamaynta socodka habaysan. Si loo xakameeyo socodka xisaabinta, waxaa jira oo keliya boodboodo shuruudo iyo shuruud la'aan ah, iyo, haddii aan u tixgelinno amarkan sida amar lagu xakameynayo socodka, amarka soo celinta.

Dhab ahaantii, halkan waxaad fiiro gaar ah u yeelan kartaa xaqiiqda ah in barnaamijku aan loo qaybin blocks iyadoo la adeegsanayo xargaha curyaanka ah (sida qoyska C ee luqadaha). Waxa loo qaybiyaa calaamado, oo xasuusiya afafka shirka, waxaana loo soo bandhigay qaab blocks ah. Gudaha SSA, baloogyada aasaasiga ah waxaa lagu qeexaa inay yihiin dhawr nooc oo kood ah oo ka bilaabmaya summada oo ku dhammaanaya tilmaamaha aasaasiga ah ee dhammaystirka, sida - return ΠΈ jump.

Faahfaahin kale oo xiiso leh oo ku saabsan koodkan waxaa matalaya tilmaamaha phi. Tilmaamuhu waa kuwo aan caadi ahayn waxaana laga yaabaa inay qaadato wakhti in la fahmo. xusuusnow, taas SSA waxay u soo gaaban tahay Meelaynta Keliga ah ee Static Kani waa matalaad dhex dhexaad ah oo koodka ay isticmaalaan kombuyuutarrada, kaas oo doorsoome kasta loo qoondeeyay qiime hal mar kaliya. Tani waxay ku fiican tahay muujinta hawlaha fudud sida shaqadayada myAddkor lagu muujiyey, laakiin kuma habboona hawlo badan oo kakan sida hawsha lagaga hadlay qaybtan sum. Gaar ahaan, doorsoomayaal ayaa isbeddela inta lagu jiro fulinta wareegga i ΠΈ n.

SSA waxay dhaaftay xaddidaadda ku meelaynta qiyamka doorsoomiyaha hal mar iyadoo la isticmaalayo waxa loogu yeero tilmaamaha phi (magaceeda waxaa laga soo qaatay alifbeetada Giriiga). Xaqiiqdu waxay tahay in si matalaadda SSA ee koodka loogu soo saaro luqadaha sida C, waa inaad isticmaashaa tabaha qaar. Natiijada wicitaanka tilmaamahan waa qiimaha hadda ee doorsoomayaasha (i ama n), iyo liiska blocks aasaasiga ah ayaa loo isticmaalaa sidii cabbirkeeda. Tusaale ahaan, tixgeli tilmaantan:

t0 = phi [entry: 0:int, for.body: t6] #n

Macnaheeda waa sida soo socota: haddii block hore ee aasaasiga ah uu ahaa block entry (Input), ka dibna t0 waa joogto 0, iyo haddii block hore ee aasaasiga ah uu ahaa for.body, ka dibna waxaad u baahan tahay inaad qaadato qiimaha t6 ka block this. Dhammaan tani waxay u ekaan kartaa wax qarsoodi ah, laakiin habkani waa waxa ka dhigaya SSA inay shaqeyso. Marka loo eego aragtida bini'aadamka, dhammaan tani waxay ka dhigaysaa koodhka adag in la fahmo, laakiin xaqiiqda ah in qiime kasta loo qoondeeyey hal mar oo keliya ayaa ka dhigaysa hagaajin badan oo aad u fudud.

Ogsoonow haddii aad qorto isku-dubarid adiga kuu gaar ah, sida caadiga ah uma baahnid inaad wax ka qabato waxyaabahan oo kale. Xitaa Clang ma soo saaro tilmaamahan oo dhan phi, waxay isticmaashaa farsamo alloca (waxay u egtahay la shaqaynta doorsoomayaal maxalli ah oo caadi ah). Kadib, marka la wado kaarka hagaajinta LLVM ee loo yaqaan mem2reg, tilmaamaha alloca loo beddelay foomka SSA. TinyGo, si kastaba ha ahaatee, waxay talo ka heshaa Go SSA, taasoo, ku habboon, horeba loogu beddelay foomka SSA.

Hal-abuur kale oo ka mid ah jajabka koodka dhexe ee la tixgalinayo ayaa ah in gelitaanka walxaha jeexjeexan ee tusmaynta ay u taagan tahay qaab hawleed xisaabinta ciwaanka iyo hawlgalka meesha ka saaraya tilmaame ka dhashay. Halkan waxaad ku arki kartaa ku darista tooska ah ee koodhka IR (tusaale ahaan - 1:int). Tusaalaha leh shaqada myAdd tan lama isticmaalin. Hadda oo aan helnay astaamahaas jidka, aan eegno waxa koodkani noqonayaa marka loo beddelo foomka LLVM IR:

define i64 @sum(i64* %ptr, i64 %len, i64 %cap) {
entry:
  br label %for.loop

for.loop:                                         ; preds = %for.body, %entry
  %0 = phi i64 [ 0, %entry ], [ %5, %deref.next ]
  %1 = phi i64 [ 0, %entry ], [ %6, %deref.next ]
  %2 = icmp slt i64 %1, %len
  br i1 %2, label %for.body, label %for.done

for.body:                                         ; preds = %for.loop
  %3 = getelementptr i64, i64* %ptr, i64 %1
  %4 = load i64, i64* %3
  %5 = add i64 %0, %4
  %6 = add i64 %1, 1
  br label %for.loop

for.done:                                         ; preds = %for.loop
  ret i64 %0
}

Halkan, sidii hore, waxaan ku arki karnaa qaab isku mid ah, oo ay ku jiraan qaabab kale oo isku dhafan. Tusaale ahaan, wicitaanada phi qiyamka iyo sumadaha waa la beddelay. Si kastaba ha ahaatee, waxaa jira wax halkan ah oo mudan in fiiro gaar ah loo yeesho.

Si aad u bilawdo, halkan waxaad ku arki kartaa saxeex shaqo oo gebi ahaanba ka duwan. LLVM ma taageerto jeexjeexyada, natiijaduna, tayayn ahaan, isku xidhka TinyGo ee soo saaray koodkan dhexe ayaa u kala qaybiyay sharraxaadda qaab-dhismeedka xogtan qaybo. Waxay ka dhigan tahay saddex walxood oo jajab ah (ptr, len ΠΈ cap) qaab dhismeed ahaan (qaabdhismeed ahaan), laakiin iyaga oo u taagan sidii saddex qaybood oo kala duwan ayaa u oggolaanaya hagaajinta qaarkood. Isku-dubaridyada kale ayaa laga yaabaa inay siyaalo kale u metelaan jeexjeexa, iyadoo ku xidhan heshiisyada wacitaanka ee hawlaha madal la beegsanayo.

Muuqaal kale oo xiiso leh oo ka mid ah koodhkani waa isticmaalka tilmaamaha getelementptr (badanaa loo soo gaabiyo GEP).

Tilmaantan waxay la shaqeysaa tilmaameyaal waxaana loo isticmaalaa in lagu helo tilmaame jeex jeex ah. Tusaale ahaan, aan is barbar dhigno koodka soo socda ee ku qoran C:

int* sliceptr(int *ptr, int index) {
    return &ptr[index];
}

Ama kuwa soo socda oo u dhiganta tan:

int* sliceptr(int *ptr, int index) {
    return ptr + index;
}

Waxa ugu muhiimsan halkan waa in tilmaamaha getelementptr ma fuliyo hawlgallada dib u dhigista. Waxay xisaabinaysaa tilmaame cusub oo ku salaysan kan jira. Waxaa loo qaadan karaa tilmaamo ahaan mul ΠΈ add heerka hardware. Waxaad wax badan ka akhriyi kartaa tilmaamaha GEP halkan.

Muuqaal kale oo xiiso leh oo ka mid ah koodhkan dhexdhexaadka ah waa isticmaalka tilmaamaha icmp. Tani waa tilmaamo guud oo ujeedo ah oo loo isticmaalo in lagu hirgeliyo isbarbardhigga tirada guud. Natiijada tilmaamahan had iyo jeer waa qiimaha nooca i1 - qiimaha macquulka ah. Xaaladdan, isbarbardhigga ayaa la sameeyaa iyadoo la adeegsanayo ereyga muhiimka ah slt (oo saxeexay in ka yar), maadaama aynu is barbar dhignay laba lambar oo hore u matalay nooca int. Haddii aan is barbar dhigi lahayn laba mitir oo aan saxeexin, markaa waan isticmaali lahayn icmp, iyo ereyga muhiimka ah ee loo isticmaalo isbarbardhigga wuxuu noqon lahaa ult. Si loo isbarbardhigo tirooyinka dhibcaha sabbaynaya, tilmaamo kale ayaa la isticmaalaa, fcmp, kaas oo u shaqeeya si la mid ah.

Natiijooyinka

Waxaan aaminsanahay in walxahan aan ku daboolay sifooyinka ugu muhiimsan ee LLVM IR. Dabcan, wax badan ayaa jira halkan. Gaar ahaan, matalaadda dhexe ee koodka waxaa ku jiri kara sharraxaadyo badan oo u oggolaanaya ka-bandhigidda gudbinta si loo tixgeliyo sifooyin gaar ah oo koodka loo yaqaan isku-dubariduhu oo aan si kale lagu sheegi karin IR. Tusaale ahaan, kani waa calan inbounds Tilmaamaha GEP, ama calanka nsw ΠΈ nuw, kaas oo lagu dari karo tilmaamaha add. Si la mid ah erayga muhiimka ah private, taas oo muujinaysa hagaajinta in shaqada uu calaamadeeyay aan laga tixraaci doonin meel ka baxsan cutubka isku-darka hadda. Tani waxay u ogolaaneysaa wax badan oo xiiso leh oo ka dhexeeya habraacyada habraaca sida baabi'inta doodaha aan la isticmaalin.

Waxaad ka akhrisan kartaa wax badan oo ku saabsan LLVM gudaha dukumentiyo, Kaas oo aad inta badan tixraaci doonto marka aad samaynayso isku xidhahaaga ku salaysan LLVM. Halkan hage, kaas oo eegaya horumarinta isku-dubarid luuqad aad u fudud. Labadan ilo macluumaad ayaa ku anfici doona marka aad samaysanayso isku-duwahaaga.

Akhristayaasha sharafta leh! Ma isticmaaleysaa LLVM?

LLVM marka laga eego dhinaca Go

Source: www.habr.com

Add a comment