@@ -31,6 +31,8 @@ bool ConstantExprLowering::runOnFunction(Function& F, bool& hasI64, const Target
3131 bool Changed = false ;
3232 hasI64 = false ;
3333
34+ Module* M = F.getParent ();
35+ Function* getThreadLocalAddress = M->getFunction (" __getThreadLocalAddress" );
3436 DL = &F.getParent ()->getDataLayout ();
3537
3638 std::set<ConstantExpr*> visitedCE;
@@ -102,28 +104,55 @@ bool ConstantExprLowering::runOnFunction(Function& F, bool& hasI64, const Target
102104
103105 std::map<ConstantExpr*, Value*> mapCEToValue;
104106 std::map<GlobalValue*, Instruction*> mapGVToInst;
107+ // This is the insert point for the instructionized CEs. We update it so that
108+ // new ones are inserted before earlier ones.
109+ Instruction* ceInsertPt = F.getEntryBlock ().getFirstNonPHI ();
105110
106111 // 2. Iterate on the collected ConstantExpr, converting them to Instructions
107112 // Note that given the specific order of the visit, operands will be processed later (= will end up dominating their users)
108113 for (ConstantExpr* CE : toBeInstructionized)
109114 {
110115 Instruction* Conv = CE->getAsInstruction ();
116+ Conv->insertBefore (ceInsertPt);
117+ ceInsertPt = Conv;
111118 for (auto & O: Conv->operands ())
112119 {
120+ // 3. Process non-CE operands if needed. New instructions created
121+ // here go before all the CE instructions
113122 Value* NewC = O.get ();
114123 if (auto *GV = dyn_cast<GlobalVariable>(NewC))
115124 {
116125 // In asmjs, addresses of globals are just integers
117126 // Ask LinearMemoryHelper for the value and cast to the pointer type
118127 if (!WasmSharedModule && GV->GlobalValue ::getSection () == StringRef (" asmjs" ) && !GV->isThreadLocal ())
119128 {
120- if (mapGVToInst.count (GV) == 0 )
129+ auto it = mapGVToInst.find (GV);
130+ if (it == mapGVToInst.end ())
121131 {
122132 auto *CI = ConstantInt::get (IntegerType::get (Conv->getContext (), 32 ), LH->getGlobalVariableAddress (GV));
123- mapGVToInst[GV] = CastInst::Create (Instruction::IntToPtr, CI, NewC->getType ());
133+ it = mapGVToInst.emplace (GV, CastInst::Create (Instruction::IntToPtr, CI, NewC->getType ())).first ;
134+ // Insert before all the CEs
135+ it->second ->insertBefore (F.getEntryBlock ().getFirstNonPHI ());
124136 }
125-
126- NewC = mapGVToInst.at (GV);
137+ NewC = it->second ;
138+ }
139+ else if (GV->isThreadLocal () && F.getSection () != " asmjs" )
140+ {
141+ auto it = mapGVToInst.find (GV);
142+ if (it == mapGVToInst.end ())
143+ {
144+ // Insert before all the CEs
145+ Instruction* insertPt = F.getEntryBlock ().getFirstNonPHI ();
146+ // Access thread locals via the __getThreadLocalAddress wrapper
147+ Type* argTy = GV->getType ();
148+ Function* getThreadLocalOffset = Intrinsic::getDeclaration (M, Intrinsic::cheerp_get_threadlocal_offset, argTy);
149+ auto * offset = CallInst::Create (getThreadLocalOffset, {GV}, " tl.offset" , insertPt);
150+ Instruction* addr = CallInst::Create (getThreadLocalAddress, {offset}, " tl.addr" , insertPt);
151+ if (addr->getType () != GV->getType ())
152+ addr = CastInst::CreateBitOrPointerCast (addr, argTy, " tl.cast" , insertPt);
153+ it = mapGVToInst.emplace (GV, addr).first ;
154+ }
155+ NewC = it->second ;
127156 }
128157 }
129158 else if (isa<UndefValue>(NewC) && NewC->getType ()->isFloatingPointTy ())
@@ -134,17 +163,9 @@ bool ConstantExprLowering::runOnFunction(Function& F, bool& hasI64, const Target
134163 }
135164 O.set (NewC);
136165 }
137- Conv->insertBefore (F.getEntryBlock ().getFirstNonPHI ());
138166 Changed = true ;
139167 mapCEToValue[CE] = Conv;
140168 }
141-
142- // 3. Insert also PtrToIntInst that has been created while folding GV
143- for (auto & pair : mapGVToInst)
144- {
145- pair.second ->insertBefore (F.getEntryBlock ().getFirstNonPHI ());
146- }
147-
148169 // 4. Actually substitute any ConstantExpr operand with the mapped Instruction (that will be in the Function entry BB)
149170 std::map<ConstantVector*, Value*> mapCVToValue;
150171 for (Instruction& I : instructions (F))
0 commit comments