mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-02-23 07:03:13 +01:00
[svn r86] Changed the way arguments are given storage. It is now detected if they will need it during semantic passes.
Initial support for debug information. Very limited, but MUCH better than nothing :)
This commit is contained in:
1
demos/readme.txt
Normal file
1
demos/readme.txt
Normal file
@@ -0,0 +1 @@
|
||||
use rebuild with -dc=llvmdc-posix to build the demos
|
||||
@@ -552,6 +552,7 @@ VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer
|
||||
llvmNestedIndex = -1;
|
||||
llvmFieldIndex = -1;
|
||||
llvmFieldIndexOffset = 0;
|
||||
llvmNeedsStorage = false;
|
||||
}
|
||||
|
||||
Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s)
|
||||
|
||||
@@ -262,6 +262,7 @@ struct VarDeclaration : Declaration
|
||||
int llvmNestedIndex;
|
||||
int llvmFieldIndex;
|
||||
size_t llvmFieldIndexOffset;
|
||||
bool llvmNeedsStorage;
|
||||
};
|
||||
|
||||
/**************************************************************/
|
||||
@@ -525,6 +526,7 @@ struct FuncDeclaration : Declaration
|
||||
llvm::Value* llvmNested;
|
||||
llvm::Value* llvmArguments;
|
||||
llvm::Value* llvmArgPtr;
|
||||
llvm::Constant* llvmDwarfSubProgram;
|
||||
};
|
||||
|
||||
struct FuncAliasDeclaration : FuncDeclaration
|
||||
|
||||
@@ -3445,7 +3445,10 @@ Expression *SymOffExp::semantic(Scope *sc)
|
||||
type = var->type->pointerTo();
|
||||
VarDeclaration *v = var->isVarDeclaration();
|
||||
if (v)
|
||||
v->checkNestedReference(sc, loc);
|
||||
{
|
||||
v->checkNestedReference(sc, loc);
|
||||
v->llvmNeedsStorage = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -3589,6 +3592,7 @@ Expression *VarExp::modifiableLvalue(Scope *sc, Expression *e)
|
||||
if (v && v->canassign == 0 &&
|
||||
(var->isConst() || (global.params.Dversion > 1 && var->isFinal())))
|
||||
error("cannot modify final variable '%s'", var->toChars());
|
||||
v->llvmNeedsStorage = true;
|
||||
|
||||
if (var->isCtorinit())
|
||||
{ // It's only modifiable if inside the right constructor
|
||||
|
||||
@@ -78,6 +78,7 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC s
|
||||
llvmNested = NULL;
|
||||
llvmArguments = NULL;
|
||||
llvmArgPtr = NULL;
|
||||
llvmDwarfSubProgram = NULL;
|
||||
}
|
||||
|
||||
Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s)
|
||||
|
||||
187
gen/dwarftypes.c
Normal file
187
gen/dwarftypes.c
Normal file
@@ -0,0 +1,187 @@
|
||||
// Generated by llvm2cpp - DO NOT MODIFY!
|
||||
|
||||
#include <llvm/Module.h>
|
||||
#include <llvm/DerivedTypes.h>
|
||||
#include <llvm/Constants.h>
|
||||
#include <llvm/GlobalVariable.h>
|
||||
#include <llvm/Function.h>
|
||||
#include <llvm/CallingConv.h>
|
||||
#include <llvm/BasicBlock.h>
|
||||
#include <llvm/Instructions.h>
|
||||
#include <llvm/InlineAsm.h>
|
||||
#include <llvm/ParameterAttributes.h>
|
||||
#include <llvm/Support/MathExtras.h>
|
||||
#include <llvm/Pass.h>
|
||||
#include <llvm/PassManager.h>
|
||||
#include <llvm/Analysis/Verifier.h>
|
||||
#include <llvm/Assembly/PrintModulePass.h>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
void RegisterDwarfSymbols(llvm::Module* mod) {
|
||||
using namespace llvm;
|
||||
// Type Definitions
|
||||
std::vector<const Type*>StructTy_llvm_dbg_anchor_type_fields;
|
||||
StructTy_llvm_dbg_anchor_type_fields.push_back(IntegerType::get(32));
|
||||
StructTy_llvm_dbg_anchor_type_fields.push_back(IntegerType::get(32));
|
||||
StructType* StructTy_llvm_dbg_anchor_type = StructType::get(StructTy_llvm_dbg_anchor_type_fields, /*isPacked=*/false);
|
||||
mod->addTypeName("llvm.dbg.anchor.type", StructTy_llvm_dbg_anchor_type);
|
||||
|
||||
std::vector<const Type*>StructTy_llvm_dbg_basictype_type_fields;
|
||||
StructTy_llvm_dbg_basictype_type_fields.push_back(IntegerType::get(32));
|
||||
std::vector<const Type*>StructTy_1_fields;
|
||||
StructType* StructTy_1 = StructType::get(StructTy_1_fields, /*isPacked=*/false);
|
||||
|
||||
PointerType* PointerTy_0 = PointerType::get(StructTy_1);
|
||||
|
||||
StructTy_llvm_dbg_basictype_type_fields.push_back(PointerTy_0);
|
||||
PointerType* PointerTy_2 = PointerType::get(IntegerType::get(8));
|
||||
|
||||
StructTy_llvm_dbg_basictype_type_fields.push_back(PointerTy_2);
|
||||
StructTy_llvm_dbg_basictype_type_fields.push_back(PointerTy_0);
|
||||
StructTy_llvm_dbg_basictype_type_fields.push_back(IntegerType::get(32));
|
||||
StructTy_llvm_dbg_basictype_type_fields.push_back(IntegerType::get(64));
|
||||
StructTy_llvm_dbg_basictype_type_fields.push_back(IntegerType::get(64));
|
||||
StructTy_llvm_dbg_basictype_type_fields.push_back(IntegerType::get(64));
|
||||
StructTy_llvm_dbg_basictype_type_fields.push_back(IntegerType::get(32));
|
||||
StructTy_llvm_dbg_basictype_type_fields.push_back(IntegerType::get(32));
|
||||
StructType* StructTy_llvm_dbg_basictype_type = StructType::get(StructTy_llvm_dbg_basictype_type_fields, /*isPacked=*/false);
|
||||
mod->addTypeName("llvm.dbg.basictype.type", StructTy_llvm_dbg_basictype_type);
|
||||
|
||||
std::vector<const Type*>StructTy_llvm_dbg_compile_unit_type_fields;
|
||||
StructTy_llvm_dbg_compile_unit_type_fields.push_back(IntegerType::get(32));
|
||||
StructTy_llvm_dbg_compile_unit_type_fields.push_back(PointerTy_0);
|
||||
StructTy_llvm_dbg_compile_unit_type_fields.push_back(IntegerType::get(32));
|
||||
StructTy_llvm_dbg_compile_unit_type_fields.push_back(PointerTy_2);
|
||||
StructTy_llvm_dbg_compile_unit_type_fields.push_back(PointerTy_2);
|
||||
StructTy_llvm_dbg_compile_unit_type_fields.push_back(PointerTy_2);
|
||||
StructType* StructTy_llvm_dbg_compile_unit_type = StructType::get(StructTy_llvm_dbg_compile_unit_type_fields, /*isPacked=*/false);
|
||||
mod->addTypeName("llvm.dbg.compile_unit.type", StructTy_llvm_dbg_compile_unit_type);
|
||||
|
||||
std::vector<const Type*>StructTy_llvm_dbg_compositetype_type_fields;
|
||||
StructTy_llvm_dbg_compositetype_type_fields.push_back(IntegerType::get(32));
|
||||
StructTy_llvm_dbg_compositetype_type_fields.push_back(PointerTy_0);
|
||||
StructTy_llvm_dbg_compositetype_type_fields.push_back(PointerTy_2);
|
||||
StructTy_llvm_dbg_compositetype_type_fields.push_back(PointerTy_0);
|
||||
StructTy_llvm_dbg_compositetype_type_fields.push_back(IntegerType::get(32));
|
||||
StructTy_llvm_dbg_compositetype_type_fields.push_back(IntegerType::get(64));
|
||||
StructTy_llvm_dbg_compositetype_type_fields.push_back(IntegerType::get(64));
|
||||
StructTy_llvm_dbg_compositetype_type_fields.push_back(IntegerType::get(64));
|
||||
StructTy_llvm_dbg_compositetype_type_fields.push_back(IntegerType::get(32));
|
||||
StructTy_llvm_dbg_compositetype_type_fields.push_back(PointerTy_0);
|
||||
StructTy_llvm_dbg_compositetype_type_fields.push_back(PointerTy_0);
|
||||
StructType* StructTy_llvm_dbg_compositetype_type = StructType::get(StructTy_llvm_dbg_compositetype_type_fields, /*isPacked=*/false);
|
||||
mod->addTypeName("llvm.dbg.compositetype.type", StructTy_llvm_dbg_compositetype_type);
|
||||
|
||||
std::vector<const Type*>StructTy_llvm_dbg_derivedtype_type_fields;
|
||||
StructTy_llvm_dbg_derivedtype_type_fields.push_back(IntegerType::get(32));
|
||||
StructTy_llvm_dbg_derivedtype_type_fields.push_back(PointerTy_0);
|
||||
StructTy_llvm_dbg_derivedtype_type_fields.push_back(PointerTy_2);
|
||||
StructTy_llvm_dbg_derivedtype_type_fields.push_back(PointerTy_0);
|
||||
StructTy_llvm_dbg_derivedtype_type_fields.push_back(IntegerType::get(32));
|
||||
StructTy_llvm_dbg_derivedtype_type_fields.push_back(IntegerType::get(64));
|
||||
StructTy_llvm_dbg_derivedtype_type_fields.push_back(IntegerType::get(64));
|
||||
StructTy_llvm_dbg_derivedtype_type_fields.push_back(IntegerType::get(64));
|
||||
StructTy_llvm_dbg_derivedtype_type_fields.push_back(IntegerType::get(32));
|
||||
StructTy_llvm_dbg_derivedtype_type_fields.push_back(PointerTy_0);
|
||||
StructType* StructTy_llvm_dbg_derivedtype_type = StructType::get(StructTy_llvm_dbg_derivedtype_type_fields, /*isPacked=*/false);
|
||||
mod->addTypeName("llvm.dbg.derivedtype.type", StructTy_llvm_dbg_derivedtype_type);
|
||||
|
||||
std::vector<const Type*>StructTy_llvm_dbg_global_variable_type_fields;
|
||||
StructTy_llvm_dbg_global_variable_type_fields.push_back(IntegerType::get(32));
|
||||
StructTy_llvm_dbg_global_variable_type_fields.push_back(PointerTy_0);
|
||||
StructTy_llvm_dbg_global_variable_type_fields.push_back(PointerTy_0);
|
||||
StructTy_llvm_dbg_global_variable_type_fields.push_back(PointerTy_2);
|
||||
StructTy_llvm_dbg_global_variable_type_fields.push_back(PointerTy_2);
|
||||
StructTy_llvm_dbg_global_variable_type_fields.push_back(PointerTy_2);
|
||||
StructTy_llvm_dbg_global_variable_type_fields.push_back(PointerTy_0);
|
||||
StructTy_llvm_dbg_global_variable_type_fields.push_back(IntegerType::get(32));
|
||||
StructTy_llvm_dbg_global_variable_type_fields.push_back(PointerTy_0);
|
||||
StructTy_llvm_dbg_global_variable_type_fields.push_back(IntegerType::get(1));
|
||||
StructTy_llvm_dbg_global_variable_type_fields.push_back(IntegerType::get(1));
|
||||
StructTy_llvm_dbg_global_variable_type_fields.push_back(PointerTy_0);
|
||||
StructType* StructTy_llvm_dbg_global_variable_type = StructType::get(StructTy_llvm_dbg_global_variable_type_fields, /*isPacked=*/false);
|
||||
mod->addTypeName("llvm.dbg.global_variable.type", StructTy_llvm_dbg_global_variable_type);
|
||||
|
||||
std::vector<const Type*>StructTy_llvm_dbg_subprogram_type_fields;
|
||||
StructTy_llvm_dbg_subprogram_type_fields.push_back(IntegerType::get(32));
|
||||
StructTy_llvm_dbg_subprogram_type_fields.push_back(PointerTy_0);
|
||||
StructTy_llvm_dbg_subprogram_type_fields.push_back(PointerTy_0);
|
||||
StructTy_llvm_dbg_subprogram_type_fields.push_back(PointerTy_2);
|
||||
StructTy_llvm_dbg_subprogram_type_fields.push_back(PointerTy_2);
|
||||
StructTy_llvm_dbg_subprogram_type_fields.push_back(PointerTy_2);
|
||||
StructTy_llvm_dbg_subprogram_type_fields.push_back(PointerTy_0);
|
||||
StructTy_llvm_dbg_subprogram_type_fields.push_back(IntegerType::get(32));
|
||||
StructTy_llvm_dbg_subprogram_type_fields.push_back(PointerTy_0);
|
||||
StructTy_llvm_dbg_subprogram_type_fields.push_back(IntegerType::get(1));
|
||||
StructTy_llvm_dbg_subprogram_type_fields.push_back(IntegerType::get(1));
|
||||
StructType* StructTy_llvm_dbg_subprogram_type = StructType::get(StructTy_llvm_dbg_subprogram_type_fields, /*isPacked=*/false);
|
||||
mod->addTypeName("llvm.dbg.subprogram.type", StructTy_llvm_dbg_subprogram_type);
|
||||
|
||||
std::vector<const Type*>StructTy_llvm_dbg_variable_type_fields;
|
||||
StructTy_llvm_dbg_variable_type_fields.push_back(IntegerType::get(32));
|
||||
StructTy_llvm_dbg_variable_type_fields.push_back(PointerTy_0);
|
||||
StructTy_llvm_dbg_variable_type_fields.push_back(PointerTy_2);
|
||||
StructTy_llvm_dbg_variable_type_fields.push_back(PointerTy_0);
|
||||
StructTy_llvm_dbg_variable_type_fields.push_back(IntegerType::get(32));
|
||||
StructTy_llvm_dbg_variable_type_fields.push_back(PointerTy_0);
|
||||
StructType* StructTy_llvm_dbg_variable_type = StructType::get(StructTy_llvm_dbg_variable_type_fields, /*isPacked=*/false);
|
||||
mod->addTypeName("llvm.dbg.variable.type", StructTy_llvm_dbg_variable_type);
|
||||
|
||||
std::vector<const Type*>FuncTy_3_args;
|
||||
FuncTy_3_args.push_back(PointerTy_0);
|
||||
ParamAttrsList *FuncTy_3_PAL = 0;
|
||||
FunctionType* FuncTy_3 = FunctionType::get(
|
||||
/*Result=*/Type::VoidTy,
|
||||
/*Params=*/FuncTy_3_args,
|
||||
/*isVarArg=*/false,
|
||||
/*ParamAttrs=*/FuncTy_3_PAL);
|
||||
|
||||
std::vector<const Type*>FuncTy_4_args;
|
||||
FuncTy_4_args.push_back(IntegerType::get(32));
|
||||
FuncTy_4_args.push_back(IntegerType::get(32));
|
||||
FuncTy_4_args.push_back(PointerTy_0);
|
||||
ParamAttrsList *FuncTy_4_PAL = 0;
|
||||
FunctionType* FuncTy_4 = FunctionType::get(
|
||||
/*Result=*/Type::VoidTy,
|
||||
/*Params=*/FuncTy_4_args,
|
||||
/*isVarArg=*/false,
|
||||
/*ParamAttrs=*/FuncTy_4_PAL);
|
||||
|
||||
std::vector<const Type*>FuncTy_5_args;
|
||||
FuncTy_5_args.push_back(PointerTy_0);
|
||||
FuncTy_5_args.push_back(PointerTy_0);
|
||||
ParamAttrsList *FuncTy_5_PAL = 0;
|
||||
FunctionType* FuncTy_5 = FunctionType::get(
|
||||
/*Result=*/Type::VoidTy,
|
||||
/*Params=*/FuncTy_5_args,
|
||||
/*isVarArg=*/false,
|
||||
/*ParamAttrs=*/FuncTy_5_PAL);
|
||||
|
||||
|
||||
// Function Declarations
|
||||
|
||||
Function* func_llvm_dbg_func_start = new Function(
|
||||
/*Type=*/FuncTy_3,
|
||||
/*Linkage=*/GlobalValue::ExternalLinkage,
|
||||
/*Name=*/"llvm.dbg.func.start", mod); // (external, no body)
|
||||
func_llvm_dbg_func_start->setCallingConv(CallingConv::C);
|
||||
|
||||
Function* func_llvm_dbg_stoppoint = new Function(
|
||||
/*Type=*/FuncTy_4,
|
||||
/*Linkage=*/GlobalValue::ExternalLinkage,
|
||||
/*Name=*/"llvm.dbg.stoppoint", mod); // (external, no body)
|
||||
func_llvm_dbg_stoppoint->setCallingConv(CallingConv::C);
|
||||
|
||||
Function* func_llvm_dbg_declare = new Function(
|
||||
/*Type=*/FuncTy_5,
|
||||
/*Linkage=*/GlobalValue::ExternalLinkage,
|
||||
/*Name=*/"llvm.dbg.declare", mod); // (external, no body)
|
||||
func_llvm_dbg_declare->setCallingConv(CallingConv::C);
|
||||
|
||||
Function* func_llvm_dbg_region_end = new Function(
|
||||
/*Type=*/FuncTy_3,
|
||||
/*Linkage=*/GlobalValue::ExternalLinkage,
|
||||
/*Name=*/"llvm.dbg.region.end", mod); // (external, no body)
|
||||
func_llvm_dbg_region_end->setCallingConv(CallingConv::C);
|
||||
}
|
||||
@@ -38,6 +38,7 @@ IRState::IRState()
|
||||
emitMain = false;
|
||||
mainFunc = 0;
|
||||
ir.state = this;
|
||||
dwarfCompileUnit = 0;
|
||||
}
|
||||
|
||||
IRFunction& IRState::func()
|
||||
|
||||
@@ -162,6 +162,9 @@ struct IRState
|
||||
|
||||
// builder helper
|
||||
IRBuilderHelper ir;
|
||||
|
||||
// Dwarf debugging info
|
||||
llvm::GlobalVariable* dwarfCompileUnit;
|
||||
};
|
||||
|
||||
#endif // LLVMDC_GEN_IRSTATE_H
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "gen/tollvm.h"
|
||||
#include "gen/runtime.h"
|
||||
#include "gen/arrays.h"
|
||||
#include "gen/todebug.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -63,6 +64,8 @@ void ReturnStatement::toIR(IRState* p)
|
||||
TypeFunction* f = p->topfunctype();
|
||||
assert(f->llvmRetInPtr && f->llvmRetArg);
|
||||
|
||||
if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum);
|
||||
|
||||
p->exps.push_back(IRExp(NULL,exp,f->llvmRetArg));
|
||||
elem* e = exp->toElem(p);
|
||||
p->exps.pop_back();
|
||||
@@ -93,14 +96,17 @@ void ReturnStatement::toIR(IRState* p)
|
||||
assert(0);
|
||||
|
||||
IRFunction::FinallyVec& fin = p->func().finallys;
|
||||
if (fin.empty())
|
||||
if (fin.empty()) {
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(p->func().decl);
|
||||
new llvm::ReturnInst(p->scopebb());
|
||||
}
|
||||
else {
|
||||
new llvm::BranchInst(fin.back().retbb, p->scopebb());
|
||||
}
|
||||
delete e;
|
||||
}
|
||||
else {
|
||||
if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum);
|
||||
elem* e = exp->toElem(p);
|
||||
llvm::Value* v = e->getValue();
|
||||
delete e;
|
||||
@@ -108,6 +114,7 @@ void ReturnStatement::toIR(IRState* p)
|
||||
|
||||
IRFunction::FinallyVec& fin = p->func().finallys;
|
||||
if (fin.empty()) {
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(p->func().decl);
|
||||
new llvm::ReturnInst(v, p->scopebb());
|
||||
}
|
||||
else {
|
||||
@@ -124,6 +131,7 @@ void ReturnStatement::toIR(IRState* p)
|
||||
if (p->topfunc()->getReturnType() == llvm::Type::VoidTy) {
|
||||
IRFunction::FinallyVec& fin = p->func().finallys;
|
||||
if (fin.empty()) {
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(p->func().decl);
|
||||
new llvm::ReturnInst(p->scopebb());
|
||||
}
|
||||
else {
|
||||
@@ -145,6 +153,9 @@ void ExpStatement::toIR(IRState* p)
|
||||
Logger::println("ExpStatement::toIR(%d): %s", esi++, toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
|
||||
if (exp != 0) {
|
||||
elem* e = exp->toElem(p);
|
||||
delete e;
|
||||
@@ -473,6 +484,7 @@ void TryFinallyStatement::toIR(IRState* p)
|
||||
// no outer
|
||||
else
|
||||
{
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(p->func().decl);
|
||||
llvm::Value* retval = p->func().finallyretval;
|
||||
if (retval) {
|
||||
retval = p->ir->CreateLoad(retval,"tmp");
|
||||
|
||||
183
gen/todebug.c
Normal file
183
gen/todebug.c
Normal file
@@ -0,0 +1,183 @@
|
||||
#include "gen/llvm.h"
|
||||
#include "llvm/Support/Dwarf.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
|
||||
#include "declaration.h"
|
||||
#include "module.h"
|
||||
#include "mars.h"
|
||||
|
||||
#include "gen/todebug.h"
|
||||
#include "gen/irstate.h"
|
||||
#include "gen/tollvm.h"
|
||||
#include "gen/logger.h"
|
||||
|
||||
using namespace llvm::dwarf;
|
||||
|
||||
static const llvm::PointerType* ptrTy(const llvm::Type* t)
|
||||
{
|
||||
return llvm::PointerType::get(t);
|
||||
}
|
||||
|
||||
static const llvm::PointerType* dbgArrTy()
|
||||
{
|
||||
std::vector<const llvm::Type*> t;
|
||||
return ptrTy(llvm::StructType::get(t));
|
||||
}
|
||||
|
||||
static llvm::Constant* dbgToArrTy(llvm::Constant* c)
|
||||
{
|
||||
Logger::cout() << "casting: " << *c << '\n';
|
||||
return llvm::ConstantExpr::getBitCast(c, dbgArrTy());
|
||||
}
|
||||
|
||||
#define Ty(X) llvm::Type::X
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static llvm::GlobalVariable* dbg_compile_units = 0;
|
||||
static llvm::GlobalVariable* dbg_global_variables = 0;
|
||||
static llvm::GlobalVariable* dbg_subprograms = 0;
|
||||
|
||||
const llvm::StructType* GetDwarfAnchorType()
|
||||
{
|
||||
/*
|
||||
%llvm.dbg.anchor.type = type {
|
||||
uint, ;; Tag = 0 + LLVMDebugVersion
|
||||
uint ;; Tag of descriptors grouped by the anchor
|
||||
}
|
||||
*/
|
||||
std::vector<const llvm::Type*> elems(2, Ty(Int32Ty));
|
||||
const llvm::StructType* t = llvm::cast<llvm::StructType>(gIR->module->getTypeByName("llvm.dbg.anchor.type"));
|
||||
|
||||
/*
|
||||
%llvm.dbg.compile_units = linkonce constant %llvm.dbg.anchor.type { uint 0, uint 17 } ;; DW_TAG_compile_unit
|
||||
%llvm.dbg.global_variables = linkonce constant %llvm.dbg.anchor.type { uint 0, uint 52 } ;; DW_TAG_variable
|
||||
%llvm.dbg.subprograms = linkonce constant %llvm.dbg.anchor.type { uint 0, uint 46 } ;; DW_TAG_subprogram
|
||||
*/
|
||||
if (!gIR->module->getNamedGlobal("llvm.dbg.compile_units")) {
|
||||
std::vector<llvm::Constant*> vals;
|
||||
vals.push_back(DtoConstUint(0));
|
||||
vals.push_back(DtoConstUint(DW_TAG_compile_unit));
|
||||
llvm::Constant* i = llvm::ConstantStruct::get(t, vals);
|
||||
dbg_compile_units = new llvm::GlobalVariable(t,true,llvm::GlobalValue::LinkOnceLinkage,i,"llvm.dbg.compile_units",gIR->module);
|
||||
dbg_compile_units->setSection("llvm.metadata");
|
||||
}
|
||||
if (!gIR->module->getNamedGlobal("llvm.dbg.global_variables")) {
|
||||
std::vector<llvm::Constant*> vals;
|
||||
vals.push_back(DtoConstUint(0));
|
||||
vals.push_back(DtoConstUint(DW_TAG_variable));
|
||||
llvm::Constant* i = llvm::ConstantStruct::get(t, vals);
|
||||
dbg_global_variables = new llvm::GlobalVariable(t,true,llvm::GlobalValue::LinkOnceLinkage,i,"llvm.dbg.global_variables",gIR->module);
|
||||
dbg_global_variables->setSection("llvm.metadata");
|
||||
}
|
||||
if (!gIR->module->getNamedGlobal("llvm.dbg.subprograms")) {
|
||||
std::vector<llvm::Constant*> vals;
|
||||
vals.push_back(DtoConstUint(0));
|
||||
vals.push_back(DtoConstUint(DW_TAG_subprogram));
|
||||
llvm::Constant* i = llvm::ConstantStruct::get(t, vals);
|
||||
dbg_subprograms = new llvm::GlobalVariable(t,true,llvm::GlobalValue::LinkOnceLinkage,i,"llvm.dbg.subprograms",gIR->module);
|
||||
dbg_subprograms->setSection("llvm.metadata");
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
llvm::Constant* GetDwarfAnchor(llvm::dwarf::dwarf_constants c)
|
||||
{
|
||||
GetDwarfAnchorType();
|
||||
switch (c)
|
||||
{
|
||||
case DW_TAG_compile_unit:
|
||||
return dbg_compile_units;
|
||||
case DW_TAG_variable:
|
||||
return dbg_global_variables;
|
||||
case DW_TAG_subprogram:
|
||||
return dbg_subprograms;
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const llvm::StructType* GetDwarfCompileUnitType() {
|
||||
return llvm::cast<llvm::StructType>(gIR->module->getTypeByName("llvm.dbg.compile_unit.type"));
|
||||
}
|
||||
|
||||
const llvm::StructType* GetDwarfSubProgramType() {
|
||||
return llvm::cast<llvm::StructType>(gIR->module->getTypeByName("llvm.dbg.subprogram.type"));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
llvm::GlobalVariable* DtoDwarfCompileUnit(Module* m)
|
||||
{
|
||||
std::vector<llvm::Constant*> vals;
|
||||
vals.push_back(llvm::ConstantExpr::getAdd(
|
||||
DtoConstUint(DW_TAG_compile_unit),
|
||||
DtoConstUint(llvm::LLVMDebugVersion)));
|
||||
vals.push_back(dbgToArrTy(GetDwarfAnchor(DW_TAG_compile_unit)));
|
||||
|
||||
vals.push_back(DtoConstUint(DW_LANG_D));
|
||||
vals.push_back(DtoConstStringPtr(m->srcfile->name->toChars(), "llvm.metadata"));
|
||||
std::string srcpath(FileName::path(m->srcfile->name->toChars()));
|
||||
srcpath.append("/");
|
||||
vals.push_back(DtoConstStringPtr(srcpath.c_str(), "llvm.metadata"));
|
||||
vals.push_back(DtoConstStringPtr("LLVMDC (http://www.dsource.org/projects/llvmdc)", "llvm.metadata"));
|
||||
|
||||
llvm::Constant* c = llvm::ConstantStruct::get(GetDwarfCompileUnitType(), vals);
|
||||
llvm::GlobalVariable* gv = new llvm::GlobalVariable(c->getType(), true, llvm::GlobalValue::InternalLinkage, c, "llvm.dbg.compile_unit", gIR->module);
|
||||
gv->setSection("llvm.metadata");
|
||||
return gv;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
llvm::GlobalVariable* DtoDwarfSubProgram(FuncDeclaration* fd)
|
||||
{
|
||||
std::vector<llvm::Constant*> vals;
|
||||
vals.push_back(llvm::ConstantExpr::getAdd(
|
||||
DtoConstUint(DW_TAG_subprogram),
|
||||
DtoConstUint(llvm::LLVMDebugVersion)));
|
||||
vals.push_back(dbgToArrTy(GetDwarfAnchor(DW_TAG_subprogram)));
|
||||
|
||||
vals.push_back(dbgToArrTy(gIR->dwarfCompileUnit));
|
||||
vals.push_back(DtoConstStringPtr(fd->toPrettyChars(), "llvm.metadata"));
|
||||
vals.push_back(DtoConstStringPtr(fd->mangle(), "llvm.metadata"));
|
||||
vals.push_back(llvm::ConstantPointerNull::get(llvm::PointerType::get(llvm::Type::Int8Ty)));
|
||||
vals.push_back(dbgToArrTy(gIR->dwarfCompileUnit));
|
||||
vals.push_back(DtoConstUint(fd->loc.linnum));
|
||||
vals.push_back(llvm::ConstantPointerNull::get(dbgArrTy()));
|
||||
vals.push_back(DtoConstBool(fd->protection == PROTprivate));
|
||||
vals.push_back(DtoConstBool(fd->getModule() == gIR->dmodule));
|
||||
|
||||
llvm::Constant* c = llvm::ConstantStruct::get(GetDwarfSubProgramType(), vals);
|
||||
llvm::GlobalVariable* gv = new llvm::GlobalVariable(c->getType(), true, llvm::GlobalValue::InternalLinkage, c, "llvm.dbg.subprogram", gIR->module);
|
||||
gv->setSection("llvm.metadata");
|
||||
return gv;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoDwarfFuncStart(FuncDeclaration* fd)
|
||||
{
|
||||
assert(fd->llvmDwarfSubProgram);
|
||||
gIR->ir->CreateCall(gIR->module->getFunction("llvm.dbg.func.start"), dbgToArrTy(fd->llvmDwarfSubProgram));
|
||||
}
|
||||
|
||||
void DtoDwarfFuncEnd(FuncDeclaration* fd)
|
||||
{
|
||||
assert(fd->llvmDwarfSubProgram);
|
||||
gIR->ir->CreateCall(gIR->module->getFunction("llvm.dbg.region.end"), dbgToArrTy(fd->llvmDwarfSubProgram));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoDwarfStopPoint(unsigned ln)
|
||||
{
|
||||
std::vector<llvm::Value*> args;
|
||||
args.push_back(DtoConstUint(ln));
|
||||
args.push_back(DtoConstUint(0));
|
||||
args.push_back(dbgToArrTy(gIR->dwarfCompileUnit));
|
||||
gIR->ir->CreateCall(gIR->module->getFunction("llvm.dbg.stoppoint"), args.begin(), args.end());
|
||||
}
|
||||
20
gen/todebug.h
Normal file
20
gen/todebug.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef LLVMDC_GEN_TODEBUG_H
|
||||
#define LLVMDC_GEN_TODEBUG_H
|
||||
|
||||
void RegisterDwarfSymbols(llvm::Module* mod);
|
||||
|
||||
const llvm::StructType* GetDwarfAnchorType();
|
||||
const llvm::StructType* GetDwarfCompileUnitType();
|
||||
const llvm::StructType* GetDwarfSubProgramType();
|
||||
|
||||
llvm::GlobalVariable* DtoDwarfCompileUnit(Module* m);
|
||||
llvm::GlobalVariable* DtoDwarfSubProgram(FuncDeclaration* fd);
|
||||
|
||||
void DtoDwarfFuncStart(FuncDeclaration* fd);
|
||||
void DtoDwarfFuncEnd(FuncDeclaration* fd);
|
||||
|
||||
void DtoDwarfStopPoint(unsigned ln);
|
||||
|
||||
#endif // LLVMDC_GEN_TODEBUG_H
|
||||
|
||||
|
||||
61
gen/toir.c
61
gen/toir.c
@@ -168,29 +168,17 @@ elem* VarExp::toElem(IRState* p)
|
||||
// this happens when the DMD frontend generates by pointer wrappers for struct opEquals(S) and opCmp(S)
|
||||
vd->llvmValue = &p->func().func->getArgumentList().back();
|
||||
}
|
||||
if (vd->isRef() || vd->isOut()) {
|
||||
if (vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type) || llvm::isa<llvm::AllocaInst>(vd->llvmValue)) {
|
||||
e->mem = vd->llvmValue;
|
||||
e->type = elem::VAR;
|
||||
e->vardecl = vd;
|
||||
}
|
||||
else {
|
||||
if (DtoIsPassedByRef(vd->type)) {
|
||||
e->mem = vd->llvmValue;
|
||||
e->type = elem::VAR;
|
||||
}
|
||||
else {
|
||||
if (llvm::isa<llvm::Argument>(vd->llvmValue)) {
|
||||
e->val = vd->llvmValue;
|
||||
e->type = elem::VAL;
|
||||
e->vardecl = vd;
|
||||
}
|
||||
else if (llvm::isa<llvm::AllocaInst>(vd->llvmValue)) {
|
||||
e->mem = vd->llvmValue;
|
||||
e->type = elem::VAR;
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
else if (llvm::isa<llvm::Argument>(vd->llvmValue)) {
|
||||
e->val = vd->llvmValue;
|
||||
e->type = elem::VAL;
|
||||
e->vardecl = vd;
|
||||
}
|
||||
else assert(0);
|
||||
}
|
||||
else {
|
||||
// take care of forward references of global variables
|
||||
@@ -463,18 +451,6 @@ elem* AssignExp::toElem(IRState* p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// handle function argument - allocate temp storage for it :/ annoying
|
||||
if (l->mem == 0) {
|
||||
assert(l->val);
|
||||
if (llvm::isa<llvm::Argument>(l->val))
|
||||
DtoGiveArgumentStorage(l);
|
||||
else {
|
||||
Logger::cout() << "here it comes... " << *l->val << '\n';
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
//e->val = l->store(r->getValue());
|
||||
|
||||
Type* e1type = DtoDType(e1->type);
|
||||
Type* e2type = DtoDType(e2->type);
|
||||
TY e1ty = e1type->ty;
|
||||
@@ -689,8 +665,7 @@ elem* AddAssignExp::toElem(IRState* p)
|
||||
tmp = DtoPointedType(storeVal, tmp);
|
||||
}*/
|
||||
|
||||
if (l->mem == 0)
|
||||
DtoGiveArgumentStorage(l);
|
||||
assert(l->mem);
|
||||
new llvm::StoreInst(val,l->mem,p->scopebb());
|
||||
e->type = elem::VAR;
|
||||
|
||||
@@ -762,8 +737,7 @@ elem* MinAssignExp::toElem(IRState* p)
|
||||
tmp = DtoPointedType(storeVal, tmp);
|
||||
}*/
|
||||
|
||||
if (l->mem == 0)
|
||||
DtoGiveArgumentStorage(l);
|
||||
assert(l->mem);
|
||||
new llvm::StoreInst(tmp, l->mem, p->scopebb());
|
||||
|
||||
delete l;
|
||||
@@ -814,8 +788,7 @@ elem* MulAssignExp::toElem(IRState* p)
|
||||
tmp = DtoPointedType(storeVal, tmp);
|
||||
}*/
|
||||
|
||||
if (l->mem == 0)
|
||||
DtoGiveArgumentStorage(l);
|
||||
assert(l->mem);
|
||||
new llvm::StoreInst(tmp,l->mem,p->scopebb());
|
||||
|
||||
delete l;
|
||||
@@ -881,8 +854,7 @@ elem* DivAssignExp::toElem(IRState* p)
|
||||
tmp = DtoPointedType(storeVal, tmp);
|
||||
}*/
|
||||
|
||||
if (l->mem == 0)
|
||||
DtoGiveArgumentStorage(l);
|
||||
assert(l->mem);
|
||||
new llvm::StoreInst(tmp,l->mem,p->scopebb());
|
||||
|
||||
delete l;
|
||||
@@ -948,8 +920,7 @@ elem* ModAssignExp::toElem(IRState* p)
|
||||
tmp = DtoPointedType(storeVal, tmp);
|
||||
}*/
|
||||
|
||||
if (l->mem == 0)
|
||||
DtoGiveArgumentStorage(l);
|
||||
assert(l->mem);
|
||||
new llvm::StoreInst(tmp,l->mem,p->scopebb());
|
||||
|
||||
delete l;
|
||||
@@ -1020,7 +991,7 @@ elem* CallExp::toElem(IRState* p)
|
||||
va_magic = true;
|
||||
}
|
||||
else if (fn->funcdecl->llvmInternal == LLVMva_arg) {
|
||||
Argument* fnarg = Argument::getNth(tf->parameters, 0);
|
||||
//Argument* fnarg = Argument::getNth(tf->parameters, 0);
|
||||
Expression* exp = (Expression*)arguments->data[0];
|
||||
elem* expelem = exp->toElem(p);
|
||||
assert(expelem->mem);
|
||||
@@ -2158,8 +2129,7 @@ elem* PostExp::toElem(IRState* p)
|
||||
else
|
||||
assert(post);
|
||||
|
||||
if (l->mem == 0)
|
||||
DtoGiveArgumentStorage(l);
|
||||
assert(l->mem);
|
||||
new llvm::StoreInst(post,l->mem,p->scopebb());
|
||||
|
||||
delete l;
|
||||
@@ -2503,8 +2473,7 @@ elem* X##AssignExp::toElem(IRState* p) \
|
||||
llvm::Value* vval = v->getValue(); \
|
||||
assert(vval); \
|
||||
llvm::Value* tmp = llvm::BinaryOperator::create(llvm::Instruction::Y, uval, vval, "tmp", p->scopebb()); \
|
||||
if (u->mem == 0) \
|
||||
DtoGiveArgumentStorage(u); \
|
||||
assert(u->mem); \
|
||||
Logger::cout() << *tmp << '|' << *u->mem << '\n'; \
|
||||
new llvm::StoreInst(DtoPointedType(u->mem, tmp), u->mem, p->scopebb()); \
|
||||
delete u; \
|
||||
|
||||
26
gen/tollvm.c
26
gen/tollvm.c
@@ -482,6 +482,7 @@ llvm::Value* DtoStructZeroInit(llvm::Value* v)
|
||||
|
||||
llvm::Value* DtoStructCopy(llvm::Value* dst, llvm::Value* src)
|
||||
{
|
||||
Logger::cout() << "dst = " << *dst << " src = " << *src << '\n';
|
||||
assert(dst->getType() == src->getType());
|
||||
assert(gIR);
|
||||
|
||||
@@ -1093,20 +1094,6 @@ llvm::Function* DtoDeclareFunction(FuncDeclaration* fdecl)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoGiveArgumentStorage(elem* l)
|
||||
{
|
||||
assert(l->mem == 0);
|
||||
assert(l->val);
|
||||
assert(llvm::isa<llvm::Argument>(l->val));
|
||||
assert(l->vardecl != 0);
|
||||
|
||||
llvm::AllocaInst* allocainst = new llvm::AllocaInst(l->val->getType(), l->val->getName()+"_storage", gIR->topallocapoint());
|
||||
l->mem = allocainst;
|
||||
l->vardecl->llvmValue = l->mem;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
llvm::Value* DtoRealloc(llvm::Value* ptr, const llvm::Type* ty)
|
||||
{
|
||||
/*size_t sz = gTargetData->getTypeSize(ty);
|
||||
@@ -1235,7 +1222,6 @@ llvm::Value* DtoArgument(const llvm::Type* paramtype, Argument* fnarg, Expressio
|
||||
if (paramtype && retval->getType() != paramtype)
|
||||
{
|
||||
assert(retval->getType() == paramtype->getContainedType(0));
|
||||
DtoGiveArgumentStorage(arg);
|
||||
new llvm::StoreInst(retval, arg->mem, gIR->scopebb());
|
||||
retval = arg->mem;
|
||||
}
|
||||
@@ -1373,6 +1359,16 @@ llvm::Constant* DtoConstString(const char* str)
|
||||
llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2)
|
||||
);
|
||||
}
|
||||
llvm::Constant* DtoConstStringPtr(const char* str, const char* section)
|
||||
{
|
||||
std::string s(str);
|
||||
llvm::Constant* init = llvm::ConstantArray::get(s, true);
|
||||
llvm::GlobalVariable* gvar = new llvm::GlobalVariable(
|
||||
init->getType(), true,llvm::GlobalValue::InternalLinkage, init, "stringliteral", gIR->module);
|
||||
if (section) gvar->setSection(section);
|
||||
llvm::Constant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) };
|
||||
return llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -46,8 +46,6 @@ llvm::Value* DtoGEP(llvm::Value* ptr, const std::vector<unsigned>& src, const st
|
||||
llvm::Value* DtoGEPi(llvm::Value* ptr, unsigned i0, const std::string& var, llvm::BasicBlock* bb=NULL);
|
||||
llvm::Value* DtoGEPi(llvm::Value* ptr, unsigned i0, unsigned i1, const std::string& var, llvm::BasicBlock* bb=NULL);
|
||||
|
||||
void DtoGiveArgumentStorage(elem* e);
|
||||
|
||||
llvm::Value* DtoRealloc(llvm::Value* ptr, const llvm::Type* ty);
|
||||
llvm::Value* DtoRealloc(llvm::Value* ptr, llvm::Value* len);
|
||||
|
||||
@@ -63,6 +61,7 @@ llvm::ConstantInt* DtoConstSize_t(size_t);
|
||||
llvm::ConstantInt* DtoConstUint(unsigned i);
|
||||
llvm::ConstantInt* DtoConstInt(int i);
|
||||
llvm::Constant* DtoConstString(const char*);
|
||||
llvm::Constant* DtoConstStringPtr(const char* str, const char* section = 0);
|
||||
llvm::Constant* DtoConstBool(bool);
|
||||
|
||||
void DtoMemCpy(llvm::Value* dst, llvm::Value* src, llvm::Value* nbytes);
|
||||
|
||||
37
gen/toobj.c
37
gen/toobj.c
@@ -36,6 +36,7 @@
|
||||
#include "gen/logger.h"
|
||||
#include "gen/tollvm.h"
|
||||
#include "gen/arrays.h"
|
||||
#include "gen/todebug.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -75,6 +76,12 @@ Module::genobjfile()
|
||||
llvm::TargetMachine &targetMachine = *targetPtr.get();
|
||||
gTargetData = targetMachine.getTargetData();
|
||||
|
||||
// debug info
|
||||
if (global.params.symdebug) {
|
||||
RegisterDwarfSymbols(ir.module);
|
||||
ir.dwarfCompileUnit = DtoDwarfCompileUnit(this);
|
||||
}
|
||||
|
||||
// process module members
|
||||
for (int k=0; k < members->dim; k++) {
|
||||
Dsymbol* dsym = (Dsymbol*)(members->data[k]);
|
||||
@@ -750,6 +757,11 @@ void FuncDeclaration::toObjFile()
|
||||
return; // we wait with the definition as they might invoke a virtual method and the vtable is not yet complete
|
||||
}
|
||||
|
||||
// debug info
|
||||
if (global.params.symdebug) {
|
||||
llvmDwarfSubProgram = DtoDwarfSubProgram(this);
|
||||
}
|
||||
|
||||
assert(f->llvmType);
|
||||
const llvm::FunctionType* functype = llvm::cast<llvm::FunctionType>(llvmValue->getType()->getContainedType(0));
|
||||
|
||||
@@ -809,6 +821,29 @@ void FuncDeclaration::toObjFile()
|
||||
f->llvmAllocaPoint = new llvm::BitCastInst(llvm::ConstantInt::get(llvm::Type::Int32Ty,0,false),llvm::Type::Int32Ty,"alloca point",gIR->scopebb());
|
||||
gIR->func().allocapoint = f->llvmAllocaPoint;
|
||||
|
||||
// give arguments storage
|
||||
size_t n = Argument::dim(f->parameters);
|
||||
for (int i=0; i < n; ++i) {
|
||||
Argument* arg = Argument::getNth(f->parameters, i);
|
||||
if (arg && arg->vardecl) {
|
||||
VarDeclaration* vd = arg->vardecl;
|
||||
if (!vd->llvmNeedsStorage || vd->nestedref || vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type))
|
||||
continue;
|
||||
llvm::Value* a = vd->llvmValue;
|
||||
assert(a);
|
||||
std::string s(a->getName());
|
||||
Logger::println("giving argument '%s' storage", s.c_str());
|
||||
s.append("_storage");
|
||||
llvm::Value* v = new llvm::AllocaInst(a->getType(),s,f->llvmAllocaPoint);
|
||||
gIR->ir->CreateStore(a,v);
|
||||
vd->llvmValue = v;
|
||||
}
|
||||
else assert(0);
|
||||
}
|
||||
|
||||
// debug info
|
||||
if (global.params.symdebug) DtoDwarfFuncStart(this);
|
||||
|
||||
llvm::Value* parentNested = NULL;
|
||||
if (FuncDeclaration* fd = toParent()->isFuncDeclaration()) {
|
||||
parentNested = fd->llvmNested;
|
||||
@@ -866,7 +901,7 @@ void FuncDeclaration::toObjFile()
|
||||
if (!isMain()) {
|
||||
if (!gIR->scopereturned()) {
|
||||
// pass the previous block into this block
|
||||
//new llvm::BranchInst(irs.end, irs.begin);
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(this);
|
||||
if (func->getReturnType() == llvm::Type::VoidTy) {
|
||||
new llvm::ReturnInst(gIR->scopebb());
|
||||
}
|
||||
|
||||
15
test/bug47.d
Normal file
15
test/bug47.d
Normal file
@@ -0,0 +1,15 @@
|
||||
module bug47;
|
||||
|
||||
bool func(bool a, bool b)
|
||||
{
|
||||
if (a) b = false;
|
||||
return b;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
assert(func(0,0) == 0);
|
||||
assert(func(0,1) == 1);
|
||||
assert(func(1,0) == 0);
|
||||
assert(func(1,1) == 0);
|
||||
}
|
||||
12
test/fail1.d
Normal file
12
test/fail1.d
Normal file
@@ -0,0 +1,12 @@
|
||||
module fail1;
|
||||
|
||||
void func()
|
||||
{
|
||||
float* fp;
|
||||
float f = *fp;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
func();
|
||||
}
|
||||
Reference in New Issue
Block a user