FoxTRMBackend.Mod 87 KB

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