2
0

FoxTRMBackend.Mod 87 KB

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