FoxIntermediateCode.Mod 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315
  1. MODULE FoxIntermediateCode; (** AUTHOR "fof"; PURPOSE "Oberon Compiler Abstract Intermediate Code"; *)
  2. (* Active Oberon Compiler, (c) 2009 Felix Friedrich *)
  3. IMPORT
  4. Sections := FoxSections, Basic := FoxBasic, SyntaxTree := FoxSyntaxTree, BinaryCode := FoxBinaryCode, Backend := FoxBackend,
  5. SYSTEM, Streams, Global := FoxGlobal, D := Debugging, ObjectFile;
  6. CONST
  7. (* operand modes *)
  8. Undefined*=0;
  9. ModeRegister*=1; (* register operand *)
  10. ModeMemory*=2; (* memory operand, may be memory on register or immediate *)
  11. ModeImmediate*=3; (* immediate number with type, may include section implying a fixup of the immediate *)
  12. ModeNumber*=4; (* immediate integer number without any type, typically used as meta-information for instructions *)
  13. ModeString*=5; (* for inline code *)
  14. ModeRule*=6; (* for inline code with replacements *)
  15. (* operand classes *)
  16. Undef* = {Undefined};
  17. Imm*={ModeImmediate};
  18. Reg*={ModeRegister};
  19. RegMem* = {ModeRegister,ModeMemory};
  20. RegMemImm* = {ModeRegister,ModeMemory,ModeImmediate};
  21. UndefReg*={Undefined,ModeRegister};
  22. UndefRegMem*={Undefined, ModeRegister, ModeMemory};
  23. UndefRule*= {Undefined, ModeRule};
  24. Num* = {ModeNumber};
  25. Str*= {ModeString};
  26. Any = {Undefined, ModeRegister, ModeMemory, ModeImmediate};
  27. (* operand types *)
  28. SignedInteger* = 1;
  29. UnsignedInteger* = 2;
  30. Integer*= {SignedInteger,UnsignedInteger};
  31. Float* = 3;
  32. (* instruction format flags *)
  33. SameType12*=0; (* type of first operand must match type of second operand *)
  34. SameType23*=1; (* type of second operand must match type of third operand *)
  35. Op1IsDestination*=2; (* first operand is a destination operand (=>may not be register with offset) *)
  36. Commute23*=3; (* second and third operand can be exchanged *)
  37. SameSize12*=4;
  38. (* operand sizes in bits *)
  39. Bits8*=8; Bits16*=16; Bits32*=32; Bits64*=64; Bits128*=128;
  40. (* register classes *)
  41. GeneralPurpose*=0;
  42. Parameter*=1; (* *)
  43. (* special registers *)
  44. None*=-1; (* no register assigned *)
  45. SP*=-2; (* stack pointer *)
  46. FP*=-3; (* frame pointer *)
  47. AP*=-4; (* activity pointer *)
  48. LR*=-5; (* link register *)
  49. HwRegister*=-32; (* any value below or equal hwreg is a user defined hardware register *)
  50. (* FoxProgTools.Enum -e -l=8
  51. nop mov conv call enter exit leave return result trap
  52. br breq brne brge brlt
  53. pop push neg not abs
  54. mul div mod sub add and or xor shl shr rol ror
  55. cas copy fill asm data reserve label special NofOpcodes~
  56. *)
  57. nop*= 0; mov*= 1; conv*= 2; call*= 3; enter*= 4; exit*= 5; leave*= 6; return*= 7;
  58. result*= 8; trap*= 9; br*= 10; breq*= 11; brne*= 12; brge*= 13; brlt*= 14; pop*= 15;
  59. push*= 16; neg*= 17; not*= 18; abs*= 19; mul*= 20; div*= 21; mod*= 22; sub*= 23;
  60. add*= 24; and*= 25; or*= 26; xor*= 27; shl*= 28; shr*= 29; rol*= 30; ror*= 31;
  61. cas*= 32; copy*= 33; fill*= 34; asm*= 35; data*= 36; reserve*= 37; label*= 38; special*= 39;
  62. NofOpcodes*= 40;
  63. NotYetCalculatedSize = -2;
  64. TYPE
  65. Type*=RECORD
  66. form-: SHORTINT; (* SignedInteger, UnsignedInteger or Float *)
  67. sizeInBits-: INTEGER; (* size in bits *)
  68. length-: LONGINT; (* vector length, if any. If zero then type is scalar *)
  69. END;
  70. RegisterClass*=RECORD
  71. class-: SHORTINT;
  72. number-: INTEGER;
  73. END;
  74. Rules*= POINTER TO ARRAY OF Operand;
  75. RegisterMap*= RECORD register*: LONGINT; name*: SyntaxTree.SourceCode END;
  76. BackendRules*= POINTER TO ARRAY OF RegisterMap;
  77. Operand* = RECORD
  78. mode-: SHORTINT; (* Undefined, ModeRegister, ModeImmediate, ModeMemory, ModeNumber or ModeString *)
  79. type-: Type; (* size and form *)
  80. register-: LONGINT; (* (virtual) register number, equals None if no register *)
  81. registerClass-: RegisterClass; (* normal register vs. special registers such as parameter registers *)
  82. offset-: LONGINT; (* offset on register or immediate symbol, in units *)
  83. intValue-: HUGEINT; (* integer value, if mode = ModeImmediate and type.form IN Integer or ModeNumber *)
  84. floatValue-: LONGREAL; (* real value, if mode = ModeImmediate and type.form = Float *)
  85. symbol-: ObjectFile.Identifier; (* referenced symbol, only valid for mode = ModeImmediate or mode = ModeMemory *)
  86. symbolOffset-: LONGINT; (* offset in IntermediateCode section, the difference to offset is that symbolOffset needs a resolving to real address offset *)
  87. resolved*: Sections.Section; (** only cache ! *)
  88. string-: SyntaxTree.SourceCode; (* string, if Mode = ModeString *)
  89. rule-: Rules;
  90. END;
  91. (*
  92. OperandMode Used Fields
  93. ModeRegister mode, type, register & offset
  94. ModeImmediate mode, type, intValue or floatValue or symbol & offset
  95. ModeMemory mode, type, register, offset, intValue or symbol & offset
  96. ModeNumber mode, intValue
  97. ModeString mode, string
  98. *)
  99. Instruction* = POINTER TO RECORD
  100. opcode-: SHORTINT; (* instruction opcode *)
  101. subtype-: SHORTINT; (* for special backend instruction *)
  102. textPosition-: Basic.Position; (* for error handling and tracking (findPC) *)
  103. pc-: LONGINT; (* backend program counter (in bits) for debugging and for label fixups in backend *)
  104. op1*,op2*,op3*: Operand; (* first operand typically provides the result, if any *)
  105. END;
  106. InstructionFormat* = RECORD
  107. name-: ARRAY 16 OF CHAR; (* name, for assemby and disassembly *)
  108. op1-,op2-,op3-: SET; (* permitted modes for this kind of instruction *)
  109. flags-: SET; (* more flags determining restrictions (such as operand type matching etc.) *)
  110. END;
  111. Instructions*=POINTER TO ARRAY OF Instruction;
  112. (** code object *)
  113. Section*= OBJECT (Sections.Section)
  114. VAR
  115. instructions-: Instructions; (* array of instructions *)
  116. pc-: LONGINT; (* points to next instruction = len *)
  117. finally-: LONGINT; (* finally section starts at, -1 if none *)
  118. resolved-, alias-: BinaryCode.Section; (* reference to section containing compiled byte array *) (* TODO: ret rid of that? *)
  119. aliasOffset-: LONGINT; (* for aliases *)
  120. comments-: Sections.CommentWriter;
  121. sizeInUnits: LONGINT;
  122. exported-: BOOLEAN;
  123. PROCEDURE GetPC(): LONGINT;
  124. BEGIN RETURN pc
  125. END GetPC;
  126. PROCEDURE & InitIntermediateSection*(type: SHORTINT; CONST n: Basic.SegmentedName; symbol: SyntaxTree.Symbol; comment: BOOLEAN);
  127. BEGIN
  128. InitSection(type,n,symbol); (*InitArray;*) pc := 0; resolved := NIL;
  129. IF comment THEN NEW(comments,GetPC) ELSE comments := NIL END;
  130. finally := -1;
  131. sizeInUnits := NotYetCalculatedSize;
  132. exported := FALSE;
  133. END InitIntermediateSection;
  134. PROCEDURE SetExported*(e: BOOLEAN);
  135. BEGIN
  136. exported := e
  137. END SetExported;
  138. PROCEDURE EnableComments*(enabled: BOOLEAN);
  139. BEGIN
  140. IF enabled & (comments = NIL) THEN NEW(comments, GetPC)
  141. ELSIF ~enabled THEN comments := NIL
  142. END;
  143. END EnableComments;
  144. PROCEDURE DeleteComments*;
  145. BEGIN comments := NIL
  146. END DeleteComments;
  147. PROCEDURE SetResolved*(section: BinaryCode.Section);
  148. BEGIN resolved := section
  149. END SetResolved;
  150. PROCEDURE SetAlias*(section: BinaryCode.Section; offset: LONGINT);
  151. BEGIN
  152. alias := section; aliasOffset := offset;
  153. END SetAlias;
  154. PROCEDURE SetFinally*(atPc: LONGINT);
  155. BEGIN finally := atPc
  156. END SetFinally;
  157. PROCEDURE GetSize*(): LONGINT;
  158. VAR
  159. i: LONGINT;
  160. instruction: Instruction;
  161. BEGIN
  162. IF sizeInUnits = NotYetCalculatedSize THEN
  163. sizeInUnits := Sections.UnknownSize; (* default value *)
  164. IF bitsPerUnit # Sections.UnknownSize THEN (* only calculate the size if the unit size is known *)
  165. IF (type = Sections.VarSection) OR (type = Sections.ConstSection) THEN
  166. sizeInUnits := 0;
  167. (* go through all instructions *)
  168. FOR i := 0 TO pc - 1 DO
  169. instruction := instructions[i];
  170. CASE instruction.opcode OF
  171. | data:
  172. (* TODO: correct? *)
  173. ASSERT((instruction.op1.mode = ModeImmediate) OR (instruction.op1.mode = ModeMemory));
  174. ASSERT((instruction.op1.type.sizeInBits MOD bitsPerUnit) = 0);
  175. INC(sizeInUnits, instruction.op1.type.sizeInBits DIV bitsPerUnit); (* TODO: correct conversion from bits to units? *)
  176. | reserve:
  177. ASSERT(instruction.op1.mode = ModeNumber);
  178. INC(sizeInUnits, LONGINT(instruction.op1.intValue))
  179. ELSE
  180. HALT(100); (* a var/const section may not contain any other type of instruction *)
  181. END
  182. END
  183. END
  184. END
  185. END;
  186. RETURN sizeInUnits
  187. END GetSize;
  188. PROCEDURE InitArray;
  189. CONST MinInstructions = 8;
  190. BEGIN
  191. IF instructions = NIL THEN NEW(instructions, MinInstructions); END;
  192. pc := 0;
  193. END InitArray;
  194. (* very useful for debugging:
  195. PROCEDURE Assert*(b: BOOLEAN; CONST s: ARRAY OF CHAR);
  196. BEGIN
  197. IF ~b THEN commentWriter.String("ASSERT FAILED: "); commentWriter.String(s); commentWriter.Ln END;
  198. END Assert;
  199. *)
  200. PROCEDURE Emit*(instruction: Instruction);
  201. VAR new: Instructions;
  202. op1size,op2size,op3size,op1form,op2form,op3form: LONGINT;
  203. i: SIZE;
  204. BEGIN
  205. op1size := instruction.op1.type.sizeInBits;
  206. op2size := instruction.op2.type.sizeInBits;
  207. op3size := instruction.op3.type.sizeInBits;
  208. op1form := instruction.op1.type.form;
  209. op2form := instruction.op2.type.form;
  210. op3form := instruction.op3.type.form;
  211. IF SameType12 IN instructionFormat[instruction.opcode].flags THEN
  212. Assert(TypeEquals(instruction.op1.type,instruction.op2.type),"operands 1 and 2 not of same type");
  213. END;
  214. IF SameSize12 IN instructionFormat[instruction.opcode].flags THEN
  215. Assert(instruction.op1.type.sizeInBits*instruction.op1.type.length = instruction.op2.type.sizeInBits*instruction.op2.type.length, "operands 1 and 2 not of same size");
  216. END;
  217. IF SameType23 IN instructionFormat[instruction.opcode].flags THEN
  218. Assert(TypeEquals(instruction.op2.type,instruction.op3.type),"operands 2 and 3 not of same type");
  219. END;
  220. IF Op1IsDestination IN instructionFormat[instruction.opcode].flags THEN
  221. Assert((instruction.op1.mode # ModeRegister) OR (instruction.op1.offset = 0),"destination operand may not be register with nonzero offset");
  222. END;
  223. Assert(instruction.op1.mode IN instructionFormat[instruction.opcode].op1,"invalid format of op 1");
  224. Assert(instruction.op2.mode IN instructionFormat[instruction.opcode].op2,"invalid format of op 2");
  225. Assert(instruction.op3.mode IN instructionFormat[instruction.opcode].op3,"invalid format of op 3");
  226. Assert(instruction.op1.symbol.name[0] # 0, "not intialized operand 1");
  227. Assert(instruction.op2.symbol.name[0] # 0, "not intialized operand 2");
  228. Assert(instruction.op3.symbol.name[0] # 0, "not intialized operand 3");
  229. IF (instructions = NIL) THEN
  230. NEW(instructions, 16);
  231. ELSIF pc = LEN(instructions) THEN
  232. NEW(new,4*LEN(instructions));
  233. FOR i := 0 TO LEN(instructions)-1 DO
  234. new[i] := instructions[i];
  235. END;
  236. instructions := new;
  237. END;
  238. instruction.pc := pc;
  239. instructions[pc] := instruction;
  240. INC(pc);
  241. sizeInUnits := NotYetCalculatedSize;
  242. END Emit;
  243. PROCEDURE EmitAt*(at: LONGINT; instruction: Instruction);
  244. VAR oldpc: LONGINT;
  245. BEGIN
  246. oldpc := pc;
  247. pc := at; Assert(pc < LEN(instructions),"EmitAt only in existing code");
  248. Emit(instruction);
  249. pc := oldpc;
  250. END EmitAt;
  251. PROCEDURE Reset*;
  252. BEGIN
  253. sizeInUnits := NotYetCalculatedSize;
  254. pc := 0;
  255. END Reset;
  256. PROCEDURE PatchOperands*(pc: LONGINT; op1,op2,op3: Operand);
  257. BEGIN instructions[pc].op1 := op1; instructions[pc].op2 := op2; instructions[pc].op3 := op3;
  258. END PatchOperands;
  259. PROCEDURE PatchAddress*(pc: LONGINT; symbolOffset: LONGINT);
  260. BEGIN
  261. ASSERT((br <= instructions[pc].opcode) & (instructions[pc].opcode <= brlt));
  262. ASSERT(instructions[pc].op1.symbol.name = SELF.name);
  263. (*
  264. ASSERT(instr[pc].op1.symbol = SELF);
  265. *)
  266. instructions[pc].op1.symbolOffset := symbolOffset;
  267. END PatchAddress;
  268. PROCEDURE SetPC*(at: LONGINT; pc: LONGINT);
  269. BEGIN instructions[at].pc := pc;
  270. END SetPC;
  271. PROCEDURE DumpCode*(w: Streams.Writer; from,to: LONGINT);
  272. VAR
  273. i: LONGINT;
  274. c: Sections.Comment;
  275. BEGIN
  276. IF comments # NIL THEN
  277. c := comments.firstComment;
  278. WHILE(c # NIL) & (c.pos <from) DO
  279. c := c.nextComment;
  280. END;
  281. i := from;
  282. WHILE(i<=to) DO
  283. IF (c # NIL) & (c.pos = i) THEN
  284. c.Dump(w); w.Ln;
  285. c := c.nextComment;
  286. END;
  287. w.Int(i,2); w.String(": ");
  288. DumpInstruction(w,instructions[i]);
  289. w.Ln;
  290. INC(i);
  291. END;
  292. IF (c#NIL) & (c.pos = to) THEN
  293. c.Dump(w); w.Ln;
  294. END;
  295. ELSE
  296. i := from;
  297. WHILE(i<=to) DO
  298. w.Int(i,2); w.String(": ");
  299. DumpInstruction(w,instructions[i]); w.Ln;
  300. INC(i);
  301. END;
  302. END;
  303. END DumpCode;
  304. (* inherited method *)
  305. PROCEDURE Dump*(w: Streams.Writer);
  306. VAR ww: Basic.Writer;
  307. BEGIN
  308. IF resolved # NIL THEN
  309. Dump^(w);
  310. resolved.Dump(w)
  311. ELSE
  312. Dump^(w);
  313. ww := Basic.GetWriter(w);
  314. ww.IncIndent;
  315. ww.Ln;
  316. DumpCode(ww,0,pc-1);
  317. ww.DecIndent;
  318. END;
  319. END Dump;
  320. PROCEDURE WriteRaw*(w: Streams.Writer);
  321. VAR i: LONGINT;
  322. BEGIN
  323. FOR i := 0 TO pc-1 DO
  324. w.Int(i,2); w.String(": ");
  325. WriteRawInstruction(w,instructions[i]); w.Ln;
  326. INC(i);
  327. END;
  328. END WriteRaw;
  329. END Section;
  330. IntermediateBackend*= OBJECT (Backend.Backend)
  331. VAR
  332. builtinsModuleName-: SyntaxTree.IdentifierString;
  333. PROCEDURE SupportedInstruction*(CONST instr: Instruction; VAR moduleName,procedureName: ARRAY OF CHAR): BOOLEAN;
  334. BEGIN
  335. moduleName := ""; procedureName := "";
  336. RETURN TRUE
  337. END SupportedInstruction;
  338. PROCEDURE SetBuiltinsModuleName*(CONST name: ARRAY OF CHAR);
  339. BEGIN
  340. COPY(name, builtinsModuleName);
  341. END SetBuiltinsModuleName;
  342. END IntermediateBackend;
  343. VAR
  344. instructionFormat-: ARRAY NofOpcodes OF InstructionFormat;
  345. int8-, int16-, int32-, int64-, uint8-, uint16-, uint32-, uint64-, float32-, float64-, undef-: Type;
  346. GeneralPurposeRegister-: RegisterClass;
  347. empty: Operand;
  348. PROCEDURE Assert(condition: BOOLEAN; CONST reason: ARRAY OF CHAR);
  349. BEGIN (*ASSERT(condition);*) IF ~condition THEN D.TraceBack END;
  350. END Assert;
  351. (** create a new section in a given section list
  352. - if the section already exists, reuse the existing section
  353. note: for compatibility with the old binary object file format, const sections can also be referred to as var sections
  354. **)
  355. PROCEDURE NewSection*(list: Sections.SectionList; type: SHORTINT; CONST name: Basic.SegmentedName; syntaxTreeSymbol: SyntaxTree.Symbol; dump: BOOLEAN): Section;
  356. VAR
  357. t0: SHORTINT;
  358. result: Sections.Section;
  359. section: Section;
  360. BEGIN
  361. ASSERT(name[0] > 0); (* must be initialized *)
  362. IF syntaxTreeSymbol # NIL THEN
  363. result := list.FindBySymbol(syntaxTreeSymbol);
  364. END;
  365. (* search by name *)
  366. IF result = NIL THEN
  367. result := list.FindByName(name);
  368. END;
  369. IF result # NIL THEN
  370. section := result(Section);
  371. (*
  372. t0 := result.type;
  373. IF t0 # type THEN
  374. D.String("section entered twice: "); Basic.WriteSegmentedName(D.Log, name);
  375. D.String(" type "); D.Int(t0,1); D.String(" --> "); D.Int(type,1); D.Ln
  376. END;
  377. *)
  378. ASSERT(result.name= name);
  379. (*ASSERT(result.symbol = syntaxTreeSymbol);*)
  380. RETURN section
  381. END;
  382. (* a valid name must be present *)
  383. ASSERT(name[0] > 0);
  384. (* create a new section and enter it *)
  385. NEW(section, type, name, syntaxTreeSymbol, dump);
  386. IF syntaxTreeSymbol # NIL THEN section.SetFingerprint(syntaxTreeSymbol.fingerprint.public) END;
  387. list.AddSection(section);
  388. RETURN section
  389. END NewSection;
  390. PROCEDURE SameOperand*(CONST left, right: Operand): BOOLEAN;
  391. VAR mode: LONGINT;
  392. BEGIN
  393. mode := left.mode;
  394. IF (left.type.form =right.type.form) & (left.type.sizeInBits=right.type.sizeInBits) & (left.type.length = right.type.length) & (mode = right.mode) THEN
  395. CASE mode OF
  396. ModeRegister: RETURN (left.register = right.register) & (left.offset = right.offset)
  397. |ModeMemory: RETURN (left.register = right.register) &(left.offset = right.offset) & (left.symbol = right.symbol) & (left.symbolOffset = right.symbolOffset);
  398. |ModeImmediate:
  399. IF left.type.form = Float THEN
  400. RETURN (left.floatValue = right.floatValue) & (left.symbol = right.symbol) & (left.symbolOffset = right.symbolOffset)
  401. ELSE
  402. RETURN (left.intValue = right.intValue) & (left.symbol = right.symbol) & (left.symbolOffset = right.symbolOffset)
  403. END;
  404. |ModeNumber:
  405. RETURN left.intValue = right.intValue
  406. |ModeString:
  407. RETURN left.string = right.string
  408. |Undefined: (* nothing *) RETURN TRUE
  409. END;
  410. ELSE RETURN FALSE
  411. END;
  412. END SameOperand;
  413. (** check if an operand is valid at a certain location for a given instruction opcode **)
  414. PROCEDURE CheckOperand*(operand: Operand; opCode, location: LONGINT; VAR message: ARRAY OF CHAR): BOOLEAN;
  415. VAR
  416. validOperandModes: SET;
  417. BEGIN
  418. validOperandModes := {};
  419. CASE location OF
  420. | 0: validOperandModes := instructionFormat[opCode].op1
  421. | 1: validOperandModes := instructionFormat[opCode].op2
  422. | 2: validOperandModes := instructionFormat[opCode].op3
  423. END;
  424. IF ~(operand.mode IN validOperandModes) THEN
  425. message := "operand mode mismatch"; RETURN FALSE
  426. END;
  427. (* the following code was taken from the previous version of 'PROCEDURE CheckOperand' and adapted: *)
  428. CASE operand.mode OF
  429. | Undefined:
  430. | ModeNumber:
  431. | ModeMemory:
  432. IF operand.type.form = Undefined THEN message := "memory type form undefined"; RETURN FALSE END;
  433. IF operand.type.sizeInBits = 0 THEN message :="memory type size undefined"; RETURN FALSE END;
  434. IF operand.register # None THEN
  435. IF operand.symbol.name # "" THEN message :="symbol and register cannot be both set in a memory operand"; RETURN FALSE END
  436. ELSIF operand.symbol.name # "" THEN
  437. IF operand.intValue # 0 THEN message :="memory operand on non zero immediate with symbol # NIL"; RETURN FALSE END
  438. (*ELSE
  439. IF operand.intValue = 0 THEN message :="memory operand on address 0 zero without register and symbol"; RETURN FALSE END
  440. *)
  441. END
  442. | ModeRegister:
  443. IF operand.type.form = Undefined THEN message :="register type form undefined"; RETURN FALSE END;
  444. IF operand.type.sizeInBits = 0 THEN message :="register type size undefined"; RETURN FALSE END;
  445. IF operand.register = None THEN message :="register undefined in register operand"; RETURN FALSE END
  446. | ModeImmediate:
  447. IF operand.symbol.name # "" THEN
  448. IF operand.intValue # 0 THEN message :="forbidden immediate with symbol and intValue # 0"; RETURN FALSE END;
  449. IF operand.floatValue # 0 THEN message :="forbidden immediate with symbol and floatValue # 0"; RETURN FALSE END
  450. END
  451. | ModeString:
  452. IF operand.string = NIL THEN message :="nil string in string operand"; RETURN FALSE END
  453. END;
  454. RETURN TRUE
  455. END CheckOperand;
  456. (** check if an instruction is valid **)
  457. PROCEDURE CheckInstruction*(instruction: Instruction; VAR message: ARRAY OF CHAR): BOOLEAN;
  458. BEGIN
  459. IF (SameType12 IN instructionFormat[instruction.opcode].flags) & ~TypeEquals(instruction.op1.type, instruction.op2.type) THEN
  460. message := "operands 1 and 2 not of same type";
  461. RETURN FALSE
  462. END;
  463. IF (SameSize12 IN instructionFormat[instruction.opcode].flags) & (instruction.op1.type.sizeInBits # instruction.op2.type.sizeInBits) THEN
  464. message := "operands 1 and 2 not of same size";
  465. RETURN FALSE
  466. END;
  467. IF (SameType23 IN instructionFormat[instruction.opcode].flags) & ~TypeEquals(instruction.op2.type, instruction.op3.type) THEN
  468. message := "operands 2 and 3 not of same type";
  469. RETURN FALSE
  470. END;
  471. IF (Op1IsDestination IN instructionFormat[instruction.opcode].flags) & (instruction.op1.mode = ModeRegister) & (instruction.op1.offset # 0) THEN
  472. message := "destination operand may not be register with nonzero offset";
  473. RETURN FALSE
  474. END;
  475. RETURN TRUE
  476. END CheckInstruction;
  477. PROCEDURE DumpRegister*(w: Streams.Writer; registerNumber: LONGINT; CONST registerClass: RegisterClass);
  478. BEGIN
  479. IF registerNumber = SP THEN
  480. w.String("sp")
  481. ELSIF registerNumber = FP THEN
  482. w.String("fp")
  483. ELSIF registerNumber = AP THEN
  484. w.String("ap")
  485. ELSIF registerNumber = LR THEN
  486. w.String("lr")
  487. ELSIF registerNumber > None THEN
  488. w.String("r"); w.Int(registerNumber, 0);
  489. IF registerClass.class = Parameter THEN w.String(":p"); w.Int(registerClass.number,0) END;
  490. ELSIF registerNumber <= HwRegister THEN
  491. w.String("h"); w.Int(HwRegister - registerNumber, 0)
  492. ELSE
  493. w.String("(invalid register)")
  494. END
  495. END DumpRegister;
  496. PROCEDURE DumpType*(w: Streams.Writer; type: Type);
  497. BEGIN
  498. IF type.length > 1 THEN
  499. w.String("v"); w.Int(type.length,0);
  500. END;
  501. CASE type.form OF
  502. | Undefined: w.String("(invalid type)")
  503. | UnsignedInteger: w.String("u"); w.Int(type.sizeInBits, 0)
  504. | SignedInteger: w.String("s"); w.Int(type.sizeInBits, 0)
  505. | Float: w.String("f"); w.Int(type.sizeInBits, 0)
  506. END
  507. END DumpType;
  508. PROCEDURE DumpOperand*(w: Streams.Writer; CONST operand: Operand );
  509. VAR i: LONGINT;
  510. PROCEDURE DumpString(CONST str: ARRAY OF CHAR);
  511. VAR
  512. i: LONGINT;
  513. ch: CHAR;
  514. newln: BOOLEAN;
  515. BEGIN
  516. w.String('"');
  517. i := 0;
  518. ch := str[i];
  519. WHILE ch # 0X DO
  520. IF (ch = 0DX) OR (ch = 0AX) THEN
  521. newln := TRUE
  522. ELSE
  523. IF newln THEN
  524. w.Ln;
  525. newln := FALSE;
  526. END;
  527. IF (ch = '"') OR (ch = '\') THEN
  528. w.Char( '\' );
  529. w.Char(ch);
  530. ELSE
  531. w.Char(ch);
  532. END
  533. END;
  534. INC(i);
  535. ch := str[i];
  536. END;
  537. w.String('"');
  538. END DumpString;
  539. BEGIN
  540. IF operand.type.form # Undefined THEN
  541. DumpType(w,operand.type); w.String(" ");
  542. END;
  543. CASE operand.mode OF
  544. Undefined: w.String("!Undefined");
  545. |ModeMemory:
  546. w.String("[");
  547. IF operand.register # None THEN
  548. DumpRegister(w,operand.register, operand.registerClass);
  549. IF operand.offset > 0 THEN w.String("+"); w.Int(operand.offset,1);
  550. ELSIF operand.offset < 0 THEN w.String("-"); w.Int(-operand.offset,1);
  551. END;
  552. ELSIF operand.symbol.name # "" THEN
  553. Basic.WriteSegmentedName(w,operand.symbol.name);
  554. IF operand.symbol.fingerprint # 0 THEN w.String("["); w.Hex(operand.symbol.fingerprint,-8); w.String("]"); END;
  555. w.String(":"); w.Int(operand.symbolOffset,1);
  556. IF operand.offset > 0 THEN w.String("+"); w.Int(operand.offset, 1);
  557. ELSIF operand.offset < 0 THEN w.String("-"); w.Int(-operand.offset, 1);
  558. END;
  559. ELSE w.Int(SHORT(operand.intValue),1);
  560. END;
  561. w.String("]");
  562. |ModeRegister:
  563. DumpRegister(w,operand.register, operand.registerClass);
  564. IF operand.offset > 0 THEN w.String("+"); w.Int(operand.offset,1);
  565. ELSIF operand.offset < 0 THEN w.String("-"); w.Int(-operand.offset,1);
  566. END;
  567. |ModeImmediate:
  568. IF operand.symbol.name # "" THEN
  569. Basic.WriteSegmentedName(w,operand.symbol.name);
  570. IF operand.symbol.fingerprint # 0 THEN w.String("["); w.Hex(operand.symbol.fingerprint,-8); w.String("]"); END;
  571. w.String(":"); w.Int(operand.symbolOffset,1);
  572. IF operand.offset > 0 THEN w.String("+"); w.Int(operand.offset, 1);
  573. ELSIF operand.offset < 0 THEN w.String("-"); w.Int(-operand.offset, 1);
  574. END
  575. ELSE
  576. IF operand.type.form IN Integer THEN
  577. IF (operand.intValue > MAX(LONGINT)) OR (operand.intValue < MIN(LONGINT)) THEN
  578. w.String("0");
  579. w.Hex(operand.intValue,0);
  580. w.String("H");
  581. ELSE
  582. w.Int(SHORT(operand.intValue),1);
  583. END
  584. ELSE
  585. w.Float(operand.floatValue,24);
  586. END;
  587. END;
  588. |ModeString:
  589. DumpString(operand.string^);
  590. |ModeNumber: w.Int(SHORT(operand.intValue),1);
  591. |ModeRule:
  592. w.String("rules");
  593. FOR i := 0 TO LEN(operand.rule)-1 DO
  594. w.String(" "); DumpOperand(w,operand.rule[i]); w.String(" = "); DumpString(operand.rule[i].string^);
  595. END;
  596. END;
  597. (*
  598. w.Update();
  599. CheckOperand(operand);
  600. *)
  601. END DumpOperand;
  602. PROCEDURE WriteRawOperand*(w: Streams.Writer; CONST operand: Operand );
  603. VAR i: LONGINT;
  604. BEGIN
  605. w.RawLInt(operand.type.form);
  606. w.RawLInt(operand.type.sizeInBits);
  607. w.RawLInt(operand.type.length);
  608. CASE operand.mode OF
  609. Undefined:
  610. |ModeMemory:
  611. IF operand.register # None THEN
  612. w.RawLInt(operand.register);
  613. w.RawSInt(operand.registerClass.class);
  614. w.RawInt(operand.registerClass.number);
  615. w.RawLInt(operand.offset);
  616. ELSIF operand.symbol.name # "" THEN
  617. Basic.WriteSegmentedName(w,operand.symbol.name);
  618. IF operand.symbol.fingerprint # 0 THEN w.RawLInt(operand.symbol.fingerprint);END;
  619. w.RawLInt(operand.symbolOffset);
  620. w.RawLInt(operand.offset);
  621. ELSE w.RawLInt(SHORT(operand.intValue));
  622. END;
  623. |ModeRegister:
  624. w.RawLInt(operand.register);
  625. w.RawSInt(operand.registerClass.class);
  626. w.RawInt(operand.registerClass.number);
  627. w.RawLInt(operand.offset);
  628. |ModeImmediate:
  629. IF operand.symbol.name # "" THEN
  630. Basic.WriteSegmentedName(w,operand.symbol.name);
  631. IF operand.symbol.fingerprint # 0 THEN w.RawLInt(operand.symbol.fingerprint);END;
  632. w.RawLInt(operand.symbolOffset);
  633. w.RawLInt(operand.offset);
  634. ELSE
  635. IF operand.type.form IN Integer THEN
  636. w.RawLInt(SHORT(operand.intValue));
  637. ELSE
  638. w.RawLReal(operand.floatValue);
  639. END;
  640. END;
  641. |ModeString:
  642. w.RawString(operand.string^);
  643. |ModeNumber: w.RawLInt(SHORT(operand.intValue));
  644. |ModeRule:
  645. FOR i := 0 TO LEN(operand.rule)-1 DO
  646. WriteRawOperand(w,operand.rule[i]); w.RawString(operand.rule[i].string^);
  647. END;
  648. END;
  649. END WriteRawOperand;
  650. PROCEDURE TypeEquals*(CONST s1,s2: Type): BOOLEAN;
  651. BEGIN RETURN (s1.form = s2.form) & (s1.sizeInBits = s2.sizeInBits) & (s1.length = s2.length);
  652. END TypeEquals;
  653. PROCEDURE OperandEquals*(CONST s1,s2: Operand) : BOOLEAN;
  654. BEGIN
  655. RETURN (s1.mode = s2.mode) & (s1.register = s2.register) & (s1.offset = s2.offset) & (s1.intValue = s2.intValue) & (s1.floatValue = s2.floatValue)
  656. & (s1.symbol.name = s2.symbol.name) & (s1.string = s2.string) & (s1.symbolOffset = s2.symbolOffset) & TypeEquals(s1.type,s2.type);
  657. END OperandEquals;
  658. PROCEDURE Equals*(CONST i1, i2: Instruction):BOOLEAN;
  659. BEGIN
  660. IF i1.opcode # i2.opcode THEN RETURN FALSE END;
  661. IF i1.subtype # i2.subtype THEN RETURN FALSE END;
  662. IF i1.pc # i2.pc THEN RETURN FALSE END;
  663. IF ~OperandEquals(i1.op1, i2.op1) THEN RETURN FALSE END;
  664. IF ~OperandEquals(i1.op2, i2.op2) THEN RETURN FALSE END;
  665. IF ~OperandEquals(i1.op3, i2.op3) THEN RETURN FALSE END;
  666. RETURN TRUE
  667. END Equals;
  668. PROCEDURE WriteRawInstruction*(w: Streams.Writer; CONST instr: Instruction);
  669. BEGIN
  670. w.RawLInt(instr.opcode);
  671. IF instr.op1.mode # Undefined THEN WriteRawOperand(w,instr.op1) END;
  672. IF instr.op2.mode # Undefined THEN WriteRawOperand(w,instr.op2) END;
  673. IF instr.op3.mode # Undefined THEN WriteRawOperand(w,instr.op3) END;
  674. IF instr.opcode = special THEN w.RawLInt(instr.subtype) END;
  675. END WriteRawInstruction;
  676. PROCEDURE DumpInstruction*(w: Streams.Writer; CONST instr: Instruction);
  677. BEGIN
  678. w.String(instructionFormat[instr.opcode].name);
  679. IF instr.op1.mode # Undefined THEN w.String(" "); DumpOperand(w,instr.op1) END;
  680. IF instr.op2.mode # Undefined THEN w.String(", "); DumpOperand(w,instr.op2) END;
  681. IF instr.op3.mode # Undefined THEN w.String(", "); DumpOperand(w,instr.op3) END;
  682. IF instr.opcode = special THEN w.String(" sub "); w.Int(instr.subtype,1) END;
  683. END DumpInstruction;
  684. PROCEDURE InitInstructions;
  685. PROCEDURE AddFormat(opcode: SHORTINT; CONST name: ARRAY OF CHAR; op1,op2,op3: SET; flags: SET);
  686. BEGIN
  687. COPY(name,instructionFormat[opcode].name);
  688. instructionFormat[opcode].op1 := op1;
  689. instructionFormat[opcode].op2 := op2;
  690. instructionFormat[opcode].op3 := op3;
  691. instructionFormat[opcode].flags := flags
  692. END AddFormat;
  693. BEGIN
  694. (* nop - no operation, may be used for optimisations *)
  695. AddFormat(nop, "nop", Undef, Undef, Undef, {});
  696. (* mov dest src - mov content of src to dest, if a third parameter is provided (set to a register),
  697. it has no meaning for interpreters or execution but provides a "reuse" hint for register allocators *)
  698. AddFormat(mov, "mov", RegMem, RegMemImm, UndefReg, {SameSize12,Op1IsDestination});
  699. (* conv dest src - convert src to dest, type of conversion derived from type of operands *)
  700. AddFormat(conv, "conv", RegMem, RegMemImm, Undef, {Op1IsDestination});
  701. (* call adr parSize - procedure call, second operand contains parameter size *)
  702. AddFormat(call, "call", RegMemImm, Num, Undef,{});
  703. (* enter cc pafSize - set up procedure activation frame; op1 = calling convention, op2 = size to be allocated on stack *)
  704. AddFormat(enter, "enter", Num, Num, Undef ,{});
  705. (* leave cc - remove paf, does not imply return, op1= calling convention, does not imply exit from procedure *)
  706. AddFormat(leave, "leave", Num, Undef, Undef ,{});
  707. (* return value : return value, op1= returned value, if any, does not imply exit from procedure *)
  708. AddFormat(return,"return",RegMemImm, Undef, Undef,{});
  709. (* exit parSize pcOffset cc - exit from procedure, op1 = offset that has to be subtracted from return address (e.g., used for ARM interrupt procedures), op2 = calling convention, op3 = stack offset for calller cleanup calling convention *)
  710. AddFormat(exit, "exit", Num, Num, Num,{});
  711. (* result, store result to operand op1 *)
  712. AddFormat(result,"result",RegMem,Undef,Undef,{Op1IsDestination});
  713. (* trap num- interrupt*)
  714. AddFormat(trap, "trap", Num, Undef, Undef,{});
  715. (* br op1 - unconditional branch to op1 *)
  716. AddFormat(br, "br", RegMemImm, Undef, Undef,{});
  717. (* breq op1 op2 op3- branch to op1 if op2 = op3 *)
  718. AddFormat(breq, "breq", RegMemImm, RegMemImm, RegMemImm, {SameType23});
  719. (* brne op1 op2 op3 - branch to op2 if op2 # op3 *)
  720. AddFormat(brne, "brne", RegMemImm, RegMemImm, RegMemImm, {SameType23});
  721. (* brlt op1 op2 op3 - branch to op1 if op2 < op3 , information about sign is derived from operands *)
  722. AddFormat(brlt, "brlt", RegMemImm, RegMemImm, RegMemImm, {SameType23}); (* sign of comparison is derived from types of op1 and op2 *)
  723. (* brge op1 op2 op3 - branch to op1 if op2 >= op3 , information about sign is derived from operands *)
  724. AddFormat(brge, "brge", RegMemImm, RegMemImm, RegMemImm, {SameType23});
  725. (* pop op1 - pop op1 from stack *)
  726. AddFormat(pop, "pop", RegMem, Undef, Undef,{Op1IsDestination});
  727. (* push op1 - push op1 to stack *)
  728. AddFormat(push, "push", RegMemImm, Undef, Undef,{});
  729. (* not dest src - invert bit mask *)
  730. AddFormat(not, "not", RegMem, RegMemImm, Undef,{SameType12,Op1IsDestination});
  731. (* neg dest src - negate (arithmetic) *)
  732. AddFormat(neg, "neg", RegMem, RegMemImm, Undef,{SameType12,Op1IsDestination});
  733. (* abs dest src - absolute value (arithmetic) *)
  734. AddFormat(abs, "abs", RegMem, RegMemImm, Undef,{SameType12,Op1IsDestination});
  735. (* mul dest left right - multiply, information about sign and form (integer/float) in operands *)
  736. AddFormat(mul, "mul", RegMem, RegMemImm, RegMemImm,{SameType12,SameType23,Op1IsDestination,Commute23});
  737. (* div dest left right - divide, information about sign and form (integer/float) in operands *)
  738. AddFormat(div, "div", RegMem, RegMemImm, RegMemImm,{SameType12,SameType23,Op1IsDestination});
  739. (* mod dest left right - modulus, information about sign and form (integer/float) in operands *)
  740. AddFormat(mod, "mod", RegMem, RegMemImm, RegMemImm,{SameType12,SameType23,Op1IsDestination});
  741. (* sub dest left right - subtract, information about sign and form (integer/float) in operands *)
  742. AddFormat(sub, "sub", RegMem, RegMemImm, RegMemImm,{SameType12,SameType23,Op1IsDestination});
  743. (* add dest left right - add, information about sign and form (integer/float) in operands *)
  744. AddFormat(add, "add", RegMem, RegMemImm, RegMemImm,{SameType12,SameType23,Op1IsDestination,Commute23});
  745. (* and dest left right - bitwise and *)
  746. AddFormat(and, "and", RegMem, RegMemImm, RegMemImm,{SameType12,SameType23,Op1IsDestination,Commute23});
  747. (* or dest left right - bitwise or *)
  748. AddFormat(or, "or", RegMem, RegMemImm, RegMemImm,{SameType12,SameType23,Op1IsDestination,Commute23});
  749. (* xor dest left right - bitwise xor *)
  750. AddFormat(xor, "xor", RegMem, RegMemImm, RegMemImm,{SameType12,SameType23,Op1IsDestination,Commute23});
  751. (* shl dest left right - shift left (arithmetic or logical, derived from sign of operands) *)
  752. AddFormat(shl, "shl", RegMem, RegMemImm, RegMemImm,{SameType12,Op1IsDestination}); (* logical or arithemtic shift, derived from type of operands *)
  753. (* shr dest left right - shift right (arithmetic or logical, derived from sign of operands)*)
  754. AddFormat(shr, "shr", RegMem, RegMemImm, RegMemImm,{SameType12,Op1IsDestination});
  755. (* rol dest left right - rotate left *)
  756. AddFormat(rol, "rol", RegMem, RegMemImm, RegMemImm,{SameType12,Op1IsDestination});
  757. (* ror dest left right - rotate right *)
  758. AddFormat(ror, "ror", RegMem, RegMemImm, RegMemImm,{SameType12,Op1IsDestination});
  759. (* cas dest old new - compare value at dest with old and store new if equal, previous value in result register *)
  760. AddFormat(cas, "cas", RegMemImm, RegMemImm, RegMemImm,{SameType23});
  761. (* copy dest src size - move a block of size op3 units of memory from [op2] to [op1] *)
  762. AddFormat(copy, "copy", RegMemImm, RegMemImm, RegMemImm,{SameType12,SameType23});
  763. (* fill dest val size - fill a block of size op2 units of memory from [op1] with value in op3 *)
  764. AddFormat(fill, "fill", RegMemImm, RegMemImm, RegMemImm,{SameType12});
  765. (* asm attribute - asm code contained in attribute *)
  766. AddFormat(asm, "asm", Str, UndefRule, UndefRule,{});
  767. (* data imm - instruction to build up constants or (global) variables *)
  768. AddFormat(data, "data", Imm, Undef, Undef,{});
  769. (* reserve number - instruction to build (global) variables *)
  770. AddFormat(reserve, "reserve",Num,Undef,Undef,{});
  771. (* label - pseudo-instruction to reference back to source code positions *)
  772. AddFormat(label, "label",Num,Undef,Undef,{});
  773. (* special instruction support for backend addtions *)
  774. AddFormat(special,"special",Any, Any, Any, {} );
  775. END InitInstructions;
  776. PROCEDURE InitInstruction*(VAR instr: Instruction; textPosition: Basic.Position; opcode: SHORTINT; CONST op1,op2,op3: Operand);
  777. VAR format: InstructionFormat; mode1, mode2, mode3: LONGINT; (* debugging *)
  778. BEGIN
  779. IF instr = NIL THEN NEW(instr) END;
  780. format := instructionFormat[opcode];
  781. mode1 := op1.mode;
  782. mode2 := op2.mode;
  783. mode3 := op3.mode;
  784. (*
  785. Assert(op1.mode IN format.op1,"first operand mode mismatch");
  786. Assert(op2.mode IN format.op2,"second operand mode mismatch");
  787. Assert(op3.mode IN format.op3,"third operand mode mismatch");
  788. *)
  789. Assert(op1.symbol.name[0] # 0, "not intialized operand 1");
  790. Assert(op2.symbol.name[0] # 0, "not intialized operand 2");
  791. Assert(op3.symbol.name[0] # 0, "not intialized operand 3");
  792. instr.opcode := opcode;
  793. instr.op1 := op1;
  794. instr.op2 := op2;
  795. instr.op3 := op3;
  796. instr.textPosition := textPosition;
  797. END InitInstruction;
  798. PROCEDURE InitInstruction2*(VAR instr: Instruction; textPosition: Basic.Position; opcode: SHORTINT; op1,op2: Operand);
  799. BEGIN
  800. InitInstruction(instr, textPosition, opcode, op1, op2, empty);
  801. END InitInstruction2;
  802. PROCEDURE InitInstruction1*(VAR instr: Instruction; textPosition: Basic.Position; opcode: SHORTINT; op1: Operand);
  803. BEGIN
  804. InitInstruction(instr, textPosition, opcode, op1, empty, empty);
  805. END InitInstruction1;
  806. PROCEDURE InitInstruction0*(VAR instr: Instruction; textPosition: Basic.Position; opcode: SHORTINT);
  807. BEGIN
  808. InitInstruction(instr, textPosition, opcode, empty, empty, empty);
  809. END InitInstruction0;
  810. PROCEDURE SetSubType*(VAR instr: Instruction; subType: SHORTINT);
  811. BEGIN
  812. instr.subtype := subType
  813. END SetSubType;
  814. PROCEDURE InitOperand*(VAR op: Operand);
  815. BEGIN
  816. op.mode := Undefined;
  817. op.type.form := Undefined; op.type.sizeInBits := Undefined; op.type.length := 1;
  818. op.register := None; op.offset := 0; op.registerClass := GeneralPurposeRegister;
  819. op.intValue := 0;
  820. op.floatValue := 0;
  821. op.symbol.name := "";
  822. op.symbol.fingerprint := 0;
  823. op.symbolOffset := 0;
  824. END InitOperand;
  825. PROCEDURE InitRegister*(VAR op: Operand; type: Type; registerClass: RegisterClass; register: LONGINT);
  826. BEGIN
  827. Assert((register >0) OR (register = SP) OR (register = FP) OR (register = AP) OR (register = LR) OR (register <= HwRegister) ,"unmapped register number");
  828. InitOperand(op);
  829. op.mode := ModeRegister;
  830. op.type := type;
  831. op.registerClass := registerClass;
  832. op.register := register;
  833. END InitRegister;
  834. PROCEDURE Register*(type: Type; registerClass: RegisterClass; register: LONGINT): Operand;
  835. VAR op: Operand;
  836. BEGIN InitRegister(op,type,registerClass, register); RETURN op
  837. END Register;
  838. PROCEDURE RegisterOffset*(type: Type; registerClass: RegisterClass; register, offset: LONGINT): Operand;
  839. VAR op: Operand;
  840. BEGIN InitRegister(op,type,registerClass, register); SetOffset (op, offset); RETURN op
  841. END RegisterOffset;
  842. PROCEDURE AddOffset*(VAR op: Operand; offset: LONGINT);
  843. BEGIN
  844. Assert((op.mode = ModeRegister) OR (op.mode = ModeMemory) OR (op.mode = ModeImmediate) & (op.type.form IN {SignedInteger, UnsignedInteger}),"offset not on register or integer immediate");
  845. IF (op.mode = ModeImmediate) & (op.symbol.name = "") THEN
  846. INC(op.intValue,offset)
  847. ELSE
  848. INC(op.offset,offset)
  849. END
  850. END AddOffset;
  851. PROCEDURE SetOffset*(VAR op: Operand; offset: LONGINT);
  852. BEGIN
  853. Assert((op.mode = ModeRegister) OR (op.mode = ModeImmediate) & (op.type.form IN {SignedInteger, UnsignedInteger}),"offset not on register or integer immediate");
  854. op.offset := offset
  855. END SetOffset;
  856. PROCEDURE SetSymbol*(VAR op: Operand; symbol: Sections.SectionName; fp: LONGINT);
  857. BEGIN
  858. op.symbol.name := symbol;
  859. op.symbol.fingerprint := fp;
  860. END SetSymbol;
  861. PROCEDURE SetIntValue*(VAR op: Operand; intValue: HUGEINT);
  862. BEGIN op.intValue := intValue
  863. END SetIntValue;
  864. PROCEDURE MakeMemory*(VAR op: Operand; type: Type);
  865. BEGIN
  866. Assert((op.mode = ModeRegister) & (op.type.length < 2) OR (op.mode = ModeMemory) OR (op.mode = ModeImmediate) & (op.type.form = UnsignedInteger) ,"operand mode not of register or unsigned integer immediate");
  867. op.type := type;
  868. op.mode := ModeMemory;
  869. ASSERT(op.register # 0);
  870. END MakeMemory;
  871. PROCEDURE MakeAddress*(VAR op: Operand; CONST type: Type);
  872. BEGIN
  873. ASSERT(op.mode = ModeMemory);
  874. IF op.register = None THEN
  875. op.mode := ModeImmediate;
  876. ELSE
  877. op.mode := ModeRegister;
  878. ASSERT(op.symbol.name = "");
  879. END;
  880. op.type := type;
  881. END MakeAddress;
  882. PROCEDURE InitAddress*(VAR op: Operand; type: Type; symbol: Sections.SectionName; fp: LONGINT; symbolOffset: LONGINT);
  883. BEGIN
  884. Assert(symbol # "","forbidden nil symbol");
  885. ASSERT(symbol[0] # 0); (* not initialized *)
  886. InitImmediate(op,type,0); op.symbol.name := symbol; op.symbol.fingerprint := fp; op.type := type; op.symbolOffset := symbolOffset
  887. END InitAddress;
  888. PROCEDURE Address*(type: Type; symbol: Sections.SectionName; fp: LONGINT; offset: LONGINT): Operand;
  889. VAR op: Operand;
  890. BEGIN InitAddress(op,type,symbol,fp, offset); RETURN op
  891. END Address;
  892. PROCEDURE InitMemory*(VAR op:Operand; type: Type; base: Operand; offset: LONGINT);
  893. BEGIN
  894. Assert((base.mode = ModeRegister) OR (base.mode = ModeImmediate) & ((offset=0) OR (base.symbol.name#"")),"base operand must be register");
  895. op := base; INC(op.offset,offset); MakeMemory(op,type);
  896. END InitMemory;
  897. PROCEDURE Memory*(type: Type; base: Operand; offset: LONGINT): Operand;
  898. VAR op: Operand;
  899. BEGIN InitMemory(op,type,base,offset); RETURN op
  900. END Memory;
  901. PROCEDURE IsConstantInteger*(CONST op: Operand; VAR value: HUGEINT): BOOLEAN;
  902. BEGIN
  903. IF (op.mode = ModeImmediate) & (op.type.form IN Integer) & (op.symbol.name = "") THEN
  904. value := op.intValue;
  905. RETURN TRUE
  906. ELSE
  907. RETURN FALSE
  908. END;
  909. END IsConstantInteger;
  910. PROCEDURE InitImmediate*(VAR op: Operand; type: Type; value: HUGEINT);
  911. BEGIN
  912. Assert(type.form IN Integer,"operand type does not match value type");
  913. InitOperand(op); op.mode := ModeImmediate; op.type := type; op.intValue := value;
  914. END InitImmediate;
  915. PROCEDURE Immediate*(type: Type; value: HUGEINT): Operand;
  916. VAR op: Operand;
  917. BEGIN InitImmediate(op,type,value); RETURN op
  918. END Immediate;
  919. PROCEDURE InitFloatImmediate*(VAR op: Operand; type: Type; value: LONGREAL);
  920. BEGIN
  921. Assert(type.form = Float,"operand type does not match value type");
  922. InitOperand(op); op.mode := ModeImmediate; op.type := type; op.floatValue := value;
  923. END InitFloatImmediate;
  924. PROCEDURE FloatImmediate*(type: Type; value: LONGREAL): Operand;
  925. VAR op: Operand;
  926. BEGIN InitFloatImmediate(op,type,value); RETURN op
  927. END FloatImmediate;
  928. PROCEDURE InitNumber*(VAR op: Operand; value: HUGEINT);
  929. BEGIN InitOperand(op); op.mode := ModeNumber; op.intValue := value;
  930. END InitNumber;
  931. PROCEDURE Number*(value: HUGEINT): Operand;
  932. VAR op: Operand;
  933. BEGIN InitNumber(op,value); RETURN op
  934. END Number;
  935. PROCEDURE InitRule*(VAR op: Operand; rules: Rules);
  936. BEGIN
  937. InitOperand(op); op.mode := ModeRule; op.rule := rules
  938. END InitRule;
  939. PROCEDURE InitString*(VAR op: Operand; string: SyntaxTree.SourceCode);
  940. BEGIN InitOperand(op); op.mode := ModeString; op.string := string;
  941. END InitString;
  942. PROCEDURE SetString*(VAR op: Operand; string: POINTER TO ARRAY OF CHAR);
  943. BEGIN op.string := string
  944. END SetString;
  945. PROCEDURE String*(string: SyntaxTree.SourceCode): Operand;
  946. VAR op: Operand;
  947. BEGIN InitString(op,string); RETURN op
  948. END String;
  949. PROCEDURE InitType*(VAR type: Type; form: SHORTINT; sizeInBits: INTEGER);
  950. BEGIN type.form := form; type.sizeInBits := sizeInBits; type.length := 1;
  951. END InitType;
  952. PROCEDURE ToVectorType*(VAR type: Type; length: LONGINT);
  953. BEGIN type.length := length
  954. END ToVectorType;
  955. PROCEDURE InitRegisterClass*(VAR registerClass: RegisterClass; class: SHORTINT; number: LONGINT);
  956. BEGIN registerClass.class := class; registerClass.number := INTEGER(number)
  957. END InitRegisterClass;
  958. PROCEDURE InitParameterRegisterClass*(VAR registerClass: RegisterClass; number: LONGINT);
  959. BEGIN registerClass.class := Parameter; registerClass.number := INTEGER(number)
  960. END InitParameterRegisterClass;
  961. PROCEDURE NewType*(form: SHORTINT; sizeInBits: INTEGER): Type;
  962. VAR type: Type;
  963. BEGIN InitType(type, form, sizeInBits); RETURN type
  964. END NewType;
  965. PROCEDURE SetType*(VAR op: Operand; CONST type: Type);
  966. BEGIN op.type := type
  967. END SetType;
  968. (** assembler related part *)
  969. PROCEDURE FindMnemonic*(CONST name: ARRAY OF CHAR): SHORTINT;
  970. VAR i: SHORTINT;
  971. BEGIN
  972. FOR i := 0 TO NofOpcodes-1 DO
  973. IF name = instructionFormat[i].name THEN
  974. RETURN i
  975. END;
  976. END;
  977. RETURN None;
  978. END FindMnemonic;
  979. PROCEDURE SetRegister*(VAR op: Operand; reg: LONGINT);
  980. BEGIN
  981. op.register := reg; ASSERT(reg # 0);
  982. END SetRegister;
  983. PROCEDURE DecimalNumber(ch: CHAR; VAR nr: LONGINT): BOOLEAN;
  984. BEGIN
  985. IF (ch < "0") OR (ch > "9") THEN RETURN FALSE
  986. ELSE
  987. nr := nr *10;
  988. INC(nr,ORD(ch)-ORD("0"));
  989. RETURN TRUE
  990. END;
  991. END DecimalNumber;
  992. PROCEDURE Numbers(CONST name: ARRAY OF CHAR; VAR pos: LONGINT; VAR number: LONGINT): BOOLEAN;
  993. BEGIN
  994. number := 0;
  995. IF DecimalNumber(name[pos], number) THEN
  996. INC(pos);
  997. WHILE (pos<LEN(name)) & DecimalNumber(name[pos], number) DO INC(pos) END;
  998. RETURN TRUE
  999. ELSE
  1000. RETURN FALSE
  1001. END;
  1002. END Numbers;
  1003. PROCEDURE Character(CONST name: ARRAY OF CHAR; VAR pos: LONGINT; char: CHAR): BOOLEAN;
  1004. BEGIN
  1005. IF name[pos] = char THEN INC(pos); RETURN TRUE ELSE RETURN FALSE END;
  1006. END Character;
  1007. PROCEDURE DenotesRegister*(CONST name: ARRAY OF CHAR; VAR registerClass: RegisterClass; VAR register: LONGINT): BOOLEAN;
  1008. VAR pos, registerNumber: LONGINT;
  1009. BEGIN
  1010. pos := 0;
  1011. IF Character(name,pos,'r') THEN
  1012. IF Numbers(name,pos,register) THEN
  1013. IF Character(name,pos,0X) THEN registerClass := GeneralPurposeRegister; RETURN TRUE
  1014. ELSIF Character(name,pos,':') & Character(name,pos,'p') & Numbers(name,pos,registerNumber) & Character(name,pos,0X) THEN
  1015. InitRegisterClass(registerClass, Parameter, SHORT(registerNumber));
  1016. RETURN TRUE
  1017. END
  1018. END;
  1019. ELSIF Character(name,pos,'h') THEN
  1020. IF Numbers(name,pos,register) & Character(name,pos,0X) THEN
  1021. register := HwRegister - register; RETURN TRUE
  1022. END;
  1023. ELSIF name = "sp" THEN register := SP; RETURN TRUE
  1024. ELSIF name = "fp" THEN register := FP ; RETURN TRUE
  1025. ELSIF name = "ap" THEN register := AP ; RETURN TRUE
  1026. ELSIF name = "lr" THEN register := LR ; RETURN TRUE
  1027. ELSE RETURN FALSE
  1028. END;
  1029. END DenotesRegister;
  1030. PROCEDURE UnsignedIntegerType*(bits: LONGINT): Type;
  1031. BEGIN
  1032. IF bits = 8 THEN RETURN uint8
  1033. ELSIF bits=16 THEN RETURN uint16
  1034. ELSIF bits=32 THEN RETURN uint32
  1035. ELSIF bits=64 THEN RETURN uint64
  1036. ELSE RETURN NewType(UnsignedInteger, SHORTINT(bits))
  1037. END;
  1038. END UnsignedIntegerType;
  1039. PROCEDURE SignedIntegerType*(bits: LONGINT): Type;
  1040. BEGIN
  1041. IF bits = 8 THEN RETURN int8
  1042. ELSIF bits=16 THEN RETURN int16
  1043. ELSIF bits=32 THEN RETURN int32
  1044. ELSIF bits=64 THEN RETURN int64
  1045. ELSE RETURN NewType(SignedInteger, SHORTINT(bits))
  1046. END;
  1047. END SignedIntegerType;
  1048. PROCEDURE FloatType*(bits: LONGINT): Type;
  1049. BEGIN
  1050. IF bits=32 THEN RETURN float32
  1051. ELSIF bits=64 THEN RETURN float64
  1052. ELSE RETURN NewType(Float, SHORTINT(bits))
  1053. END;
  1054. END FloatType;
  1055. (** make an integer operand unsigned
  1056. - note that no conversion is done, but only the type is changed **)
  1057. PROCEDURE ToUnsigned*(operand: Operand): Operand;
  1058. VAR
  1059. type: Type;
  1060. result: Operand;
  1061. BEGIN
  1062. ASSERT(operand.type.form IN Integer);
  1063. result := operand;
  1064. result.type.form := UnsignedInteger;
  1065. RETURN result
  1066. END ToUnsigned;
  1067. PROCEDURE DenotesType*(CONST name: ARRAY OF CHAR; VAR type: Type): BOOLEAN;
  1068. VAR
  1069. sizeInBits: LONGINT; pos: LONGINT;
  1070. BEGIN
  1071. pos := 0;
  1072. IF Character(name,pos,'s') THEN
  1073. IF Numbers(name, pos, sizeInBits) & Character(name,pos,0X) & (sizeInBits >0) THEN
  1074. type := SignedIntegerType(sizeInBits); RETURN TRUE
  1075. END;
  1076. ELSIF Character(name,pos,'u') THEN
  1077. IF Numbers(name, pos, sizeInBits) & Character(name,pos,0X) & (sizeInBits >0) THEN
  1078. type := UnsignedIntegerType(sizeInBits); RETURN TRUE
  1079. END;
  1080. ELSIF Character(name,pos, 'f') THEN
  1081. IF Numbers(name, pos, sizeInBits) & Character(name,pos,0X) & (sizeInBits >0) THEN
  1082. type := FloatType(sizeInBits); RETURN TRUE
  1083. END;
  1084. ELSE RETURN FALSE
  1085. END;
  1086. END DenotesType;
  1087. PROCEDURE GetType*(system: Global.System; type: SyntaxTree.Type): Type;
  1088. VAR t: Type;
  1089. BEGIN
  1090. type := type.resolved;
  1091. IF type IS SyntaxTree.CharacterType THEN
  1092. RETURN UnsignedIntegerType(system.SizeOf(type))
  1093. ELSIF type IS SyntaxTree.IntegerType THEN
  1094. IF type(SyntaxTree.IntegerType).signed THEN
  1095. RETURN SignedIntegerType(system.SizeOf(type))
  1096. ELSE
  1097. RETURN UnsignedIntegerType(system.SizeOf(type))
  1098. END;
  1099. ELSIF type IS SyntaxTree.FloatType THEN
  1100. RETURN FloatType(system.SizeOf(type))
  1101. ELSIF type IS SyntaxTree.RangeType THEN
  1102. RETURN GetType(system,system.addressType)
  1103. ELSIF type IS SyntaxTree.BasicType THEN
  1104. IF type IS SyntaxTree.SizeType THEN
  1105. RETURN SignedIntegerType(system.SizeOf(type))
  1106. ELSE
  1107. RETURN UnsignedIntegerType(system.SizeOf(type))
  1108. END;
  1109. ELSIF type IS SyntaxTree.PointerType THEN
  1110. RETURN GetType(system,system.addressType)
  1111. ELSIF type IS SyntaxTree.EnumerationType THEN
  1112. RETURN int32
  1113. ELSIF type IS SyntaxTree.ProcedureType THEN
  1114. RETURN GetType(system,system.addressType)
  1115. ELSIF type IS SyntaxTree.MathArrayType THEN
  1116. WITH type: SyntaxTree.MathArrayType DO
  1117. IF type.form = SyntaxTree.Static THEN
  1118. t := GetType(system, type.arrayBase);
  1119. ASSERT(t.length = 1);
  1120. ToVectorType(t, type.staticLength);
  1121. RETURN t
  1122. END;
  1123. END;
  1124. (* TODO: ok to comment out the following assertion?:
  1125. ASSERT(type(SyntaxTree.MathArrayType).form IN {SyntaxTree.Static, SyntaxTree.Tensor}); *)
  1126. RETURN GetType(system,system.addressType);
  1127. ELSIF (type IS SyntaxTree.ArrayType) & (type(SyntaxTree.ArrayType).form = SyntaxTree.SemiDynamic) THEN
  1128. RETURN GetType(system,system.addressType);
  1129. ELSIF type IS SyntaxTree.ArrayType THEN
  1130. WITH type: SyntaxTree.ArrayType DO
  1131. IF type.form = SyntaxTree.Static THEN
  1132. t := GetType(system, type.arrayBase);
  1133. ASSERT(t.length = 1);
  1134. ToVectorType(t, type.staticLength);
  1135. RETURN t
  1136. END;
  1137. END;
  1138. RETURN GetType(system,system.addressType);
  1139. ELSIF type IS SyntaxTree.PortType THEN
  1140. RETURN GetType(system, system.addressType);
  1141. ELSIF type IS SyntaxTree.CellType THEN
  1142. RETURN GetType(system, system.addressType);
  1143. ELSE
  1144. HALT(100);
  1145. END;
  1146. END GetType;
  1147. BEGIN
  1148. InitInstructions;
  1149. InitType(int8, SignedInteger,8);
  1150. InitType(int16, SignedInteger,16);
  1151. InitType(int32, SignedInteger,32);
  1152. InitType(int64, SignedInteger,64);
  1153. InitType(uint8, UnsignedInteger,8);
  1154. InitType(uint16, UnsignedInteger,16);
  1155. InitType(uint32, UnsignedInteger,32);
  1156. InitType(uint64, UnsignedInteger,64);
  1157. InitType(float32, Float,32);
  1158. InitType(float64, Float,64);
  1159. InitType(undef, Undefined,0);
  1160. InitOperand(empty);
  1161. END FoxIntermediateCode.