LLVM lati irisi Go

Ṣiṣe idagbasoke alakojọ jẹ iṣẹ ti o nira pupọ. Ṣugbọn, laanu, pẹlu idagbasoke awọn iṣẹ akanṣe bi LLVM, ojutu si iṣoro yii jẹ irọrun pupọ, eyiti o fun laaye paapaa olupilẹṣẹ kan lati ṣẹda ede tuntun ti o sunmọ ni iṣẹ si C. Nṣiṣẹ pẹlu LLVM jẹ idiju nipasẹ otitọ pe eyi eto jẹ aṣoju nipasẹ iye nla ti koodu, ni ipese pẹlu iwe kekere. Lati le gbiyanju lati ṣatunṣe aṣiṣe yii, onkọwe ohun elo naa, itumọ eyiti a ṣe atẹjade loni, yoo ṣe afihan awọn apẹẹrẹ ti koodu ti a kọ ni Go ati ṣafihan bii wọn ṣe tumọ wọn ni akọkọ si Lọ SSA, ati lẹhinna ni LLVM IR lilo alakojo kekereGO. Go SSA ati koodu LLVM IR ti ni atunṣe diẹ lati yọ awọn nkan ti ko ṣe pataki si awọn alaye ti a fun ni ibi, lati jẹ ki awọn alaye ni oye diẹ sii.

LLVM lati irisi Go

Àpẹrẹ àkọ́kọ́

Iṣẹ akọkọ ti Emi yoo wo nibi ni ẹrọ ti o rọrun fun fifi awọn nọmba kun:

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

Iṣẹ yii rọrun pupọ, ati, boya, ko si ohun ti o rọrun. O tumọ si koodu Go SSA atẹle yii:

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

Pẹlu wiwo yii, awọn amọran iru data ni a gbe si apa ọtun ati pe a le kọju ni ọpọlọpọ awọn ọran.

Apeere kekere yii ti gba ọ laaye lati rii pataki ti abala kan ti SSA. Eyun, nigba ti iyipada koodu sinu SSA fọọmu, kọọkan ikosile ti wa ni dà si isalẹ sinu awọn julọ alakọbẹrẹ awọn ẹya ara ti o ti wa ni kq. Ninu ọran wa, aṣẹ naa return a + b, ni otitọ, duro fun awọn iṣẹ meji: fifi awọn nọmba meji kun ati ipadabọ abajade.

Ni afikun, nibi o le rii awọn bulọọki ipilẹ ti eto naa; ninu koodu yii bulọọki kan nikan wa - bulọọki titẹsi. A yoo sọrọ diẹ sii nipa awọn bulọọki ni isalẹ.

Koodu Go SSA ni irọrun yipada si LLVM IR:

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

Ohun ti o le ṣe akiyesi ni pe botilẹjẹpe o yatọ si awọn ẹya syntactic ti lo nibi, eto iṣẹ naa jẹ ipilẹ ko yipada. Awọn koodu LLVM IR ni okun diẹ sii ju koodu Go SSA lọ, ti o jọra si C. Nibi, ninu ikede iṣẹ, akọkọ ni apejuwe ti iru data ti o pada, iru ariyanjiyan jẹ itọkasi ṣaaju orukọ ariyanjiyan. Ni afikun, lati di irọrun IR parsing, awọn orukọ ti awọn nkan agbaye ti ṣaju aami naa @, ati ṣaaju awọn orukọ agbegbe ni aami kan wa % (iṣẹ kan tun jẹ nkan ti agbaye).

Ohun kan lati ṣe akiyesi nipa koodu yii ni pe ipinnu aṣoju iru Go int, eyiti o le ṣe aṣoju bi iye 32-bit tabi 64-bit, ti o da lori alakojọ ati ibi-afẹde ti akopọ, jẹ itẹwọgba nigbati LLVM ṣe ipilẹṣẹ koodu IR. Eyi jẹ ọkan ninu ọpọlọpọ awọn idi ti koodu LLVM IR kii ṣe, bi ọpọlọpọ eniyan ṣe ro, ominira Syeed. Iru koodu naa, ti a ṣẹda fun pẹpẹ kan, ko le mu nirọrun ati ṣajọ fun pẹpẹ miiran (ayafi ti o ba dara lati yanju iṣoro yii pẹlu awọn iwọn itoju).

