//unlike NodeBinaryOp, NodeBinaryOpCompare has a node type that's different from // its nodes, where left and right nodes are casted to be the same. bool NodeBinaryOpCompare::doBinaryOperationImmediate(s32 lslot, s32 rslot, u32 slots) { assert(slots == 1); UTI luti = m_nodeLeft->getNodeType(); u32 len = m_state.getTotalBitSize(luti); UlamValue luv = m_state.m_nodeEvalStack.loadUlamValueFromSlot(lslot); //immediate value UlamValue ruv = m_state.m_nodeEvalStack.loadUlamValueFromSlot(rslot); //immediate value if((luv.getUlamValueTypeIdx() == Nav) || (ruv.getUlamValueTypeIdx() == Nav)) return false; UlamValue rtnUV; u32 wordsize = m_state.getTotalWordSize(luti); if(wordsize == MAXBITSPERINT) { u32 ldata = luv.getImmediateData(len); u32 rdata = ruv.getImmediateData(len); rtnUV = makeImmediateBinaryOp(luti, ldata, rdata, len); } else if(wordsize == MAXBITSPERLONG) { u64 ldata = luv.getImmediateDataLong(len); u64 rdata = ruv.getImmediateDataLong(len); rtnUV = makeImmediateLongBinaryOp(luti, ldata, rdata, len); } //else //assert(0); if(rtnUV.getUlamValueTypeIdx() == Nav) return false; m_state.m_nodeEvalStack.storeUlamValueInSlot(rtnUV, -1); return true; } //dobinaryopImmediate
bool NodeUnaryOp::doUnaryOperationImmediate(s32 slot, u32 nslots) { assert(nslots == 1); UTI nuti = getNodeType(); u32 len = m_state.getTotalBitSize(nuti); UlamValue uv = m_state.m_nodeEvalStack.loadUlamValueFromSlot(slot); //immediate valueg if((uv.getUlamValueTypeIdx() == Nav) || (nuti == Nav)) return false; if((uv.getUlamValueTypeIdx() == Hzy) || (nuti == Hzy)) return false; UlamValue rtnUV; u32 wordsize = m_state.getUlamTypeByIndex(nuti)->getTotalWordSize(); if(wordsize <= MAXBITSPERINT) { u32 data = uv.getImmediateData(len, m_state); rtnUV = makeImmediateUnaryOp(nuti, data, len); } else if(wordsize <= MAXBITSPERLONG) { u64 data = uv.getImmediateDataLong(len, m_state); //t3849 rtnUV = makeImmediateLongUnaryOp(nuti, data, len); } else m_state.abortGreaterThanMaxBitsPerLong(); m_state.m_nodeEvalStack.storeUlamValueInSlot(rtnUV, -1); return true; } //dounaryopImmediate
bool UlamTypeInt::castTo64(UlamValue & val, UTI typidx) { bool brtn = true; UTI valtypidx = val.getUlamValueTypeIdx(); u32 valwordsize = m_state.getTotalWordSize(valtypidx); u64 data; if(valwordsize == MAXBITSPERINT) data = (u64) val.getImmediateData(m_state); else if(valwordsize == MAXBITSPERLONG) data = val.getImmediateDataLong(m_state); else assert(0); u64 sdata = 0; s32 bitsize = getBitSize(); s32 valbitsize = m_state.getBitSize(valtypidx); ULAMTYPE valtypEnum = m_state.getUlamTypeByIndex(valtypidx)->getUlamTypeEnum(); switch(valtypEnum) { case Int: // casting Int to Int to change bits size sdata = _Int64ToInt64(data, valbitsize, bitsize); break; case Unsigned: // casting Unsigned to Int to change type sdata = _Unsigned64ToInt64(data, valbitsize, bitsize); break; case Bits: // casting Bits to Int to change type sdata = _Bits64ToInt64(data, valbitsize, bitsize); break; case Unary: sdata = _Unary64ToInt64(data, valbitsize, bitsize); break; case Bool: sdata = _Bool64ToInt64(data, valbitsize, bitsize); break; case Void: default: //std::cerr << "UlamTypeInt (cast) error! Value Type was: " << valtypidx << std::endl; brtn = false; }; if(brtn) { u32 wordsize = getTotalWordSize(); //tobe if(wordsize == MAXBITSPERINT) //downcast val = UlamValue::makeImmediate(typidx, (u32) sdata, m_state); //overwrite val else if(wordsize == MAXBITSPERLONG) val = UlamValue::makeImmediateLong(typidx, sdata, m_state); //overwrite val else assert(0); } return brtn; } //castTo64
bool UlamTypePrimitiveUnary::castTo64(UlamValue & val, UTI typidx) { bool brtn = true; UTI valtypidx = val.getUlamValueTypeIdx(); u32 valwordsize = m_state.getTotalWordSize(valtypidx); u64 data; if(valwordsize <= MAXBITSPERINT) data = (u64) val.getImmediateData(m_state); else if(valwordsize <= MAXBITSPERLONG) data = val.getImmediateDataLong(m_state); else m_state.abortGreaterThanMaxBitsPerLong(); s32 bitsize = getBitSize(); s32 valbitsize = m_state.getBitSize(valtypidx); //base types e.g. Int, Bool, Unary, Foo, Bar.. ULAMTYPE valtypEnum = m_state.getUlamTypeByIndex(valtypidx)->getUlamTypeEnum(); switch(valtypEnum) { case Int: // cast from Int->Unary, OR Bool->Unary (same as Bool->Int) data = _Int64ToUnary64(data, valbitsize, bitsize); break; case Unsigned: data = _Unsigned64ToUnary64(data, valbitsize, bitsize); break; case Bool: // Bool -> Unary is the same as Bool -> Int data = _Bool64ToUnary64(data, valbitsize, bitsize); break; case Unary: data = _Unary64ToUnary64(data, valbitsize, bitsize); break; case Bits: break; case Void: default: //std::cerr << "UlamTypePrimitiveUnary (cast) error! Value Type was: " << valtypidx << std::endl; brtn = false; }; if(brtn) { u32 wordsize = getTotalWordSize(); //tobe if(wordsize <= MAXBITSPERINT) //downcast val = UlamValue::makeImmediate(typidx, data, m_state); //overwrite val else if(wordsize <= MAXBITSPERLONG) val = UlamValue::makeImmediateLong(typidx, data, m_state); //overwrite val else m_state.abortGreaterThanMaxBitsPerLong(); } return brtn; } //castTo64
// eval() no longer performed before check and label // returns false if error; UNKNOWNSIZE is not an error! bool NodeSquareBracket::getArraysizeInBracket(s32 & rtnArraySize) { bool noerr = true; // since square brackets determine the constant size for this type, else error s32 newarraysize = NONARRAYSIZE; UTI sizetype = m_nodeRight->checkAndLabelType(); if(sizetype == Nav) { rtnArraySize = UNKNOWNSIZE; return true; } UlamType * sizeut = m_state.getUlamTypeByIndex(sizetype); // expects a constant, numeric type within [] if(sizeut->isNumericType() && m_nodeRight->isAConstant()) { evalNodeProlog(0); //new current frame pointer makeRoomForNodeType(sizetype); //offset a constant expression if(m_nodeRight->eval() == NORMAL) { UlamValue arrayUV = m_state.m_nodeEvalStack.popArg(); u32 arraysizedata = arrayUV.getImmediateData(m_state); newarraysize = sizeut->getDataAsCs32(arraysizedata); if(newarraysize < 0 && newarraysize != UNKNOWNSIZE) //NONARRAY or UNKNOWN { MSG(getNodeLocationAsString().c_str(), "Array size specifier in [] is not a positive number", ERR); noerr = false; } //else unknown is not an error } else //newarraysize = UNKNOWNSIZE; //still true noerr = false; evalNodeEpilog(); } else { MSG(getNodeLocationAsString().c_str(), "Array size specifier in [] is not a constant number", ERR); noerr = false; } rtnArraySize = newarraysize; return noerr; } //getArraysizeInBracket
//overrides parent due to short-circuiting requirement EvalStatus NodeBinaryOpLogicalOr::eval() { assert(m_nodeLeft && m_nodeRight); UTI nuti = getNodeType(); u32 len = m_state.getTotalBitSize(nuti); evalNodeProlog(0); //new current frame pointer u32 slot = makeRoomForNodeType(nuti); EvalStatus evs = m_nodeLeft->eval(); if(evs != NORMAL) { evalNodeEpilog(); return evs; } //short-circuit if lhs is true UlamValue luv = m_state.m_nodeEvalStack.loadUlamValueFromSlot(slot); //immediate value u32 ldata = luv.getImmediateData(len, m_state); if(_Bool32ToCbool(ldata, len) == true) { //copies return UV to stack, -1 relative to current frame pointer m_state.m_nodeEvalStack.storeUlamValueInSlot(luv, -1); } else { u32 slot2 = makeRoomForNodeType(getNodeType()); evs = m_nodeRight->eval(); if(evs != NORMAL) { evalNodeEpilog(); return evs; } UlamValue ruv = m_state.m_nodeEvalStack.loadUlamValueFromSlot(slot+slot2); //immediate value //copies return UV to stack, -1 relative to current frame pointer m_state.m_nodeEvalStack.storeUlamValueInSlot(ruv, -1); } evalNodeEpilog(); return NORMAL; } //eval
bool UlamTypeInt::castTo32(UlamValue & val, UTI typidx) { bool brtn = true; UTI valtypidx = val.getUlamValueTypeIdx(); s32 bitsize = getBitSize(); s32 valbitsize = m_state.getBitSize(valtypidx); u32 data = val.getImmediateData(m_state); u32 sdata = 0; ULAMTYPE valtypEnum = m_state.getUlamTypeByIndex(valtypidx)->getUlamTypeEnum(); switch(valtypEnum) { case Int: // casting Int to Int to change bits size sdata = _Int32ToInt32(data, valbitsize, bitsize); break; case Unsigned: // casting Unsigned to Int to change type sdata = _Unsigned32ToInt32(data, valbitsize, bitsize); break; case Bits: // casting Bits to Int to change type sdata = _Bits32ToInt32(data, valbitsize, bitsize); break; case Unary: sdata = _Unary32ToInt32(data, valbitsize, bitsize); break; case Bool: sdata = _Bool32ToInt32(data, valbitsize, bitsize); break; case Void: default: //std::cerr << "UlamTypeInt (cast) error! Value Type was: " << valtypidx << std::endl; brtn = false; }; if(brtn) val = UlamValue::makeImmediate(typidx, sdata, m_state); //overwrite val return brtn; } //castTo32
bool UlamTypePrimitiveUnary::castTo32(UlamValue & val, UTI typidx) { bool brtn = true; UTI valtypidx = val.getUlamValueTypeIdx(); u32 data = val.getImmediateData(m_state); s32 bitsize = getBitSize(); s32 valbitsize = m_state.getBitSize(valtypidx); //base types e.g. Int, Bool, Unary, Foo, Bar.. ULAMTYPE valtypEnum = m_state.getUlamTypeByIndex(valtypidx)->getUlamTypeEnum(); switch(valtypEnum) { case Int: // cast from Int->Unary, OR Bool->Unary (same as Bool->Int) data = _Int32ToUnary32(data, valbitsize, bitsize); break; case Unsigned: data = _Unsigned32ToUnary32(data, valbitsize, bitsize); break; case Bool: // Bool -> Unary is the same as Bool -> Int data = _Bool32ToUnary32(data, valbitsize, bitsize); break; case Unary: data = _Unary32ToUnary32(data, valbitsize, bitsize); break; case Bits: break; case Void: default: //std::cerr << "UlamTypePrimitiveUnary (cast) error! Value Type was: " << valtypidx << std::endl; brtn = false; }; if(brtn) val = UlamValue::makeImmediate(typidx, data, m_state); //overwrite val, same data return brtn; } //castTo32
UTI NodeUnaryOp::constantFold() { u64 val = U64_MAX; UTI nuti = getNodeType(); if(nuti == Nav) return Nav; //nothing to do yet //if(nuti == Hzy) return Hzy; //nothing to do yet TRY? // if here, must be a constant.. assert(isAConstant()); NNO pno = Node::getYourParentNo(); assert(pno); Node * parentNode = m_state.findNodeNoInThisClassForParent(pno); //t3767 assert(parentNode); evalNodeProlog(0); //new current frame pointer makeRoomForNodeType(nuti); //offset a constant expression EvalStatus evs = eval(); if( evs == NORMAL) { UlamValue cnstUV = m_state.m_nodeEvalStack.popArg(); u32 wordsize = m_state.getTotalWordSize(nuti); if(wordsize <= MAXBITSPERINT) val = cnstUV.getImmediateData(m_state); else if(wordsize <= MAXBITSPERLONG) val = cnstUV.getImmediateDataLong(m_state); else m_state.abortGreaterThanMaxBitsPerLong(); } evalNodeEpilog(); if(evs == ERROR) { std::ostringstream msg; msg << "Constant value expression for unary op" << getName(); msg << " is erroneous while compiling class: "; msg << m_state.getUlamTypeNameBriefByIndex(m_state.getCompileThisIdx()).c_str(); MSG(getNodeLocationAsString().c_str(), msg.str().c_str(), ERR); setNodeType(Nav); return Nav; } if(evs == NOTREADY) { std::ostringstream msg; msg << "Constant value expression for unary op" << getName(); msg << " is not yet ready while compiling class: "; msg << m_state.getUlamTypeNameBriefByIndex(m_state.getCompileThisIdx()).c_str(); MSG(getNodeLocationAsString().c_str(), msg.str().c_str(), WAIT); setNodeType(Hzy); m_state.setGoAgain(); //for compiler counts return Hzy; } //replace ourselves (and kids) with a node terminal; new NNO unlike template's NodeTerminal * newnode = new NodeTerminal(val, nuti, m_state); assert(newnode); newnode->setNodeLocation(getNodeLocation()); AssertBool swapOk = parentNode->exchangeKids(this, newnode); assert(swapOk); std::ostringstream msg; msg << "Exchanged kids! for unary " << getName(); msg << ", with a constant == " << newnode->getName(); msg << " while compiling class: "; msg << m_state.getUlamTypeNameBriefByIndex(m_state.getCompileThisIdx()).c_str(); MSG(getNodeLocationAsString().c_str(), msg.str().c_str(), DEBUG); newnode->setYourParentNo(pno); newnode->resetNodeNo(getNodeNo()); delete this; //suicide is painless.. return newnode->checkAndLabelType(); } //constantFold
void NodeCast::genCodeReadIntoATmpVar(File * fp, UlamValue& uvpass) { // e.g. called by NodeFunctionCall on a NodeTerminal.. if(!needsACast()) { return m_node->genCodeReadIntoATmpVar(fp, uvpass); } UTI nuti = getNodeType(); UlamType * nut = m_state.getUlamTypeByIndex(nuti); UTI vuti = uvpass.getUlamValueTypeIdx(); bool isTerminal = false; s32 tmpVarNum = 0; if(vuti == Ptr) { tmpVarNum = uvpass.getPtrSlotIndex(); vuti = uvpass.getPtrTargetType(); //replace } else { // an immediate terminal value isTerminal = true; } if(nuti == vuti) return; //nothing to do! UlamType * vut = m_state.getUlamTypeByIndex(vuti); //after vuti replacement ULAMCLASSTYPE nclasstype = nut->getUlamClass(); ULAMCLASSTYPE vclasstype = vut->getUlamClass(); //handle element-atom and atom-element casting differently: // handle element->quark, atom->quark, not quark->element or quark->atom if(nuti == UAtom || vuti == UAtom || vclasstype == UC_ELEMENT || vclasstype == UC_QUARK) { //only to be nclasstype quark makes sense!!! check first, one might be element if(nclasstype == UC_QUARK || vclasstype == UC_QUARK) return genCodeCastAtomAndQuark(fp, uvpass); if(nclasstype == UC_ELEMENT || vclasstype == UC_ELEMENT) return genCodeCastAtomAndElement(fp, uvpass); { std::ostringstream msg; msg << "Casting 'incomplete' types: "; msg << m_state.getUlamTypeNameByIndex(nuti).c_str(); msg << "(UTI" << nuti << ") to be " << m_state.getUlamTypeNameByIndex(vuti).c_str(); msg << "(UTI" << vuti << ")"; MSG(getNodeLocationAsString().c_str(), msg.str().c_str(), DEBUG); return; } } s32 tmpVarCastNum = m_state.getNextTmpVarNumber(); m_state.indent(fp); fp->write("const "); fp->write(nut->getTmpStorageTypeAsString().c_str()); //e.g. u32, s32, u64, etc. fp->write(" "); fp->write(m_state.getTmpVarAsString(nuti, tmpVarCastNum).c_str()); fp->write(" = "); // write the cast method (e.g. _Unsigned32ToInt32, _Int32ToUnary32, etc..) fp->write(nut->castMethodForCodeGen(vuti).c_str()); fp->write("("); if(isTerminal) { s32 len = m_state.getBitSize(vuti); assert(len != UNKNOWNSIZE); if(len <= MAXBITSPERINT) { u32 data = uvpass.getImmediateData(m_state); char dstr[40]; vut->getDataAsString(data, dstr, 'z'); fp->write(dstr); } else if(len <= MAXBITSPERLONG) { u64 data = uvpass.getImmediateDataLong(m_state); char dstr[70]; vut->getDataLongAsString(data, dstr, 'z'); fp->write(dstr); } else assert(0); } else { fp->write(m_state.getTmpVarAsString(nuti, tmpVarNum).c_str()); } fp->write(", "); assert(!(nuti == UAtom || vuti == UAtom)); //LENGTH of node being casted (Uh_AP_mi::LENGTH ?) //fp->write(m_state.getBitVectorLengthAsStringForCodeGen(nodetype).c_str()); fp->write_decimal(m_state.getTotalBitSize(vuti)); //src length fp->write(", "); fp->write_decimal(m_state.getTotalBitSize(nuti)); //tobe length fp->write(")"); fp->write(";\n"); //PROBLEM is that funccall checks for 0 nameid to use the tmp var! // but then if we don't pass it along Node::genMemberNameForMethod fails.. if(isTerminal) uvpass = UlamValue::makePtr(tmpVarCastNum, TMPREGISTER, nuti, m_state.determinePackable(nuti), m_state, 0); //POS 0 rightjustified. else uvpass = UlamValue::makePtr(tmpVarCastNum, TMPREGISTER, nuti, m_state.determinePackable(nuti), m_state, 0, uvpass.getPtrNameId()); //POS 0 rightjustified; pass along name id } //genCodeReadIntoTmp
EvalStatus NodeSquareBracket::evalToStoreInto() { assert(m_nodeLeft && m_nodeRight); UTI nuti = getNodeType(); if(nuti == Nav) return ERROR; evalNodeProlog(0); //new current frame pointer makeRoomForSlots(1); //always 1 slot for ptr EvalStatus evs = m_nodeLeft->evalToStoreInto(); if(evs != NORMAL) { evalNodeEpilog(); return evs; } UlamValue pluv = m_state.m_nodeEvalStack.popArg(); makeRoomForNodeType(m_nodeRight->getNodeType()); //offset a constant expression evs = m_nodeRight->eval(); if(evs != NORMAL) { evalNodeEpilog(); return evs; } UlamValue offset = m_state.m_nodeEvalStack.popArg(); // constant expression only required for array declaration u32 offsetdata = offset.getImmediateData(m_state); s32 offsetInt = m_state.getUlamTypeByIndex(offset.getUlamValueTypeIdx())->getDataAsCs32(offsetdata); UTI auti = pluv.getPtrTargetType(); UlamType * aut = m_state.getUlamTypeByIndex(auti); if(aut->isCustomArray()) { UTI caType = ((UlamTypeClass *) aut)->getCustomArrayType(); UlamType * caut = m_state.getUlamTypeByIndex(caType); u32 pos = pluv.getPtrPos(); if(caut->getBitSize() > MAXBITSPERINT) pos = 0; // itemUV = UlamValue::makeAtom(caType); //else // itemUV = UlamValue::makeImmediate(caType, 0, m_state); //quietly skip for now XXX //use CA type, not the left ident's type UlamValue scalarPtr = UlamValue::makePtr(pluv.getPtrSlotIndex(), pluv.getPtrStorage(), caType, m_state.determinePackable(caType), //PACKEDLOADABLE m_state, pos /* base pos of array */ ); //copy result UV to stack, -1 relative to current frame pointer assignReturnValuePtrToStack(scalarPtr); } else { //adjust pos by offset * len, according to its scalar type UlamValue scalarPtr = UlamValue::makeScalarPtr(pluv, m_state); if(scalarPtr.incrementPtr(m_state, offsetInt)) //copy result UV to stack, -1 relative to current frame pointer assignReturnValuePtrToStack(scalarPtr); else { s32 arraysize = m_state.getArraySize(pluv.getPtrTargetType()); Symbol * lsymptr; u32 lid = 0; if(getSymbolPtr(lsymptr)) lid = lsymptr->getId(); std::ostringstream msg; msg << "Array subscript [" << offsetInt << "] exceeds the size (" << arraysize; msg << ") of array '" << m_state.m_pool.getDataAsString(lid).c_str() << "'"; MSG(getNodeLocationAsString().c_str(), msg.str().c_str(), ERR); evs = ERROR; } } evalNodeEpilog(); return evs; } //evalToStoreInto
EvalStatus NodeSquareBracket::eval() { assert(m_nodeLeft && m_nodeRight); UTI nuti = getNodeType(); if(nuti == Nav) return ERROR; evalNodeProlog(0); //new current frame pointer makeRoomForSlots(1); //always 1 slot for ptr EvalStatus evs = m_nodeLeft->evalToStoreInto(); if(evs != NORMAL) { evalNodeEpilog(); return evs; } UlamValue pluv = m_state.m_nodeEvalStack.popArg(); UTI ltype = pluv.getPtrTargetType(); //could be a custom array which is a scalar quark. already checked. UlamType * lut = m_state.getUlamTypeByIndex(ltype); bool isCustomArray = lut->isCustomArray(); assert(!m_state.isScalar(ltype) || isCustomArray); //already checked, must be array makeRoomForNodeType(m_nodeRight->getNodeType()); //offset a constant expression evs = m_nodeRight->eval(); if(evs != NORMAL) { evalNodeEpilog(); return evs; } UlamValue offset = m_state.m_nodeEvalStack.popArg(); UlamType * offut = m_state.getUlamTypeByIndex(offset.getUlamValueTypeIdx()); s32 offsetInt = 0; if(offut->isNumericType()) { // constant expression only required for array declaration s32 arraysize = m_state.getArraySize(ltype); u32 offsetdata = offset.getImmediateData(m_state); offsetInt = offut->getDataAsCs32(offsetdata); if((offsetInt >= arraysize) && !isCustomArray) { Symbol * lsymptr; u32 lid = 0; if(getSymbolPtr(lsymptr)) lid = lsymptr->getId(); std::ostringstream msg; msg << "Array subscript [" << offsetInt << "] exceeds the size (" << arraysize; msg << ") of array '" << m_state.m_pool.getDataAsString(lid).c_str() << "'"; MSG(getNodeLocationAsString().c_str(), msg.str().c_str(), ERR); evalNodeEpilog(); return ERROR; } } else if(!isCustomArray) { Symbol * lsymptr; u32 lid = 0; if(getSymbolPtr(lsymptr)) lid = lsymptr->getId(); std::ostringstream msg; msg << "Array subscript of array '"; msg << m_state.m_pool.getDataAsString(lid).c_str(); msg << "' requires a numeric type"; MSG(getNodeLocationAsString().c_str(), msg.str().c_str(), ERR); evalNodeEpilog(); return ERROR; } assignReturnValueToStack(pluv.getValAt(offsetInt, m_state)); evalNodeEpilog(); return NORMAL; } //eval