From 5ad469587770ad0e11b34a6b4c087ab7589b3bca Mon Sep 17 00:00:00 2001 From: Mateusz Baginski Date: Sat, 30 Dec 2023 14:28:56 +0100 Subject: [PATCH] feat: add prototype --- .../call-conventions/X86StdcallFnCaller.ts | 5 +- .../data/compileArrayInitializerDef.ts | 2 +- .../reg-allocator/X86BasicRegAllocator.ts | 6 +- .../CVariableInitializerPrintVisitor.ts | 35 +++++--- .../CVariableInitializerVisitor.ts | 13 ++- .../builder/CTypeInitializerBuilderVisitor.ts | 27 +++--- .../variables/CVariableInitializerTree.ts | 35 +++++--- .../src/frontend/analyze/types/CArrayType.ts | 10 +-- .../src/frontend/analyze/types/CType.ts | 2 +- .../analyze/types/struct/CStructType.ts | 6 +- .../analyze/types/union/CUnionType.ts | 25 +++++- .../emitVariableLoadInitializerIR.ts | 7 +- .../emitStringLiteralPtrInitializerIR.ts | 9 +- .../tests/codegen/declarations/unions.test.ts | 90 +++++++++++++++++++ .../tests/codegen/statements/fn.test.ts | 76 ++++++++++++++++ 15 files changed, 286 insertions(+), 62 deletions(-) diff --git a/packages/compiler-pico-c/src/arch/x86/backend/call-conventions/X86StdcallFnCaller.ts b/packages/compiler-pico-c/src/arch/x86/backend/call-conventions/X86StdcallFnCaller.ts index cbb56e02..19910c3d 100644 --- a/packages/compiler-pico-c/src/arch/x86/backend/call-conventions/X86StdcallFnCaller.ts +++ b/packages/compiler-pico-c/src/arch/x86/backend/call-conventions/X86StdcallFnCaller.ts @@ -230,15 +230,14 @@ export class X86StdcallFnCaller implements X86ConventionalFnCaller { }; } - private getReturnReg({ context, declInstruction }: X86FnBasicCompilerAttrs) { - const regs = context.allocator.regs.ownership.getAvailableRegs(); + private getReturnReg({ declInstruction }: X86FnBasicCompilerAttrs) { const { returnType } = declInstruction; if (!returnType || returnType.isVoid()) { return null; } - return regs.general.list[0]; + return returnType.getByteSize() === 1 ? 'al' : 'ax'; } private preserveConventionRegsAsm({ diff --git a/packages/compiler-pico-c/src/arch/x86/backend/compilers/data/compileArrayInitializerDef.ts b/packages/compiler-pico-c/src/arch/x86/backend/compilers/data/compileArrayInitializerDef.ts index dd7f3697..f5b86f1b 100644 --- a/packages/compiler-pico-c/src/arch/x86/backend/compilers/data/compileArrayInitializerDef.ts +++ b/packages/compiler-pico-c/src/arch/x86/backend/compilers/data/compileArrayInitializerDef.ts @@ -35,7 +35,7 @@ export function compileArrayInitializerDefAsm({ // [1, 2, "as", 3] -> [[1, 2], "as", [3]] const groupedDefs = initializer.fields.reduce( - ({ prevFieldType, groups }, field) => { + ({ prevFieldType, groups }, { value: field }) => { const currentFieldType = typeof field; if (currentFieldType !== prevFieldType) { diff --git a/packages/compiler-pico-c/src/arch/x86/backend/reg-allocator/X86BasicRegAllocator.ts b/packages/compiler-pico-c/src/arch/x86/backend/reg-allocator/X86BasicRegAllocator.ts index 2d3f491c..0e8865f2 100644 --- a/packages/compiler-pico-c/src/arch/x86/backend/reg-allocator/X86BasicRegAllocator.ts +++ b/packages/compiler-pico-c/src/arch/x86/backend/reg-allocator/X86BasicRegAllocator.ts @@ -123,9 +123,9 @@ export class X86BasicRegAllocator { if ( !castToPointerIfArray(arg.type).isScalar() && - (!isUnionLikeType(arg.type) || - !isStructLikeType(arg.type) || - !arg.type.canBeStoredInReg()) + !isUnionLikeType(arg.type) && + !isStructLikeType(arg.type) && + !arg.type.canBeStoredInReg() ) { throw new CBackendError(CBackendErrorCode.REG_ALLOCATOR_ERROR); } diff --git a/packages/compiler-pico-c/src/frontend/analyze/ast/initializer-builder/CVariableInitializerPrintVisitor.ts b/packages/compiler-pico-c/src/frontend/analyze/ast/initializer-builder/CVariableInitializerPrintVisitor.ts index 2aa471ec..cd54eafa 100644 --- a/packages/compiler-pico-c/src/frontend/analyze/ast/initializer-builder/CVariableInitializerPrintVisitor.ts +++ b/packages/compiler-pico-c/src/frontend/analyze/ast/initializer-builder/CVariableInitializerPrintVisitor.ts @@ -1,10 +1,12 @@ +import { isNil } from 'ramda'; import { isTreeNode } from '@ts-c-compiler/grammar'; import { CVariableInitializerVisitor } from './CVariableInitializerVisitor'; import { - CVariableInitializerTree, + CVariableInitializePair, CVariableInitializeValue, - isInitializerTreeValue, + CVariableInitializerTree, + isInitializerValuePair, } from '../../scope/variables/CVariableInitializerTree'; /** @@ -17,23 +19,36 @@ export class CVariableInitializerPrintVisitor extends CVariableInitializerVisito return this._reduced; } - override enter(value: CVariableInitializeValue) { + override enter( + maybePair: CVariableInitializePair | CVariableInitializerTree, + ) { if (this._reduced && this._reduced[this._reduced.length - 2] !== '{') { this._reduced += ', '; } - let serializedValue = value; - if (isInitializerTreeValue(value)) { + let serializedValue: CVariableInitializeValue = ''; + + if (isTreeNode(maybePair)) { serializedValue = '{ '; - } else if (isTreeNode(value)) { - serializedValue = ''; + } else if (isInitializerValuePair(maybePair)) { + if (isTreeNode(maybePair.value)) { + serializedValue = ''; + } else { + serializedValue = maybePair.value; + } + } else if (isNil(maybePair)) { + serializedValue = 'null'; } - this._reduced += serializedValue; + if (serializedValue) { + this._reduced += serializedValue; + } } - override leave(value: CVariableInitializeValue) { - if (isInitializerTreeValue(value)) { + override leave( + maybePair: CVariableInitializePair | CVariableInitializerTree, + ) { + if (isTreeNode(maybePair)) { this._reduced += ' }'; } } diff --git a/packages/compiler-pico-c/src/frontend/analyze/ast/initializer-builder/CVariableInitializerVisitor.ts b/packages/compiler-pico-c/src/frontend/analyze/ast/initializer-builder/CVariableInitializerVisitor.ts index 306b895a..f93ce929 100644 --- a/packages/compiler-pico-c/src/frontend/analyze/ast/initializer-builder/CVariableInitializerVisitor.ts +++ b/packages/compiler-pico-c/src/frontend/analyze/ast/initializer-builder/CVariableInitializerVisitor.ts @@ -1,10 +1,17 @@ import { isCompilerTreeNode } from 'frontend/parser'; import { AbstractTreeVisitor } from '@ts-c-compiler/grammar'; -import { CVariableInitializeValue } from '../../scope/variables'; +import { + CVariableInitializePair, + CVariableInitializerTree, +} from '../../scope/variables'; -export class CVariableInitializerVisitor extends AbstractTreeVisitor { - shouldVisitNode(node: CVariableInitializeValue): boolean { +export class CVariableInitializerVisitor extends AbstractTreeVisitor< + CVariableInitializePair | CVariableInitializerTree +> { + shouldVisitNode( + node: CVariableInitializePair | CVariableInitializerTree, + ): boolean { return !isCompilerTreeNode(node); } } diff --git a/packages/compiler-pico-c/src/frontend/analyze/ast/initializer-builder/builder/CTypeInitializerBuilderVisitor.ts b/packages/compiler-pico-c/src/frontend/analyze/ast/initializer-builder/builder/CTypeInitializerBuilderVisitor.ts index de1fb2ed..f02f92e5 100644 --- a/packages/compiler-pico-c/src/frontend/analyze/ast/initializer-builder/builder/CTypeInitializerBuilderVisitor.ts +++ b/packages/compiler-pico-c/src/frontend/analyze/ast/initializer-builder/builder/CTypeInitializerBuilderVisitor.ts @@ -29,7 +29,7 @@ import { import { CVariableInitializerTree, - CVariableInitializeValue, + CVariableInitializePair, } from '../../../scope/variables'; import { @@ -87,7 +87,7 @@ export class CTypeInitializerBuilderVisitor extends CInnerTypeTreeVisitor { if (!this.tree) { this.tree = new CVariableInitializerTree(baseType, node); - this.maxSize = this.tree.scalarValuesCount; + this.maxSize = this.tree.c89initializerFieldsCount; } const arrayType = isArrayLikeType(baseType); @@ -223,15 +223,20 @@ export class CTypeInitializerBuilderVisitor extends CInnerTypeTreeVisitor { } } - this.appendNextOffsetValue(exprValue, noSizeCheck); - } else if (isCompilerTreeNode(exprValue)) { this.appendNextOffsetValue( - this.parseTreeNodeExpressionValue(node, expectedType, exprValue), + { type: expectedType, value: exprValue }, + noSizeCheck, ); + } else if (isCompilerTreeNode(exprValue)) { + this.appendNextOffsetValue({ + type: expectedType, + value: this.parseTreeNodeExpressionValue(node, expectedType, exprValue), + }); } else { - this.appendNextOffsetValue( - this.parseScalarValue(node, expectedType, exprValue), - ); + this.appendNextOffsetValue({ + type: expectedType, + value: this.parseScalarValue(node, expectedType, exprValue), + }); } } @@ -311,7 +316,7 @@ export class CTypeInitializerBuilderVisitor extends CInnerTypeTreeVisitor { offset += +constExprResult.right * dimensions.reduce((acc, num, index) => (index ? acc * num : 1), 1) * - type.scalarValuesCount; + type.c89initializerFieldsCount; } } @@ -424,13 +429,13 @@ export class CTypeInitializerBuilderVisitor extends CInnerTypeTreeVisitor { * Appends next value to tree and increments currentKey if number */ private appendNextOffsetValue( - entryValue: CVariableInitializeValue, + entryValue: CVariableInitializePair, noSizeCheck?: boolean, ) { const { tree, maxSize, baseType } = this; // handle struct Vec2 vec[] = { of_vector(), of_vector() }; initializers const delta = isCompilerTreeNode(entryValue) - ? entryValue.type.scalarValuesCount + ? entryValue.type.c89initializerFieldsCount : 1; if (isStructLikeType(baseType) || isUnionLikeType(baseType)) { diff --git a/packages/compiler-pico-c/src/frontend/analyze/scope/variables/CVariableInitializerTree.ts b/packages/compiler-pico-c/src/frontend/analyze/scope/variables/CVariableInitializerTree.ts index 04f0c3bb..3b44052c 100644 --- a/packages/compiler-pico-c/src/frontend/analyze/scope/variables/CVariableInitializerTree.ts +++ b/packages/compiler-pico-c/src/frontend/analyze/scope/variables/CVariableInitializerTree.ts @@ -18,7 +18,12 @@ export type CVariableInitializeValue = | CVariableInitializerTree | ASTCCompilerNode; -export type CVariableInitializerFields = CVariableInitializeValue[]; +export type CVariableInitializePair = { + type: CType; + value: CVariableInitializeValue; +}; + +export type CVariableInitializerFields = CVariableInitializePair[]; export function isConstantVariableInitializer(value: CVariableInitializeValue) { if (!value) { @@ -36,6 +41,12 @@ export function isInitializerTreeValue( return R.is(Object, value) && R.has('_baseType', value); } +export function isInitializerValuePair( + pair: any, +): pair is CVariableInitializePair { + return !!pair && 'type' in pair && 'value' in pair; +} + type CVariableByteInitializerAttrs = { baseType: CType; parentAST?: C; @@ -83,8 +94,8 @@ export class CVariableInitializerTree< return new CVariableInitializerTree(baseType, parentAST, fields); } - fill(value: CVariableInitializeValue) { - this._fields = new Array(this.scalarValuesCount).fill(value); + fill(value: CVariableInitializePair) { + this._fields = new Array(this.c89initializerFieldsCount).fill(value); } walk(visitor: AbstractTreeVisitor): void { @@ -92,7 +103,9 @@ export class CVariableInitializerTree< } hasOnlyConstantExpressions() { - return this._fields.every(isConstantVariableInitializer); + return this._fields.every(item => + isConstantVariableInitializer(item.value), + ); } getSingleItemByteSize() { @@ -130,7 +143,7 @@ export class CVariableInitializerTree< /** * Sets values on given offset and if offset is bigger than array fills with null */ - setAndExpand(offset: number, value: CVariableInitializeValue) { + setAndExpand(offset: number, value: CVariableInitializePair) { const { fields } = this; this.ensureSize(offset); @@ -140,7 +153,7 @@ export class CVariableInitializerTree< /** * Used to return value for non-array type initializers */ - getFirstValue(): CVariableInitializeValue { + getFirstValue(): CVariableInitializePair { return this._fields[0]; } @@ -177,7 +190,7 @@ export class CVariableInitializerTree< return baseType.ofSize( Math.ceil( this.getFlattenNonLiteralScalarFieldsCount() / - baseType.baseType.scalarValuesCount, + baseType.baseType.c89initializerFieldsCount, ), ); } @@ -192,7 +205,7 @@ export class CVariableInitializerTree< const { baseType } = this; if (isStructLikeType(baseType) || isUnionLikeType(baseType)) { - return baseType.getFieldTypeByIndex( + return baseType.getFieldTypeByC89InitializerIndex( offset % baseType.getFlattenFieldsCount(), ); } @@ -201,7 +214,7 @@ export class CVariableInitializerTree< const baseArrayType = baseType.getSourceType(); if (isStructLikeType(baseArrayType) || isUnionLikeType(baseArrayType)) { - return baseArrayType.getFieldTypeByIndex( + return baseArrayType.getFieldTypeByC89InitializerIndex( offset % baseArrayType.getFlattenFieldsCount(), ); } @@ -235,7 +248,7 @@ export class CVariableInitializerTree< * @example * int abc[3][4] => 12 */ - get scalarValuesCount(): number { - return this.baseType.scalarValuesCount; + get c89initializerFieldsCount(): number { + return this.baseType.c89initializerFieldsCount; } } diff --git a/packages/compiler-pico-c/src/frontend/analyze/types/CArrayType.ts b/packages/compiler-pico-c/src/frontend/analyze/types/CArrayType.ts index 797af98a..6b953aef 100644 --- a/packages/compiler-pico-c/src/frontend/analyze/types/CArrayType.ts +++ b/packages/compiler-pico-c/src/frontend/analyze/types/CArrayType.ts @@ -83,17 +83,17 @@ export class CArrayType extends CType { } get itemScalarValuesCount() { - return this.baseType.scalarValuesCount; + return this.baseType.c89initializerFieldsCount; } - get scalarValuesCount() { - const { scalarValuesCount } = this.baseType; + get c89initializerFieldsCount() { + const { c89initializerFieldsCount } = this.baseType; - if (this.isUnknownSize() || R.isNil(scalarValuesCount)) { + if (this.isUnknownSize() || R.isNil(c89initializerFieldsCount)) { return null; } - return this.size * scalarValuesCount; + return this.size * c89initializerFieldsCount; } /** diff --git a/packages/compiler-pico-c/src/frontend/analyze/types/CType.ts b/packages/compiler-pico-c/src/frontend/analyze/types/CType.ts index e03d4df4..3ebaabd8 100644 --- a/packages/compiler-pico-c/src/frontend/analyze/types/CType.ts +++ b/packages/compiler-pico-c/src/frontend/analyze/types/CType.ts @@ -39,7 +39,7 @@ export abstract class CType return this.value.qualifiers; } - get scalarValuesCount() { + get c89initializerFieldsCount() { return 1; } diff --git a/packages/compiler-pico-c/src/frontend/analyze/types/struct/CStructType.ts b/packages/compiler-pico-c/src/frontend/analyze/types/struct/CStructType.ts index 3be723c7..c0ff72ea 100644 --- a/packages/compiler-pico-c/src/frontend/analyze/types/struct/CStructType.ts +++ b/packages/compiler-pico-c/src/frontend/analyze/types/struct/CStructType.ts @@ -51,7 +51,7 @@ export class CStructType extends CType { return this.value.align; } - get scalarValuesCount() { + get c89initializerFieldsCount() { return this.getFlattenFieldsTypes().length; } @@ -86,7 +86,7 @@ export class CStructType extends CType { new CStructEntry({ ...entry.unwrap(), index: prevEntry - ? prevEntry.index + prevEntry.type.scalarValuesCount + ? prevEntry.index + prevEntry.type.c89initializerFieldsCount : 0, offset: alignerFn(this, entry.type), bitset, @@ -253,7 +253,7 @@ export class CStructType extends CType { return null; } - getFieldTypeByIndex(index: number): CType { + getFieldTypeByC89InitializerIndex(index: number): CType { return this.getFlattenFieldsTypes()[index]?.[1]; } } diff --git a/packages/compiler-pico-c/src/frontend/analyze/types/union/CUnionType.ts b/packages/compiler-pico-c/src/frontend/analyze/types/union/CUnionType.ts index 8ed8ff8f..61fb9f56 100644 --- a/packages/compiler-pico-c/src/frontend/analyze/types/union/CUnionType.ts +++ b/packages/compiler-pico-c/src/frontend/analyze/types/union/CUnionType.ts @@ -24,6 +24,8 @@ export function isUnionLikeType(type: CType): type is CUnionType { /** * Defines C-like Union + * + * @see {@link https://www.ibm.com/docs/en/zos/2.2.0?topic=initializers-initialization-structures-unions} */ export class CUnionType extends CType { static ofBlank(arch: CCompilerArch, name?: string) { @@ -46,8 +48,13 @@ export class CUnionType extends CType { return this.value.fields; } - get scalarValuesCount() { - return this.getFlattenFieldsTypes().length; + /** + * According to standard only first field can be initialized using c89 initializer + */ + get c89initializerFieldsCount() { + const [, { type }] = this.getFieldsList()[0]; + + return type.c89initializerFieldsCount; } /** @@ -198,7 +205,17 @@ export class CUnionType extends CType { return this.getFlattenFieldsTypes().length; } - getFieldTypeByIndex(index: number): CType { - return this.getFlattenFieldsTypes()[index]?.[1]; + getFieldTypeByC89InitializerIndex(index: number): CType { + const [, { type }] = this.getFieldsList()[0]; + + if (isUnionLikeType(type) || type.isStruct()) { + return (type as any).getFieldTypeByC89InitializerIndex(index); + } + + if (isArrayLikeType(type)) { + return type.baseType; + } + + return type; } } diff --git a/packages/compiler-pico-c/src/frontend/ir/generator/emitters/emit-initializer/emitVariableLoadInitializerIR.ts b/packages/compiler-pico-c/src/frontend/ir/generator/emitters/emit-initializer/emitVariableLoadInitializerIR.ts index 05435914..8ca713e1 100644 --- a/packages/compiler-pico-c/src/frontend/ir/generator/emitters/emit-initializer/emitVariableLoadInitializerIR.ts +++ b/packages/compiler-pico-c/src/frontend/ir/generator/emitters/emit-initializer/emitVariableLoadInitializerIR.ts @@ -47,12 +47,15 @@ export function emitVariableLoadInitializerIR({ let offset: number = 0; - initializerTree.fields.forEach((initializer, index) => { + initializerTree.fields.forEach((pair, index) => { + const initializer = pair?.value; + if (isInitializerTreeValue(initializer)) { throw new IRError(IRErrorCode.INCORRECT_INITIALIZER_BLOCK); } - const itemOffsetType = initializerTree.getIndexExpectedType(index); + const itemOffsetType = + pair?.type ?? initializerTree.getIndexExpectedType(index); if (R.is(String, initializer)) { const attrs: StringPtrInitializerLocalIREmitAttrs = { diff --git a/packages/compiler-pico-c/src/frontend/ir/generator/emitters/emit-initializer/literal/emitStringLiteralPtrInitializerIR.ts b/packages/compiler-pico-c/src/frontend/ir/generator/emitters/emit-initializer/literal/emitStringLiteralPtrInitializerIR.ts index fe2de10d..073318bc 100644 --- a/packages/compiler-pico-c/src/frontend/ir/generator/emitters/emit-initializer/literal/emitStringLiteralPtrInitializerIR.ts +++ b/packages/compiler-pico-c/src/frontend/ir/generator/emitters/emit-initializer/literal/emitStringLiteralPtrInitializerIR.ts @@ -56,14 +56,13 @@ export function emitStringLiteralPtrInitializerIR({ const constArrayVar = allocator.allocDataVariable(dataType); const dataLabel = IRLabel.ofName(constArrayVar.name); + const literalType = CArrayType.ofStringLiteral(config.arch, literal.length); result.data.push( new IRDefDataInstruction( - new CVariableInitializerTree( - CArrayType.ofStringLiteral(config.arch, literal.length), - null, - [literal], - ), + new CVariableInitializerTree(literalType, null, [ + { type: literalType, value: literal }, + ]), constArrayVar, ), ); diff --git a/packages/compiler-pico-c/tests/codegen/declarations/unions.test.ts b/packages/compiler-pico-c/tests/codegen/declarations/unions.test.ts index d20de8e0..7e76f122 100644 --- a/packages/compiler-pico-c/tests/codegen/declarations/unions.test.ts +++ b/packages/compiler-pico-c/tests/codegen/declarations/unions.test.ts @@ -170,7 +170,97 @@ describe('Unions', () => { union Data data = fun(); } `).toCompiledAsmBeEqual(` + cpu 386 + ; def fun(): [ret: union Data1B] + @@_fn_fun: + push bp + mov bp, sp + sub sp, 1 + mov byte [bp - 1], 2 ; *(tmp{0}: char*2B) = store %2: char1B + mov al, [bp - 1] + mov sp, bp + pop bp + ret + ; def main(): + @@_fn_main: + push bp + mov bp, sp + sub sp, 1 + call @@_fn_fun + mov byte [bp - 1], al ; *(data{0}: union Data*2B) = store %t{2}: union Data1B + mov sp, bp + pop bp + ret + `); + }); + + test('reading data from union member works', () => { + expect(/* cpp */ ` + typedef union Data { + char k; + int a[4]; + } abc; + + void main() { + abc data = { + .a = { 1, 2, 3, 4 } + }; + + int k = data.a[2]; + asm("xchg dx, dx"); + } + `).toCompiledAsmBeEqual(` + cpu 386 + ; def main(): + @@_fn_main: + push bp + mov bp, sp + sub sp, 10 + mov word [bp - 8], 1 ; *(data{0}: int*2B) = store %1: int2B + mov word [bp - 6], 2 ; *(data{0}: int*2B + %2) = store %2: int2B + mov word [bp - 4], 3 ; *(data{0}: int*2B + %4) = store %3: int2B + mov word [bp - 2], 4 ; *(data{0}: int*2B + %6) = store %4: int2B + lea bx, [bp - 8] ; %t{0}: union Data**2B = lea data{0}: union Data*2B + add bx, 4 ; %t{1}: int[4]*2B = %t{0}: int[4]*2B plus %4: int2B + mov ax, [bx] ; %t{2}: int2B = load %t{1}: int[4]*2B + mov word [bp - 10], ax ; *(k{0}: int*2B) = store %t{2}: int2B + xchg dx, dx + mov sp, bp + pop bp + ret + `); + }); + + test('c89 initializer for single char value', () => { + expect(/* cpp */ ` + // fixme: ZŁY WYNIK + typedef union Data { + char k; + int a[4]; + } abc; + + void main() { + abc data = { 1 }; + + int k = data.a[0]; + asm("xchg dx, dx"); + } + `).toCompiledAsmBeEqual(` + cpu 386 + ; def main(): + @@_fn_main: + push bp + mov bp, sp + sub sp, 10 + mov byte [bp - 8], 1 ; *(data{0}: char*2B) = store %1: char1B + lea bx, [bp - 8] ; %t{0}: union Data**2B = lea data{0}: union Data*2B + mov ax, [bx] ; %t{2}: int2B = load %t{1}: int[4]*2B + mov word [bp - 10], ax ; *(k{0}: int*2B) = store %t{2}: int2B + xchg dx, dx + mov sp, bp + pop bp + ret `); }); }); diff --git a/packages/compiler-pico-c/tests/codegen/statements/fn.test.ts b/packages/compiler-pico-c/tests/codegen/statements/fn.test.ts index f50d5a85..f157549b 100644 --- a/packages/compiler-pico-c/tests/codegen/statements/fn.test.ts +++ b/packages/compiler-pico-c/tests/codegen/statements/fn.test.ts @@ -36,4 +36,80 @@ describe('Fn statement', () => { ret `); }); + + test('small variables using registers directly to initializer', () => { + expect(/* cpp */ ` + char fn() { + return 2; + } + + int main() { + char a = fn(); + } + `).toCompiledAsmBeEqual(` + cpu 386 + ; def fn(): [ret: char1B] + @@_fn_fn: + push bp + mov bp, sp + mov al, byte 2 + mov sp, bp + pop bp + ret + + ; def main(): [ret: int2B] + @@_fn_main: + push bp + mov bp, sp + sub sp, 1 + call @@_fn_fn + mov byte [bp - 1], al ; *(a{0}: char*2B) = store %t{1}: char1B + mov sp, bp + pop bp + ret + `); + }); + + test('small structures using registers directly to initializer', () => { + expect(/* cpp */ ` + struct Data { + char k; + }; + + struct Data fun() { + struct Data tmp = { + .k = 2 + }; + + return tmp; + }; + + void main() { + struct Data data = fun(); + } + `).toCompiledAsmBeEqual(` + cpu 386 + ; def fun(): [ret: struct Data1B] + @@_fn_fun: + push bp + mov bp, sp + sub sp, 1 + mov byte [bp - 1], 2 ; *(tmp{0}: struct Data*2B) = store %2: char1B + mov al, [bp - 1] + mov sp, bp + pop bp + ret + + ; def main(): + @@_fn_main: + push bp + mov bp, sp + sub sp, 1 + call @@_fn_fun + mov byte [bp - 1], al ; *(data{0}: struct Data*2B) = store %t{2}: struct Data1B + mov sp, bp + pop bp + ret + `); + }); });