Miiran awon ojuami tọ kiyesi ni wipe iru i64 kii ṣe odidi wole: o jẹ didoju ni awọn ofin ti o nsoju ami ti nọmba naa. Ti o da lori itọnisọna naa, o le ṣe aṣoju awọn nọmba mejeeji ti a fowo si ati ti a ko fowo si. Ni ọran ti aṣoju ti iṣẹ afikun, eyi ko ṣe pataki, nitorina ko si iyatọ ninu ṣiṣẹ pẹlu awọn nọmba ti a fọwọsi tabi ti a ko wọle. Nibi Emi yoo fẹ lati ṣe akiyesi pe ni ede C, ṣigọgọ oniyipada nomba odidi ti o fowo si yori si ihuwasi ti ko ṣe alaye, nitorinaa iwaju Clang ṣe afikun asia kan si iṣẹ naa nsw (ko si ipari ti o fowo si), eyiti o sọ fun LLVM pe o le ro pe afikun ko ṣabọ.

Eyi le ṣe pataki fun diẹ ninu awọn iṣapeye. Fun apẹẹrẹ, fifi awọn iye meji kun i16 lori pẹpẹ 32-bit (pẹlu awọn iforukọsilẹ 32-bit) nilo, lẹhin afikun, iṣẹ imugboroja ami kan lati le wa ni iwọn. i16. Nitori eyi, o jẹ nigbagbogbo daradara siwaju sii lati ṣe awọn iṣẹ odidi da lori awọn iwọn iforukọsilẹ ẹrọ.

Ohun ti o ṣẹlẹ ni atẹle pẹlu koodu IR yii kii ṣe iwulo pataki si wa ni bayi. Awọn koodu ti wa ni iṣapeye (ṣugbọn ninu ọran ti apẹẹrẹ ti o rọrun bi tiwa, ko si ohun ti o wa ni iṣapeye) ati lẹhinna yipada si koodu ẹrọ.

Apeere keji

Apẹẹrẹ atẹle ti a yoo wo yoo jẹ idiju diẹ sii. Eyun, a n sọrọ nipa iṣẹ kan ti o ṣe akopọ bibẹ pẹlẹbẹ ti awọn nọmba kan:

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

Koodu yii yipada si koodu Go SSA atẹle yii:

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

Nibi o ti le rii diẹ sii awọn iṣelọpọ aṣoju fun aṣoju koodu ni fọọmu SSA. Boya ẹya ti o han julọ julọ ti koodu yii ni otitọ pe ko si awọn aṣẹ iṣakoso sisan ti eleto. Lati ṣakoso sisan ti awọn iṣiro, awọn ipo ipo nikan ati awọn fo lainidi, ati, ti a ba gbero aṣẹ yii bi aṣẹ lati ṣakoso ṣiṣan, pipaṣẹ ipadabọ.

Ni otitọ, nibi o le san ifojusi si otitọ pe eto naa ko pin si awọn bulọọki nipa lilo awọn àmúró curly (bii ninu idile C ti awọn ede). O pin nipasẹ awọn akole, ti o ṣe iranti awọn ede apejọ, ati gbekalẹ ni irisi awọn bulọọki ipilẹ. Ni SSA, awọn bulọọki ipilẹ jẹ asọye bi awọn itọsẹ ti o tẹle koodu ti o bẹrẹ pẹlu aami kan ati ipari pẹlu awọn ilana ipari idina ipilẹ, gẹgẹbi - return и jump.

