diff options
Diffstat (limited to 'nim/ccgexprs.pas')
-rw-r--r-- | nim/ccgexprs.pas | 1350 |
1 files changed, 719 insertions, 631 deletions
diff --git a/nim/ccgexprs.pas b/nim/ccgexprs.pas index 027f6a816..7668f114a 100644 --- a/nim/ccgexprs.pas +++ b/nim/ccgexprs.pas @@ -17,25 +17,34 @@ begin // Nimrod has the same bug for the same reasons :-) result := toRope('(-2147483647 -1)') else if i > low(int64) then - result := ropeFormat('IL64($1)', [toRope(i)]) + result := ropef('IL64($1)', [toRope(i)]) else result := toRope('(IL64(-9223372036854775807) - IL64(1))') end; +function int32Literal(i: Int): PRope; +begin + if i = low(int32) then + // Nimrod has the same bug for the same reasons :-) + result := toRope('(-2147483647 -1)') + else + result := toRope(i) +end; + function genHexLiteral(v: PNode): PRope; // in C hex literals are unsigned (at least I think so) // so we don't generate hex literals any longer. begin - assert(v.kind in [nkIntLit..nkInt64Lit]); + if not (v.kind in [nkIntLit..nkInt64Lit]) then + internalError(v.info, 'genHexLiteral'); result := intLiteral(v.intVal) end; -function getStrLit(const s: string): PRope; +function getStrLit(m: BModule; const s: string): PRope; begin - inc(currMod.unique); - result := con('Str', toRope(currMod.unique)); - appRopeFormat(currMod.s[cfsData], - 'STRING_LITERAL($1, $2, $3);$n', + inc(gunique); + result := con('Str', toRope(gunique)); + appf(m.s[cfsData], 'STRING_LITERAL($1, $2, $3);$n', [result, makeCString(s), ToRope(length(s))]) end; @@ -45,15 +54,21 @@ var begin if ty = nil then internalError(v.info, 'genLiteral: ty is nil'); case v.kind of - nkIntLit..nkInt64Lit, nkCharLit..nkRCharLit: begin + nkCharLit..nkInt64Lit: begin case skipVarGenericRange(ty).kind of - tyChar, tyInt..tyInt64, tyNil: result := intLiteral(v.intVal); + tyChar, tyInt64, tyNil: result := intLiteral(v.intVal); + tyInt..tyInt32: begin + if (v.intVal >= low(int32)) and (v.intVal <= high(int32)) then + result := int32Literal(int32(v.intVal)) + else + result := intLiteral(v.intVal); + end; tyBool: begin if v.intVal <> 0 then result := toRope('NIM_TRUE') - else result := toRope('NIM_FALSE'); + else result := toRope('NIM_FALSE'); end; else - result := ropeFormat('(($1) $2)', [getTypeDesc( + result := ropef('(($1) $2)', [getTypeDesc(p.module, skipVarGenericRange(ty)), intLiteral(v.intVal)]) end end; @@ -61,7 +76,7 @@ begin result := toRope('0'+''); nkStrLit..nkTripleStrLit: begin if skipVarGenericRange(ty).kind = tyString then - result := ropeFormat('((string) &$1)', [getStrLit(v.strVal)]) + result := ropef('((string) &$1)', [getStrLit(p.module, v.strVal)]) else result := makeCString(v.strVal) end; @@ -81,71 +96,7 @@ begin InternalError(v.info, 'genLiteral(' +{&} nodeKindToStr[v.kind] +{&} ')'); result := nil end - end; - (* - case ty.Kind of - tyRange: result := genLiteral(p, v, ty.sons[0]); - tyInt..tyInt64, tyEnum: - result := intLiteral(v.intVal); - tyPointer, tyRef, tyPtr, tyProc: - if v.kind = nkNilLit then - result := toRope('0'+'') // 0 is better for C++ - else - result := ropeFormat('(($1) $2)', - [getTypeDesc(ty), intLiteral(v.intVal)]); - tyFloat..tyFloat128: begin - f := v.floatVal; - // BUGFIX: handle INF and NAN correctly: - if f <> f then // NAN - result := toRope('NAN') - else if f = 0.0 then - result := toRopeF(f) - else if f = 0.5 * f then - if f > 0.0 then - result := toRope('INF') - else - result := toRope('-INF') - else - result := toRopeF(f); - end; - tyString: begin // also merges constants - if v.kind = nkNilLit then result := toRope('0'+'') - else result := ropeFormat('((string) &$1)', [getStrLit(v.strVal)]); - end; - tyCString: begin - if v.kind = nkNilLit then - result := toRope('0'+'') - else if v.kind in [nkIntLit..nkInt64Lit] then begin - result := ropeFormat('((NCSTRING) $1)', [intLiteral(v.intVal)]) - end - else - result := makeCString(v.strVal) - end; - tySequence: begin - if v.kind = nkNilLit then - result := toRope('0'+'') - else if v.kind in [nkIntLit..nkInt64Lit] then - result := ropeFormat('(($1) $2)', - [getTypeDesc(ty), intLiteral(v.intVal)]) - else begin - assert(false); - result := nil // XXX: to implement - end - end; - tyChar: begin - result := toRope('''' + toCChar(Chr(int(v.intVal))) + '''') - end; - tyBool: - if v.intVal <> 0 then result := toRope('NIM_TRUE') - else result := toRope('NIM_FALSE'); - tyNil: - result := toRope('0'+''); // 0-pointer is better for C++ - tyVar: result := genLiteral(p, v, ty.sons[0]); - else begin - InternalError(v.info, 'genLiteral(' +{&} typeKindToStr[ty.kind] +{&} ')'); - result := nil - end - end*) + end end; function genLiteral(p: BProc; v: PNode): PRope; overload; @@ -160,11 +111,13 @@ begin result := 0; if CPU[hostCPU].endian = CPU[targetCPU].endian then begin for j := 0 to size-1 do - if j < length(s) then result := result or shlu(s[j], j * 8) + if j < length(s) then + result := result or shlu(Ze64(s[j]), j * 8) end else begin for j := 0 to size-1 do - if j < length(s) then result := result or shlu(s[j], (Size - 1 - j) * 8) + if j < length(s) then + result := result or shlu(Ze64(s[j]), (Size-1-j) * 8) end end; @@ -181,11 +134,11 @@ begin else frmt := '0x$1, ' end else frmt := '0x$1}$n'; - appRopeFormat(result, frmt, [toRope(toHex(cs[i], 2))]) + appf(result, frmt, [toRope(toHex(Ze64(cs[i]), 2))]) end end else - result := toRope('0x' + ToHex(bitSetToWord(cs, size), IntSize * 2)) + result := toRope('0x' + ToHex(bitSetToWord(cs, size), size * 2)) end; function genSetNode(p: BProc; n: PNode): PRope; @@ -197,9 +150,9 @@ begin toBitSet(n, cs); if size > 8 then begin result := getTempName(); - appRopeFormat(currMod.s[cfsData], - 'static $1$2 $3 = $4;', // BUGFIX - [constTok, getTypeDesc(n.typ), result, genRawSetData(cs, size)]) + appf(p.module.s[cfsData], + 'static NIM_CONST $1 $2 = $3;', + [getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)]) end else result := genRawSetData(cs, size) @@ -207,22 +160,45 @@ end; // --------------------------- assignment generator ----------------------- +function getStorageLoc(n: PNode): TStorageLoc; +begin + case n.kind of + nkSym: begin + case n.sym.kind of + skParam, skForVar, skTemp: result := OnStack; + skVar: begin + if sfGlobal in n.sym.flags then result := OnHeap + else result := OnStack + end; + else result := OnUnknown; + end + end; + //nkHiddenAddr, nkAddr: + nkDerefExpr, nkHiddenDeref: + case n.sons[0].typ.kind of + tyVar: result := OnUnknown; + tyPtr: result := OnStack; + tyRef: result := OnHeap; + else InternalError(n.info, 'getStorageLoc'); + end; + nkBracketExpr, nkDotExpr, nkObjDownConv, nkObjUpConv: + result := getStorageLoc(n.sons[0]); + else result := OnUnknown; + end +end; + function rdLoc(const a: TLoc): PRope; // 'read' location (deref if indirect) begin result := a.r; - if a.indirect > 0 then - result := ropeFormat('($2$1)', - [result, toRope(repeatChar(a.indirect, '*'))]) + if lfIndirect in a.flags then + result := ropef('(*$1 /*rdLoc*/)', [result]) end; function addrLoc(const a: TLoc): PRope; begin result := a.r; - if a.indirect = 0 then + if not (lfIndirect in a.flags) then result := con('&'+'', result) - else if a.indirect > 1 then - result := ropeFormat('($2$1)', - [result, toRope(repeatChar(a.indirect-1, '*'))]) end; function rdCharLoc(const a: TLoc): PRope; @@ -230,22 +206,22 @@ function rdCharLoc(const a: TLoc): PRope; begin result := rdLoc(a); if skipRange(a.t).kind = tyChar then - result := ropeFormat('((NU8)($1))', [result]) + result := ropef('((NU8)($1))', [result]) end; procedure genRefAssign(p: BProc; const dest, src: TLoc); begin - if (lfOnStack in dest.flags) or not (optRefcGC in gGlobalOptions) then + if (dest.s = OnStack) or not (optRefcGC in gGlobalOptions) then // location is on hardware stack - appRopeFormat(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]) - else if lfOnHeap in dest.flags then begin // location is on heap - UseMagic('asgnRef'); - appRopeFormat(p.s[cpsStmts], 'asgnRef((void**) $1, $2);$n', + appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]) + else if dest.s = OnHeap then begin // location is on heap + UseMagic(p.module, 'asgnRef'); + appf(p.s[cpsStmts], 'asgnRef((void**) $1, $2);$n', [addrLoc(dest), rdLoc(src)]) end else begin - UseMagic('unsureAsgnRef'); - appRopeFormat(p.s[cpsStmts], 'unsureAsgnRef((void**) $1, $2);$n', + UseMagic(p.module, 'unsureAsgnRef'); + appf(p.s[cpsStmts], 'unsureAsgnRef((void**) $1, $2);$n', [addrLoc(dest), rdLoc(src)]) end end; @@ -261,8 +237,7 @@ procedure genAssignment(p: BProc; const dest, src: TLoc; var ty: PType; begin; - ty := skipAbstract(dest.t); - while ty.kind = tyVar do ty := ty.sons[0]; + ty := skipVarGenericRange(dest.t); case ty.kind of tyRef: genRefAssign(p, dest, src); @@ -270,92 +245,89 @@ begin; if not (needToCopy in flags) then genRefAssign(p, dest, src) else begin - useMagic('genericSeqAssign'); // BUGFIX - appRopeFormat(p.s[cpsStmts], 'genericSeqAssign($1, $2, $3);$n', - [addrLoc(dest), rdLoc(src), genTypeInfo(currMod, dest.t)]) + useMagic(p.module, 'genericSeqAssign'); // BUGFIX + appf(p.s[cpsStmts], 'genericSeqAssign($1, $2, $3);$n', + [addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t)]) end end; tyString: begin if not (needToCopy in flags) then genRefAssign(p, dest, src) else begin - useMagic('copyString'); - if (lfOnStack in dest.flags) or not (optRefcGC in gGlobalOptions) then - // location is on hardware stack - appRopeFormat(p.s[cpsStmts], '$1 = copyString($2);$n', + useMagic(p.module, 'copyString'); + if (dest.s = OnStack) or not (optRefcGC in gGlobalOptions) then + appf(p.s[cpsStmts], '$1 = copyString($2);$n', [rdLoc(dest), rdLoc(src)]) - else if lfOnHeap in dest.flags then begin // location is on heap - useMagic('asgnRef'); - useMagic('copyString'); // BUGFIX - appRopeFormat(p.s[cpsStmts], 'asgnRef((void**) $1, copyString($2));$n', + else if dest.s = OnHeap then begin + useMagic(p.module, 'asgnRef'); + useMagic(p.module, 'copyString'); // BUGFIX + appf(p.s[cpsStmts], 'asgnRef((void**) $1, copyString($2));$n', [addrLoc(dest), rdLoc(src)]) end else begin - useMagic('unsureAsgnRef'); - useMagic('copyString'); // BUGFIX - appRopeFormat(p.s[cpsStmts], + useMagic(p.module, 'unsureAsgnRef'); + useMagic(p.module, 'copyString'); // BUGFIX + appf(p.s[cpsStmts], 'unsureAsgnRef((void**) $1, copyString($2));$n', [addrLoc(dest), rdLoc(src)]) end end end; - tyRecordConstr, tyRecord: - // BUGFIX + tyTuple: if needsComplexAssignment(dest.t) then begin - useMagic('genericAssign'); - appRopeFormat(p.s[cpsStmts], + useMagic(p.module, 'genericAssign'); + appf(p.s[cpsStmts], 'genericAssign((void*)$1, (void*)$2, $3);$n', - [addrLoc(dest), addrLoc(src), genTypeInfo(currMod, dest.t)]) + [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)]) end else - appRopeFormat(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]); + appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]); tyArray, tyArrayConstr: if needsComplexAssignment(dest.t) then begin - useMagic('genericAssign'); - appRopeFormat(p.s[cpsStmts], + useMagic(p.module, 'genericAssign'); + appf(p.s[cpsStmts], 'genericAssign((void*)$1, (void*)$2, $3);$n', - // XXX: is this correct for arrays? - [addrLoc(dest), addrLoc(src), genTypeInfo(currMod, dest.t)]) + [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)]) end else - appRopeFormat(p.s[cpsStmts], - 'memcpy((void*)$1, (const void*)$2, sizeof($1));$n', - [addrLoc(dest), addrLoc(src)]); + appf(p.s[cpsStmts], + 'memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1));$n', + [rdLoc(dest), rdLoc(src)]); tyObject: // XXX: check for subtyping? if needsComplexAssignment(dest.t) then begin - useMagic('genericAssign'); - appRopeFormat(p.s[cpsStmts], + useMagic(p.module, 'genericAssign'); + appf(p.s[cpsStmts], 'genericAssign((void*)$1, (void*)$2, $3);$n', - [addrLoc(dest), addrLoc(src), genTypeInfo(currMod, dest.t)]) + [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)]) end else - appRopeFormat(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]); + appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]); tyOpenArray: begin - // open arrays are always on the stack, really? What if a sequence is + // open arrays are always on the stack - really? What if a sequence is // passed to an open array? if needsComplexAssignment(dest.t) then begin - useMagic('genericAssignOpenArray'); - appRopeFormat(p.s[cpsStmts],// XXX: is this correct for arrays? + useMagic(p.module, 'genericAssignOpenArray'); + appf(p.s[cpsStmts],// XXX: is this correct for arrays? 'genericAssignOpenArray((void*)$1, (void*)$2, $1Len0, $3);$n', - [addrLoc(dest), addrLoc(src), genTypeInfo(currMod, dest.t)]) + [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)]) end else - appRopeFormat(p.s[cpsStmts], - 'memcpy((void*)$1, (const void*)$2, sizeof($1[0])*$1Len0);$n', - [addrLoc(dest), addrLoc(src)]); + appf(p.s[cpsStmts], + 'memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len0);$n', + [rdLoc(dest), rdLoc(src)]); end; tySet: - if getSize(ty) <= 8 then - appRopeFormat(p.s[cpsStmts], '$1 = $2;$n', - [rdLoc(dest), rdLoc(src)]) + if mapType(ty) = ctArray then + appf(p.s[cpsStmts], 'memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n', + [rdLoc(dest), rdLoc(src), toRope(getSize(dest.t))]) else - appRopeFormat(p.s[cpsStmts], 'memcpy((void*)$1, (const void*)$2, $3);$n', - [rdLoc(dest), rdLoc(src), toRope(getSize(dest.t))]); + appf(p.s[cpsStmts], '$1 = $2;$n', + [rdLoc(dest), rdLoc(src)]); tyPtr, tyPointer, tyChar, tyBool, tyProc, tyEnum, tyCString, tyInt..tyFloat128, tyRange: - appRopeFormat(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]); + appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]); else InternalError('genAssignment(' + typeKindToStr[ty.kind] + ')') end @@ -367,7 +339,7 @@ procedure expr(p: BProc; e: PNode; var d: TLoc); forward; function initLocExpr(p: BProc; e: PNode): TLoc; begin - result := initLoc(locNone, e.typ); + result := initLoc(locNone, getUniqueType(e.typ), OnUnknown); expr(p, e, result) end; @@ -392,7 +364,7 @@ var a: TLoc; begin if d.k <> locNone then begin // need to generate an assignment here - a := initLoc(locExpr, t); + a := initLoc(locExpr, getUniqueType(t), OnUnknown); a.r := r; if lfNoDeepCopy in d.flags then genAssignment(p, d, a, {@set}[]) @@ -402,7 +374,7 @@ begin else begin // we cannot call initLoc() here as that would overwrite // the flags field! d.k := locExpr; - d.t := t; + d.t := getUniqueType(t); d.r := r; d.a := -1 end @@ -413,12 +385,11 @@ procedure binaryStmt(p: BProc; e: PNode; var d: TLoc; var a, b: TLoc; begin - assert(d.k = locNone); - if magic <> '' then - useMagic(magic); + if (d.k <> locNone) then InternalError(e.info, 'binaryStmt'); + if magic <> '' then useMagic(p.module, magic); a := InitLocExpr(p, e.sons[1]); b := InitLocExpr(p, e.sons[2]); - appRopeFormat(p.s[cpsStmts], frmt, [rdLoc(a), rdLoc(b)]); + appf(p.s[cpsStmts], frmt, [rdLoc(a), rdLoc(b)]); freeTemp(p, a); freeTemp(p, b) end; @@ -428,12 +399,11 @@ procedure binaryStmtChar(p: BProc; e: PNode; var d: TLoc; var a, b: TLoc; begin - assert(d.k = locNone); - if magic <> '' then - useMagic(magic); + if (d.k <> locNone) then InternalError(e.info, 'binaryStmtChar'); + if magic <> '' then useMagic(p.module, magic); a := InitLocExpr(p, e.sons[1]); b := InitLocExpr(p, e.sons[2]); - appRopeFormat(p.s[cpsStmts], frmt, [rdCharLoc(a), rdCharLoc(b)]); + appf(p.s[cpsStmts], frmt, [rdCharLoc(a), rdCharLoc(b)]); freeTemp(p, a); freeTemp(p, b) end; @@ -443,13 +413,12 @@ procedure binaryExpr(p: BProc; e: PNode; var d: TLoc; var a, b: TLoc; begin - if magic <> '' then - useMagic(magic); + if magic <> '' then useMagic(p.module, magic); assert(e.sons[1].typ <> nil); assert(e.sons[2].typ <> nil); a := InitLocExpr(p, e.sons[1]); b := InitLocExpr(p, e.sons[2]); - putIntoDest(p, d, e.typ, ropeFormat(frmt, [rdLoc(a), rdLoc(b)])); + putIntoDest(p, d, e.typ, ropef(frmt, [rdLoc(a), rdLoc(b)])); if d.k <> locExpr then begin // BACKPORT freeTemp(p, a); freeTemp(p, b) @@ -461,13 +430,12 @@ procedure binaryExprChar(p: BProc; e: PNode; var d: TLoc; var a, b: TLoc; begin - if magic <> '' then - useMagic(magic); + if magic <> '' then useMagic(p.module, magic); assert(e.sons[1].typ <> nil); assert(e.sons[2].typ <> nil); a := InitLocExpr(p, e.sons[1]); b := InitLocExpr(p, e.sons[2]); - putIntoDest(p, d, e.typ, ropeFormat(frmt, [rdCharLoc(a), rdCharLoc(b)])); + putIntoDest(p, d, e.typ, ropef(frmt, [rdCharLoc(a), rdCharLoc(b)])); if d.k <> locExpr then begin // BACKPORT freeTemp(p, a); freeTemp(p, b) @@ -479,10 +447,9 @@ procedure unaryExpr(p: BProc; e: PNode; var d: TLoc; var a: TLoc; begin - if magic <> '' then - useMagic(magic); + if magic <> '' then useMagic(p.module, magic); a := InitLocExpr(p, e.sons[1]); - putIntoDest(p, d, e.typ, ropeFormat(frmt, [rdLoc(a)])); + putIntoDest(p, d, e.typ, ropef(frmt, [rdLoc(a)])); if d.k <> locExpr then // BACKPORT freeTemp(p, a) end; @@ -492,10 +459,9 @@ procedure unaryExprChar(p: BProc; e: PNode; var d: TLoc; var a: TLoc; begin - if magic <> '' then - useMagic(magic); + if magic <> '' then useMagic(p.module, magic); a := InitLocExpr(p, e.sons[1]); - putIntoDest(p, d, e.typ, ropeFormat(frmt, [rdCharLoc(a)])); + putIntoDest(p, d, e.typ, ropef(frmt, [rdCharLoc(a)])); if d.k <> locExpr then // BACKPORT freeTemp(p, a) end; @@ -510,15 +476,15 @@ const '($1 + $2)', '($1 - $2)', '($1 * $2)', '($1 / $2)', '($1 % $2)' ); binArithTab: array [mShrI..mXor] of string = ( - '(NS)((NU)($1) >> (NU)($2))', // ShrI - '(NS)((NU)($1) << (NU)($2))', // ShlI + '(NI)((NU)($1) >> (NU)($2))', // ShrI + '(NI)((NU)($1) << (NU)($2))', // ShlI '($1 & $2)', // BitandI '($1 | $2)', // BitorI '($1 ^ $2)', // BitxorI '(($1 <= $2) ? $1 : $2)', // MinI '(($1 >= $2) ? $1 : $2)', // MaxI - '(NS64)((NU64)($1) >> (NU64)($2))', // ShrI64 - '(NS64)((NU64)($1) << (NU64)($2))', // ShlI64 + '(NI64)((NU64)($1) >> (NU64)($2))', // ShrI64 + '(NI64)((NU64)($1) << (NU64)($2))', // ShlI64 '($1 & $2)', // BitandI64 '($1 | $2)', // BitorI64 '($1 ^ $2)', // BitxorI64 @@ -532,16 +498,16 @@ const '(($1 <= $2) ? $1 : $2)', // MinF64 '(($1 >= $2) ? $1 : $2)', // MaxF64 - '(NS)((NU)($1) + (NU)($2))', // AddU - '(NS)((NU)($1) - (NU)($2))', // SubU - '(NS)((NU)($1) * (NU)($2))', // MulU - '(NS)((NU)($1) / (NU)($2))', // DivU - '(NS)((NU)($1) % (NU)($2))', // ModU - '(NS64)((NU64)($1) + (NU64)($2))', // AddU64 - '(NS64)((NU64)($1) - (NU64)($2))', // SubU64 - '(NS64)((NU64)($1) * (NU64)($2))', // MulU64 - '(NS64)((NU64)($1) / (NU64)($2))', // DivU64 - '(NS64)((NU64)($1) % (NU64)($2))', // ModU64 + '(NI)((NU)($1) + (NU)($2))', // AddU + '(NI)((NU)($1) - (NU)($2))', // SubU + '(NI)((NU)($1) * (NU)($2))', // MulU + '(NI)((NU)($1) / (NU)($2))', // DivU + '(NI)((NU)($1) % (NU)($2))', // ModU + '(NI64)((NU64)($1) + (NU64)($2))', // AddU64 + '(NI64)((NU64)($1) - (NU64)($2))', // SubU64 + '(NI64)((NU64)($1) * (NU64)($2))', // MulU64 + '(NI64)((NU64)($1) / (NU64)($2))', // DivU64 + '(NI64)((NU64)($1) % (NU64)($2))', // ModU64 '($1 == $2)', // EqI '($1 <= $2)', // LeI @@ -587,11 +553,16 @@ const '-($1)', // UnaryMinusF64 '($1 > 0? ($1) : -($1))', // AbsF64; BUGFIX: fabs() makes problems for Tiny C, so we don't use it - '((NS)(NU)($1))', // Ze - '((NS64)(NU64)($1))', // Ze64 - '((NS8)(NU8)(NU)($1))', // ToU8 - '((NS16)(NU16)(NU)($1))', // ToU16 - '((NS32)(NU32)(NU64)($1))', // ToU32 + '((NI)(NU)(NU8)($1))', // mZe8ToI + '((NI64)(NU64)(NU8)($1))', // mZe8ToI64 + '((NI)(NU)(NU16)($1))', // mZe16ToI + '((NI64)(NU64)(NU16)($1))', // mZe16ToI64 + '((NI64)(NU64)(NU32)($1))', // mZe32ToI64 + '((NI64)(NU64)(NU)($1))', // mZeIToI64 + + '((NI8)(NU8)(NU)($1))', // ToU8 + '((NI16)(NU16)(NU)($1))', // ToU16 + '((NI32)(NU32)(NU64)($1))', // ToU32 '((double) ($1))', // ToFloat '((double) ($1))', // ToBiggestFloat @@ -641,29 +612,42 @@ procedure genDeref(p: BProc; e: PNode; var d: TLoc); var a: TLoc; begin - a := initLocExpr(p, e.sons[0]); - putIntoDest(p, d, a.t.sons[0], ropeFormat('(*$1)', [rdLoc(a)])); - if d.k <> locExpr then // BACKPORT - freeTemp(p, a) + if mapType(e.sons[0].typ) = ctArray then + expr(p, e.sons[0], d) + else begin + a := initLocExpr(p, e.sons[0]); + case skipGeneric(a.t).kind of + tyRef: d.s := OnHeap; + tyVar: d.s := OnUnknown; + tyPtr: d.s := OnStack; + else InternalError(e.info, 'genDeref ' + typekindToStr[a.t.kind]); + end; + putIntoDest(p, d, a.t.sons[0], ropef('(*$1)', [rdLoc(a)])); + end end; -procedure fillInLocation(var a, d: TLoc); +procedure genAddr(p: BProc; e: PNode; var d: TLoc); +var + a: TLoc; begin - case skipAbstract(a.t).kind of - tyRef: begin - if d.k = locNone then d.flags := {@set}[lfOnHeap]; - a.r := ropeFormat('(*$1)', [a.r]) - end; - tyPtr: begin - if d.k = locNone then d.flags := {@set}[lfOnUnknown]; - a.r := ropeFormat('(*$1)', [a.r]) - end; - // element has same flags as the array (except lfIndirect): - else - if d.k = locNone then inheritStorage(d, a) + if mapType(e.sons[0].typ) = ctArray then + expr(p, e.sons[0], d) + else begin + a := InitLocExpr(p, e.sons[0]); + putIntoDest(p, d, e.typ, addrLoc(a)); + if d.k <> locExpr then freeTemp(p, a) end end; +function genRecordFieldAux(p: BProc; e: PNode; var d, a: TLoc): PType; +begin + a := initLocExpr(p, e.sons[0]); + if (e.sons[1].kind <> nkSym) then InternalError(e.info, 'genRecordFieldAux'); + if d.k = locNone then d.s := a.s; + {@discard} getTypeDesc(p.module, a.t); // fill the record's fields.loc + result := getUniqueType(a.t); +end; + procedure genRecordField(p: BProc; e: PNode; var d: TLoc); var a: TLoc; @@ -671,45 +655,76 @@ var ty: PType; r: PRope; begin - a := initLocExpr(p, e.sons[0]); - assert(e.sons[1].kind = nkSym); - f := e.sons[1].sym; - - if d.k = locNone then inheritStorage(d, a); - // for objects we have to search the hierarchy for determining - // how much ``Sup`` we need: - ty := skipAbstract(a.t); - while true do begin - case ty.kind of - tyRef: begin - if d.k = locNone then d.flags := {@set}[lfOnHeap]; - inc(a.indirect); - end; - tyPtr: begin - if d.k = locNone then d.flags := {@set}[lfOnUnknown]; - inc(a.indirect); - end; - tyVar: begin - if d.k = locNone then d.flags := {@set}[lfOnUnknown]; - end; - else break - end; - ty := skipAbstract(ty.sons[0]); - end; + ty := genRecordFieldAux(p, e, d, a); r := rdLoc(a); - {@discard} getTypeDesc(ty); // fill the record's fields.loc + f := e.sons[1].sym; field := nil; while ty <> nil do begin - assert(ty.kind in [tyRecord, tyObject]); + assert(ty.kind in [tyTuple, tyObject]); field := lookupInRecord(ty.n, f.name); if field <> nil then break; if gCmd <> cmdCompileToCpp then app(r, '.Sup'); - ty := ty.sons[0] + ty := GetUniqueType(ty.sons[0]); end; - assert((field <> nil) and (field.loc.r <> nil)); - appRopeFormat(r, '.$1', [field.loc.r]); + if field = nil then InternalError(e.info, 'genRecordField'); + if field.loc.r = nil then InternalError(e.info, 'genRecordField'); + appf(r, '.$1', [field.loc.r]); putIntoDest(p, d, field.typ, r); - // freeTemp(p, a) // BACKPORT +end; + +procedure genInExprAux(p: BProc; e: PNode; var a, b, d: TLoc); forward; + +procedure genCheckedRecordField(p: BProc; e: PNode; var d: TLoc); +var + a, u, v, test: TLoc; + f, field, op: PSym; + ty: PType; + r: PRope; + i: int; + it: PNode; +begin + if optFieldCheck in p.options then begin + useMagic(p.module, 'raiseFieldError'); + ty := genRecordFieldAux(p, e.sons[0], d, a); + r := rdLoc(a); + f := e.sons[0].sons[1].sym; + field := nil; + while ty <> nil do begin + assert(ty.kind in [tyTuple, tyObject]); + field := lookupInRecord(ty.n, f.name); + if field <> nil then break; + if gCmd <> cmdCompileToCpp then app(r, '.Sup'); + ty := getUniqueType(ty.sons[0]) + end; + if field = nil then InternalError(e.info, 'genCheckedRecordField'); + if field.loc.r = nil then InternalError(e.info, 'genCheckedRecordField'); + // generate the checks: + for i := 1 to sonsLen(e)-1 do begin + it := e.sons[i]; + assert(it.kind = nkCall); + assert(it.sons[0].kind = nkSym); + op := it.sons[0].sym; + if op.magic = mNot then it := it.sons[1]; + assert(it.sons[2].kind = nkSym); + test := initLoc(locNone, it.typ, OnStack); + u := InitLocExpr(p, it.sons[1]); + v := initLoc(locExpr, it.sons[2].typ, OnUnknown); + v.r := ropef('$1.$2', [r, it.sons[2].sym.loc.r]); + genInExprAux(p, it, u, v, test); + if op.magic = mNot then + appf(p.s[cpsStmts], + 'if ($1) raiseFieldError(((string) &$2));$n', + [rdLoc(test), getStrLit(p.module, field.name.s)]) + else + appf(p.s[cpsStmts], + 'if (!($1)) raiseFieldError(((string) &$2));$n', + [rdLoc(test), getStrLit(p.module, field.name.s)]) + end; + appf(r, '.$1', [field.loc.r]); + putIntoDest(p, d, field.typ, r); + end + else + genRecordField(p, e.sons[0], d) end; procedure genArrayElem(p: BProc; e: PNode; var d: TLoc); @@ -720,19 +735,18 @@ var begin a := initLocExpr(p, e.sons[0]); b := initLocExpr(p, e.sons[1]); - ty := skipAbstract(a.t); - if ty.kind in [tyRef, tyPtr] then ty := skipAbstract(ty.sons[0]); + ty := skipPtrsGeneric(skipVarGenericRange(a.t)); first := intLiteral(firstOrd(ty)); // emit range check: if optBoundsCheck in p.options then if b.k <> locImmediate then begin // semantic pass has already checked: - useMagic('raiseIndexError'); - appRopeFormat(p.s[cpsStmts], + useMagic(p.module, 'raiseIndexError'); + appf(p.s[cpsStmts], 'if ($1 < $2 || $1 > $3) raiseIndexError();$n', [rdCharLoc(b), first, intLiteral(lastOrd(ty))]) end; - fillInLocation(a, d); - putIntoDest(p, d, elemType(skipVarGeneric(ty)), ropeFormat('$1[($2)-$3]', + if d.k = locNone then d.s := a.s; + putIntoDest(p, d, elemType(skipVarGeneric(ty)), ropef('$1[($2)-$3]', [rdLoc(a), rdCharLoc(b), first])); // freeTemp(p, a); // backport // freeTemp(p, b) @@ -745,9 +759,9 @@ var begin a := initLocExpr(p, e.sons[0]); b := initLocExpr(p, e.sons[1]); - ty := skipAbstract(a.t); - fillInLocation(a, d); - putIntoDest(p, d, elemType(skipVarGeneric(ty)), ropeFormat('$1[$2]', + ty := skipVarGenericRange(a.t); + if d.k = locNone then d.s := a.s; + putIntoDest(p, d, elemType(skipVarGeneric(ty)), ropef('$1[$2]', [rdLoc(a), rdCharLoc(b)])); // freeTemp(p, a); // backport // freeTemp(p, b) @@ -760,14 +774,13 @@ begin a := initLocExpr(p, e.sons[0]); b := initLocExpr(p, e.sons[1]); // emit range check: - if optBoundsCheck in p.options then - if b.k <> locImmediate then begin // semantic pass has already checked: - useMagic('raiseIndexError'); - appRopeFormat(p.s[cpsStmts], - 'if ((NU)($1) > (NU)($2Len0)) raiseIndexError();$n', [rdLoc(b), a.r]) - end; - if d.k = locNone then inheritStorage(d, a); - putIntoDest(p, d, elemType(skipVarGeneric(a.t)), ropeFormat('$1[$2]', + if optBoundsCheck in p.options then begin + useMagic(p.module, 'raiseIndexError'); + appf(p.s[cpsStmts], + 'if ((NU)($1) > (NU)($2Len0)) raiseIndexError();$n', [rdLoc(b), a.r]) + end; + if d.k = locNone then d.s := a.s; + putIntoDest(p, d, elemType(skipVarGeneric(a.t)), ropef('$1[$2]', [rdLoc(a), rdCharLoc(b)])); // freeTemp(p, a); // backport // freeTemp(p, b) @@ -780,26 +793,24 @@ var begin a := initLocExpr(p, e.sons[0]); b := initLocExpr(p, e.sons[1]); - ty := skipAbstract(a.t); - if ty.kind in [tyRef, tyPtr] then ty := skipAbstract(ty.sons[0]); + ty := skipVarGenericRange(a.t); + if ty.kind in [tyRef, tyPtr] then ty := skipVarGenericRange(ty.sons[0]); // emit range check: - if optBoundsCheck in p.options then - if b.k <> locImmediate then begin // semantic pass has already checked: - useMagic('raiseIndexError'); - if ty.kind = tyString then - appRopeFormat(p.s[cpsStmts], - 'if ((NU)($1) > (NU)($2->len)) raiseIndexError();$n', - [rdLoc(b), rdLoc(a)]) - else - appRopeFormat(p.s[cpsStmts], - 'if ((NU)($1) >= (NU)($2->len)) raiseIndexError();$n', - [rdLoc(b), rdLoc(a)]) - end; - // element has same flags as the array (except lfIndirect): - if d.k = locNone then d.flags := {@set}[lfOnHeap]; - if skipAbstract(a.t).kind in [tyRef, tyPtr] then - a.r := ropeFormat('(*$1)', [a.r]); - putIntoDest(p, d, elemType(skipVarGeneric(a.t)), ropeFormat('$1->data[$2]', + if optBoundsCheck in p.options then begin + useMagic(p.module, 'raiseIndexError'); + if ty.kind = tyString then + appf(p.s[cpsStmts], + 'if ((NU)($1) > (NU)($2->len)) raiseIndexError();$n', + [rdLoc(b), rdLoc(a)]) + else + appf(p.s[cpsStmts], + 'if ((NU)($1) >= (NU)($2->len)) raiseIndexError();$n', + [rdLoc(b), rdLoc(a)]) + end; + if d.k = locNone then d.s := OnHeap; + if skipVarGenericRange(a.t).kind in [tyRef, tyPtr] then + a.r := ropef('(*$1)', [a.r]); + putIntoDest(p, d, elemType(skipVarGeneric(a.t)), ropef('$1->data[$2]', [rdLoc(a), rdCharLoc(b)])); // freeTemp(p, a); // backport // freeTemp(p, b) @@ -834,9 +845,9 @@ begin expr(p, e.sons[1], tmp); L := getLabel(p); if m = mOr then - appRopeFormat(p.s[cpsStmts], 'if ($1) goto $2;$n', [rdLoc(tmp), L]) + appf(p.s[cpsStmts], 'if ($1) goto $2;$n', [rdLoc(tmp), L]) else // mAnd: - appRopeFormat(p.s[cpsStmts], 'if (!($1)) goto $2;$n', [rdLoc(tmp), L]); + appf(p.s[cpsStmts], 'if (!($1)) goto $2;$n', [rdLoc(tmp), L]); expr(p, e.sons[2], tmp); fixLabel(p, L); if d.k = locNone then @@ -874,10 +885,10 @@ begin nkElifExpr: begin a := initLocExpr(p, it.sons[0]); Lelse := getLabel(p); - appRopeFormat(p.s[cpsStmts], 'if (!$1) goto $2;$n', [rdLoc(a), Lelse]); + appf(p.s[cpsStmts], 'if (!$1) goto $2;$n', [rdLoc(a), Lelse]); freeTemp(p, a); expr(p, it.sons[1], tmp); - appRopeFormat(p.s[cpsStmts], 'goto $1;$n', [Lend]); + appf(p.s[cpsStmts], 'goto $1;$n', [Lend]); fixLabel(p, Lelse); end; nkElseExpr: begin @@ -905,9 +916,12 @@ var op, list: TLoc; len, i: int; begin +{@emit + a := []; +} op := initLocExpr(p, t.sons[0]); pl := con(op.r, '('+''); - typ := t.sons[0].typ; + typ := getUniqueType(t.sons[0].typ); assert(typ.kind = tyProc); invalidRetType := isInvalidReturnType(typ.sons[0]); len := sonsLen(t); @@ -918,8 +932,8 @@ begin if (i < sonsLen(typ)) then begin assert(typ.n.sons[i].kind = nkSym); param := typ.n.sons[i].sym; - if usePtrPassing(param) then app(pl, addrLoc(a[i-1])) - else app(pl, rdLoc(a[i-1])); + if ccgIntroducedPtr(param) then app(pl, addrLoc(a[i-1])) + else app(pl, rdLoc(a[i-1])); end else app(pl, rdLoc(a[i-1])); @@ -928,7 +942,7 @@ begin end; if (typ.sons[0] <> nil) and invalidRetType then begin if d.k = locNone then d := getTemp(p, typ.sons[0]); - app(pl, addrLoc(d)) + app(pl, addrLoc(d)); end; app(pl, ')'+''); for i := 0 to high(a) do @@ -938,12 +952,12 @@ begin if d.k = locNone then d := getTemp(p, typ.sons[0]); assert(d.t <> nil); // generate an assignment to d: - list := initLoc(locCall, nil); + list := initLoc(locCall, nil, OnUnknown); list.r := pl; genAssignment(p, d, list, {@set}[]) // no need for deep copying end else - appRopeFormat(p.s[cpsStmts], '$1;$n', [pl]) + appf(p.s[cpsStmts], '$1;$n', [pl]) end; procedure genStrConcat(p: BProc; e: PNode; var d: TLoc); @@ -969,30 +983,33 @@ var appends, lens: PRope; L, i: int; begin - useMagic('rawNewString'); + useMagic(p.module, 'rawNewString'); tmp := getTemp(p, e.typ); L := 0; appends := nil; lens := nil; +{@emit + a := []; +} setLength(a, sonsLen(e)-1); for i := 0 to sonsLen(e)-2 do begin // compute the length expression: a[i] := initLocExpr(p, e.sons[i+1]); - if skipAbstract(e.sons[i+1].Typ).kind = tyChar then begin + if skipVarGenericRange(e.sons[i+1].Typ).kind = tyChar then begin Inc(L); - useMagic('appendChar'); - appRopeFormat(appends, 'appendChar($1, $2);$n', [tmp.r, rdLoc(a[i])]) + useMagic(p.module, 'appendChar'); + appf(appends, 'appendChar($1, $2);$n', [tmp.r, rdLoc(a[i])]) end else begin if e.sons[i+1].kind in [nkStrLit..nkTripleStrLit] then // string literal? Inc(L, length(e.sons[i+1].strVal)) else - appRopeFormat(lens, '$1->len + ', [rdLoc(a[i])]); - useMagic('appendString'); - appRopeFormat(appends, 'appendString($1, $2);$n', [tmp.r, rdLoc(a[i])]) + appf(lens, '$1->len + ', [rdLoc(a[i])]); + useMagic(p.module, 'appendString'); + appf(appends, 'appendString($1, $2);$n', [tmp.r, rdLoc(a[i])]) end end; - appRopeFormat(p.s[cpsStmts], '$1 = rawNewString($2$3);$n', + appf(p.s[cpsStmts], '$1 = rawNewString($2$3);$n', [tmp.r, lens, toRope(L)]); app(p.s[cpsStmts], appends); for i := 0 to high(a) do @@ -1023,32 +1040,35 @@ var appends, lens: PRope; begin assert(d.k = locNone); - useMagic('resizeString'); + useMagic(p.module, 'resizeString'); L := 0; appends := nil; lens := nil; +{@emit + a := []; +} setLength(a, sonsLen(e)-1); expr(p, e.sons[1], a[0]); for i := 0 to sonsLen(e)-3 do begin // compute the length expression: a[i+1] := initLocExpr(p, e.sons[i+2]); - if skipAbstract(e.sons[i+2].Typ).kind = tyChar then begin + if skipVarGenericRange(e.sons[i+2].Typ).kind = tyChar then begin Inc(L); - useMagic('appendChar'); - appRopeFormat(appends, 'appendChar($1, $2);$n', + useMagic(p.module, 'appendChar'); + appf(appends, 'appendChar($1, $2);$n', [rdLoc(a[0]), rdLoc(a[i+1])]) end else begin if e.sons[i+2].kind in [nkStrLit..nkTripleStrLit] then // string literal? Inc(L, length(e.sons[i+2].strVal)) else - appRopeFormat(lens, '$1->len + ', [rdLoc(a[i+1])]); - useMagic('appendString'); - appRopeFormat(appends, 'appendString($1, $2);$n', + appf(lens, '$1->len + ', [rdLoc(a[i+1])]); + useMagic(p.module, 'appendString'); + appf(appends, 'appendString($1, $2);$n', [rdLoc(a[0]), rdLoc(a[i+1])]) end end; - appRopeFormat(p.s[cpsStmts], '$1 = resizeString($1, $2$3);$n', + appf(p.s[cpsStmts], '$1 = resizeString($1, $2$3);$n', [rdLoc(a[0]), lens, toRope(L)]); app(p.s[cpsStmts], appends); for i := 0 to high(a) do @@ -1062,16 +1082,15 @@ procedure genSeqElemAppend(p: BProc; e: PNode; var d: TLoc); var a, b, dest: TLoc; begin - useMagic('incrSeq'); + useMagic(p.module, 'incrSeq'); a := InitLocExpr(p, e.sons[1]); b := InitLocExpr(p, e.sons[2]); - appRopeFormat(p.s[cpsStmts], + appf(p.s[cpsStmts], '$1 = ($2) incrSeq((TGenericSeq*) $1, sizeof($3));$n', - [rdLoc(a), getTypeDesc(skipVarGeneric(e.sons[1].typ)), - getTypeDesc(skipVarGeneric(e.sons[2].Typ))]); - dest := initLoc(locExpr, b.t); - dest.flags := {@set}[lfOnHeap]; - dest.r := ropeFormat('$1->data[$1->len-1]', [rdLoc(a)]); + [rdLoc(a), getTypeDesc(p.module, skipVarGeneric(e.sons[1].typ)), + getTypeDesc(p.module, skipVarGeneric(e.sons[2].Typ))]); + dest := initLoc(locExpr, b.t, OnHeap); + dest.r := ropef('$1->data[$1->len-1]', [rdLoc(a)]); genAssignment(p, dest, b, {@set}[needToCopy]); freeTemp(p, a); freeTemp(p, b) @@ -1082,22 +1101,20 @@ var a, b: TLoc; reftype, bt: PType; begin - useMagic('newObj'); - refType := skipAbstract(e.sons[1].typ); - if refType.kind = tyVar then refType := skipAbstract(refType.sons[0]); + useMagic(p.module, 'newObj'); + refType := skipVarGenericRange(e.sons[1].typ); a := InitLocExpr(p, e.sons[1]); - b := initLoc(locExpr, a.t); - b.flags := {@set}[lfOnHeap]; - b.r := ropeFormat('($1) newObj($2, sizeof($3))', - [getTypeDesc(reftype), genTypeInfo(currMod, refType), - getTypeDesc(skipAbstract(reftype.sons[0]))]); + b := initLoc(locExpr, a.t, OnHeap); + b.r := ropef('($1) newObj($2, sizeof($3))', + [getTypeDesc(p.module, reftype), genTypeInfo(p.module, refType), + getTypeDesc(p.module, skipGenericRange(reftype.sons[0]))]); genAssignment(p, a, b, {@set}[]); // set the object type: - bt := skipAbstract(refType.sons[0]); + bt := skipGenericRange(refType.sons[0]); if containsObject(bt) then begin - useMagic('objectInit'); - appRopeFormat(p.s[cpsStmts], 'objectInit($1, $2);$n', - [rdLoc(a), genTypeInfo(currMod, bt)]) + useMagic(p.module, 'objectInit'); + appf(p.s[cpsStmts], 'objectInit($1, $2);$n', + [rdLoc(a), genTypeInfo(p.module, bt)]) end; freeTemp(p, a) end; @@ -1108,26 +1125,24 @@ var refType, bt: PType; ti: PRope; begin - useMagic('newObj'); - refType := skipAbstract(e.sons[1].typ); - if refType.kind = tyVar then refType := skipAbstract(refType.sons[0]); + useMagic(p.module, 'newObj'); + refType := skipVarGenericRange(e.sons[1].typ); a := InitLocExpr(p, e.sons[1]); f := InitLocExpr(p, e.sons[2]); - b := initLoc(locExpr, a.t); - b.flags := {@set}[lfOnHeap]; - ti := genTypeInfo(currMod, refType); - appRopeFormat(currMod.s[cfsTypeInit3], '$1->finalizer = (void*)$2;$n', [ + b := initLoc(locExpr, a.t, OnHeap); + ti := genTypeInfo(p.module, refType); + appf(p.module.s[cfsTypeInit3], '$1->finalizer = (void*)$2;$n', [ ti, rdLoc(f)]); - b.r := ropeFormat('($1) newObj($2, sizeof($3))', - [getTypeDesc(refType), ti, - getTypeDesc(skipAbstract(reftype.sons[0]))]); + b.r := ropef('($1) newObj($2, sizeof($3))', + [getTypeDesc(p.module, refType), ti, + getTypeDesc(p.module, skipGenericRange(reftype.sons[0]))]); genAssignment(p, a, b, {@set}[]); // set the object type: - bt := skipAbstract(refType.sons[0]); + bt := skipGenericRange(refType.sons[0]); if containsObject(bt) then begin - useMagic('objectInit'); - appRopeFormat(p.s[cpsStmts], 'objectInit($1, $2);$n', - [rdLoc(a), genTypeInfo(currMod, bt)]) + useMagic(p.module, 'objectInit'); + appf(p.s[cpsStmts], 'objectInit($1, $2);$n', + [rdLoc(a), genTypeInfo(p.module, bt)]) end; freeTemp(p, a); freeTemp(p, f) @@ -1139,67 +1154,92 @@ var t: PType; begin a := InitLocExpr(p, e.sons[1]); - t := skipAbstract(e.sons[1].typ); + t := skipVarGenericRange(e.sons[1].typ); case t.kind of tyInt..tyInt64: begin - UseMagic('reprInt'); - putIntoDest(p, d, e.typ, ropeFormat('reprInt($1)', [rdLoc(a)])) + UseMagic(p.module, 'reprInt'); + putIntoDest(p, d, e.typ, ropef('reprInt($1)', [rdLoc(a)])) end; tyFloat..tyFloat128: begin - UseMagic('reprFloat'); - putIntoDest(p, d, e.typ, ropeFormat('reprFloat($1)', [rdLoc(a)])) + UseMagic(p.module, 'reprFloat'); + putIntoDest(p, d, e.typ, ropef('reprFloat($1)', [rdLoc(a)])) end; tyBool: begin - UseMagic('reprBool'); - putIntoDest(p, d, e.typ, ropeFormat('reprBool($1)', [rdLoc(a)])) + UseMagic(p.module, 'reprBool'); + putIntoDest(p, d, e.typ, ropef('reprBool($1)', [rdLoc(a)])) end; tyChar: begin - UseMagic('reprChar'); - putIntoDest(p, d, e.typ, ropeFormat('reprChar($1)', [rdLoc(a)])) + UseMagic(p.module, 'reprChar'); + putIntoDest(p, d, e.typ, ropef('reprChar($1)', [rdLoc(a)])) end; tyEnum: begin - UseMagic('reprEnum'); + UseMagic(p.module, 'reprEnum'); putIntoDest(p, d, e.typ, - ropeFormat('reprEnum($1, $2)', [rdLoc(a), genTypeInfo(currMod, t)])) + ropef('reprEnum($1, $2)', [rdLoc(a), genTypeInfo(p.module, t)])) end; tyString: begin - UseMagic('reprStr'); - putIntoDest(p, d, e.typ, ropeFormat('reprStr($1)', [rdLoc(a)])) + UseMagic(p.module, 'reprStr'); + putIntoDest(p, d, e.typ, ropef('reprStr($1)', [rdLoc(a)])) end; tySet: begin - useMagic('reprSet'); - putIntoDest(p, d, e.typ, ropeFormat('reprSet($1, $2)', - [rdLoc(a), genTypeInfo(currMod, t)])) + useMagic(p.module, 'reprSet'); + putIntoDest(p, d, e.typ, ropef('reprSet($1, $2)', + [rdLoc(a), genTypeInfo(p.module, t)])) end; - tyCString, tyArray, tyOpenArray, tyArrayConstr, - tyRef, tyPtr, tyPointer, tyNil: begin - useMagic('reprAny'); - putIntoDest(p, d, e.typ, ropeFormat('reprAny($1, $2)', - [rdLoc(a), genTypeInfo(currMod, t)])) + tyOpenArray: begin + useMagic(p.module, 'reprOpenArray'); + case a.t.kind of + tyOpenArray: + putIntoDest(p, d, e.typ, ropef('$1, $1Len0', [rdLoc(a)])); + tyString, tySequence: + putIntoDest(p, d, e.typ, ropef('$1->data, $1->len', [rdLoc(a)])); + tyArray, tyArrayConstr: + putIntoDest(p, d, e.typ, ropef('$1, $2', + [rdLoc(a), toRope(lengthOrd(a.t))])); + else InternalError(e.sons[0].info, 'genRepr()') + end; + putIntoDest(p, d, e.typ, ropef('reprOpenArray($1, $2)', + [rdLoc(d), genTypeInfo(p.module, elemType(t))])) + end; + tyCString, tyArray, tyArrayConstr, + tyRef, tyPtr, tyPointer, tyNil, tySequence: begin + useMagic(p.module, 'reprAny'); + putIntoDest(p, d, e.typ, ropef('reprAny($1, $2)', + [rdLoc(a), genTypeInfo(p.module, t)])) end else begin - useMagic('reprAny'); - putIntoDest(p, d, e.typ, ropeFormat('reprAny($1, $2)', - [addrLoc(a), genTypeInfo(currMod, t)])) + useMagic(p.module, 'reprAny'); + putIntoDest(p, d, e.typ, ropef('reprAny($1, $2)', + [addrLoc(a), genTypeInfo(p.module, t)])) end end; if d.k <> locExpr then freeTemp(p, a); end; +procedure genDollar(p: BProc; n: PNode; var d: TLoc; const magic, frmt: string); +var + a: TLoc; +begin + a := InitLocExpr(p, n.sons[1]); + UseMagic(p.module, magic); + putIntoDest(p, d, n.typ, ropef(frmt, [rdLoc(a)])) +end; + procedure genArrayLen(p: BProc; e: PNode; var d: TLoc; op: TMagic); var typ: PType; begin - typ := skipAbstract(e.sons[1].Typ); - if typ.kind in [tyRef, tyPtr, tyVar] then - typ := skipAbstract(typ.sons[0]); + typ := skipPtrsGeneric(e.sons[1].Typ); case typ.kind of - tyOpenArray: + tyOpenArray: begin + while e.sons[1].kind = nkPassAsOpenArray do + e.sons[1] := e.sons[1].sons[0]; if op = mHigh then unaryExpr(p, e, d, '', '($1Len0-1)') else - unaryExpr(p, e, d, '', '$1Len0'); + unaryExpr(p, e, d, '', '$1Len0/*len*/'); + end; tyString, tySequence: if op = mHigh then unaryExpr(p, e, d, '', '($1->len-1)') @@ -1223,13 +1263,14 @@ var t: PType; begin assert(d.k = locNone); - useMagic('setLengthSeq'); + useMagic(p.module, 'setLengthSeq'); a := InitLocExpr(p, e.sons[1]); b := InitLocExpr(p, e.sons[2]); t := skipVarGeneric(e.sons[1].typ); - appRopeFormat(p.s[cpsStmts], + appf(p.s[cpsStmts], '$1 = ($3) setLengthSeq((TGenericSeq*) ($1), sizeof($4), $2);$n', - [rdLoc(a), rdLoc(b), getTypeDesc(t), getTypeDesc(t.sons[0])]); + [rdLoc(a), rdLoc(b), getTypeDesc(p.module, t), + getTypeDesc(p.module, t.sons[0])]); freeTemp(p, a); freeTemp(p, b) end; @@ -1265,16 +1306,15 @@ begin result := rdCharLoc(a); assert(setType.kind = tySet); if (firstOrd(setType) <> 0) then - result := ropeFormat('($1-$2)', [result, toRope(firstOrd(setType))]) + result := ropef('($1-$2)', [result, toRope(firstOrd(setType))]) end; function fewCmps(s: PNode): bool; // this function estimates whether it is better to emit code // for constructing the set or generating a bunch of comparisons directly begin - assert(s.kind in [nkSetConstr, nkConstSetConstr]); - if (getSize(s.typ) <= platform.intSize) and - (s.kind = nkConstSetConstr) then + if s.kind <> nkCurly then InternalError(s.info, 'fewCmps'); + if (getSize(s.typ) <= platform.intSize) and (nfAllConst in s.flags) then result := false // it is better to emit the set generation code else if elemType(s.typ).Kind in [tyInt, tyInt16..tyInt64] then result := true // better not emit the set if int is basetype! @@ -1282,21 +1322,27 @@ begin result := sonsLen(s) <= 8 // 8 seems to be a good value end; -procedure binaryExprIn(p: BProc; e: PNode; var d: TLoc; const frmt: string); -var - a, b: TLoc; +procedure binaryExprIn(p: BProc; e: PNode; var a, b, d: TLoc; + const frmt: string); begin - assert(e.sons[1].typ <> nil); - assert(e.sons[2].typ <> nil); - a := InitLocExpr(p, e.sons[1]); - b := InitLocExpr(p, e.sons[2]); - putIntoDest(p, d, e.typ, ropeFormat(frmt, [rdLoc(a), rdSetElemLoc(b, a.t)])); + putIntoDest(p, d, e.typ, ropef(frmt, [rdLoc(a), rdSetElemLoc(b, a.t)])); if d.k <> locExpr then begin freeTemp(p, a); freeTemp(p, b) end end; +procedure genInExprAux(p: BProc; e: PNode; var a, b, d: TLoc); +begin + case int(getSize(skipVarGeneric(e.sons[1].typ))) of + 1: binaryExprIn(p, e, a, b, d, '(($1 &(1<<(($2)&7)))!=0)'); + 2: binaryExprIn(p, e, a, b, d, '(($1 &(1<<(($2)&15)))!=0)'); + 4: binaryExprIn(p, e, a, b, d, '(($1 &(1<<(($2)&31)))!=0)'); + 8: binaryExprIn(p, e, a, b, d, '(($1 &(IL64(1)<<(($2)&IL64(63))))!=0)'); + else binaryExprIn(p, e, a, b, d, '(($1[$2/8] &(1<<($2%8)))!=0)'); + end +end; + procedure binaryStmtInExcl(p: BProc; e: PNode; var d: TLoc; const frmt: string); var a, b: TLoc; @@ -1304,7 +1350,7 @@ begin assert(d.k = locNone); a := InitLocExpr(p, e.sons[1]); b := InitLocExpr(p, e.sons[2]); - appRopeFormat(p.s[cpsStmts], frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]); + appf(p.s[cpsStmts], frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]); freeTemp(p, a); freeTemp(p, b) end; @@ -1315,25 +1361,26 @@ var c: array of TLoc; // Generate code for the 'in' operator len, i: int; begin - if (e.sons[1].Kind = nkSetConstr) and fewCmps(e.sons[1]) then begin + if (e.sons[1].Kind = nkCurly) and fewCmps(e.sons[1]) then begin // a set constructor but not a constant set: // do not emit the set, but generate a bunch of comparisons a := initLocExpr(p, e.sons[2]); - b := initLoc(locExpr, e.typ); + b := initLoc(locExpr, e.typ, OnUnknown); b.r := toRope('('+''); len := sonsLen(e.sons[1]); + {@emit c := [];} for i := 0 to len-1 do begin if e.sons[1].sons[i].Kind = nkRange then begin setLength(c, length(c)+2); c[high(c)-1] := InitLocExpr(p, e.sons[1].sons[i].sons[0]); c[high(c)] := InitLocExpr(p, e.sons[1].sons[i].sons[1]); - appRopeFormat(b.r, '$1 >= $2 && $1 <= $3', + appf(b.r, '$1 >= $2 && $1 <= $3', [rdCharLoc(a), rdCharLoc(c[high(c)-1]), rdCharLoc(c[high(c)])]) end else begin setLength(c, length(c)+1); c[high(c)] := InitLocExpr(p, e.sons[1].sons[i]); - appRopeFormat(b.r, '$1 == $2', [rdCharLoc(a), rdCharLoc(c[high(c)])]) + appf(b.r, '$1 == $2', [rdCharLoc(a), rdCharLoc(c[high(c)])]) end; if i < len - 1 then app(b.r, ' || ') @@ -1346,13 +1393,11 @@ begin end end else begin - case int(getSize(skipVarGeneric(e.sons[1].typ))) of - 1: binaryExprIn(p, e, d, '(($1 &(1<<(($2)&7)))!=0)'); - 2: binaryExprIn(p, e, d, '(($1 &(1<<(($2)&15)))!=0)'); - 4: binaryExprIn(p, e, d, '(($1 &(1<<(($2)&31)))!=0)'); - 8: binaryExprIn(p, e, d, '(($1 &(1<<(($2)&63)))!=0)'); - else binaryExprIn(p, e, d, '(($1[$2/8] &(1<<($2%8)))!=0)'); - end + assert(e.sons[1].typ <> nil); + assert(e.sons[2].typ <> nil); + a := InitLocExpr(p, e.sons[1]); + b := InitLocExpr(p, e.sons[2]); + genInExprAux(p, e, a, b, d); end end; @@ -1373,20 +1418,19 @@ var a, b, i: TLoc; ts: string; begin - setType := e.sons[1].Typ; - if setType.kind = tyVar then setType := skipAbstract(setType.sons[0]); + setType := skipVarGeneric(e.sons[1].Typ); size := int(getSize(setType)); case size of 1, 2, 4, 8: begin case op of mIncl: begin - ts := 'NS' + toString(size*8); + ts := 'NI' + toString(size*8); binaryStmtInExcl(p, e, d, - '$1 |=(1<<((' +{&} ts +{&} ')($2)%(sizeof(' +{&} ts +{&} + '$1 |=(1<<((' +{&} ts +{&} ')($2)%(sizeof(' +{&} ts +{&} ')*8)));$n'); end; mExcl: begin - ts := 'NS' + toString(size*8); + ts := 'NI' + toString(size*8); binaryStmtInExcl(p, e, d, '$1 &= ~(1 << ((' +{&} ts +{&} ')($2) % (sizeof(' +{&} ts +{&} ')*8)));$n'); @@ -1420,7 +1464,7 @@ begin b := initLocExpr(p, e.sons[2]); if d.k = locNone then d := getTemp(p, a.t); - appRopeFormat(p.s[cpsStmts], lookupOpr[op], [rdLoc(i), toRope(size), + appf(p.s[cpsStmts], lookupOpr[op], [rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b)]); freeTemp(p, a); freeTemp(p, b); @@ -1436,7 +1480,7 @@ begin b := initLocExpr(p, e.sons[2]); if d.k = locNone then d := getTemp(p, a.t); - appRopeFormat(p.s[cpsStmts], + appf(p.s[cpsStmts], 'for ($1 = 0; $1 < $2; $1++) $n' + ' $3[$1] = $4[$1] $6 $5[$1];$n', [rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b), toRope(lookupOpr[op])]); @@ -1453,6 +1497,98 @@ end; // --------------------- end of set operations ---------------------------- +procedure genOrd(p: BProc; e: PNode; var d: TLoc); +begin + unaryExprChar(p, e, d, '', '$1'); +end; + +procedure genCast(p: BProc; e: PNode; var d: TLoc); +const + ValueTypes = {@set}[tyTuple, tyObject, tyArray, tyOpenArray, tyArrayConstr]; +// we use whatever C gives us. Except if we have a value-type, we +// need to go through its address: +var + a: TLoc; +begin + a := InitLocExpr(p, e.sons[1]); + if (skipGenericRange(e.typ).kind in ValueTypes) + and not (lfIndirect in a.flags) then + putIntoDest(p, d, e.typ, ropef('(*($1*) ($2))', + [getTypeDesc(p.module, e.typ), addrLoc(a)])) + else + putIntoDest(p, d, e.typ, ropef('(($1) ($2))', + [getTypeDesc(p.module, e.typ), rdCharLoc(a)])); + if d.k <> locExpr then freeTemp(p, a) +end; + +procedure genRangeChck(p: BProc; n: PNode; var d: TLoc; const magic: string); +var + a: TLoc; + dest: PType; +begin + dest := skipVarGeneric(n.typ); + if not (optRangeCheck in p.options) then begin + a := InitLocExpr(p, n.sons[0]); + putIntoDest(p, d, n.typ, ropef('(($1) ($2))', + [getTypeDesc(p.module, dest), rdCharLoc(a)])); + end + else begin + a := InitLocExpr(p, n.sons[0]); + useMagic(p.module, magic); + putIntoDest(p, d, dest, + ropef('(($1)' +{&} magic +{&} '($2, $3, $4))', + [getTypeDesc(p.module, dest), + rdCharLoc(a), genLiteral(p, n.sons[1], dest), + genLiteral(p, n.sons[2], dest)])); + if d.k <> locExpr then freeTemp(p, a) + end +end; + +procedure genConv(p: BProc; e: PNode; var d: TLoc); +begin + genCast(p, e, d) +end; + +procedure passToOpenArray(p: BProc; n: PNode; var d: TLoc); +var + a: TLoc; + dest: PType; +begin + dest := skipVarGeneric(n.typ); + a := initLocExpr(p, n.sons[0]); + case a.t.kind of + tyOpenArray: + putIntoDest(p, d, dest, ropef('$1, $1Len0', [rdLoc(a)])); + tyString, tySequence: + putIntoDest(p, d, dest, ropef('$1->data, $1->len', [rdLoc(a)])); + tyArray, tyArrayConstr: + putIntoDest(p, d, dest, ropef('$1, $2', + [rdLoc(a), toRope(lengthOrd(a.t))])); + else InternalError(n.sons[0].info, 'passToOpenArray()') + end; + if d.k <> locExpr then freeTemp(p, a) +end; + +procedure convStrToCStr(p: BProc; n: PNode; var d: TLoc); +var + a: TLoc; +begin + a := initLocExpr(p, n.sons[0]); + putIntoDest(p, d, skipVarGeneric(n.typ), ropef('$1->data', [rdLoc(a)])); + if d.k <> locExpr then freeTemp(p, a) +end; + +procedure convCStrToStr(p: BProc; n: PNode; var d: TLoc); +var + a: TLoc; +begin + useMagic(p.module, 'cstrToNimstr'); + a := initLocExpr(p, n.sons[0]); + putIntoDest(p, d, skipVarGeneric(n.typ), + ropef('cstrToNimstr($1)', [rdLoc(a)])); + if d.k <> locExpr then freeTemp(p, a) +end; + procedure genMagicExpr(p: BProc; e: PNode; var d: TLoc; op: TMagic); var a: TLoc; @@ -1491,13 +1627,21 @@ begin mEqStr: binaryExpr(p, e, d, 'eqStrings', 'eqStrings($1, $2)'); mLeStr: binaryExpr(p, e, d, 'cmpStrings', '(cmpStrings($1, $2) <= 0)'); mLtStr: binaryExpr(p, e, d, 'cmpStrings', '(cmpStrings($1, $2) < 0)'); + mIsNil: unaryExpr(p, e, d, '', '$1 == 0'); + mIntToStr: genDollar(p, e, d, 'nimIntToStr', 'nimIntToStr($1)'); + mInt64ToStr: genDollar(p, e, d, 'nimInt64ToStr', 'nimInt64ToStr($1)'); + mBoolToStr: genDollar(p, e, d, 'nimBoolToStr', 'nimBoolToStr($1)'); + mCharToStr: genDollar(p, e, d, 'nimCharToStr', 'nimCharToStr($1)'); + mFloatToStr: genDollar(p, e, d, 'nimFloatToStr', 'nimFloatToStr($1)'); + mCStrToStr: genDollar(p, e, d, 'cstrToNimstr', 'cstrToNimstr($1)'); + mStrToStr: expr(p, e.sons[1], d); mAssert: begin if (optAssert in p.Options) then begin - useMagic('internalAssert'); + useMagic(p.module, 'internalAssert'); expr(p, e.sons[1], d); line := toRope(toLinenumber(e.info)); filen := makeCString(ToFilename(e.info)); - appRopeFormat(p.s[cpsStmts], 'internalAssert($1, $2, $3);$n', + appf(p.s[cpsStmts], 'internalAssert($1, $2, $3);$n', [filen, line, rdLoc(d)]) end end; @@ -1505,23 +1649,24 @@ begin mNewFinalize: genNewFinalize(p, e); mSizeOf: putIntoDest(p, d, e.typ, - ropeFormat('sizeof($1)', [getTypeDesc(e.sons[1].typ)])); - mChr: expr(p, e.sons[1], d); - mOrd: - // ord only allows things that are allowed in C anyway, so generate - // no code for it: - expr(p, e.sons[1], d); + ropef('sizeof($1)', [getTypeDesc(p.module, e.sons[1].typ)])); + mChr: genCast(p, e, d); // expr(p, e.sons[1], d); + mOrd: genOrd(p, e, d); mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray: genArrayLen(p, e, d, op); mInc: begin if not (optOverflowCheck in p.Options) then binaryStmt(p, e, d, '', '$1 += $2;$n') + else if skipVarGeneric(e.sons[1].typ).kind = tyInt64 then + binaryStmt(p, e, d, 'addInt64', '$1 = addInt64($1, $2);$n') else binaryStmt(p, e, d, 'addInt', '$1 = addInt($1, $2);$n') end; ast.mDec: begin if not (optOverflowCheck in p.Options) then binaryStmt(p, e, d, '', '$1 -= $2;$n') + else if skipVarGeneric(e.sons[1].typ).kind = tyInt64 then + binaryStmt(p, e, d, 'subInt64', '$1 = subInt64($1, $2);$n') else binaryStmt(p, e, d, 'subInt', '$1 = subInt($1, $2);$n') end; @@ -1530,6 +1675,8 @@ begin mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet, mInSet: genSetOp(p, e, d, op); mExit: genCall(p, e, d); + mNLen..mNError: + liMessage(e.info, errCannotGenerateCodeForX, e.sons[0].sym.name.s); else internalError(e.info, 'genMagicExpr: ' + magicToStr[op]); end end; @@ -1544,18 +1691,18 @@ var i: int; ts: string; begin - if e.kind = nkConstSetConstr then + if nfAllConst in e.flags then putIntoDest(p, d, e.typ, genSetNode(p, e)) else begin if d.k = locNone then d := getTemp(p, e.typ); if getSize(e.typ) > 8 then begin // big set: - appRopeFormat(p.s[cpsStmts], 'memset($1, 0, sizeof($1));$n', [rdLoc(d)]); + appf(p.s[cpsStmts], 'memset($1, 0, sizeof($1));$n', [rdLoc(d)]); for i := 0 to sonsLen(e)-1 do begin if e.sons[i].kind = nkRange then begin idx := getTemp(p, getSysType(tyInt)); // our counter a := initLocExpr(p, e.sons[i].sons[1]); b := initLocExpr(p, e.sons[i].sons[2]); - appRopeFormat(p.s[cpsStmts], + appf(p.s[cpsStmts], 'for ($1 = $3; $1 <= $4; $1++) $n' + '$2[$1/8] |=(1<<($1%8));$n', [rdLoc(idx), rdLoc(d), rdSetElemLoc(a, e.typ), @@ -1566,21 +1713,21 @@ begin end else begin a := initLocExpr(p, e.sons[i]); - appRopeFormat(p.s[cpsStmts], '$1[$2/8] |=(1<<($2%8));$n', + appf(p.s[cpsStmts], '$1[$2/8] |=(1<<($2%8));$n', [rdLoc(d), rdSetElemLoc(a, e.typ)]); freeTemp(p, a) end end end else begin // small set - ts := 'NS' + toString(getSize(e.typ)*8); - appRopeFormat(p.s[cpsStmts], '$1 = 0;$n', [rdLoc(d)]); + ts := 'NI' + toString(getSize(e.typ)*8); + appf(p.s[cpsStmts], '$1 = 0;$n', [rdLoc(d)]); for i := 0 to sonsLen(e) - 1 do begin if e.sons[i].kind = nkRange then begin idx := getTemp(p, getSysType(tyInt)); // our counter a := initLocExpr(p, e.sons[i].sons[1]); b := initLocExpr(p, e.sons[i].sons[2]); - appRopeFormat(p.s[cpsStmts], + appf(p.s[cpsStmts], 'for ($1 = $3; $1 <= $4; $1++) $n' +{&} '$2 |=(1<<((' +{&} ts +{&} ')($1)%(sizeof(' +{&}ts+{&}')*8)));$n', [rdLoc(idx), rdLoc(d), rdSetElemLoc(a, e.typ), @@ -1591,7 +1738,7 @@ begin end else begin a := initLocExpr(p, e.sons[i]); - appRopeFormat(p.s[cpsStmts], + appf(p.s[cpsStmts], '$1 |=(1<<((' +{&} ts +{&} ')($2)%(sizeof(' +{&}ts+{&} ')*8)));$n', [rdLoc(d), rdSetElemLoc(a, e.typ)]); @@ -1602,38 +1749,42 @@ begin end end; -procedure genRecordConstr(p: BProc; t: PNode; var d: TLoc); +procedure genTupleConstr(p: BProc; n: PNode; var d: TLoc); var - i, len: int; + i: int; rec: TLoc; + it: PNode; + t: PType; begin - {@discard} getTypeDesc(t.typ); // so that any fields are initialized - if d.k = locNone then - d := getTemp(p, t.typ); - i := 0; - len := sonsLen(t); - while i < len do begin - rec := initLoc(locExpr, t.sons[i].typ); - assert(t.sons[i].sym.loc.r <> nil); - rec.r := ropeFormat('$1.$2', [rdLoc(d), t.sons[i].sym.loc.r]); - inheritStorage(rec, d); - expr(p, t.sons[i+1], rec); - inc(i, 2) + // the code generator assumes that there are only tuple constructors with + // field names! + t := getUniqueType(n.typ); + {@discard} getTypeDesc(p.module, t); // so that any fields are initialized + if d.k = locNone then d := getTemp(p, t); + if t.n = nil then InternalError(n.info, 'genTupleConstr'); + if sonsLen(t.n) <> sonsLen(n) then + InternalError(n.info, 'genTupleConstr'); + for i := 0 to sonsLen(n)-1 do begin + it := n.sons[i]; + if it.kind <> nkExprColonExpr then InternalError(n.info, 'genTupleConstr'); + rec := initLoc(locExpr, it.sons[1].typ, d.s); + if (t.n.sons[i].kind <> nkSym) then + InternalError(n.info, 'genTupleConstr'); + rec.r := ropef('$1.$2', [rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)]); + expr(p, it.sons[1], rec); end end; -procedure genArrayConstr(p: BProc; t: PNode; var d: TLoc); +procedure genArrayConstr(p: BProc; n: PNode; var d: TLoc); var arr: TLoc; i: int; begin - if d.k = locNone then - d := getTemp(p, t.typ); - for i := 0 to sonsLen(t)-1 do begin - arr := initLoc(locExpr, elemType(skipGeneric(t.typ))); - arr.r := ropeFormat('$1[$2]', [rdLoc(d), intLiteral(i)]); - inheritStorage(arr, d); - expr(p, t.sons[i], arr) + if d.k = locNone then d := getTemp(p, n.typ); + for i := 0 to sonsLen(n)-1 do begin + arr := initLoc(locExpr, elemType(skipGeneric(n.typ)), d.s); + arr.r := ropef('$1[$2]', [rdLoc(d), intLiteral(i)]); + expr(p, n.sons[i], arr) end end; @@ -1642,157 +1793,27 @@ var newSeq, arr: TLoc; i: int; begin - useMagic('newSeq'); + useMagic(p.module, 'newSeq'); if d.k = locNone then d := getTemp(p, t.typ); // generate call to newSeq before adding the elements per hand: - newSeq := initLoc(locExpr, t.typ); - newSeq.r := ropeFormat('($1) newSeq($2, $3)', - [getTypeDesc(t.typ), genTypeInfo(currMod, t.typ), toRope(sonsLen(t))]); + newSeq := initLoc(locExpr, t.typ, OnHeap); + newSeq.r := ropef('($1) newSeq($2, $3)', + [getTypeDesc(p.module, t.typ), + genTypeInfo(p.module, t.typ), toRope(sonsLen(t))]); genAssignment(p, d, newSeq, {@set}[]); for i := 0 to sonsLen(t)-1 do begin - arr := initLoc(locExpr, elemType(skipGeneric(t.typ))); - arr.r := ropeFormat('$1->data[$2]', [rdLoc(d), intLiteral(i)]); - arr.flags := {@set}[lfOnHeap]; // we know that sequences are on the heap + arr := initLoc(locExpr, elemType(skipGeneric(t.typ)), OnHeap); + arr.r := ropef('$1->data[$2]', [rdLoc(d), intLiteral(i)]); + arr.s := OnHeap; // we know that sequences are on the heap expr(p, t.sons[i], arr) end end; -procedure genCast(p: BProc; e: PNode; var d: TLoc); -const - ValueTypes = {@set}[tyRecord, tyObject, tyArray, tyOpenArray, tyArrayConstr]; -// we use whatever C gives us. Except if we have a value-type, we -// need to go through its address: -var - a: TLoc; -begin - a := InitLocExpr(p, e.sons[0]); - if (skipAbstract(e.typ).kind in ValueTypes) and (a.indirect = 0) then - putIntoDest(p, d, e.typ, ropeFormat('(*($1*) ($2))', - [getTypeDesc(e.typ), addrLoc(a)])) - else - putIntoDest(p, d, e.typ, ropeFormat('(($1) ($2))', - [getTypeDesc(e.typ), rdCharLoc(a)])); - if d.k <> locExpr then - freeTemp(p, a) -end; - -procedure genConv(p: BProc; e: PNode; var d: TLoc); - // type conversion: it doesn't matter if implicit or explicit; - // type conversions are not casts! -var - a: TLoc; - r: PRope; - source, dest: PType; -begin - // numeric types need range checks: - dest := skipVarGeneric(e.typ); - case dest.kind of - tyRange, tyInt..tyInt64, tyEnum, tyChar, tyBool: begin - if not (optRangeCheck in p.options) or - (firstOrd(dest) <= firstOrd(skipVarGeneric(e.sons[0].typ))) and // first >= x - (lastOrd(skipVarGeneric(e.sons[0].typ)) <= lastOrd(dest)) then // x <= last - expr(p, e.sons[0], d) // no need for a range check - else begin // generate a range check: - a := InitLocExpr(p, e.sons[0]); - if (a.t.kind in [tyFloat..tyFloat128]) or - (dest.kind in [tyFloat..tyFloat128]) then begin - useMagic('chckRangeF'); - putIntoDest(p, d, dest, ropeFormat('chckRangeF($1, $2, $3)', - [rdCharLoc(a), genLiteral(p, dest.n.sons[0], dest), - genLiteral(p, dest.n.sons[1], dest)])) - end - else if (a.t.kind = tyInt64) or (dest.kind = tyInt64) then begin - useMagic('chckRange64'); - putIntoDest(p, d, dest, ropeFormat('chckRange64($1, $2, $3)', - [rdCharLoc(a), intLiteral(firstOrd(dest)), - intLiteral(lastOrd(dest))])) - end - else begin - useMagic('chckRange'); - putIntoDest(p, d, dest, ropeFormat('chckRange($1, $2, $3)', - [rdCharLoc(a), intLiteral(firstOrd(dest)), - intLiteral(lastOrd(dest))])) - end; - if d.k <> locExpr then - freeTemp(p, a) - end - end; - // open arrays need implicit length passed: - tyOpenArray: begin - a := initLocExpr(p, e.sons[0]); - case a.t.kind of - tyOpenArray: - putIntoDest(p, d, dest, ropeFormat('$1, $1Len0', [rdLoc(a)])); - tyString, tySequence: - putIntoDest(p, d, dest, ropeFormat('$1->data, $1->len', [rdLoc(a)])); - tyArray, tyArrayConstr: - putIntoDest(p, d, dest, ropeFormat('$1, $2', - [rdLoc(a), toRope(lengthOrd(a.t))])); - else InternalError(e.sons[0].info, 'genConv()') - end; - if d.k <> locExpr then freeTemp(p, a) - end; - // conversions from string to cstring: - tyCString: begin - if skipVarGeneric(e.sons[0].typ).kind = tyString then begin - a := initLocExpr(p, e.sons[0]); - putIntoDest(p, d, e.typ, ropeFormat('$1->data', [rdLoc(a)])); - if d.k <> locExpr then freeTemp(p, a) - end - else if not isCompatibleToCString(e.sons[0].typ) then - // ordinary type cast: - genCast(p, e, d) - else - expr(p, e.sons[0], d) // BUGFIX! - end; - // conversions from cstring to string: - tyString: begin - if skipVarGeneric(e.sons[0].typ).kind = tyCString then begin - useMagic('cstrToNimstr'); - a := initLocExpr(p, e.sons[0]); - putIntoDest(p, d, dest, ropeFormat('cstrToNimstr($1)', [rdLoc(a)])); - if d.k <> locExpr then freeTemp(p, a) - end - else // ordinary type cast: - genCast(p, e, d) - end; - // conversions between different object types: - tyObject: begin - source := skipVarGeneric(e.sons[0].typ); - // if source is a subtype of dest, downcast: - a := initLocExpr(p, e.sons[0]); - r := rdLoc(a); - while source.sons[0] <> nil do begin - source := source.sons[0]; - if gCmd <> cmdCompileToCpp then - app(r, '.Sup'); - if source.id = dest.id then break - end; - if source.id = dest.id then // we really have a downcast here: - if gCmd = cmdCompileToCpp then - putLocIntoDest(p, d, a) // downcast does C++ for us - else - putIntoDest(p, d, dest, r) - else if gCmd = cmdCompileToCpp then - genCast(p, e, d) // discard ``a`` - else // upcasts are uglier in C - putIntoDest(p, d, dest, ropeFormat('(*($1*) ($2))', - [getTypeDesc(dest), addrLoc(a)])); - if d.k <> locExpr then freeTemp(p, a) - end; - tyGenericParam, tyAnyEnum: - expr(p, e.sons[0], d); - // happens sometimes for generated assignments, etc. - else // use an ordinary cast - genCast(p, e, d) - end -end; - procedure genComplexConst(p: BProc; sym: PSym; var d: TLoc); begin - genConstPrototype(sym); + genConstPrototype(p.module, sym); assert((sym.loc.r <> nil) and (sym.loc.t <> nil)); putLocIntoDest(p, d, sym.loc) end; @@ -1806,68 +1827,83 @@ begin if len > 0 then expr(p, n.sons[len-1], d); end; +procedure upConv(p: BProc; n: PNode; var d: TLoc); +var + a: TLoc; + dest, t: PType; + r, nilCheck: PRope; +begin + a := initLocExpr(p, n.sons[0]); + dest := skipPtrsGeneric(n.typ); + if (optObjCheck in p.options) and not (isPureObject(dest)) then begin + useMagic(p.module, 'chckObj'); + r := rdLoc(a); + nilCheck := nil; + t := skipGeneric(a.t); + while t.kind in [tyVar, tyPtr, tyRef] do begin + if t.kind <> tyVar then nilCheck := r; + r := ropef('(*$1)', [r]); + t := skipGeneric(t.sons[0]) + end; + if gCmd <> cmdCompileToCpp then + while (t.kind = tyObject) and (t.sons[0] <> nil) do begin + app(r, '.Sup'); + t := skipGeneric(t.sons[0]); + end; + if nilCheck <> nil then + appf(p.s[cpsStmts], 'if ($1) chckObj($2.m_type, $3);$n', + [nilCheck, r, genTypeInfo(p.module, dest)]) + else + appf(p.s[cpsStmts], 'chckObj($1.m_type, $2);$n', + [r, genTypeInfo(p.module, dest)]); + end; + if n.sons[0].typ.kind <> tyObject then + putIntoDest(p, d, n.typ, ropef('(($1) ($2))', + [getTypeDesc(p.module, n.typ), rdLoc(a)])) + else + putIntoDest(p, d, n.typ, ropef('(*($1*) ($2))', + [getTypeDesc(p.module, dest), addrLoc(a)])); +end; + +procedure downConv(p: BProc; n: PNode; var d: TLoc); +var + a: TLoc; + dest, src: PType; + i: int; + r: PRope; +begin + if gCmd = cmdCompileToCpp then + expr(p, n.sons[0], d) // downcast does C++ for us + else begin + dest := skipPtrsGeneric(n.typ); + src := skipPtrsGeneric(n.sons[0].typ); + a := initLocExpr(p, n.sons[0]); + r := rdLoc(a); + if skipGeneric(n.sons[0].typ).kind in [tyRef, tyPtr, tyVar] then begin + app(r, '->Sup'); + for i := 2 to abs(inheritanceDiff(dest, src)) do app(r, '.Sup'); + r := con('&'+'', r); + end + else + for i := 1 to abs(inheritanceDiff(dest, src)) do app(r, '.Sup'); + putIntoDest(p, d, n.typ, r); + end +end; + procedure genBlock(p: BProc; t: PNode; var d: TLoc); forward; procedure expr(p: BProc; e: PNode; var d: TLoc); -// do not forget that lfIndirect in d.flags may be requested! var sym: PSym; - a: TLoc; ty: PType; begin case e.kind of - nkQualified: expr(p, e.sons[1], d); - nkStrLit..nkTripleStrLit, nkIntLit..nkInt64Lit, - nkFloatLit..nkFloat64Lit, nkNilLit, nkCharLit, nkRCharLit: begin - putIntoDest(p, d, e.typ, genLiteral(p, e)); - d.k := locImmediate // for removal of index checks - end; - nkCall, nkHiddenCallConv: begin - if (e.sons[0].kind = nkSym) and - (e.sons[0].sym.magic <> mNone) then - genMagicExpr(p, e, d, e.sons[0].sym.magic) - else - genCall(p, e, d) - end; - nkConstSetConstr, nkSetConstr: genSetConstr(p, e, d); - nkConstArrayConstr, nkArrayConstr: - if (skipAbstract(e.typ).kind = tySequence) then // BUGFIX - genSeqConstr(p, e, d) - else - genArrayConstr(p, e, d); - nkConstRecordConstr, nkRecordConstr: - genRecordConstr(p, e, d); - nkCast: genCast(p, e, d); - nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, e, d); - nkAddr: begin - a := InitLocExpr(p, e.sons[0]); - putIntoDest(p, d, e.typ, addrLoc(a)); - if d.k <> locExpr then - freeTemp(p, a) - end; - nkBracketExpr: begin - ty := skipAbstract(e.sons[0].typ); - if ty.kind in [tyRef, tyPtr, tyVar] then ty := skipAbstract(ty.sons[0]); - case ty.kind of - tyArray, tyArrayConstr: genArrayElem(p, e, d); - tyOpenArray: genOpenArrayElem(p, e, d); - tySequence, tyString: genSeqElem(p, e, d); - tyCString: genCStringElem(p, e, d); - else InternalError(e.info, - 'expr(nkBracketExpr, ' + typeKindToStr[ty.kind] + ')'); - end - end; - nkDerefExpr: genDeref(p, e, d); - nkDotExpr: genRecordField(p, e, d); - nkBlockExpr: genBlock(p, e, d); - nkStmtListExpr: genStmtListExpr(p, e, d); - nkIfExpr: genIfExpr(p, e, d); nkSym: begin sym := e.sym; case sym.Kind of - skProc: begin + skProc, skConverter: begin // generate prototype if not already declared in this translation unit - genProcPrototype(sym); + genProcPrototype(p.module, sym); if ((sym.loc.r = nil) or (sym.loc.t = nil)) then InternalError(e.info, 'expr: proc not init ' + sym.name.s); putLocIntoDest(p, d, sym.loc) @@ -1879,7 +1915,7 @@ begin genComplexConst(p, sym, d); skEnumField: putIntoDest(p, d, e.typ, toRope(sym.position)); skVar: begin - if (sfGlobal in sym.flags) then genVarPrototype(sym); + if (sfGlobal in sym.flags) then genVarPrototype(p.module, sym); if ((sym.loc.r = nil) or (sym.loc.t = nil)) then InternalError(e.info, 'expr: var not init ' + sym.name.s); putLocIntoDest(p, d, sym.loc); @@ -1898,7 +1934,57 @@ begin InternalError(e.info, 'expr(' +{&} symKindToStr[sym.kind] +{&} '); unknown symbol') end - end + end; + nkQualified: expr(p, e.sons[1], d); + nkStrLit..nkTripleStrLit, nkIntLit..nkInt64Lit, + nkFloatLit..nkFloat64Lit, nkNilLit, nkCharLit: begin + putIntoDest(p, d, e.typ, genLiteral(p, e)); + d.k := locImmediate // for removal of index checks + end; + nkCall, nkHiddenCallConv: begin + if (e.sons[0].kind = nkSym) and + (e.sons[0].sym.magic <> mNone) then + genMagicExpr(p, e, d, e.sons[0].sym.magic) + else + genCall(p, e, d) + end; + nkCurly: genSetConstr(p, e, d); + nkBracket: + if (skipVarGenericRange(e.typ).kind = tySequence) then // BUGFIX + genSeqConstr(p, e, d) + else + genArrayConstr(p, e, d); + nkPar: + genTupleConstr(p, e, d); + nkCast: genCast(p, e, d); + nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, e, d); + nkHiddenAddr, nkAddr: genAddr(p, e, d); + nkBracketExpr: begin + ty := skipVarGenericRange(e.sons[0].typ); + if ty.kind in [tyRef, tyPtr] then ty := skipVarGenericRange(ty.sons[0]); + case ty.kind of + tyArray, tyArrayConstr: genArrayElem(p, e, d); + tyOpenArray: genOpenArrayElem(p, e, d); + tySequence, tyString: genSeqElem(p, e, d); + tyCString: genCStringElem(p, e, d); + else InternalError(e.info, + 'expr(nkBracketExpr, ' + typeKindToStr[ty.kind] + ')'); + end + end; + nkDerefExpr, nkHiddenDeref: genDeref(p, e, d); + nkDotExpr: genRecordField(p, e, d); + nkCheckedFieldExpr: genCheckedRecordField(p, e, d); + nkBlockExpr: genBlock(p, e, d); + nkStmtListExpr: genStmtListExpr(p, e, d); + nkIfExpr: genIfExpr(p, e, d); + nkObjDownConv: downConv(p, e, d); + nkObjUpConv: upConv(p, e, d); + nkChckRangeF: genRangeChck(p, e, d, 'chckRangeF'); + nkChckRange64: genRangeChck(p, e, d, 'chckRange64'); + nkChckRange: genRangeChck(p, e, d, 'chckRange'); + nkStringToCString: convStrToCStr(p, e, d); + nkCStringToString: convCStrToStr(p, e, d); + nkPassAsOpenArray: passToOpenArray(p, e, d); else InternalError(e.info, 'expr(' +{&} nodeKindToStr[e.kind] +{&} '); unknown node kind') @@ -1915,8 +2001,8 @@ var begin result := copyNode(n); newSons(result, sonsLen(n)); - t := skipAbstract(n.Typ); - if t.kind = tyRecordConstr then + t := getUniqueType(skipVarGenericRange(n.Typ)); + if t.n = nil then InternalError(n.info, 'transformRecordExpr: invalid type'); for i := 0 to sonsLen(n)-1 do begin assert(n.sons[i].kind = nkExprColonExpr); @@ -1940,7 +2026,7 @@ begin len := sonsLen(n); result := toRope('{'+''); for i := 0 to len - 2 do - app(result, ropeFormat('$1,$n', [genConstExpr(p, n.sons[i])])); + app(result, ropef('$1,$n', [genConstExpr(p, n.sons[i])])); if len > 0 then app(result, genConstExpr(p, n.sons[len-1])); app(result, '}' + tnl) end; @@ -1951,17 +2037,19 @@ var cs: TBitSet; begin case n.Kind of - nkHiddenStdConv, nkHiddenSubConv: result := genConstExpr(p, n.sons[0]); - nkSetConstr, nkConstSetConstr: begin + nkHiddenStdConv, nkHiddenSubConv: result := genConstExpr(p, n.sons[1]); + nkCurly: begin toBitSet(n, cs); result := genRawSetData(cs, int(getSize(n.typ))) + end; + nkBracket: begin // XXX: tySequence! + result := genConstSimpleList(p, n); end; - nkConstArrayConstr: result := genConstSimpleList(p, n); - nkPar, nkConstRecordConstr, nkRecordConstr: begin - if hasSonWith(n, nkExprColonExpr) then + nkPar: begin + if hasSonWith(n, nkExprColonExpr) then trans := transformRecordExpr(n) - else + else trans := n; result := genConstSimpleList(p, trans); end |