FoxTRMBackend.Mod 85 KB

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