Awọn alaye iyanilenu miiran ti koodu yii jẹ aṣoju nipasẹ itọnisọna naa phi. Awọn itọnisọna jẹ ohun dani ati pe o le gba akoko diẹ lati ni oye. ranti, pe SSA jẹ kukuru fun Aimi Nikan iyansilẹ. Eyi jẹ aṣoju agbedemeji ti koodu ti awọn olupilẹṣẹ lo, ninu eyiti oniyipada kọọkan ti yan iye kan lẹẹkanṣoṣo. Eyi jẹ nla fun sisọ awọn iṣẹ ti o rọrun bi iṣẹ wa myAddti o han loke, ṣugbọn ko dara fun awọn iṣẹ eka diẹ sii gẹgẹbi iṣẹ ti a sọ ni apakan yii sum. Ni pato, awọn oniyipada yipada nigba ipaniyan ti lupu i и n.

SSA fori hihamọ lori yiyan awọn iye oniyipada ni ẹẹkan lilo ohun ti a pe ni itọnisọna phi (orukọ rẹ ti wa ni ya lati Giriki alfabeti). Otitọ ni pe ni ibere fun aṣoju SSA ti koodu lati ṣe ipilẹṣẹ fun awọn ede bii C, o ni lati lo awọn ẹtan diẹ. Abajade ti pipe itọnisọna yii jẹ iye lọwọlọwọ ti oniyipada (i tabi n), ati atokọ ti awọn bulọọki ipilẹ ti wa ni lilo bi awọn paramita rẹ. Fun apẹẹrẹ, ro ilana yii:

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

Itumọ rẹ jẹ bi atẹle: ti bulọọki ipilẹ iṣaaju jẹ bulọọki entry (igbewọle), lẹhinna t0 jẹ ibakan 0, ati ti o ba ti tẹlẹ ipilẹ Àkọsílẹ wà for.body, lẹhinna o nilo lati mu iye naa t6 lati yi Àkọsílẹ. Eyi le dabi ohun aramada pupọ, ṣugbọn ẹrọ yii jẹ ohun ti o jẹ ki SSA ṣiṣẹ. Lati irisi eniyan, gbogbo eyi jẹ ki koodu naa nira lati ni oye, ṣugbọn otitọ pe iye kọọkan ni a yan ni ẹẹkan jẹ ki ọpọlọpọ awọn iṣapeye rọrun pupọ.

Ṣe akiyesi pe ti o ba kọ olupilẹṣẹ tirẹ, igbagbogbo kii yoo ni lati koju iru nkan yii. Paapaa Clang ko ṣe gbogbo awọn ilana wọnyi phi, o nlo ẹrọ kan alloca (o jọ ṣiṣẹ pẹlu awọn oniyipada agbegbe lasan). Lẹhinna, nigbati o nṣiṣẹ iwe-iwọle iṣapeye LLVM ti a pe mem2reg, ilana alloca yipada si SSA fọọmu. TinyGo, sibẹsibẹ, gba igbewọle lati Go SSA, eyiti, ni irọrun, ti yipada tẹlẹ si fọọmu SSA.

Ilọtuntun miiran ti ajẹkù ti koodu agbedemeji ti o wa labẹ ero ni pe iraye si awọn eroja bibẹ nipasẹ atọka jẹ aṣoju ni irisi iṣẹ ṣiṣe ti iṣiro adirẹsi ati iṣẹ ti yiyọkuro itọka abajade. Nibi o le rii afikun taara ti awọn iduro si koodu IR (fun apẹẹrẹ - 1:int). Ni apẹẹrẹ pẹlu iṣẹ naa myAdd eyi ko ti lo. Ni bayi pe a ti ni awọn ẹya wọnyẹn ni ọna, jẹ ki a wo kini koodu yii di nigbati o yipada si fọọmu 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
}

Nibi, bii ti iṣaaju, a le rii eto kanna, eyiti o pẹlu awọn ẹya syntactic miiran. Fun apẹẹrẹ, ninu awọn ipe phi iye ati akole swapped. Sibẹsibẹ, ohun kan wa nibi ti o tọ lati san ifojusi pataki si.

