FoxTRMBackend.Mod 85 KB

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