FoxTRMBackend.Mod 87 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548
  1. MODULE FoxTRMBackend; (** AUTHOR "fof"; PURPOSE "backend for the tiny register machine"; *)
  2. IMPORT
  3. Basic := FoxBasic, SyntaxTree := FoxSyntaxTree, Global := FoxGlobal, Backend := FoxBackend, Sections := FoxSections,
  4. IntermediateCode := FoxIntermediateCode, IntermediateBackend := FoxIntermediateBackend, BinaryCode := FoxBinaryCode,
  5. SemanticChecker := FoxSemanticChecker, Formats := FoxFormats, Assembler := FoxTRMAssembler, InstructionSet := FoxTRMInstructionSet,
  6. SYSTEM, Diagnostics, Streams, Options, Strings, ObjectFile, Scanner := FoxScanner, ObjectFileFormat := FoxIntermediateObjectFile,
  7. CodeGenerators := FoxCodeGenerators, D := Debugging, Compiler;
  8. CONST
  9. TraceFixups = FALSE;
  10. HaltIRQNumber=8;
  11. Registers = 8; None=-1;
  12. Low=0; High=1;
  13. FPSupported = TRUE; (* setting this to false increases code size slightly but also reduces register pressure *)
  14. opAND= InstructionSet.opAND; opBIC* = InstructionSet.opBIC;
  15. opOR= InstructionSet.opOR; opXOR= InstructionSet.opXOR;
  16. opADD= InstructionSet.opADD; opFADD = InstructionSet.opFADD; opSUB= InstructionSet.opSUB; opFSUB = InstructionSet.opFSUB;
  17. opMUL= InstructionSet.opMUL; opFMUL = InstructionSet.opFMUL; opNOT= InstructionSet.opNOT;
  18. opLDH= InstructionSet.opLDH;
  19. opMOV= InstructionSet.opMOV; opROR= InstructionSet.opROR;
  20. opBLR= InstructionSet.opBLR; opBR= InstructionSet.opBR;
  21. opIRET* = InstructionSet.opIRET; opLD= InstructionSet.opLD;
  22. opST= InstructionSet.opST; opBL= InstructionSet.opBL;
  23. opBEQ= InstructionSet.opBEQ; opBNE= InstructionSet.opBNE;
  24. opBAE= InstructionSet.opBAE; opBB= InstructionSet.opBB;
  25. opBN= InstructionSet.opBN; opBNN= InstructionSet.opBNN;
  26. opBO* = InstructionSet.opBO; opBNO* = InstructionSet.opBNO;
  27. opBA= InstructionSet.opBA; opBBE= InstructionSet.opBBE;
  28. opBGE= InstructionSet.opBGE; opBLT= InstructionSet.opBLT;
  29. opBGT= InstructionSet.opBGT; opBLE= InstructionSet.opBLE;
  30. opBT= InstructionSet.opBT; opBF* = InstructionSet.opBF;
  31. opSPSR* = InstructionSet.opSPSR;
  32. VectorSupportFlag = "vectorSupport";
  33. FloatingPointSupportFlag ="floatingPoint";
  34. FPSupportFlag = "supportFP";
  35. PatchSpartan6 ="patchSpartan6";
  36. TYPE
  37. Operand=InstructionSet.Operand;
  38. FixupEntry=POINTER TO RECORD
  39. maxPC: LONGINT;
  40. fixup: BinaryCode.Fixup;
  41. next: FixupEntry;
  42. END;
  43. ForwardFixupList=OBJECT
  44. VAR
  45. first,last: FixupEntry;
  46. PROCEDURE &Init;
  47. BEGIN
  48. first := NIL; last := NIL;
  49. END Init;
  50. PROCEDURE Enter(fixup: BinaryCode.Fixup; currentPC: LONGINT; bits: LONGINT);
  51. VAR entry: FixupEntry; maxPC: LONGINT;
  52. BEGIN
  53. maxPC := currentPC + ASH(1,bits-1) -1; (* signed *)
  54. NEW(entry); entry.fixup := fixup;
  55. entry.maxPC := maxPC-1; (* one instruction necessary to jump over the instruction *)
  56. IF first = NIL THEN first := entry; last := entry;
  57. ELSE
  58. ASSERT(last.maxPC <= maxPC); (* otherwise we have to insert sorted but this does not seem necessary *)
  59. last.next := entry;
  60. last := entry;
  61. END;
  62. END Enter;
  63. PROCEDURE Check(outPC: LONGINT): BinaryCode.Fixup;
  64. VAR fixup: BinaryCode.Fixup;
  65. BEGIN
  66. IF (first # NIL) & (outPC >= first.maxPC) THEN
  67. fixup := first.fixup;
  68. IF first = last THEN first := NIL; last := NIL ELSE first := first.next END;
  69. RETURN fixup;
  70. ELSE
  71. RETURN NIL
  72. END;
  73. END Check;
  74. END ForwardFixupList;
  75. Ticket=CodeGenerators.Ticket;
  76. PhysicalRegisters*=OBJECT (CodeGenerators.PhysicalRegisters)
  77. VAR
  78. toVirtual: ARRAY Registers OF Ticket; (* registers real register -> none / reserved / split / blocked / virtual register (>0) *)
  79. reserved: ARRAY Registers OF BOOLEAN;
  80. unusable: Ticket;
  81. hint: LONGINT;
  82. PROCEDURE &InitPhysicalRegisters(supportFP: BOOLEAN);
  83. VAR i: LONGINT;
  84. BEGIN
  85. FOR i := 0 TO LEN(toVirtual)-1 DO
  86. toVirtual[i] := NIL;
  87. reserved[i] := FALSE;
  88. END;
  89. (* reserve stack and base pointer registers *)
  90. NEW(unusable);
  91. toVirtual[InstructionSet.SP] := unusable;
  92. toVirtual[InstructionSet.LR] := unusable;
  93. IF supportFP THEN
  94. toVirtual[InstructionSet.FP] := unusable
  95. END;
  96. END InitPhysicalRegisters;
  97. PROCEDURE SupportFP(b: BOOLEAN);
  98. BEGIN
  99. IF b THEN toVirtual[InstructionSet.FP] := unusable ELSE toVirtual[InstructionSet.FP] := NIL END;
  100. END SupportFP;
  101. PROCEDURE NumberRegisters*(): LONGINT;
  102. BEGIN
  103. RETURN Registers
  104. END NumberRegisters;
  105. PROCEDURE Allocate*(index: LONGINT; virtualRegister: Ticket);
  106. BEGIN
  107. Assert(toVirtual[index]=NIL,"register already allocated");
  108. toVirtual[index] := virtualRegister;
  109. ASSERT(~virtualRegister.spilled);
  110. END Allocate;
  111. PROCEDURE SetReserved*(index: LONGINT; res: BOOLEAN);
  112. BEGIN
  113. reserved[index] := res;
  114. END SetReserved;
  115. PROCEDURE Reserved*(index: LONGINT): BOOLEAN;
  116. BEGIN
  117. RETURN (index>0) & reserved[index]
  118. END Reserved;
  119. PROCEDURE Free*(index: LONGINT);
  120. BEGIN
  121. Assert((toVirtual[index] # NIL),"register not reserved");
  122. toVirtual[index] := NIL;
  123. END Free;
  124. PROCEDURE NextFree*(CONST type: IntermediateCode.Type):LONGINT;
  125. VAR i: LONGINT;
  126. BEGIN
  127. ASSERT(type.sizeInBits=32);
  128. i := 0;
  129. IF (hint # None) THEN
  130. IF toVirtual[hint] = NIL THEN i := hint END;
  131. hint := None
  132. END;
  133. WHILE (i<Registers) & (toVirtual[i] # NIL) DO
  134. INC(i);
  135. END;
  136. IF i=Registers THEN i := None END;
  137. RETURN i;
  138. END NextFree;
  139. PROCEDURE AllocationHint*(index: LONGINT);
  140. BEGIN hint := index
  141. END AllocationHint;
  142. PROCEDURE Mapped*(physical: LONGINT): Ticket;
  143. BEGIN
  144. RETURN toVirtual[physical]
  145. END Mapped;
  146. PROCEDURE Dump*(w: Streams.Writer);
  147. VAR i: LONGINT; virtual: Ticket;
  148. BEGIN
  149. w.String("---- registers ----"); w.Ln;
  150. FOR i := 0 TO LEN(toVirtual)-1 DO
  151. virtual := toVirtual[i];
  152. IF virtual # unusable THEN
  153. w.String("reg "); w.Int(i,1); w.String(": ");
  154. IF virtual = NIL THEN w.String("free")
  155. ELSE w.String(" r"); w.Int(virtual.register,1);
  156. END;
  157. IF reserved[i] THEN w.String("reserved") END;
  158. w.Ln;
  159. END;
  160. END;
  161. END Dump;
  162. END PhysicalRegisters;
  163. CodeGeneratorTRM = OBJECT (CodeGenerators.GeneratorWithTickets)
  164. VAR
  165. opSP, opLR, opFP, null, noOperand: InstructionSet.Operand;
  166. instructionSet: InstructionSet.InstructionSet;
  167. stackSize, spillStackPosition: LONGINT;
  168. stackSizeKnown: BOOLEAN;
  169. inStackAllocation: BOOLEAN;
  170. builtinsModuleName: SyntaxTree.IdentifierString;
  171. forwardFixups: ForwardFixupList;
  172. spillStackStart: LONGINT;
  173. backend: BackendTRM;
  174. supportFP: BOOLEAN;
  175. pushChainLength: LONGINT;
  176. patchSpartan6: BOOLEAN;
  177. PROCEDURE SetInstructionSet(instructionSet: InstructionSet.InstructionSet);
  178. BEGIN
  179. SELF.instructionSet:=instructionSet;
  180. END SetInstructionSet;
  181. PROCEDURE &InitGeneratorTRM(CONST runtime: SyntaxTree.IdentifierString; diagnostics: Diagnostics.Diagnostics; b: BackendTRM; instructionSet: InstructionSet.InstructionSet);
  182. VAR physicalRegisters: PhysicalRegisters;
  183. BEGIN
  184. inStackAllocation := FALSE;
  185. SELF.builtinsModuleName := runtime;
  186. SELF.instructionSet:=instructionSet;
  187. backend := b;
  188. NEW(physicalRegisters,FALSE);
  189. InitTicketGenerator(diagnostics, backend.optimize,2,physicalRegisters);
  190. error := FALSE;
  191. pushChainLength := 0;
  192. instructionSet.InitImmediate(null, 0, 0);
  193. instructionSet.InitOperand(noOperand);
  194. instructionSet.InitRegister(opSP, InstructionSet.SP);
  195. instructionSet.InitRegister(opLR, InstructionSet.LR);
  196. instructionSet.InitRegister(opFP, InstructionSet.FP);
  197. dump := NIL;
  198. patchSpartan6 := FALSE;
  199. NEW(forwardFixups);
  200. END InitGeneratorTRM;
  201. PROCEDURE CheckStackPointer(CONST dest: InstructionSet.Operand);
  202. BEGIN
  203. IF stackSizeKnown & ~inStackAllocation THEN
  204. IF(dest.type = InstructionSet.Register) & (dest.register = InstructionSet.SP) THEN
  205. IF dump # NIL THEN
  206. dump.String("stack size unknown ") ;
  207. END;
  208. stackSizeKnown := FALSE;
  209. END;
  210. END;
  211. END CheckStackPointer;
  212. PROCEDURE PatchSpartan6;
  213. VAR i: LONGINT; opx: InstructionSet.Operand;
  214. BEGIN
  215. IF patchSpartan6 THEN
  216. IF (out.os.fixed) & ((out.os.alignment + out.pc) MOD 1024 = 959) THEN
  217. instructionSet.InitImmediate(opx,0,16);
  218. instructionSet.Emit(InstructionSet.opBT, opx, emptyOperand, out);
  219. FOR i := 1 TO 16 DO
  220. out.PutBits(0,18);
  221. END;
  222. END;
  223. END;
  224. END PatchSpartan6;
  225. PROCEDURE Emit(op: LONGINT; CONST op1, op2: InstructionSet.Operand);
  226. VAR pc: LONGINT;
  227. BEGIN
  228. pc := (out.os.alignment + out.pc);
  229. ASSERT(~patchSpartan6 OR ~out.os.fixed OR ((out.os.alignment + out.pc) MOD 1024 < 960) OR ((out.os.alignment + out.pc) MOD 1024 > 975) );
  230. instructionSet.Emit(op, op1, op2, out);
  231. (* do this AFTER each instruction because otherwise presumptions on the size of the PC in the generator are wrong *)
  232. (* note, in general, by the inclusion of the following code, no assumptions are true about the actual size of instructions in code emission
  233. --> forward jumps do have to be patched in all cases
  234. *)
  235. PatchSpartan6;
  236. END Emit;
  237. PROCEDURE Emit2(op: LONGINT; CONST op1, op2: InstructionSet.Operand);
  238. BEGIN
  239. CheckStackPointer(op1);
  240. Emit(op, op1, op2);
  241. END Emit2;
  242. PROCEDURE Emit2N(op: LONGINT; CONST op1: InstructionSet.Operand; n: LONGINT);
  243. VAR op2: InstructionSet.Operand;
  244. BEGIN
  245. CheckStackPointer(op1);
  246. instructionSet.InitImmediate(op2,0,n);
  247. Emit(op, op1, op2);
  248. END Emit2N;
  249. PROCEDURE Emit1(op: LONGINT; CONST op1: InstructionSet.Operand);
  250. BEGIN
  251. Emit(op, op1, emptyOperand);
  252. END Emit1;
  253. PROCEDURE Emit1N(op: LONGINT; n: LONGINT);
  254. VAR op1: InstructionSet.Operand;
  255. BEGIN
  256. instructionSet.InitImmediate(op1,0,n);
  257. Emit(op, op1, emptyOperand);
  258. END Emit1N;
  259. (*------------------- overwritten methods ----------------------*)
  260. PROCEDURE Section*(in: IntermediateCode.Section; out: BinaryCode.Section);
  261. VAR oldSpillStackSize: LONGINT;
  262. PROCEDURE CheckEmptySpillStack(): BOOLEAN;
  263. BEGIN
  264. IF spillStack.Size()#0 THEN Error(Basic.invalidPosition,"implementation error, spill stack not cleared");
  265. IF dump # NIL THEN
  266. spillStack.Dump(dump);
  267. tickets.Dump(dump);
  268. END;
  269. RETURN FALSE ELSE RETURN TRUE END;
  270. END CheckEmptySpillStack;
  271. BEGIN
  272. physicalRegisters(PhysicalRegisters).SupportFP(FPSupported);
  273. supportFP := FPSupported;
  274. tickets.Init;
  275. spillStack.Init;
  276. stackSizeKnown := TRUE;
  277. forwardFixups.Init;
  278. Section^(in,out);
  279. IF ~stackSizeKnown THEN
  280. supportFP := TRUE;
  281. tickets.Init;
  282. spillStack.Init;
  283. forwardFixups.Init;
  284. out.Reset;
  285. physicalRegisters(PhysicalRegisters).SupportFP(TRUE);
  286. Section^(in,out);
  287. END;
  288. IF CheckEmptySpillStack() & (spillStack.MaxSize() >0) THEN
  289. forwardFixups.Init;
  290. oldSpillStackSize := spillStack.MaxSize();
  291. out.Reset;
  292. Section^(in,out);
  293. ASSERT(spillStack.MaxSize() = oldSpillStackSize);
  294. END;
  295. IF CheckEmptySpillStack() THEN END;
  296. END Section;
  297. PROCEDURE Supported*(CONST instr: IntermediateCode.Instruction; VAR moduleName, procedureName: ARRAY OF CHAR): BOOLEAN;
  298. VAR sizeInBits: LONGINT; form: LONGINT; opcode: LONGINT; value: HUGEINT; exp: LONGINT;
  299. BEGIN
  300. opcode := instr.opcode;
  301. form := instr.op1.type.form;
  302. COPY(builtinsModuleName, moduleName);
  303. IF opcode = IntermediateCode.conv THEN (* conversions between float and integer types in a library *)
  304. IF form = IntermediateCode.Float THEN
  305. IF instr.op2.type.form = IntermediateCode.Float THEN
  306. IF (instr.op1.type.sizeInBits = 32) & (instr.op2.type.sizeInBits = 64) THEN
  307. procedureName := "ConvertXR"; RETURN FALSE
  308. ELSIF (instr.op1.type.sizeInBits = 64) & (instr.op2.type.sizeInBits = 32) THEN
  309. procedureName := "ConvertRX"; RETURN FALSE
  310. ELSE HALT(100);
  311. END;
  312. ELSE
  313. ASSERT( instr.op2.type.form = IntermediateCode.SignedInteger);
  314. IF (instr.op2.type.sizeInBits = 32) THEN
  315. IF instr.op1.type.sizeInBits = 32 THEN
  316. procedureName := "ConvertIR"; RETURN FALSE
  317. ELSIF instr.op1.type.sizeInBits = 64 THEN
  318. procedureName := "ConvertHR"; RETURN FALSE
  319. ELSE HALT(100);
  320. END;
  321. ELSIF (instr.op2.type.sizeInBits=64) THEN
  322. IF instr.op1.type.sizeInBits = 32 THEN
  323. procedureName := "ConvertIX"; RETURN FALSE
  324. ELSIF instr.op1.type.sizeInBits = 64 THEN
  325. procedureName := "ConvertHX"; RETURN FALSE
  326. ELSE HALT(100);
  327. END;
  328. ELSE HALT(100);
  329. END
  330. END;
  331. ELSIF instr.op2.type.form = IntermediateCode.Float THEN
  332. ASSERT(instr.op1.type.form = IntermediateCode.SignedInteger);
  333. IF (instr.op2.type.sizeInBits = 32) THEN
  334. IF instr.op1.type.sizeInBits = 32 THEN
  335. procedureName := "ConvertRI"; RETURN FALSE
  336. ELSIF instr.op1.type.sizeInBits = 64 THEN
  337. procedureName := "ConvertRH"; RETURN FALSE
  338. ELSE HALT(100);
  339. END;
  340. ELSIF (instr.op2.type.sizeInBits=64) THEN
  341. IF instr.op1.type.sizeInBits = 32 THEN
  342. procedureName := "ConvertXI"; RETURN FALSE
  343. ELSIF instr.op1.type.sizeInBits = 64 THEN
  344. procedureName := "ConvertXH"; RETURN FALSE
  345. ELSE HALT(100);
  346. END;
  347. ELSE HALT(100);
  348. END
  349. END;
  350. ELSIF form IN IntermediateCode.Integer THEN
  351. IF instr.op1.type.sizeInBits = IntermediateCode.Bits64 THEN
  352. CASE instr.opcode OF
  353. IntermediateCode.div: procedureName := "DivH"; RETURN FALSE
  354. | IntermediateCode.mod:
  355. IF IntermediateCode.IsConstantInteger(instr.op3,value) & IntermediateBackend.PowerOf2(value,exp) THEN RETURN TRUE END;
  356. procedureName := "ModH"; RETURN FALSE
  357. | IntermediateCode.abs: procedureName := "AbsH"; RETURN FALSE;
  358. | IntermediateCode.shl :
  359. IF instr.op1.type.form = IntermediateCode.SignedInteger THEN
  360. procedureName := "AslH"; RETURN FALSE;
  361. ELSE
  362. procedureName := "LslH"; RETURN FALSE;
  363. END;
  364. | IntermediateCode.shr :
  365. IF instr.op1.type.form = IntermediateCode.SignedInteger THEN
  366. procedureName := "AsrH"; RETURN FALSE;
  367. ELSE
  368. procedureName := "LsrH"; RETURN FALSE;
  369. END;
  370. | IntermediateCode.ror: procedureName := "RorH"; RETURN FALSE;
  371. | IntermediateCode.rol: procedureName := "RolH"; RETURN FALSE;
  372. ELSE RETURN TRUE
  373. END
  374. ELSIF instr.op1.type.sizeInBits = IntermediateCode.Bits32 THEN
  375. CASE instr.opcode OF
  376. IntermediateCode.div:
  377. IF IntermediateCode.IsConstantInteger(instr.op3,value) & IntermediateBackend.PowerOf2(value,exp) THEN RETURN TRUE
  378. ELSE procedureName := "DivL"; RETURN FALSE END;
  379. | IntermediateCode.mod:
  380. IF IntermediateCode.IsConstantInteger(instr.op3,value) & IntermediateBackend.PowerOf2(value,exp) THEN RETURN TRUE END;
  381. procedureName := "ModL"; RETURN FALSE
  382. | IntermediateCode.mul:
  383. IF (Global.NoMulCapability IN backend.capabilities) THEN (*mul forbidden*)
  384. IF IntermediateCode.IsConstantInteger(instr.op3,value) & IntermediateBackend.PowerOf2(value,exp) THEN RETURN TRUE
  385. ELSE procedureName:="MulL"; RETURN FALSE END;
  386. ELSE
  387. RETURN TRUE;
  388. END
  389. ELSE
  390. RETURN TRUE
  391. END;
  392. ELSE
  393. sizeInBits := instr.op1.type.sizeInBits;
  394. HALT(100)
  395. END;
  396. ELSIF (form = IntermediateCode.Float) THEN
  397. IF instr.op1.type.sizeInBits = IntermediateCode.Bits64 THEN
  398. CASE instr.opcode OF
  399. | IntermediateCode.add: procedureName := "AddX"; RETURN FALSE;
  400. | IntermediateCode.sub: procedureName := "SubX"; RETURN FALSE;
  401. | IntermediateCode.mul: procedureName := "MulX"; RETURN FALSE;
  402. | IntermediateCode.div: procedureName := "DivX"; RETURN FALSE
  403. | IntermediateCode.abs: procedureName := "AbsX"; RETURN FALSE;
  404. ELSE RETURN TRUE
  405. END;
  406. ELSIF instr.op1.type.sizeInBits = IntermediateCode.Bits32 THEN
  407. CASE instr.opcode OF
  408. | IntermediateCode.add:
  409. IF Global.FloatingPointCapability IN backend.capabilities THEN RETURN TRUE
  410. ELSE procedureName := "AddR"; RETURN FALSE
  411. END
  412. | IntermediateCode.sub:
  413. IF Global.FloatingPointCapability IN backend.capabilities THEN RETURN TRUE
  414. ELSE procedureName := "SubR"; RETURN FALSE
  415. END
  416. | IntermediateCode.mul:
  417. IF Global.FloatingPointCapability IN backend.capabilities THEN RETURN TRUE
  418. ELSE procedureName := "MulR"; RETURN FALSE
  419. END
  420. | IntermediateCode.div: procedureName := "DivR"; RETURN FALSE
  421. | IntermediateCode.abs: procedureName := "AbsR"; RETURN FALSE;
  422. ELSE RETURN TRUE
  423. END;
  424. ELSE HALT(100)
  425. END;
  426. ELSIF form = IntermediateCode.Undefined THEN
  427. RETURN TRUE
  428. ELSE HALT(100)
  429. END;
  430. RETURN TRUE
  431. END Supported;
  432. (* input: type (such as that of an intermediate operand), output: low and high type (such as in low and high type of an operand) *)
  433. PROCEDURE GetPartType*(CONST type: IntermediateCode.Type; part: LONGINT; VAR typePart: IntermediateCode.Type);
  434. BEGIN
  435. ASSERT(type.sizeInBits >0); ASSERT(part < 2);
  436. IF (part = 0) OR (type.sizeInBits =64) THEN
  437. IntermediateCode.InitType(typePart,type.form,32);
  438. ELSE
  439. typePart := IntermediateCode.undef
  440. END;
  441. END GetPartType;
  442. PROCEDURE GetSpillOperand(ticket: Ticket; VAR mem: Operand);
  443. VAR offset: LONGINT; register: LONGINT;
  444. BEGIN
  445. D.String("spill stack used in "); Basic.WriteSegmentedName(D.Log, in.name); D.String(": "); D.Int(inPC,1); D.Ln;
  446. offset := spillStackPosition-ticket.offset; (* relative to logical frame pointer ! *)
  447. register := PhysicalRegister(IntermediateCode.FP,Low,offset);
  448. instructionSet.InitMemory(mem, register, offset);
  449. END GetSpillOperand;
  450. PROCEDURE ToSpillStack*(ticket: Ticket);
  451. VAR mem, reg:Operand;
  452. BEGIN
  453. IF dump # NIL THEN dump.String("spill: "); CodeGenerators.DumpTicket(dump,ticket); dump.Ln; END;
  454. GetSpillOperand(ticket,mem);
  455. instructionSet.InitRegister(reg,ticket.register);
  456. Emit2(opST,reg,mem);
  457. END ToSpillStack;
  458. PROCEDURE AllocateSpillStack*(size: LONGINT);
  459. BEGIN
  460. END AllocateSpillStack;
  461. PROCEDURE ToRegister*(ticket: Ticket);
  462. VAR mem,reg: Operand;
  463. BEGIN
  464. IF dump # NIL THEN dump.String("unspill: "); CodeGenerators.DumpTicket(dump,ticket); dump.Ln END;
  465. GetSpillOperand(ticket,mem);
  466. instructionSet.InitRegister(reg,ticket.register);
  467. Emit2(opLD,reg,mem);
  468. END ToRegister;
  469. PROCEDURE ExchangeTickets*(ticket1,ticket2: Ticket);
  470. VAR op1,op2,temp: Operand;
  471. BEGIN
  472. TicketToOperand(ticket1,op1);
  473. TicketToOperand(ticket2,op2);
  474. GetTemporaryRegister(temp);
  475. IF op1.type = InstructionSet.Register THEN
  476. ASSERT(op2.type = InstructionSet.Memory);
  477. Emit2(opMOV,temp,op1);
  478. Emit2(opLD,op1,op2);
  479. Emit2(opST,temp,op2);
  480. ELSE
  481. ASSERT(op2.type = InstructionSet.Register); ASSERT(op1.type = InstructionSet.Memory);
  482. Emit2(opMOV,temp,op2);
  483. Emit2(opLD,op2,op1);
  484. Emit2(opST,temp,op1);
  485. END;
  486. ReleaseHint(temp.register);
  487. (* spill stack not yet supported *)
  488. END ExchangeTickets;
  489. PROCEDURE CheckFixups;
  490. VAR fixup, forward, newFixup: BinaryCode.Fixup; fixupOp: InstructionSet.Operand; checkPC, iterCount: LONGINT;
  491. PROCEDURE CheckPC(): LONGINT;
  492. CONST safety=16; (* max number of TRM instructions to emit IR instruction *)
  493. BEGIN
  494. IF patchSpartan6 & out.os.fixed & ((out.pc+out.os.alignment) MOD 1024 < 960) & ((out.pc+out.os.alignment) MOD 1024 > 960-safety) THEN
  495. RETURN out.pc + safety + 16
  496. ELSE
  497. RETURN out.pc + safety (* assuming that an IR instruction can be emitted within at most 10 instructions *)
  498. END;
  499. END CheckPC;
  500. BEGIN
  501. fixup := forwardFixups.Check(CheckPC());
  502. iterCount:=0;
  503. WHILE(fixup # NIL) DO
  504. INC(iterCount);
  505. IF(iterCount>30) THEN
  506. D.String("too many iterations in forward fixup");D.Ln;
  507. HALT(100);
  508. END;
  509. (*problem: sometimes causes problems when there are large backwards jumps*)
  510. (*but is needed for long jumps in general*)
  511. (*!TODO: sometimes leads to infinite loop in instruction sizes <= 14*)
  512. (* sometimes, compiler continues to work fine without this section.*)
  513. (*apparently this section resolves the multihop jumps, but fails if it's supposed to go backward?*)
  514. IF fixup.symbolOffset < inPC THEN (* already resolved ok *)
  515. ELSE (* must be handled *)
  516. IF TraceFixups THEN
  517. D.String("relative branch fixup bits: ");D.Int(instructionSet.RelativeBranchFixupBits,1);
  518. D.String(" at inPC="); D.Int(inPC,1); D.String(", outPC="); D.Int(out.pc,1);
  519. D.String(", symbol offset=");D.Int(fixup.symbolOffset,1);
  520. D.String(", fixup from outPC = "); D.Int(fixup.offset,1); D.String(" to "); fixup.Dump(D.Log); D.String(" forwarded."); D.Ln;
  521. END;
  522. forward := BrForward(opBT);
  523. (*
  524. Emit1N(opBT, 1);
  525. *)
  526. newFixup := BinaryCode.NewFixup(fixup.mode, out.pc, fixup.symbol, fixup.symbolOffset, 0, 0, NIL);
  527. fixup.SetSymbol(fixup.symbol.name, fixup.symbol.fingerprint, 0, fixup.displacement+out.pc);
  528. ASSERT(ABS(out.pc - fixup.displacement) < 512);
  529. instructionSet.InitFixup(fixupOp,0,newFixup);
  530. forwardFixups.Enter(newFixup, out.pc, instructionSet.RelativeBranchFixupBits);
  531. Emit1(opBT, fixupOp);
  532. SetTarget(forward);
  533. END;
  534. fixup := forwardFixups.Check(CheckPC());
  535. END;
  536. END CheckFixups;
  537. PROCEDURE IsComplex(CONST operand: IntermediateCode.Operand): BOOLEAN;
  538. BEGIN RETURN (operand.type.sizeInBits > 32)
  539. END IsComplex;
  540. PROCEDURE IsFloat(CONST operand: IntermediateCode.Operand): BOOLEAN;
  541. BEGIN RETURN operand.type.form = IntermediateCode.Float
  542. END IsFloat;
  543. PROCEDURE Generate*(VAR instruction: IntermediateCode.Instruction);
  544. VAR opcode: SHORTINT; ticket: Ticket; hwreg, lastUse: LONGINT;
  545. BEGIN
  546. CheckFixups;
  547. (*
  548. IF ((instruction.opcode = IntermediateCode.mov) OR (instruction.opcode = IntermediateCode.pop)) & (instruction.op1.register <= IntermediateCode.ParameterRegister) THEN
  549. hwreg := ParameterRegister(IntermediateCode.ParameterRegister-instruction.op1.register, instruction.op1.type);
  550. Spill(physicalRegisters.Mapped(hwreg));
  551. lastUse := inPC+1;
  552. WHILE (lastUse < in.pc) &
  553. ((in.instructions[lastUse].opcode # IntermediateCode.push) OR (in.instructions[lastUse].op1.register # instruction.op1.register)) & (in.instructions[lastUse].opcode # IntermediateCode.call) DO
  554. INC(lastUse)
  555. END;
  556. ticket := ReservePhysicalRegister(instruction.op1.type,hwreg,lastUse);
  557. END;
  558. *)
  559. ReserveOperandRegisters(instruction.op1,TRUE); ReserveOperandRegisters(instruction.op2,TRUE);ReserveOperandRegisters(instruction.op3,TRUE);
  560. opcode := instruction.opcode;
  561. CASE opcode OF
  562. IntermediateCode.nop: (* do nothing *)
  563. |IntermediateCode.mov:
  564. EmitMov(instruction.op1,instruction.op2,Low);
  565. IF IsComplex(instruction.op1) THEN
  566. EmitMov(instruction.op1,instruction.op2,High)
  567. END;
  568. |IntermediateCode.conv: EmitConv(instruction);
  569. |IntermediateCode.call: EmitCall(instruction);
  570. |IntermediateCode.enter: EmitEnter(instruction);
  571. |IntermediateCode.leave: EmitLeave(instruction);
  572. |IntermediateCode.exit: EmitExit(instruction);
  573. |IntermediateCode.return:
  574. EmitReturn(instruction,Low);
  575. IF IsComplex(instruction.op1) THEN
  576. EmitReturn(instruction,High)
  577. END;
  578. |IntermediateCode.result:
  579. EmitResult(instruction,Low);
  580. IF IsComplex(instruction.op1) THEN
  581. EmitResult(instruction,High)
  582. END;
  583. |IntermediateCode.trap: EmitTrap(instruction);
  584. |IntermediateCode.br .. IntermediateCode.brlt: EmitBr(instruction)
  585. |IntermediateCode.pop:
  586. EmitPop(instruction.op1,Low);
  587. IF IsComplex(instruction.op1) THEN
  588. EmitPop(instruction.op1,High);
  589. END;
  590. |IntermediateCode.push:
  591. IF IsComplex(instruction.op1) THEN
  592. EmitPush(instruction.op1,High);
  593. END;
  594. EmitPush(instruction.op1,Low);
  595. |IntermediateCode.neg: EmitNeg(instruction);
  596. |IntermediateCode.not:
  597. EmitNot(instruction,Low);
  598. IF IsComplex(instruction.op1) THEN
  599. EmitNot(instruction,High)
  600. END;
  601. |IntermediateCode.abs: EmitAbs(instruction);
  602. |IntermediateCode.mul:
  603. IF IsFloat(instruction.op1) THEN
  604. EmitFMul(instruction)
  605. ELSE
  606. EmitMul(instruction)
  607. END
  608. |IntermediateCode.div: EmitDiv(instruction);
  609. |IntermediateCode.mod: EmitMod(instruction);
  610. |IntermediateCode.sub:
  611. IF IsFloat(instruction.op1) THEN
  612. EmitFSub(instruction)
  613. ELSE
  614. EmitSub(instruction)
  615. END
  616. |IntermediateCode.add:
  617. IF IsFloat(instruction.op1) THEN
  618. EmitFAdd(instruction)
  619. ELSE
  620. EmitAdd(instruction)
  621. END
  622. |IntermediateCode.and:
  623. EmitAnd(instruction);
  624. |IntermediateCode.or:
  625. EmitOr(instruction,Low);
  626. IF IsComplex(instruction.op1) THEN
  627. EmitOr(instruction,High)
  628. END;
  629. |IntermediateCode.xor:
  630. EmitXor(instruction,Low);
  631. IF IsComplex(instruction.op1) THEN
  632. EmitXor(instruction,High)
  633. END;
  634. |IntermediateCode.shl: EmitShift(instruction);
  635. |IntermediateCode.shr: EmitShift(instruction);
  636. |IntermediateCode.rol: EmitShift(instruction);
  637. |IntermediateCode.ror: EmitShift(instruction);
  638. |IntermediateCode.copy: EmitCopy(instruction);
  639. |IntermediateCode.fill: EmitFill(instruction, FALSE);
  640. |IntermediateCode.asm: EmitAsm(instruction);
  641. END;
  642. ReserveOperandRegisters(instruction.op3,FALSE); ReserveOperandRegisters(instruction.op2,FALSE); ReserveOperandRegisters(instruction.op1,FALSE);
  643. END Generate;
  644. PROCEDURE PostGenerate*(CONST instruction: IntermediateCode.Instruction);
  645. VAR ticket: Ticket;
  646. BEGIN
  647. TryUnmap(instruction.op3); TryUnmap(instruction.op2); TryUnmap(instruction.op1);
  648. ticket := tickets.live;
  649. WHILE (ticket # NIL) & (ticket.lastuse = inPC) DO
  650. UnmapTicket(ticket);
  651. ticket := tickets.live
  652. END;
  653. END PostGenerate;
  654. PROCEDURE TicketToOperand(ticket:Ticket; VAR op: InstructionSet.Operand);
  655. BEGIN
  656. ASSERT(ticket # NIL);
  657. IF ticket.spilled THEN
  658. GetSpillOperand(ticket,op);
  659. ELSE
  660. instructionSet.InitRegister(op,ticket.register)
  661. END;
  662. END TicketToOperand;
  663. (* updateStackSize is important as intermediate RETURNS should not change stack size *)
  664. PROCEDURE AllocateStack(size: LONGINT; updateStackSize: BOOLEAN);
  665. VAR sizeOperand: InstructionSet.Operand;
  666. BEGIN
  667. inStackAllocation := TRUE;
  668. IF size > 0 THEN
  669. IF size < ASH(1,instructionSet.ImmediateFixupBits) THEN
  670. instructionSet.InitImmediate(sizeOperand, 0, size)
  671. ELSE
  672. ImmediateToOperand(size,Low,FALSE,instructionSet.ImmediateFixupBits,sizeOperand)
  673. END;
  674. Emit2(opSUB, opSP, sizeOperand);
  675. IF updateStackSize THEN INC(stackSize, size) END;
  676. ELSIF size < 0 THEN
  677. size := -size;
  678. IF size < ASH(1,instructionSet.ImmediateFixupBits) THEN
  679. instructionSet.InitImmediate(sizeOperand, 0, size);
  680. ELSE
  681. ImmediateToOperand(size,Low, FALSE, instructionSet.ImmediateFixupBits,sizeOperand);
  682. END;
  683. Emit2(opADD, opSP, sizeOperand);
  684. IF updateStackSize THEN DEC(stackSize, size) END;
  685. END;
  686. inStackAllocation := FALSE;
  687. END AllocateStack;
  688. PROCEDURE EmitEnter(CONST instr: IntermediateCode.Instruction);
  689. VAR cc: LONGINT; mem: InstructionSet.Operand;
  690. BEGIN
  691. stackSize := 0;
  692. (*
  693. stack layout:
  694. p1
  695. ...
  696. pm (parameters pushed by caller)
  697. LR (explicitly pushed by frontend because hasLinkRegister = TRUE)
  698. prev FP <-- FP = logicalFP (explicitly pushed by frontend)
  699. v1
  700. ...
  701. vn
  702. spill1 <- logicalFP + spillStackPosition (negative)
  703. ...
  704. spilln <-- SP
  705. *)
  706. cc := SHORT(instr.op1.intValue);
  707. spillStackPosition := - LONGINT(instr.op2.intValue)-1; (* relative to logical frame pointer ! *)
  708. AllocateStack(LONGINT(instr.op2.intValue+spillStack.MaxSize()), TRUE);
  709. END EmitEnter;
  710. PROCEDURE EmitLeave(CONST instr: IntermediateCode.Instruction);
  711. VAR cc: LONGINT; mem: InstructionSet.Operand;
  712. BEGIN
  713. IF ~supportFP THEN (* frame pointer might have been used *)
  714. AllocateStack(-stackSize, FALSE);
  715. Emit2(opMOV, opFP, opSP);
  716. END;
  717. END EmitLeave;
  718. PROCEDURE EmitExit(CONST instr: IntermediateCode.Instruction);
  719. VAR cc: LONGINT; mem: InstructionSet.Operand;
  720. BEGIN
  721. instructionSet.InitMemory(mem, InstructionSet.SP, 0);
  722. Emit2(opLD, opLR, mem);
  723. AllocateStack(-1,FALSE);
  724. Emit1(opBR, opLR);
  725. END EmitExit;
  726. PROCEDURE ResultRegister(part: LONGINT): InstructionSet.Operand;
  727. VAR register: InstructionSet.Operand;
  728. BEGIN
  729. IF part = Low THEN instructionSet.InitRegister(register,0)
  730. ELSE instructionSet.InitRegister(register,1)
  731. END;
  732. RETURN register
  733. END ResultRegister;
  734. PROCEDURE EmitResult(VAR instr: IntermediateCode.Instruction; part: LONGINT);
  735. VAR op,result: Operand;
  736. BEGIN
  737. AcquireDestinationRegister(instr.op1, part,op);
  738. result := ResultRegister(part);
  739. MovIfDifferent(op, result);
  740. ReleaseDestinationRegister(instr.op1,part,op);
  741. END EmitResult;
  742. PROCEDURE EmitReturn(VAR instr: IntermediateCode.Instruction; part: LONGINT);
  743. VAR op,result: Operand;
  744. BEGIN
  745. MakeRegister(instr.op1,part,op);
  746. result := ResultRegister(part);
  747. MovIfDifferent(result, op);
  748. END EmitReturn;
  749. PROCEDURE EmitMov(VAR vop1,vop2: IntermediateCode.Operand; part: LONGINT);
  750. VAR left,right: Operand; rightTicket: Ticket; neg: BOOLEAN;
  751. BEGIN
  752. rightTicket := NIL;
  753. IF vop2.mode = IntermediateCode.ModeMemory THEN
  754. (*GetMemory(vop2,part,right,rightTicket);*) (* done in load *)
  755. ELSIF ~UnsignedImmediate(vop2,part,instructionSet.ImmediateFixupBits,FALSE,neg,right) THEN
  756. MakeRegister(vop2,part,right);
  757. ReleaseHint(right.register);
  758. END;
  759. AcquireDestinationRegister(vop1,part,left);
  760. IF vop2.mode = IntermediateCode.ModeMemory THEN
  761. Load(vop2,part,left);
  762. ELSE
  763. MovIfDifferent(left, right);
  764. END;
  765. IF vop1.mode = IntermediateCode.ModeMemory THEN
  766. Store(vop1,part,left);
  767. END;
  768. ReleaseHint(left.register);
  769. END EmitMov;
  770. PROCEDURE EmitConv(VAR instr: IntermediateCode.Instruction);
  771. VAR left,right,temp: Operand;
  772. srcSize, destSize: LONGINT;
  773. BEGIN
  774. srcSize := instr.op2.type.sizeInBits;
  775. destSize := instr.op1.type.sizeInBits;
  776. ASSERT( (srcSize = 32) OR (srcSize = 64));
  777. ASSERT( (destSize = 32) OR (destSize = 64));
  778. ASSERT(instr.op1.type.form IN IntermediateCode.Integer);
  779. ASSERT(instr.op2.type.form IN IntermediateCode.Integer);
  780. IF srcSize >= destSize THEN
  781. MakeRegister(instr.op2,Low,right);
  782. ReleaseHint(right.register);
  783. AcquireDestinationRegister(instr.op1,Low,left);
  784. MovIfDifferent(left, right);
  785. ReleaseDestinationRegister(instr.op1,Low, left);
  786. ELSE
  787. MakeRegister(instr.op2, Low, right);
  788. ReleaseHint(right.register);
  789. AcquireDestinationRegister(instr.op1,Low,left);
  790. MovIfDifferent(left,right);
  791. ReleaseDestinationRegister(instr.op1,Low,left);
  792. IF (instr.op2.type.form = IntermediateCode.SignedInteger) & (instr.op1.type.form = IntermediateCode.SignedInteger) THEN
  793. GetTemporaryRegister(temp);
  794. Emit2(opMOV, temp,left);
  795. AcquireDestinationRegister(instr.op1,High,left);
  796. Emit2(opMOV, left, temp);
  797. Emit2N(opROR, temp, 31);
  798. Emit2N(opAND, temp, 1);
  799. Emit2(opNOT, left, temp);
  800. Emit2N(opADD, left, 1);
  801. ELSE
  802. AcquireDestinationRegister(instr.op1,High,left);
  803. Emit2N(opMOV, left, 0);
  804. END;
  805. ReleaseDestinationRegister(instr.op1,High,left);
  806. END;
  807. END EmitConv;
  808. PROCEDURE Resolve(VAR op: IntermediateCode.Operand);
  809. BEGIN
  810. IF (op.symbol.name # "") & (op.resolved = NIL) THEN
  811. op.resolved := module.allSections.FindByName(op.symbol.name)
  812. END;
  813. END Resolve;
  814. PROCEDURE EmitCall(VAR instruction: IntermediateCode.Instruction);
  815. VAR op: InstructionSet.Operand; section: IntermediateCode.Section; code: BinaryCode.Section; symbol: ObjectFile.Identifier;
  816. fixup, newFixup: BinaryCode.Fixup; pc: LONGINT; regOp: Operand; offset,reloffset: LONGINT;
  817. BEGIN
  818. IF (instruction.op1.symbol.name # "") & (instruction.op1.mode # IntermediateCode.ModeMemory) THEN
  819. Resolve(instruction.op1);
  820. IF instruction.op1.resolved # NIL THEN
  821. section := instruction.op1.resolved(IntermediateCode.Section);
  822. END;
  823. IF (section # NIL) & (section.type = Sections.InlineCodeSection) THEN
  824. code := section.resolved;
  825. ASSERT(code # NIL);
  826. out.CopyBits(code.os.bits, 0, code.os.bits.GetSize());
  827. fixup := code.fixupList.firstFixup;
  828. pc := code.pc;
  829. WHILE (fixup # NIL) DO
  830. newFixup := BinaryCode.NewFixup(fixup.mode, fixup.offset+pc, fixup.symbol, fixup.symbolOffset, fixup.displacement, fixup.scale, fixup.pattern);
  831. out.fixupList.AddFixup(newFixup);
  832. fixup := fixup.nextFixup;
  833. END;
  834. ELSE
  835. IF out.os.fixed THEN (* only if my own address is already known .. *)
  836. offset := GetSymbolOffset(instruction.op1, symbol);
  837. ELSE
  838. offset := instruction.op1.offset;
  839. Resolve(instruction.op1);
  840. symbol := instruction.op1.symbol;
  841. END;
  842. reloffset := offset - out.pc-out.os.alignment-1;
  843. IF symbol.name # "" THEN
  844. fixup := BinaryCode.NewFixup(BinaryCode.Relative,out.pc,symbol, offset, 0, 0, NIL);
  845. instructionSet.InitFixup(op, 32, fixup);
  846. Emit1(opBL, op);
  847. ELSIF (-ASH(1,instructionSet.BranchAndLinkFixupBits-1) <= reloffset) & (reloffset < ASH(1,instructionSet.BranchAndLinkFixupBits-1)) THEN
  848. ImmediateToOperand(reloffset, Low, TRUE, instructionSet.BranchAndLinkFixupBits,op);
  849. ASSERT(op.type = InstructionSet.Immediate);
  850. Emit1(opBL, op);
  851. ELSE
  852. GetTemporaryRegister(op);
  853. ImmediateToOperand(offset, Low, FALSE, instructionSet.ImmediateFixupBits,op);
  854. ASSERT(op.type = InstructionSet.Register);
  855. Emit2(opBLR, opLR, op);
  856. END;
  857. END;
  858. ELSE
  859. MakeRegister(instruction.op1,Low,regOp);
  860. Emit2(opBLR, opLR, regOp);
  861. END;
  862. AllocateStack(-SHORT(instruction.op2.intValue), TRUE)
  863. END EmitCall;
  864. PROCEDURE GetImmediate32(val: LONGINT; CONST reg: InstructionSet.Operand; emit: BOOLEAN): LONGINT;
  865. VAR ops: LONGINT; set: SET;
  866. PROCEDURE Add(val,pos: LONGINT; VAR first: BOOLEAN): LONGINT;
  867. VAR imm: InstructionSet.Operand; ops: LONGINT; op: InstructionSet.Operand;
  868. BEGIN
  869. instructionSet.InitImmediate(imm, 0, val);
  870. IF pos # 0 THEN
  871. IF first THEN
  872. ops := 2;
  873. IF emit THEN
  874. Emit2(opMOV, reg, imm);
  875. instructionSet.InitImmediate(imm, 0, 32-pos); (*!TODO: if instruction width is <=13, immediate for ror is so small it can't express this number!*)
  876. Emit2(opROR, reg, imm);
  877. END;
  878. ELSE
  879. ops := 3;
  880. IF emit THEN
  881. GetTemporaryRegister(op);
  882. Emit2(opMOV, op, imm);
  883. instructionSet.InitImmediate(imm, 0, 32-pos);
  884. Emit2(opROR, op, imm);
  885. Emit2(opADD, reg, op);
  886. ReleaseHint(op.register);
  887. END;
  888. END;
  889. ELSE
  890. ops := 1;
  891. IF emit THEN Emit2(opADD, reg, imm) END;
  892. END;
  893. first := FALSE;
  894. RETURN ops
  895. END Add;
  896. PROCEDURE Compute(val: SET): LONGINT;
  897. VAR v,i: LONGINT; ops: LONGINT; first: BOOLEAN;
  898. BEGIN
  899. v := 0; ops := 0; first := TRUE;
  900. FOR i := 31 TO 0 BY -1 DO
  901. v := v * 2;
  902. IF i IN val THEN INC(v) END;
  903. IF v*2 >= ASH(1,instructionSet.ImmediateFixupBits) THEN
  904. ops := ops + Add(v,i,first);
  905. v := 0;
  906. END;
  907. END;
  908. IF v # 0 THEN ops := ops + Add(v,0,first) END;
  909. RETURN ops
  910. END Compute;
  911. BEGIN
  912. set := SYSTEM.VAL(SET,val);
  913. ops := Compute(set);
  914. RETURN ops
  915. END GetImmediate32;
  916. PROCEDURE ImmediateToOperand(imm: HUGEINT; part: LONGINT; signed: BOOLEAN; bits: LONGINT; VAR op: Operand);
  917. VAR immOp: InstructionSet.Operand; maxImmValue, minImmValue : LONGINT;
  918. PROCEDURE ImmediateToOp32(imm: LONGINT; VAR op: InstructionSet.Operand);
  919. VAR ops: LONGINT;
  920. BEGIN
  921. IF (imm>=0) & (imm < ASH(1,instructionSet.ImmediateFixupBits)) THEN
  922. instructionSet.InitImmediate(immOp, 0, imm);
  923. Emit2(opMOV, op, immOp);
  924. ELSIF (imm <0) & (imm > MIN(LONGINT)) & (ABS(imm) < ASH(1,instructionSet.ImmediateFixupBits)) THEN
  925. instructionSet.InitImmediate(immOp, 0, 0);
  926. Emit2(opMOV, op, immOp);
  927. instructionSet.InitImmediate(immOp, 0, ABS(imm));
  928. Emit2(opSUB, op, immOp);
  929. ELSE
  930. ops := GetImmediate32(imm, op, TRUE);
  931. END;
  932. END ImmediateToOp32;
  933. BEGIN
  934. IF signed THEN
  935. minImmValue := -ASH(1,bits-1); maxImmValue := ASH(1,bits-1)-1;
  936. ELSE
  937. minImmValue := 0; maxImmValue := ASH(1,bits)-1
  938. END;
  939. IF (op.type # InstructionSet.Register) & (imm >=minImmValue) & (imm <=maxImmValue) THEN (* immediate operand *)
  940. IF part = Low THEN
  941. instructionSet.InitImmediate(op,0,SHORT(imm));
  942. ELSE
  943. instructionSet.InitImmediate(op,0,0);
  944. END;
  945. ELSE
  946. IF op.type # InstructionSet.Register THEN
  947. GetTemporaryRegister(op);
  948. END;
  949. IF part = Low THEN
  950. ImmediateToOp32(SHORT(imm), op)
  951. ELSE
  952. ImmediateToOp32(SHORT(imm DIV 10000H DIV 10000H),op);
  953. END
  954. END;
  955. END ImmediateToOperand;
  956. PROCEDURE MakeRegister(VAR vop: IntermediateCode.Operand; part: LONGINT; VAR rop: Operand);
  957. VAR virtualReg: LONGINT; tmp, imm: Operand; offset: LONGINT; symbol: ObjectFile.Identifier;
  958. sizeInBits: LONGINT;
  959. BEGIN
  960. (*InstructionSet.InitOperand(rop); *)
  961. instructionSet.InitOperand(imm);
  962. sizeInBits := vop.type.sizeInBits;
  963. virtualReg := vop.register;
  964. offset := GetSymbolOffset(vop,symbol);
  965. CASE vop.mode OF
  966. IntermediateCode.ModeMemory:
  967. GetTemporaryRegister(rop);
  968. Load(vop,part,rop);
  969. |IntermediateCode.ModeRegister:
  970. GetRegister(vop,part,rop);
  971. |IntermediateCode.ModeImmediate:
  972. IF symbol.name # "" THEN
  973. instructionSet.InitFixup(tmp, 14, BinaryCode.NewFixup(BinaryCode.Absolute,out.pc,vop.symbol, vop.symbolOffset, vop.offset,0,NIL));
  974. GetTemporaryRegister(rop);
  975. Emit2(opMOV, rop, tmp);
  976. ELSE
  977. IF vop.type.form IN IntermediateCode.Integer THEN
  978. ASSERT ((vop.intValue = 0) OR (offset = 0));
  979. ImmediateToOperand(vop.intValue+offset, part, FALSE, instructionSet.ImmediateFixupBits,rop);
  980. ELSE ASSERT(vop.type.form = IntermediateCode.Float); ASSERT(vop.type.sizeInBits=32);
  981. ImmediateToOperand(BinaryCode.ConvertReal(SHORT(vop.floatValue)),part,FALSE,instructionSet.ImmediateFixupBits,rop);
  982. END;
  983. IF rop.type # InstructionSet.Register THEN
  984. GetTemporaryRegister(tmp);
  985. Emit2(opMOV, tmp, rop);
  986. rop := tmp
  987. END;
  988. END;
  989. ELSE HALT(200)
  990. END;
  991. END MakeRegister;
  992. (* if the symbol has a statically known offset then return offset and set resulting section to nil, otherwise do not set resulting section to nil *)
  993. PROCEDURE GetSymbolOffset(VAR vop: IntermediateCode.Operand; VAR sectionName: ObjectFile.Identifier): LONGINT;
  994. VAR offset: LONGINT; section: Sections.Section;
  995. BEGIN
  996. sectionName := vop.symbol;
  997. Resolve(vop);
  998. section := vop.resolved; offset := vop.offset;
  999. IF (section # NIL) & (section(IntermediateCode.Section).resolved # NIL) & (section(IntermediateCode.Section).resolved.os.fixed) THEN
  1000. INC(offset, section(IntermediateCode.Section).resolved.os.alignment);
  1001. IF vop.symbolOffset > 0 THEN
  1002. INC(offset, section(IntermediateCode.Section).instructions[vop.symbolOffset].pc);
  1003. END;
  1004. sectionName.name := "";
  1005. END;
  1006. RETURN offset
  1007. END GetSymbolOffset;
  1008. PROCEDURE GetMemory(VAR vop: IntermediateCode.Operand; part: LONGINT; VAR memoryOperand: InstructionSet.Operand; ticket: Ticket);
  1009. VAR virtualReg: LONGINT; register: LONGINT; registerOperand, temporary: InstructionSet.Operand; symbol: ObjectFile.Identifier;
  1010. offset: LONGINT;
  1011. BEGIN
  1012. virtualReg := vop.register;
  1013. ASSERT(vop.mode = IntermediateCode.ModeMemory);
  1014. offset := GetSymbolOffset(vop, symbol) + part;
  1015. register := PhysicalRegister(vop.register,Low,offset);
  1016. IF register = None THEN
  1017. IF symbol.name = "" THEN
  1018. offset := offset + SHORT(vop.intValue);
  1019. END;
  1020. register := InstructionSet.None;
  1021. END;
  1022. IF (0<=offset) & (offset < ASH(1,instructionSet.MemoryOffsetFixupBits)) THEN
  1023. instructionSet.InitMemory(memoryOperand, register, offset);
  1024. ELSE
  1025. IF ticket = NIL THEN
  1026. ticket := TemporaryTicket(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32);
  1027. END;
  1028. TicketToOperand(ticket, temporary);
  1029. ImmediateToOperand(offset, Low, FALSE, instructionSet.ImmediateFixupBits,temporary);
  1030. instructionSet.InitRegister(registerOperand,register);
  1031. IF register # InstructionSet.None THEN
  1032. Emit2(opADD,temporary,registerOperand);
  1033. END;
  1034. instructionSet.InitMemory(memoryOperand, temporary.register, 0);
  1035. END;
  1036. IF symbol.name # "" THEN
  1037. instructionSet.AddFixup(memoryOperand, BinaryCode.NewFixup(BinaryCode.Absolute, 0, symbol, vop.symbolOffset, offset, 0, NIL));
  1038. END;
  1039. END GetMemory;
  1040. PROCEDURE Load(VAR vop: IntermediateCode.Operand; part: LONGINT; CONST register: Operand);
  1041. VAR memoryOperand: Operand;
  1042. BEGIN
  1043. ASSERT(register.type = InstructionSet.Register);
  1044. GetMemory(vop,part,memoryOperand,physicalRegisters.Mapped(register.register));
  1045. Emit2(opLD,register,memoryOperand);
  1046. END Load;
  1047. PROCEDURE Store(VAR vop: IntermediateCode.Operand; part: LONGINT; CONST register: Operand);
  1048. VAR memoryOperand: Operand;
  1049. BEGIN
  1050. GetMemory(vop,part,memoryOperand,NIL);
  1051. Emit2(opST,register,memoryOperand);
  1052. END Store;
  1053. PROCEDURE UnsignedImmediate(vop: IntermediateCode.Operand; part: LONGINT; bits: LONGINT; allowNegation: BOOLEAN; VAR neg: BOOLEAN; VAR rop: Operand): BOOLEAN;
  1054. VAR value,offset : LONGINT; symbol: ObjectFile.Identifier;
  1055. BEGIN
  1056. IF (vop.mode = IntermediateCode.ModeImmediate) THEN
  1057. offset := GetSymbolOffset(vop, symbol);
  1058. IF part = Low THEN
  1059. value := SHORT(vop.intValue + offset);
  1060. ELSE
  1061. value := SHORT((vop.intValue + offset) DIV 1000H DIV 1000H);
  1062. END;
  1063. IF symbol.name # "" THEN RETURN FALSE
  1064. ELSIF vop.type.form = IntermediateCode.Float THEN RETURN FALSE
  1065. ELSIF (value >= 0) & (value < ASH(1,bits)) THEN
  1066. instructionSet.InitImmediate(rop, 0, value); neg := FALSE;
  1067. RETURN TRUE
  1068. ELSIF allowNegation & (value <0) & (value # MIN(LONGINT)) & (-value < ASH(1,bits)) THEN
  1069. instructionSet.InitImmediate(rop, 0, -value); neg := TRUE;
  1070. RETURN TRUE
  1071. END;
  1072. END;
  1073. RETURN FALSE
  1074. END UnsignedImmediate;
  1075. PROCEDURE HardwareIntegerRegister(index: LONGINT; sizeInBits: LONGINT): LONGINT;
  1076. BEGIN RETURN index
  1077. END HardwareIntegerRegister;
  1078. PROCEDURE HardwareFloatRegister(index: LONGINT; sizeInBits: LONGINT): LONGINT;
  1079. BEGIN RETURN index
  1080. END HardwareFloatRegister;
  1081. PROCEDURE GetTypedHardwareRegister(index: LONGINT; type: IntermediateCode.Type): LONGINT;
  1082. VAR size: LONGINT;
  1083. BEGIN
  1084. IF type.form IN IntermediateCode.Integer THEN
  1085. RETURN HardwareIntegerRegister(index, type.sizeInBits)
  1086. ELSIF type.form = IntermediateCode.Float THEN
  1087. RETURN HardwareFloatRegister(index, type.sizeInBits)
  1088. ELSE
  1089. HALT(100);
  1090. END;
  1091. END GetTypedHardwareRegister;
  1092. PROCEDURE ParameterRegister(CONST type: IntermediateCode.Type; index: LONGINT): LONGINT;
  1093. BEGIN
  1094. RETURN GetTypedHardwareRegister(index, type)
  1095. END ParameterRegister;
  1096. PROCEDURE PhysicalRegister(virtualReg: LONGINT; part: LONGINT; VAR offset: LONGINT): LONGINT;
  1097. VAR register: LONGINT; fpOffset: LONGINT; ticket: Ticket;
  1098. BEGIN
  1099. IF virtualReg = IntermediateCode.FP THEN
  1100. IF stackSizeKnown THEN
  1101. register := InstructionSet.SP;
  1102. INC(offset, stackSize);
  1103. ELSE (* stack size unknown, actually fp must be supported *)
  1104. register := InstructionSet.FP;
  1105. END;
  1106. ELSIF virtualReg = IntermediateCode.SP THEN
  1107. register := InstructionSet.SP;
  1108. ELSIF virtualReg = IntermediateCode.LR THEN
  1109. register := InstructionSet.LR;
  1110. (*!ELSIF virtualReg <= IntermediateCode.ParameterRegister THEN
  1111. register := ParameterRegister(IntermediateCode.ParameterRegister-virtualReg, IntermediateCode.int32);
  1112. *)
  1113. ELSE
  1114. ticket := virtualRegisters.Mapped(virtualReg,part);
  1115. IF ticket = NIL THEN register := None
  1116. ELSE
  1117. UnSpill(ticket);
  1118. register := ticket.register
  1119. END;
  1120. END;
  1121. RETURN register
  1122. END PhysicalRegister;
  1123. PROCEDURE GetRegister(CONST virtual: IntermediateCode.Operand; part:LONGINT; VAR physical: Operand);
  1124. VAR type: IntermediateCode.Type; virtualRegister, physicalRegister: LONGINT;
  1125. tmp,imm: Operand; offset: LONGINT; ticket: Ticket; ops: LONGINT;
  1126. BEGIN
  1127. ASSERT(virtual.mode = IntermediateCode.ModeRegister);
  1128. GetPartType(virtual.type,part,type);
  1129. virtualRegister := virtual.register;
  1130. offset := virtual.offset;
  1131. physicalRegister := PhysicalRegister(virtual.register,part,offset);
  1132. instructionSet.InitRegister(physical, physicalRegister);
  1133. IF offset # 0 THEN
  1134. (*
  1135. offset := virtual.offset;
  1136. *)
  1137. Assert(type.form # IntermediateCode.Float,"forbidden offset on float");
  1138. ReleaseHint(physical.register);
  1139. GetTemporaryRegister(tmp);
  1140. MovIfDifferent(tmp, physical);
  1141. physical := tmp;
  1142. IF (offset >= 0) & (offset < ASH(1,instructionSet.ImmediateFixupBits)) THEN
  1143. instructionSet.InitImmediate(imm, 0, offset);
  1144. Emit2(opADD,physical,imm);
  1145. ELSIF (offset <0) & (-offset < ASH(1,instructionSet.ImmediateFixupBits)) THEN
  1146. instructionSet.InitImmediate(imm, 0, -offset);
  1147. Emit2(opSUB,physical,imm);
  1148. ELSE
  1149. GetTemporaryRegister(tmp);
  1150. ops := GetImmediate32(offset,tmp,TRUE);
  1151. Emit2(opADD,physical,tmp);
  1152. ReleaseHint(tmp.register);
  1153. END;
  1154. END;
  1155. END GetRegister;
  1156. PROCEDURE IsSameRegister(CONST a, b : InstructionSet.Operand) : BOOLEAN;
  1157. BEGIN
  1158. IF (a.fixup # NIL) OR (b.fixup # NIL) OR (a.type # InstructionSet.Register) OR (b.type # InstructionSet.Register) THEN RETURN FALSE END;
  1159. RETURN a.register = b.register;
  1160. END IsSameRegister;
  1161. PROCEDURE MovIfDifferent(CONST a,b: InstructionSet.Operand);
  1162. BEGIN
  1163. IF ~IsSameRegister(a,b) THEN Emit2(opMOV, a, b) END;
  1164. END MovIfDifferent;
  1165. PROCEDURE AcquireDestinationRegister(CONST vop: IntermediateCode.Operand; part: LONGINT; VAR op: Operand);
  1166. VAR type: IntermediateCode.Type;
  1167. BEGIN
  1168. GetPartType(vop.type,part,type);
  1169. IF vop.mode = IntermediateCode.ModeMemory THEN
  1170. GetTemporaryRegister(op);
  1171. ELSE
  1172. IF virtualRegisters.Mapped(vop.register,part)=NIL THEN
  1173. TryAllocate(vop,part);
  1174. END;
  1175. GetRegister(vop,part,op);
  1176. END;
  1177. END AcquireDestinationRegister;
  1178. PROCEDURE PrepareOp3(CONST instruction: IntermediateCode.Instruction;part: LONGINT; allowNegation: BOOLEAN; VAR negate: BOOLEAN; VAR dest, left, right: Assembler.Operand);
  1179. VAR vop1,vop2, vop3: IntermediateCode.Operand; op2: InstructionSet.Operand;
  1180. opx: Operand;
  1181. BEGIN
  1182. vop1 := instruction.op1; vop2 := instruction.op2; vop3 := instruction.op3;
  1183. IF (IntermediateCode.Commute23 IN IntermediateCode.instructionFormat[instruction.opcode].flags) THEN
  1184. IF IntermediateCode.OperandEquals(vop1,vop3) OR UnsignedImmediate(vop2,part,instructionSet.ImmediateFixupBits,FALSE,negate,right) THEN
  1185. vop3 := instruction.op2; vop2 := instruction.op3;
  1186. END;
  1187. END;
  1188. IF ~UnsignedImmediate(vop3, part, instructionSet.ImmediateFixupBits, allowNegation, negate,right) THEN
  1189. instructionSet.InitOperand(right);
  1190. MakeRegister(vop3,part,right);
  1191. END;
  1192. MakeRegister(vop2,part,op2);
  1193. ReleaseHint(op2.register);
  1194. AcquireDestinationRegister(vop1,part,left);
  1195. dest := left;
  1196. IF ~IsSameRegister(left,op2) THEN
  1197. IF IsSameRegister(left,right) THEN
  1198. GetTemporaryRegister(opx);
  1199. MovIfDifferent(opx, op2);
  1200. dest := left;
  1201. left := opx;
  1202. ELSE
  1203. MovIfDifferent(left, op2);
  1204. END;
  1205. END;
  1206. END PrepareOp3;
  1207. PROCEDURE PrepareFOp3(CONST instruction: IntermediateCode.Instruction; VAR dest, left, right: Assembler.Operand);
  1208. VAR vop1,vop2, vop3: IntermediateCode.Operand; op2: InstructionSet.Operand;
  1209. opx: Operand;
  1210. BEGIN
  1211. vop1 := instruction.op1; vop2 := instruction.op2; vop3 := instruction.op3;
  1212. instructionSet.InitOperand(right);
  1213. MakeRegister(vop3,Low,right);
  1214. MakeRegister(vop2,Low,op2);
  1215. ReleaseHint(op2.register);
  1216. AcquireDestinationRegister(vop1,Low,left);
  1217. dest := left;
  1218. IF ~IsSameRegister(left,op2) THEN
  1219. IF IsSameRegister(left,right) THEN
  1220. GetTemporaryRegister(opx);
  1221. MovIfDifferent(opx, op2);
  1222. dest := left;
  1223. left := opx;
  1224. ELSE
  1225. MovIfDifferent(left, op2);
  1226. END;
  1227. END;
  1228. END PrepareFOp3;
  1229. PROCEDURE PrepareOp2(CONST instruction: IntermediateCode.Instruction;part: LONGINT; allowNegation: BOOLEAN; VAR negate: BOOLEAN; VAR left, right: Assembler.Operand);
  1230. VAR vop1,vop2: IntermediateCode.Operand;
  1231. BEGIN
  1232. vop1 := instruction.op1; vop2 := instruction.op2;
  1233. IF ~UnsignedImmediate(vop2, part, instructionSet.ImmediateFixupBits, allowNegation, negate,right) THEN
  1234. instructionSet.InitOperand(right);
  1235. MakeRegister(vop2,part,right);
  1236. END;
  1237. ReleaseHint(right.register);
  1238. AcquireDestinationRegister(vop1,part,left);
  1239. END PrepareOp2;
  1240. PROCEDURE ReleaseDestinationRegister(VAR vop: IntermediateCode.Operand; part: LONGINT; left: Assembler.Operand);
  1241. BEGIN
  1242. IF vop.mode = IntermediateCode.ModeMemory THEN
  1243. ASSERT(left.type = InstructionSet.Register);
  1244. Store(vop,part,left);
  1245. ReleaseHint(left.register);
  1246. END;
  1247. END ReleaseDestinationRegister;
  1248. PROCEDURE FinishOp(VAR vop: IntermediateCode.Operand; part: LONGINT; dest, left: Assembler.Operand);
  1249. VAR op: Operand;
  1250. BEGIN
  1251. IF vop.mode = IntermediateCode.ModeMemory THEN
  1252. ASSERT(left.type = InstructionSet.Register);
  1253. Store(vop,part,left);
  1254. ReleaseHint(left.register);
  1255. ELSIF dest.register # left.register THEN
  1256. Emit2(opMOV, dest, left);
  1257. END;
  1258. END FinishOp;
  1259. PROCEDURE EmitAdd(VAR instruction: IntermediateCode.Instruction);
  1260. VAR destLow, destHigh, leftLow,rightLow,leftHigh,rightHigh: InstructionSet.Operand;negateLow,negateHigh: BOOLEAN;
  1261. fixup: BinaryCode.Fixup;
  1262. BEGIN
  1263. PrepareOp3(instruction,Low,TRUE,negateLow,destLow, leftLow,rightLow);
  1264. IF IsComplex(instruction.op1) THEN
  1265. PrepareOp3(instruction,High,TRUE,negateHigh,destHigh, leftHigh,rightHigh);
  1266. END;
  1267. IF negateLow THEN Emit2(opSUB,leftLow,rightLow) ELSE Emit2(opADD,leftLow,rightLow) END;
  1268. FinishOp(instruction.op1,Low,destLow, leftLow);
  1269. IF IsComplex(instruction.op1) THEN
  1270. fixup := BrForward(opBB);
  1271. (*
  1272. Emit1N(opBB, 1);
  1273. *)
  1274. Emit2N(opADD, leftHigh, 1);
  1275. SetTarget(fixup);
  1276. IF negateHigh THEN Emit2(opSUB,leftHigh,rightHigh) ELSE Emit2(opADD,leftHigh,rightHigh) END;
  1277. FinishOp(instruction.op1,High,destHigh, leftHigh);
  1278. END;
  1279. END EmitAdd;
  1280. PROCEDURE EmitFAdd(VAR instruction: IntermediateCode.Instruction);
  1281. VAR destLow, destHigh, leftLow, rightLow, leftHigh, rightHigh: Operand; negateLow, negateHigh: BOOLEAN;
  1282. BEGIN
  1283. PrepareFOp3(instruction,destLow, leftLow,rightLow);
  1284. Emit2(opFADD,leftLow,rightLow);
  1285. FinishOp(instruction.op1,Low,destLow, leftLow);
  1286. END EmitFAdd;
  1287. PROCEDURE EmitSub(VAR instruction: IntermediateCode.Instruction);
  1288. VAR destLow, destHigh, leftLow, rightLow, leftHigh, rightHigh: Operand; negateLow, negateHigh: BOOLEAN; fixup: BinaryCode.Fixup;
  1289. BEGIN
  1290. IF (instruction.op1.mode = IntermediateCode.ModeRegister) & (instruction.op1.register = IntermediateCode.SP) &
  1291. (instruction.op2.mode = IntermediateCode.ModeRegister) & (instruction.op2.register = IntermediateCode.SP) &
  1292. (instruction.op3.mode = IntermediateCode.ModeImmediate) & (instruction.op3.symbol.name = "") THEN
  1293. AllocateStack(SHORT(instruction.op3.intValue), TRUE); RETURN
  1294. END;
  1295. PrepareOp3(instruction,Low,TRUE,negateLow, destLow, leftLow,rightLow);
  1296. IF IsComplex(instruction.op1) THEN
  1297. PrepareOp3(instruction,High,TRUE,negateHigh,destHigh, leftHigh,rightHigh);
  1298. IF negateHigh THEN Emit2(opADD,leftHigh,rightHigh) ELSE Emit2(opSUB,leftHigh,rightHigh) END;
  1299. END;
  1300. IF negateLow THEN Emit2(opADD,leftLow,rightLow) ELSE Emit2(opSUB,leftLow,rightLow) END;
  1301. FinishOp(instruction.op1,Low,destLow, leftLow);
  1302. IF IsComplex(instruction.op1) THEN
  1303. fixup := BrForward(opBAE);
  1304. (*
  1305.  Emit1N(opBAE, 1);
  1306.  *)
  1307. Emit2N(opSUB,leftHigh, 1);
  1308. SetTarget(fixup);
  1309. FinishOp(instruction.op1,High,destHigh, leftHigh)
  1310. END;
  1311. END EmitSub;
  1312. PROCEDURE EmitFSub(VAR instruction: IntermediateCode.Instruction);
  1313. VAR destLow, destHigh, leftLow, rightLow, leftHigh, rightHigh: Operand; negateLow, negateHigh: BOOLEAN;
  1314. BEGIN
  1315. PrepareFOp3(instruction,destLow, leftLow,rightLow);
  1316. Emit2(opFSUB,leftLow,rightLow);
  1317. FinishOp(instruction.op1,Low,destLow, leftLow);
  1318. END EmitFSub;
  1319. PROCEDURE EmitMul(VAR instruction: IntermediateCode.Instruction);
  1320. VAR negate: BOOLEAN;
  1321. op1Low, op2Low, op3Low, op1High, op2High, op3High, destLow, destHigh: Operand;
  1322. value: HUGEINT; exp: LONGINT; iop3: IntermediateCode.Operand;
  1323. inst: IntermediateCode.Instruction;
  1324. BEGIN
  1325. IF IntermediateCode.IsConstantInteger(instruction.op3,value) & IntermediateBackend.PowerOf2(value,exp) THEN
  1326. IntermediateCode.InitImmediate(iop3, instruction.op3.type, exp);
  1327. IntermediateCode.InitInstruction(inst, Basic.invalidPosition, IntermediateCode.shl, instruction.op1, instruction.op2, iop3);
  1328. EmitShift(inst);
  1329. RETURN;
  1330. END;
  1331. IF ~IsComplex(instruction.op1) THEN
  1332. PrepareOp3(instruction,Low,FALSE,negate,destLow, op1Low,op2Low);
  1333. Emit2(opMUL,op1Low,op2Low);
  1334. FinishOp(instruction.op1,Low,destLow, op1Low)
  1335. ELSE
  1336. AcquireDestinationRegister(instruction.op1,Low,op1Low);
  1337. AcquireDestinationRegister(instruction.op1,High,op1High);
  1338. MakeRegister(instruction.op2,Low,op2Low);
  1339. MakeRegister(instruction.op2,High,op2High);
  1340. MakeRegister(instruction.op3,Low,op3Low);
  1341. MakeRegister(instruction.op3,High,op3High);
  1342. Emit2(opMOV, op1Low, op2Low);
  1343. Emit2(opMUL, op1Low, op3Low);
  1344. Emit1(opLDH, op1High);
  1345. Emit2(opMUL, op2High, op3Low);
  1346. Emit2(opADD, op1High, op2High);
  1347. Emit2(opMUL, op2Low, op3High);
  1348. Emit2(opADD, op1High, op2Low);
  1349. ReleaseDestinationRegister(instruction.op1,Low,op1Low);
  1350. ReleaseDestinationRegister(instruction.op1,High,op1High);
  1351. END;
  1352. END EmitMul;
  1353. PROCEDURE EmitFMul(VAR instruction: IntermediateCode.Instruction);
  1354. VAR destLow, destHigh, leftLow, rightLow, leftHigh, rightHigh: Operand; negateLow, negateHigh: BOOLEAN;
  1355. BEGIN
  1356. PrepareFOp3(instruction,destLow, leftLow,rightLow);
  1357. Emit2(opFMUL,leftLow,rightLow);
  1358. FinishOp(instruction.op1,Low,destLow, leftLow);
  1359. END EmitFMul;
  1360. PROCEDURE EmitDiv(CONST instruction: IntermediateCode.Instruction);
  1361. VAR
  1362. value: HUGEINT; exp: LONGINT; iop3: IntermediateCode.Operand;
  1363. inst: IntermediateCode.Instruction;
  1364. BEGIN
  1365. IF instruction.opcode = IntermediateCode.div THEN
  1366. IF IntermediateCode.IsConstantInteger(instruction.op3,value) & IntermediateBackend.PowerOf2(value,exp) THEN
  1367. IntermediateCode.InitImmediate(iop3, instruction.op3.type, exp);
  1368. IntermediateCode.InitInstruction(inst, Basic.invalidPosition, IntermediateCode.shr, instruction.op1, instruction.op2, iop3);
  1369. EmitShift(inst);
  1370. RETURN;
  1371. END;
  1372. END;
  1373. HALT(100); (*! div is not supported by hardware, must be runtime call -- cf. method Supported *)
  1374. END EmitDiv;
  1375. (* undefined for float and huegint, huegint version as library *)
  1376. PROCEDURE EmitMod(CONST instruction: IntermediateCode.Instruction);
  1377. VAR
  1378. value: HUGEINT;exp: LONGINT; op3:IntermediateCode.Operand; inst: IntermediateCode.Instruction;
  1379. BEGIN
  1380. IF IntermediateCode.IsConstantInteger(instruction.op3,value) & IntermediateBackend.PowerOf2(value,exp) THEN
  1381. IntermediateCode.InitImmediate(op3, instruction.op3.type, value-1);
  1382. IntermediateCode.InitInstruction(inst, Basic.invalidPosition, IntermediateCode.and, instruction.op1, instruction.op2, op3);
  1383. EmitAnd(inst);
  1384. RETURN;
  1385. END;
  1386. HALT(100); (*! mod is not supported by hardware, must be runtime call -- cf. method Supported *)
  1387. END EmitMod;
  1388. PROCEDURE EmitAndPart(VAR instruction: IntermediateCode.Instruction; part: LONGINT);
  1389. VAR left, right, dest: Operand; negate: BOOLEAN;
  1390. BEGIN
  1391. PrepareOp3(instruction,part,FALSE,negate,dest,left,right);
  1392. Emit2(opAND,left,right);
  1393. FinishOp(instruction.op1, part,dest, left)
  1394. END EmitAndPart;
  1395. PROCEDURE EmitAnd(VAR instruction: IntermediateCode.Instruction);
  1396. BEGIN
  1397. EmitAndPart(instruction,Low);
  1398. IF IsComplex(instruction.op1) THEN
  1399. EmitAndPart(instruction,High);
  1400. END;
  1401. END EmitAnd;
  1402. PROCEDURE EmitOr(VAR instruction: IntermediateCode.Instruction; part: LONGINT);
  1403. VAR left, right, dest: Operand; negate: BOOLEAN;
  1404. BEGIN
  1405. PrepareOp3(instruction,part,FALSE,negate,dest, left,right);
  1406. Emit2(opOR,left,right);
  1407. FinishOp(instruction.op1,part,dest, left)
  1408. END EmitOr;
  1409. PROCEDURE EmitXor(VAR instruction: IntermediateCode.Instruction; part: LONGINT);
  1410. VAR dest, left, right: Operand; negate: BOOLEAN;
  1411. BEGIN
  1412. PrepareOp3(instruction,part,FALSE,negate,dest,left,right);
  1413. Emit2(opXOR,left,right);
  1414. FinishOp(instruction.op1,part,dest,left)
  1415. END EmitXor;
  1416. PROCEDURE GetTemporaryRegister(VAR op: Operand);
  1417. VAR ticket: Ticket;
  1418. BEGIN
  1419. ticket := TemporaryTicket(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32);
  1420. TicketToOperand(ticket,op);
  1421. END GetTemporaryRegister;
  1422. PROCEDURE EmitShift(VAR instr: IntermediateCode.Instruction);
  1423. VAR op2, op3, dest, imm, one, opx, mask, opx2: Operand; shift: LONGINT; fixup, fixup2: BinaryCode.Fixup;
  1424. BEGIN
  1425. instructionSet.InitOperand(imm); instructionSet.InitOperand(one);
  1426. ASSERT(instr.op1.type.sizeInBits < 64);
  1427. AcquireDestinationRegister(instr.op1, Low, dest);
  1428. MakeRegister(instr.op2, Low, op2);
  1429. (*! caution: do not use dest and op2 / op3 more than once in one line: dest might be source (as in shl $1,1,$1) *)
  1430. IF instr.op3.mode = IntermediateCode.ModeImmediate THEN
  1431. shift := SHORT(instr.op3.intValue) MOD 32;
  1432. IF shift = 0 THEN
  1433. MovIfDifferent(dest, op2);
  1434. Emit2N(opROR, dest, shift);
  1435. ELSE
  1436. CASE instr.opcode OF
  1437. |IntermediateCode.ror:
  1438. MovIfDifferent(dest, op2);
  1439. Emit2N(opROR, dest, shift);
  1440. |IntermediateCode.rol:
  1441. MovIfDifferent(dest, op2);
  1442. Emit2N(opROR, dest, 32-shift);
  1443. |IntermediateCode.shl:
  1444. MovIfDifferent(dest, op2);
  1445. Emit2N(opROR, dest, 32-shift);
  1446. ImmediateToOperand(ASH(1, shift)-1, Low, FALSE, instructionSet.ImmediateFixupBits,imm);
  1447. Emit2(opBIC, dest, imm);
  1448. ReleaseHint(imm.register);
  1449. |IntermediateCode.shr:
  1450. IF instr.op1.type.form # IntermediateCode.SignedInteger THEN
  1451. (* logical shift right *)
  1452. ImmediateToOperand(ASH(1,shift)-1,Low,FALSE,instructionSet.ImmediateFixupBits,imm);
  1453. Emit2(opBIC, op2, imm);
  1454. MovIfDifferent(dest, op2);
  1455. Emit2N(opROR, dest, shift);
  1456. ReleaseHint(imm.register);
  1457. ELSE
  1458. (* arithmetic shift right *)
  1459. ImmediateToOperand(ASH(1,shift)-1,Low,FALSE,instructionSet.ImmediateFixupBits,imm);
  1460. MovIfDifferent(dest, op2);
  1461. Emit2(opOR,dest,dest);
  1462. fixup := BrForward(opBN);
  1463. (*
  1464. Emit1N(opBN, 2); (* if op2 < 0 then skip next two instructions *)
  1465. *)
  1466. Emit2(opBIC, dest,imm);
  1467. fixup2 := BrForward(opBT);
  1468. (*
  1469. Emit1N(opBT, 1); (* skip next instruction *)
  1470. *)
  1471. SetTarget(fixup);
  1472. Emit2(opOR, dest, imm);
  1473. SetTarget(fixup2);
  1474. Emit2N(opROR, dest, shift);
  1475. ReleaseHint(imm.register);
  1476. END;
  1477. END;
  1478. END;
  1479. ELSE
  1480. MakeRegister(instr.op3, Low, op3);
  1481. CASE instr.opcode OF
  1482. |IntermediateCode.ror:
  1483. Emit2(opROR, op2, op3);
  1484. MovIfDifferent(dest, op2);
  1485. |IntermediateCode.rol:
  1486. GetTemporaryRegister(imm);
  1487. ImmediateToOperand(32, Low, FALSE, instructionSet.ImmediateFixupBits, imm);
  1488. Emit2(opSUB, imm, op3);
  1489. Emit2(opROR, op2, imm);
  1490. MovIfDifferent(dest, op2);
  1491. ReleaseHint(imm.register);
  1492. |IntermediateCode.shl:
  1493. GetTemporaryRegister(imm);
  1494. ImmediateToOperand(32, Low, FALSE, instructionSet.ImmediateFixupBits,imm);
  1495. Emit2(opSUB, imm, op3);
  1496. Emit2(opROR, op2, imm);
  1497. IF IsSameRegister(dest, op2) THEN
  1498. GetTemporaryRegister(op2);
  1499. ELSE
  1500. Emit2(opMOV, dest, op2);
  1501. END;
  1502. (*GetTemporaryRegister(one,32);*)
  1503. ImmediateToOperand(1, Low, FALSE, instructionSet.ImmediateFixupBits, op2);
  1504. Emit2(opROR, op2, imm);
  1505. Emit2N(opSUB, op2, 1);
  1506. Emit2(opBIC, dest, op2);
  1507. ReleaseHint(imm.register);
  1508. ReleaseHint(op2.register);
  1509. |IntermediateCode.shr:
  1510. IF instr.op1.type.form # IntermediateCode.SignedInteger THEN
  1511. GetTemporaryRegister(mask);
  1512. ImmediateToOperand(1, Low, FALSE, instructionSet.ImmediateFixupBits,mask);
  1513. IF IsSameRegister(dest, op3) THEN
  1514. GetTemporaryRegister(opx);
  1515. Emit2(opMOV, opx, op3);
  1516. Emit2(opMOV, dest, op2);
  1517. op3 := opx;
  1518. ELSE
  1519. MovIfDifferent(dest, op2);
  1520. END;
  1521. IF physicalRegisters.NextFree(IntermediateCode.int32)#None THEN
  1522. GetTemporaryRegister(opx2);
  1523. ELSE
  1524. EmitPush(instr.op1,Low); (* save dest *)
  1525. opx2 := dest;
  1526. END;
  1527. Emit2N(opMOV, opx2, 32);
  1528. Emit2(opSUB, opx2, op3);
  1529. Emit2(opROR, mask, opx2);
  1530. Emit2N(opSUB, mask, 1);
  1531. IF opx2.register = dest.register THEN
  1532. EmitPop(instr.op1,Low); (* restore dest *)
  1533. ELSE
  1534. ReleaseHint(opx2.register);
  1535. END;
  1536. Emit2(opBIC, dest, mask);
  1537. Emit2(opROR, dest, op3);
  1538. ReleaseHint(opx.register);
  1539. ReleaseHint(mask.register);
  1540. ELSE
  1541. GetTemporaryRegister(imm);
  1542. ImmediateToOperand(32, Low, FALSE, instructionSet.ImmediateFixupBits, imm);
  1543. Emit2(opSUB, imm, op3);
  1544. GetTemporaryRegister(one);
  1545. ImmediateToOperand(1, Low, FALSE, instructionSet.ImmediateFixupBits, one);
  1546. Emit2(opROR, one, imm);
  1547. Emit2N(opSUB, one, 1);
  1548. Emit2(opOR, op2, op2); (* if negative *)
  1549. fixup := BrForward(opBN);
  1550. (*
  1551. Emit1N(opBN, 2); (* then skip next two instructions *)
  1552. *)
  1553. Emit2(opBIC, op2,one);
  1554. fixup2 := BrForward(opBT);
  1555. (*
  1556. Emit1N(opBT, 1); (* skip next instruction *)
  1557. *)
  1558. SetTarget(fixup);
  1559. Emit2(opOR, op2, one);
  1560. SetTarget(fixup2);
  1561. Emit2(opROR, op2, op3);
  1562. MovIfDifferent(dest, op2);
  1563. ReleaseHint(imm.register);
  1564. ReleaseHint(one.register);
  1565. END;
  1566. END;
  1567. END;
  1568. ReleaseDestinationRegister(instr.op1, Low, dest);
  1569. END EmitShift;
  1570. PROCEDURE EmitCopy(VAR instr: IntermediateCode.Instruction);
  1571. VAR op1, op2, op3: Operand; mem1, mem2: InstructionSet.Operand; reg: Operand;
  1572. prevSize, i: LONGINT; ticket: Ticket;
  1573. BEGIN
  1574. MakeRegister(instr.op1, Low, op1);
  1575. MakeRegister(instr.op2, Low, op2);
  1576. IF (instr.op3.mode = IntermediateCode.ModeImmediate) & (instr.op3.intValue < 16) THEN
  1577. GetTemporaryRegister(reg);
  1578. FOR i := 0 TO SHORT(instr.op3.intValue)-1 DO
  1579. instructionSet.InitMemory(mem1, op1.register, i);
  1580. instructionSet.InitMemory(mem2, op2.register, i);
  1581. Emit2(opLD, reg, mem2);
  1582. Emit2(opST, reg, mem1);
  1583. END;
  1584. ReleaseHint(reg.register);
  1585. ELSE
  1586. MakeRegister(instr.op3, Low, op3);
  1587. ticket := TemporaryTicket(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32);
  1588. TicketToOperand(ticket,reg);
  1589. instructionSet.InitMemory(mem1, op1.register, 0);
  1590. instructionSet.InitMemory(mem2, op2.register, 0);
  1591. prevSize := out.pc;
  1592. Emit2(opLD, reg, mem2);
  1593. Emit2(opST, reg, mem1);
  1594. Emit2N(opADD, op1, 1);
  1595. Emit2N(opADD, op2, 1);
  1596. Emit2N(opSUB, op3, 1);
  1597. Emit1N(opBGT, -(out.pc-prevSize+1));
  1598. UnmapTicket(ticket);
  1599. END;
  1600. END EmitCopy;
  1601. PROCEDURE EmitFill(VAR instr: IntermediateCode.Instruction; down: BOOLEAN);
  1602. VAR op1, op2, op3: Operand; mem1: InstructionSet.Operand;
  1603. prevSize: LONGINT; i: LONGINT; ticket: Ticket;
  1604. BEGIN
  1605. MakeRegister(instr.op1, Low, op1);
  1606. MakeRegister(instr.op2, Low, op2);
  1607. IF ~down & (instr.op3.mode = IntermediateCode.ModeImmediate) & (instr.op3.intValue < 16) THEN
  1608. FOR i := 0 TO SHORT(instr.op3.intValue)-1 DO
  1609. instructionSet.InitMemory(mem1, op1.register, i);
  1610. Emit2(opST, op2, mem1);
  1611. END;
  1612. ELSE
  1613. MakeRegister(instr.op3, Low, op3);
  1614. instructionSet.InitMemory(mem1, op1.register, 0);
  1615. prevSize := out.pc;
  1616. Emit2(opST, op2, mem1);
  1617. IF down THEN
  1618. Emit2N(opSUB, op1, 1);
  1619. ELSE
  1620. Emit2N(opADD, op1, 1);
  1621. END;
  1622. Emit2N(opSUB, op3, 1);
  1623. Emit1N(opBGT, -(out.pc-prevSize+1));
  1624. UnmapTicket(ticket);
  1625. END;
  1626. END EmitFill;
  1627. PROCEDURE BrForward(op: LONGINT): BinaryCode.Fixup;
  1628. VAR fixupOp: InstructionSet.Operand; fixup: BinaryCode.Fixup; identifier: ObjectFile.Identifier;
  1629. BEGIN
  1630. identifier.name := in.name;
  1631. identifier.fingerprint := in.fingerprint;
  1632. fixup := BinaryCode.NewFixup(BinaryCode.Relative, out.pc, identifier, 0,0,0,NIL);
  1633. fixup.resolved := in;
  1634. instructionSet.InitFixup(fixupOp,32,fixup);
  1635. Emit1(op, fixupOp);
  1636. RETURN fixup;
  1637. END BrForward;
  1638. PROCEDURE SetTarget(fixup: BinaryCode.Fixup);
  1639. BEGIN
  1640. fixup.SetSymbol(in.name, in.fingerprint, 0, out.pc+fixup.displacement (* displacement offset computed during operand emission, typically -1 *) );
  1641. fixup.resolved := in;
  1642. END SetTarget;
  1643. PROCEDURE EmitBr (VAR instr: IntermediateCode.Instruction);
  1644. VAR dest, destPC, offset: LONGINT; target: Operand; reverse: BOOLEAN;
  1645. (* jump operands *) op2, op3: Operand; hiHit, hiFail, lowHit: LONGINT;
  1646. failPC: LONGINT;
  1647. pattern: ObjectFile.FixupPatterns; fixup, failFixup: BinaryCode.Fixup;
  1648. float,negate: BOOLEAN; identifier: ObjectFile.Identifier;
  1649. PROCEDURE JmpDest(brop: LONGINT);
  1650. VAR op1: Operand; fixupOp: InstructionSet.Operand; oldLR, thisPC: Operand; ticket1, ticket2: Ticket;
  1651. BEGIN
  1652. IF instr.op1.mode = IntermediateCode.ModeImmediate THEN
  1653. Assert(instr.op1.symbol.name # "", "branch without symbol destination");
  1654. dest := (instr.op1.symbolOffset); (* this is the offset in the in-data section (intermediate code), it is not byte-relative *)
  1655. destPC := in.instructions[dest].pc + instr.op1.offset;
  1656. offset := destPC - out.pc;
  1657. fixup := BinaryCode.NewFixup(BinaryCode.Relative, out.pc, instr.op1.symbol, instr.op1.symbolOffset, instr.op1.offset,0,NIL);
  1658. IF (fixup.symbol.name = in.name) & (fixup.symbolOffset > inPC) THEN (* forward jump *)
  1659. forwardFixups.Enter(fixup, out.pc, instructionSet.RelativeBranchFixupBits);
  1660. ELSIF (fixup.symbol.name = in.name) & (fixup.symbolOffset < inPC) THEN (* backward jump *)
  1661. ASSERT(offset < 0); offset := -offset;
  1662. IF offset >= ASH(1,instructionSet.RelativeBranchFixupBits-1)-1 THEN
  1663. (*D.String("fixup too far for immediate fixup, offset=");D.Int(offset,1);D.Ln;*)
  1664. (* cannot enter fixup / use immediate jump, jump too far *)
  1665. fixup := BrForward(instructionSet.inverseCondition[brop]); (* jump over absolute branch (skip) *)
  1666. (*
  1667. fixup := BinaryCode.NewFixup(BinaryCode.Relative, out.pc, in, 0,0,0,NIL);
  1668. InstructionSet.InitFixup(fixupOp,32,fixup);
  1669. Emit1(InstructionSet.inverseCondition[brop], fixupOp); (* jump over absolute branch (skip) *)
  1670. *)
  1671. (* do a relative register jump, an absolute jump would require a fixup with unpredictable size
  1672. => have to get program counter, misuse BL here:
  1673. MOV Rx, LR
  1674. BL 0; get PC of next line
  1675. MOV Ry, LR
  1676. MOV LR, Rx ; restore LR
  1677. ADD Ry, offset
  1678. BR R2
  1679. *)
  1680. ticket1 := TemporaryTicket(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32);
  1681. ticket2 := TemporaryTicket(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32);
  1682. TicketToOperand(ticket1,oldLR);
  1683. TicketToOperand(ticket2,thisPC);
  1684. Emit2(opMOV,oldLR, opLR);
  1685. Emit1N(opBL,0);
  1686. (* exactly here we have the current PC in LR, so we compute the offset here *)
  1687. offset := out.pc-destPC;
  1688. Emit2(opMOV, thisPC, opLR);
  1689. Emit2(opMOV, opLR, oldLR);
  1690. UnmapTicket(ticket1);
  1691. instructionSet.InitOperand(target);
  1692. ImmediateToOperand(offset,Low,FALSE, instructionSet.ImmediateFixupBits,target);
  1693. Emit2(opSUB, thisPC, target);
  1694. Emit1(InstructionSet.opBR, thisPC);
  1695. ReleaseHint(target.register);
  1696. (* patch fixup for skip long jump code *)
  1697. SetTarget(fixup);
  1698. (*
  1699. fixup.SetSymbol(in, 0, out.pc+fixup.displacement (* displacement offset computed during operand emission, typically -1 *) );
  1700. *)
  1701. RETURN
  1702. END;
  1703. END;
  1704. instructionSet.InitFixup(target, 32, fixup);
  1705. (* fixup mask entered curing code emission *)
  1706. Emit1(brop, target);
  1707. ELSIF brop = opBT THEN (* register jump, unconditional *)
  1708. MakeRegister(instr.op1,Low,op1);
  1709. Emit1(opBR, op1);
  1710. ELSE
  1711. HALT(100); (* no conditional jump on register implemented *)
  1712. END;
  1713. END JmpDest;
  1714. PROCEDURE Cmp(left, right: InstructionSet.Operand);
  1715. VAR destOp: Operand; ticket: Ticket; fixup, fixup2: BinaryCode.Fixup;
  1716. BEGIN
  1717. IF float THEN
  1718. ticket := TemporaryTicket(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32);
  1719. TicketToOperand(ticket,destOp);
  1720. Emit2(opMOV, destOp, left);
  1721. Emit2(opAND, destOp, right);
  1722. fixup := BrForward(opBN);
  1723. (*
  1724. Emit1N(opBN, 3);
  1725. *)
  1726. Emit2(opMOV, destOp, left);
  1727. Emit2(opSUB, destOp, right);
  1728. fixup2 := BrForward(opBT);
  1729. SetTarget(fixup);
  1730. (* Emit1N(opBT, 2); *)
  1731. Emit2(opMOV, destOp, right);
  1732. Emit2(opSUB, destOp, left);
  1733. SetTarget(fixup2);
  1734. UnmapTicket(ticket);
  1735. ELSE
  1736. IF (left.register >= 0) & (physicalRegisters.Mapped(left.register) = NIL) THEN
  1737. IF negate THEN
  1738. Emit2(opADD, left, right);
  1739. ELSE
  1740. Emit2(opSUB, left, right);
  1741. END;
  1742. ELSE
  1743. ticket := TemporaryTicket(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32);
  1744. TicketToOperand(ticket,destOp);
  1745. Emit2(opMOV, destOp, left);
  1746. IF negate THEN
  1747. Emit2(opADD, destOp, right);
  1748. ELSE
  1749. Emit2(opSUB, destOp, right);
  1750. END;
  1751. UnmapTicket(ticket);
  1752. END;
  1753. END;
  1754. END Cmp;
  1755. BEGIN
  1756. hiFail := None; hiHit := None; lowHit := None;
  1757. float := instr.op2.type.form = IntermediateCode.Float;
  1758. failPC := 0;
  1759. IF (instr.op1.symbol.name = in.name) & (instr.op1.symbolOffset = inPC +1) THEN (* jump to next instruction can be ignored *)
  1760. IF dump # NIL THEN dump.String("jump to next instruction ignored"); dump.Ln END;
  1761. RETURN
  1762. END;
  1763. IF instr.opcode = IntermediateCode.br THEN
  1764. JmpDest(opBT);
  1765. ELSE
  1766. (*
  1767. conditional branch
  1768. for 32 bit operands quite simple
  1769. cmp left right
  1770. brc(hit) target
  1771. ...
  1772. target:
  1773. ....
  1774. for 64 bit operands transformed to
  1775. cmp hi(left) hi(right)
  1776. brc(hiHit) target
  1777. brc(hiFail) fail
  1778. cmp low(left) low(right)
  1779. brc(lowHit) target
  1780. fail:
  1781. ....
  1782. target:
  1783. .....
  1784. *)
  1785. IF instr.op2.type.sizeInBits # 64 THEN
  1786. CASE instr.opcode OF
  1787. IntermediateCode.breq:
  1788. lowHit := opBEQ;
  1789. |IntermediateCode.brne:
  1790. lowHit := opBNE;
  1791. |IntermediateCode.brge:
  1792. IF instr.op2.type.form IN {IntermediateCode.SignedInteger, IntermediateCode.Float} THEN
  1793. IF reverse THEN lowHit := opBLE ELSE lowHit := opBGE END;
  1794. ELSIF instr.op2.type.form = IntermediateCode.UnsignedInteger THEN
  1795. IF reverse THEN lowHit := opBBE ELSE lowHit := opBAE END;
  1796. END;
  1797. |IntermediateCode.brlt:
  1798. IF instr.op2.type.form IN {IntermediateCode.SignedInteger, IntermediateCode.Float} THEN
  1799. IF reverse THEN lowHit := opBGT ELSE lowHit := opBLT END;
  1800. ELSIF instr.op2.type.form = IntermediateCode.UnsignedInteger THEN
  1801. IF reverse THEN lowHit := opBA ELSE lowHit := opBB END;
  1802. END;
  1803. END;
  1804. ELSE
  1805. Assert(instr.op2.type.form # IntermediateCode.UnsignedInteger, "no unsigned integer64 branch implemented");
  1806. CASE instr.opcode OF
  1807. IntermediateCode.breq:
  1808. hiHit := None; hiFail := opBNE; lowHit := opBEQ
  1809. |IntermediateCode.brne:
  1810. hiHit := opBNE; hiFail := None; lowHit := opBNE
  1811. |IntermediateCode.brge:
  1812. IF reverse THEN
  1813. hiHit := opBLT; hiFail := opBGT; lowHit := opBBE
  1814. ELSE
  1815. hiHit := opBGT; hiFail := opBLT; lowHit := opBAE
  1816. END;
  1817. |IntermediateCode.brlt:
  1818. IF reverse THEN
  1819. hiHit := opBGT; hiFail := opBLT; lowHit := opBA
  1820. ELSE
  1821. hiHit := opBLT; hiFail := opBGT; lowHit := opBB
  1822. END;
  1823. END;
  1824. MakeRegister(instr.op2, High, op2); negate := FALSE;
  1825. IF float THEN
  1826. MakeRegister(instr.op3, High, op3)
  1827. ELSIF ~UnsignedImmediate(instr.op3, High, instructionSet.ImmediateFixupBits, TRUE, negate,op3) THEN
  1828. MakeRegister(instr.op3, High, op3)
  1829. END;
  1830. Cmp(op2, op3);
  1831. ReleaseHint(op2.register); ReleaseHint(op3.register);
  1832. float := FALSE; (* lower bits must always be compared as (unsigned) integers *)
  1833. IF hiHit # None THEN
  1834. JmpDest(hiHit);
  1835. END;
  1836. IF hiFail # None THEN
  1837. NEW(pattern,1);
  1838. pattern[0].offset := 0; pattern[0].bits := instructionSet.RelativeBranchFixupBits;
  1839. identifier.name := in.name;
  1840. identifier.fingerprint := in.fingerprint;
  1841. failFixup := BinaryCode.NewFixup(BinaryCode.Relative, out.pc, identifier, 0, 0, 0 , pattern);
  1842. failFixup.resolved := in;
  1843. instructionSet.InitImmediate(target,32,0);
  1844. instructionSet.AddFixup(target, failFixup);
  1845. Emit1(hiFail, target);
  1846. END;
  1847. (*ReleaseHint(op2.register);
  1848. ReleaseHint(op3.register);*)
  1849. END;
  1850. MakeRegister(instr.op2, Low, op2); negate := FALSE;
  1851. IF float THEN
  1852. MakeRegister(instr.op3, Low, op3)
  1853. ELSIF ~UnsignedImmediate(instr.op3, Low, instructionSet.ImmediateFixupBits, TRUE, negate,op3) THEN
  1854. MakeRegister(instr.op3, Low, op3)
  1855. END;
  1856. Cmp(op2, op3);
  1857. ReleaseHint(op2.register); ReleaseHint(op3.register);
  1858. ASSERT(lowHit # None);
  1859. JmpDest(lowHit);
  1860. IF hiFail # None THEN
  1861. failFixup.SetSymbol(in.name, in.fingerprint, 0, out.pc+failFixup.displacement (* displacement offset computed during operand emission, typically -1 *) );
  1862. failFixup.resolved := in;
  1863. END;
  1864. END;
  1865. END EmitBr;
  1866. PROCEDURE EmitPop(VAR vop: IntermediateCode.Operand; part: LONGINT);
  1867. VAR mem: InstructionSet.Operand; reg: Operand;
  1868. BEGIN
  1869. instructionSet.InitMemory(mem, InstructionSet.SP, 0);
  1870. AcquireDestinationRegister(vop, part, reg);
  1871. Emit2(opLD, reg, mem);
  1872. AllocateStack(-1, TRUE);
  1873. ReleaseDestinationRegister(vop, part, reg);
  1874. END EmitPop;
  1875. PROCEDURE EmitPush(VAR vop: IntermediateCode.Operand; part: LONGINT);
  1876. VAR mem: InstructionSet.Operand; reg: Operand; pc: LONGINT;
  1877. BEGIN
  1878. MakeRegister(vop, part, reg);
  1879. IF pushChainLength = 0 THEN (* check for chain of pushes *)
  1880. pc := inPC+1; pushChainLength := 1;
  1881. WHILE ~inEmulation & (pc < in.pc) & (in.instructions[pc].opcode = IntermediateCode.push) DO
  1882. INC(pc); INC(pushChainLength);
  1883. END;
  1884. AllocateStack(pushChainLength,TRUE);
  1885. END;
  1886. DEC(pushChainLength);
  1887. instructionSet.InitMemory(mem, InstructionSet.SP, pushChainLength);
  1888. Emit2(opST, reg, mem);
  1889. END EmitPush;
  1890. PROCEDURE EmitNeg(VAR instr: IntermediateCode.Instruction);
  1891. VAR leftLow, leftHigh, rightLow, rightHigh, reg: Operand; neg: BOOLEAN; fixup: BinaryCode.Fixup;
  1892. BEGIN
  1893. IF instr.op1.type.form IN IntermediateCode.Integer THEN
  1894. PrepareOp2(instr,Low,FALSE,neg,leftLow, rightLow);
  1895. Emit2(opNOT, leftLow, rightLow);
  1896. IF IsComplex(instr.op1) THEN
  1897. PrepareOp2(instr,High,FALSE,neg,leftHigh,rightHigh);
  1898. Emit2(opNOT, leftHigh, rightHigh);
  1899. END;
  1900. Emit2N(opADD,leftLow,1);
  1901. FinishOp(instr.op1,Low,leftLow, leftLow);
  1902. IF IsComplex(instr.op1) THEN
  1903. fixup := BrForward(opBB);
  1904. (*
  1905. Emit1N(opBB, 1);
  1906. *)
  1907. Emit2N(opADD, leftHigh, 1);
  1908. SetTarget(fixup);
  1909. FinishOp(instr.op1,High,leftHigh, leftHigh);
  1910. END;
  1911. ELSIF instr.op1.type.form = IntermediateCode.Float THEN
  1912. PrepareOp2(instr,Low,FALSE,neg,leftLow,rightLow);
  1913. IF IsComplex(instr.op1) THEN
  1914. PrepareOp2(instr,High,FALSE,neg,leftHigh,rightHigh);
  1915. END;
  1916. Emit2(opMOV,leftLow,rightLow);
  1917. IF ~IsComplex(instr.op1) THEN
  1918. reg := leftLow
  1919. ELSE ASSERT(instr.op1.type.sizeInBits=64);
  1920. Emit2(opMOV,leftHigh,rightHigh);
  1921. reg := leftHigh;
  1922. END;
  1923. Emit2N(opROR,reg,31);
  1924. Emit2N(opXOR,reg,1);
  1925. Emit2N(opROR,reg,1);
  1926. ReleaseDestinationRegister(instr.op1, Low, leftLow);
  1927. IF IsComplex(instr.op1) THEN
  1928. ReleaseDestinationRegister(instr.op1,High,leftHigh);
  1929. END;
  1930. END;
  1931. END EmitNeg;
  1932. PROCEDURE EmitNot(VAR instr: IntermediateCode.Instruction; part: LONGINT);
  1933. VAR left,right: Operand; negate: BOOLEAN;
  1934. BEGIN
  1935. PrepareOp2(instr,part,FALSE,negate,left,right);
  1936. Emit2(opNOT, left,right);
  1937. FinishOp(instr.op1,part,left,left);
  1938. END EmitNot;
  1939. PROCEDURE EmitAbs(VAR instr: IntermediateCode.Instruction);
  1940. VAR left,right: Operand; neg: BOOLEAN; fixup: BinaryCode.Fixup;
  1941. BEGIN
  1942. PrepareOp2(instr,Low,FALSE,neg,left,right);
  1943. Emit2(opMOV, left, right);
  1944. fixup := BrForward(opBNN);
  1945. (*
  1946. Emit1N(opBNN, 2);
  1947. *)
  1948. Emit2(opNOT, left,right);
  1949. Emit2N(opADD, left, 1);
  1950. SetTarget(fixup);
  1951. FinishOp(instr.op1,Low, left,left);
  1952. END EmitAbs;
  1953. PROCEDURE EmitTrap(CONST instr: IntermediateCode.Instruction);
  1954. VAR reg: Operand; reserve: Ticket;
  1955. BEGIN
  1956. instructionSet.InitRegister(reg, 0);
  1957. ImmediateToOperand(instr.op1.intValue,Low, FALSE, instructionSet.ImmediateFixupBits,reg);
  1958. IF physicalRegisters.Mapped(0)=NIL THEN
  1959. reserve := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32,0,inPC);
  1960. ELSE
  1961. reserve := NIL
  1962. END;
  1963. GetTemporaryRegister(reg);
  1964. Emit2N(opMOV, reg, HaltIRQNumber);
  1965. Emit2(opBLR, opLR, reg);
  1966. ReleaseHint(reg.register);
  1967. IF reserve # NIL THEN UnmapTicket(reserve) END;
  1968. END EmitTrap;
  1969. PROCEDURE EmitAsm(CONST instr: IntermediateCode.Instruction);
  1970. VAR reader: Streams.StringReader; procedure: SyntaxTree.Procedure; scope: SyntaxTree.Scope;
  1971. len: LONGINT; symbol: SyntaxTree.Symbol; assembler: Assembler.Assembler;
  1972. scanner: Scanner.AssemblerScanner;
  1973. BEGIN
  1974. len := Strings.Length(instr.op1.string^);
  1975. NEW(reader, len);
  1976. reader.Set(instr.op1.string^);
  1977. symbol := in.symbol;
  1978. IF (symbol = NIL) THEN
  1979. scope := NIL
  1980. ELSE
  1981. procedure := symbol(SyntaxTree.Procedure);
  1982. scope := procedure.procedureScope;
  1983. END;
  1984. NEW(assembler, diagnostics, backend.capabilities,instructionSet );
  1985. scanner := Scanner.NewAssemblerScanner(module.moduleName(*module.module.sourceName*), reader, SHORT(instr.op1.intValue), diagnostics);
  1986. scanner.useLineNumbers := Compiler.UseLineNumbers IN backend.flags;
  1987. assembler.InlineAssemble(scanner, in, scope, module);
  1988. error := error OR assembler.error
  1989. END EmitAsm;
  1990. END CodeGeneratorTRM;
  1991. System = OBJECT (Global.System)
  1992. PROCEDURE SizeOf*(type: SyntaxTree.Type): LONGINT;
  1993. BEGIN
  1994. type := type.resolved;
  1995. IF type IS SyntaxTree.BasicType THEN
  1996. IF (type.sizeInBits=64) THEN
  1997. RETURN 64
  1998. ELSE
  1999. RETURN 32
  2000. END
  2001. ELSE RETURN SizeOf^(type)
  2002. END;
  2003. END SizeOf;
  2004. END System;
  2005. BackendTRM = OBJECT (IntermediateBackend.IntermediateBackend)
  2006. VAR
  2007. cg: CodeGeneratorTRM;
  2008. patchSpartan6: BOOLEAN;
  2009. myInstructionSet: InstructionSet.InstructionSet;
  2010. recentInstructionWidth : LONGINT;
  2011. PROCEDURE &InitBackendTRM;
  2012. BEGIN
  2013. InitIntermediateBackend;
  2014. SetNewObjectFile(TRUE,TRUE);
  2015. myInstructionSet:=defaultInstructionSet;
  2016. SetHasLinkRegister;
  2017. recentInstructionWidth := Sections.UnknownSize;
  2018. SetName("TRM");
  2019. END InitBackendTRM;
  2020. PROCEDURE Initialize*(diagnostics: Diagnostics.Diagnostics; log: Streams.Writer; flags: SET; checker: SemanticChecker.Checker; system: Global.System);
  2021. VAR
  2022. BEGIN
  2023. Initialize^(diagnostics, log, flags, checker, system); (*goes up the inheritance hierarchy all the way to Backend.Mod*)
  2024. NEW(cg, builtinsModuleName, diagnostics, SELF,myInstructionSet);
  2025. cg.patchSpartan6 := patchSpartan6;
  2026. recentInstructionWidth := Sections.UnknownSize;
  2027. END Initialize;
  2028. PROCEDURE SetInstructionWidth* (instructionWidth: LONGINT); (*override*)
  2029. BEGIN
  2030. IF SELF.instructionWidth # instructionWidth THEN
  2031. SetInstructionWidth^(instructionWidth);
  2032. NEW(myInstructionSet,instructionWidth);
  2033. cg.SetInstructionSet(myInstructionSet);
  2034. END;
  2035. END SetInstructionWidth;
  2036. PROCEDURE GetSystem*(): Global.System;
  2037. VAR system: System;
  2038. BEGIN
  2039. NEW(system, 18, 32, 32, 32, 32, 32, 32, 64(* parameter offset 0: handled locally *), cooperative);
  2040. Global.SetDefaultDeclarations(system,32);
  2041. Global.SetDefaultOperators(system);
  2042. RETURN system
  2043. END GetSystem;
  2044. PROCEDURE SupportedInstruction*(CONST instruction: IntermediateCode.Instruction; VAR moduleName, procedureName: ARRAY OF CHAR): BOOLEAN;
  2045. BEGIN
  2046. RETURN cg.Supported(instruction, moduleName, procedureName);
  2047. END SupportedInstruction;
  2048. PROCEDURE SupportedImmediate*(CONST immediate: IntermediateCode.Operand): BOOLEAN;
  2049. VAR reg: InstructionSet.Operand; int: LONGINT;
  2050. BEGIN
  2051. IF immediate.type.form IN IntermediateCode.Integer THEN
  2052. IF immediate.type.sizeInBits < 64 THEN
  2053. int := LONGINT(immediate.intValue);
  2054. RETURN ((ABS(int) < ASH(1,myInstructionSet.ImmediateFixupBits)) OR (cg.GetImmediate32(int, reg, FALSE) < 3))
  2055. ELSE
  2056. RETURN (ABS(immediate.intValue) < ASH(1,myInstructionSet.ImmediateFixupBits))
  2057. END;
  2058. ELSE
  2059. RETURN FALSE
  2060. END
  2061. END SupportedImmediate;
  2062. PROCEDURE GenerateBinary(module: Sections.Module; dump: Streams.Writer);
  2063. VAR
  2064. in: Sections.Section;
  2065. out: BinaryCode.Section;
  2066. name: Basic.SectionName;
  2067. procedure: SyntaxTree.Procedure;
  2068. i, j, initialSectionCount: LONGINT;
  2069. PROCEDURE Resolve(VAR fixup: BinaryCode.Fixup);
  2070. BEGIN
  2071. IF (fixup.symbol.name #"") & (fixup.resolved = NIL) THEN
  2072. fixup.resolved := module.allSections.FindByName(fixup.symbol.name)
  2073. END;
  2074. END Resolve;
  2075. (* recompute fixup positions and assign binary sections *)
  2076. PROCEDURE PatchFixups(section: BinaryCode.Section);
  2077. VAR resolved: BinaryCode.Section; fixup: BinaryCode.Fixup; symbolOffset: LONGINT; in: IntermediateCode.Section;
  2078. BEGIN
  2079. fixup := section.fixupList.firstFixup;
  2080. WHILE fixup # NIL DO
  2081. Resolve(fixup);
  2082. IF (fixup.resolved # NIL) THEN
  2083. resolved := fixup.resolved(IntermediateCode.Section).resolved(BinaryCode.Section);
  2084. in := fixup.resolved(IntermediateCode.Section);
  2085. symbolOffset := fixup.symbolOffset;
  2086. IF (symbolOffset # 0) & (symbolOffset < in.pc) THEN
  2087. symbolOffset := in.instructions[symbolOffset].pc;
  2088. END;
  2089. fixup.SetSymbol(fixup.symbol.name, fixup.symbol.fingerprint, 0, symbolOffset+fixup.displacement);
  2090. END;
  2091. fixup := fixup.nextFixup;
  2092. END;
  2093. END PatchFixups;
  2094. BEGIN
  2095. cg.SetModule(module);
  2096. cg.dump := dump;
  2097. FOR i := 0 TO module.allSections.Length() - 1 DO
  2098. in := module.allSections.GetSection(i);
  2099. in(IntermediateCode.Section).EnableComments(trace);
  2100. IF in.type = Sections.InlineCodeSection THEN
  2101. Basic.SegmentedNameToString(in.name, name);
  2102. out := ResolvedSection(in(IntermediateCode.Section));
  2103. cg.dump := out.comments;
  2104. SetInstructionWidth(out.os.unit);
  2105. cg.Section(in(IntermediateCode.Section), out); (*compilation*)
  2106. IF in.symbol # NIL THEN
  2107. procedure := in.symbol(SyntaxTree.Procedure);
  2108. procedure.procedureScope.body.code.SetBinaryCode(out.os.bits);
  2109. END;
  2110. END
  2111. END;
  2112. initialSectionCount := 0;
  2113. REPEAT
  2114. j := initialSectionCount;
  2115. initialSectionCount := module.allSections.Length() ;
  2116. FOR i := j TO initialSectionCount - 1 DO
  2117. in := module.allSections.GetSection(i);
  2118. IF (in.type # Sections.InlineCodeSection) (*& (in(IntermediateCode.Section).resolved = NIL) *) THEN
  2119. out := ResolvedSection(in(IntermediateCode.Section));
  2120. SetInstructionWidth(out.os.unit);
  2121. cg.Section(in(IntermediateCode.Section),out);
  2122. END
  2123. END
  2124. UNTIL initialSectionCount = module.allSections.Length(); (* process remaining sections that have been added during traversal of sections *)
  2125. (*
  2126. FOR i := 0 TO module.allSections.Length() - 1 DO
  2127. in := module.allSections.GetSection(i);
  2128. IF ~in.IsExternal() THEN
  2129. IF in.type # Sections.InlineCodeSection THEN
  2130. Basic.SegmentedNameToString(in.name, name);
  2131. out := ResolvedSection(in(IntermediateCode.Section));
  2132. cg.Section(in(IntermediateCode.Section), out);
  2133. END
  2134. END;
  2135. END;
  2136. *)
  2137. FOR i := 0 TO module.allSections.Length() - 1 DO
  2138. in := module.allSections.GetSection(i);
  2139. PatchFixups(in(IntermediateCode.Section).resolved)
  2140. END;
  2141. IF cg.error THEN Error("", Basic.invalidPosition, Diagnostics.Invalid, "") END;
  2142. END GenerateBinary;
  2143. (* genasm *)
  2144. PROCEDURE ProcessIntermediateCodeModule*(intermediateCodeModule: Formats.GeneratedModule): Formats.GeneratedModule;
  2145. VAR
  2146. result: Formats.GeneratedModule;
  2147. BEGIN
  2148. ASSERT(intermediateCodeModule IS Sections.Module);
  2149. result := ProcessIntermediateCodeModule^(intermediateCodeModule);
  2150. recentInstructionWidth := Sections.UnknownSize;
  2151. IF ~error THEN
  2152. GenerateBinary(result(Sections.Module), dump);
  2153. IF dump # NIL THEN
  2154. dump.Ln; dump.Ln;
  2155. dump.String("------------------ binary code -------------------"); dump.Ln;
  2156. IF (traceString="") OR (traceString="*") THEN
  2157. result.Dump(dump);
  2158. dump.Update
  2159. ELSE
  2160. Sections.DumpFiltered(dump, result(Sections.Module), traceString);
  2161. dump.Update;
  2162. END
  2163. END;
  2164. END;
  2165. RETURN result
  2166. FINALLY
  2167. IF dump # NIL THEN
  2168. dump.Ln; dump.Ln;
  2169. dump.String("------------------ rescued code (code generation trapped) -------------------"); dump.Ln;
  2170. IF (traceString="") OR (traceString="*") THEN
  2171. result.Dump(dump);
  2172. dump.Update
  2173. ELSE
  2174. Sections.DumpFiltered(dump,result(Sections.Module),traceString);
  2175. dump.Update;
  2176. END
  2177. END;
  2178. RETURN result
  2179. END ProcessIntermediateCodeModule;
  2180. PROCEDURE DefineOptions*(options: Options.Options);
  2181. BEGIN
  2182. options.Add(0X,VectorSupportFlag,Options.Flag);
  2183. options.Add(0X,FloatingPointSupportFlag,Options.Flag);
  2184. options.Add(0X,PatchSpartan6, Options.Flag);
  2185. DefineOptions^(options);
  2186. END DefineOptions;
  2187. PROCEDURE GetOptions*(options: Options.Options);
  2188. VAR capabilities: SET;
  2189. BEGIN
  2190. capabilities := SELF.capabilities;
  2191. IF options.GetFlag(VectorSupportFlag) THEN INCL(capabilities, Global.VectorCapability) END;
  2192. IF options.GetFlag(FloatingPointSupportFlag) THEN INCL(capabilities, Global.FloatingPointCapability) END;
  2193. IF options.GetFlag(PatchSpartan6) THEN D.String("patchSpartan6=TRUE"); D.Ln; patchSpartan6 := TRUE END;
  2194. SetCapabilities(capabilities);
  2195. GetOptions^(options);
  2196. END GetOptions;
  2197. PROCEDURE DefaultObjectFileFormat*(): Formats.ObjectFileFormat;
  2198. BEGIN RETURN ObjectFileFormat.Get();
  2199. END DefaultObjectFileFormat;
  2200. PROCEDURE DefaultSymbolFileFormat*(): Formats.SymbolFileFormat;
  2201. BEGIN
  2202. RETURN NIL
  2203. END DefaultSymbolFileFormat;
  2204. PROCEDURE GetDescription*(VAR instructionSet: ARRAY OF CHAR);
  2205. BEGIN instructionSet := "TRM"
  2206. END GetDescription;
  2207. PROCEDURE FindPC*(x: SyntaxTree.Module; CONST sectionName: ARRAY OF CHAR; sectionOffset: LONGINT);
  2208. VAR
  2209. section: Sections.Section; binarySection: BinaryCode.Section; label: BinaryCode.LabelList; module: Formats.GeneratedModule;
  2210. i: LONGINT; pooledName: Basic.SegmentedName;
  2211. BEGIN
  2212. module := ProcessSyntaxTreeModule(x);
  2213. Basic.ToSegmentedName(sectionName, pooledName);
  2214. i := 0;
  2215. REPEAT
  2216. section := module(Sections.Module).allSections.GetSection(i);
  2217. INC(i);
  2218. UNTIL (i = module(Sections.Module).allSections.Length()) OR (section.name = pooledName);
  2219. IF section.name # pooledName THEN
  2220. Basic.Error(diagnostics, module.module.sourceName,Basic.invalidPosition," could not locate pc");
  2221. ELSE
  2222. binarySection := section(IntermediateCode.Section).resolved;
  2223. label := binarySection.labels;
  2224. WHILE (label # NIL) & (label.offset >= sectionOffset) DO
  2225. label := label.prev;
  2226. END;
  2227. IF label # NIL THEN
  2228. Basic.Information(diagnostics, module.module.sourceName,label.position," pc position");
  2229. ELSE
  2230. Basic.Error(diagnostics, module.module.sourceName, Basic.invalidPosition," could not locate pc");
  2231. END;
  2232. END;
  2233. END FindPC;
  2234. PROCEDURE CheckCodeAddress*(VAR adr: LONGINT);
  2235. BEGIN
  2236. IF (patchSpartan6) & (adr MOD 1024 >= 959) (* need one instruction to jump, therefore include 959 in check *) & (adr MOD 1024 <= 975) THEN
  2237. adr := (adr DIV 1024) * 1024 +976;
  2238. END;
  2239. END CheckCodeAddress;
  2240. PROCEDURE ResolvedSection(in: IntermediateCode.Section): BinaryCode.Section;
  2241. VAR section: BinaryCode.Section; unit: LONGINT;
  2242. BEGIN
  2243. (*VAR and CONST sections go to the data memory, only code sections go to code memory
  2244. Note that data memory has 32 bit words while code has standard 18.
  2245. *)
  2246. IF in.bitsPerUnit # Sections.UnknownSize THEN
  2247. unit := in.bitsPerUnit;
  2248. ELSIF in.type IN {Sections.VarSection, Sections.ConstSection} THEN
  2249. unit := 32;
  2250. ELSE
  2251. IF (recentInstructionWidth # Sections.UnknownSize) THEN
  2252. unit := recentInstructionWidth(* instructionWidth*);
  2253. ELSE
  2254. unit:=18;
  2255. END
  2256. END;
  2257. IF in.IsCode() THEN
  2258. recentInstructionWidth := unit;
  2259. END;
  2260. IF in.resolved = NIL THEN
  2261. NEW(section, in.type, unit, in.name, in.comments # NIL, FALSE);
  2262. section.SetAlignment(in.fixed, in.positionOrAlignment);
  2263. in.SetResolved(section);
  2264. ELSE
  2265. section := in.resolved
  2266. END;
  2267. RETURN section
  2268. END ResolvedSection;
  2269. END BackendTRM;
  2270. VAR
  2271. defaultInstructionSet: InstructionSet.InstructionSet;
  2272. emptyOperand: InstructionSet.Operand;
  2273. PROCEDURE Assert(b: BOOLEAN; CONST s: ARRAY OF CHAR);
  2274. BEGIN
  2275. ASSERT(b, 100);
  2276. END Assert;
  2277. PROCEDURE Halt(CONST s: ARRAY OF CHAR);
  2278. BEGIN
  2279. HALT(100);
  2280. END Halt;
  2281. PROCEDURE Init;
  2282. BEGIN
  2283. NEW(defaultInstructionSet,18); (*TODO: maybe it's better to have all these init functions outside of instruction set object?*)
  2284. defaultInstructionSet.InitOperand(emptyOperand);
  2285. END Init;
  2286. PROCEDURE Get*(): Backend.Backend;
  2287. VAR backend: BackendTRM;
  2288. BEGIN NEW(backend); RETURN backend
  2289. END Get;
  2290. BEGIN
  2291. Init;
  2292. END FoxTRMBackend.
  2293. SystemTools.FreeDownTo FoxTRMBackend ~