Lati bẹrẹ pẹlu, nibi o le wo ibuwọlu iṣẹ ti o yatọ patapata. LLVM ko ṣe atilẹyin awọn ege, ati bi abajade, bi iṣapeye, olupilẹṣẹ TinyGo ti o ṣe ipilẹṣẹ koodu agbedemeji yii pin apejuwe ti igbekalẹ data yii si awọn apakan. O le ṣe aṣoju awọn eroja bibẹ mẹta (ptr, len и cap) bi eto (struct), ṣugbọn o nsoju wọn bi awọn nkan lọtọ mẹta laaye fun diẹ ninu awọn iṣapeye. Awọn olupilẹṣẹ miiran le ṣe aṣoju bibẹ pẹlẹbẹ ni awọn ọna miiran, da lori awọn apejọ pipe ti awọn iṣẹ iru ẹrọ ibi-afẹde.

Ẹya miiran ti o nifẹ ti koodu yii ni lilo itọnisọna naa getelementptr (igba abbreviated bi GEP).

Ilana yii n ṣiṣẹ pẹlu awọn itọka ati pe a lo lati gba itọka si nkan bibẹ. Fun apẹẹrẹ, jẹ ki a ṣe afiwe rẹ pẹlu koodu atẹle ti a kọ sinu C:

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

Tabi pẹlu iwọnyi deede si eyi:

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

Ohun pataki julọ nibi ni pe awọn itọnisọna getelementptr ko ṣe awọn iṣẹ imukuro. O kan ṣe iṣiro itọka tuntun kan ti o da lori ọkan ti o wa tẹlẹ. O le gba bi awọn itọnisọna mul и add ni ipele hardware. O le ka diẹ sii nipa awọn ilana GEP nibi.

Ẹya ti o nifẹ si ti koodu agbedemeji yii ni lilo itọnisọna naa icmp. Eyi jẹ itọnisọna idi gbogbogbo ti a lo lati ṣe awọn afiwe odidi. Abajade itọnisọna yii jẹ nigbagbogbo iye ti iru i1 - mogbonwa iye. Ni idi eyi, a ṣe afiwe pẹlu lilo koko slt (fọwọsi kere ju), nitori a n ṣe afiwe awọn nọmba meji ni iṣaaju ni ipoduduro nipasẹ iru int. Ti a ba n ṣe afiwe awọn odidi meji ti a ko fowo si, lẹhinna a yoo lo icmp, ati Koko ti a lo ninu lafiwe yoo jẹ ult. Lati ṣe afiwe awọn nọmba aaye lilefoofo, ilana miiran ti lo, fcmp, eyi ti o ṣiṣẹ ni ọna kanna.

Awọn esi

Mo gbagbọ pe ninu ohun elo yii Mo ti bo awọn ẹya pataki julọ ti LLVM IR. Dajudaju, ọpọlọpọ diẹ sii wa nibi. Ni pataki, aṣoju agbedemeji koodu naa le ni ọpọlọpọ awọn asọye ti o gba laaye awọn igbasilẹ iṣapeye lati ṣe akiyesi awọn ẹya kan ti koodu ti a mọ si olupilẹṣẹ ti ko le bibẹẹkọ ṣe afihan ni IR. Fun apẹẹrẹ, eyi jẹ asia inbounds Awọn ilana GEP, tabi awọn asia nsw и nuw, eyi ti o le fi kun si awọn ilana add. Kanna n lọ fun Koko private, ti n tọka si oluṣapejuwe pe iṣẹ ti o samisi kii yoo ṣe itọkasi lati ita akojọpọ akojọpọ lọwọlọwọ. Eyi ngbanilaaye fun ọpọlọpọ awọn iṣapeye interprocedural ti o nifẹ bii imukuro awọn ariyanjiyan ti ko lo.

O le ka diẹ sii nipa LLVM ni iwe, eyiti iwọ yoo tọka si nigbagbogbo nigbati o ba n ṣe agbekalẹ akojọpọ orisun LLVM tirẹ. Nibi isakoso, eyi ti o n wo idagbasoke alakojọ fun ede ti o rọrun pupọ. Mejeji ti awọn orisun alaye wọnyi yoo wulo fun ọ nigbati o ba ṣẹda akojọpọ tirẹ.

Eyin onkawe! Ṣe o nlo LLVM?

LLVM lati irisi Go

orisun: www.habr.com

Fi ọrọìwòye kun