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.
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.
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 myAdd
kor 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 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
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
Akhristayaasha sharafta leh! Ma isticmaaleysaa LLVM?
Source: www.habr.com